19 |
*/ |
*/ |
20 |
|
|
21 |
/* |
/* |
22 |
* This file contains the code renders the graphics during the game. |
* This file contains the code renders the graphics during the game |
23 |
* This includes displaying the current landscape with all its objects |
* and in the editor. This includes displaying the current landscape |
24 |
* and the inventory at the bottom of the screen. |
* with all its objects and the inventory at the bottom of the screen. |
25 |
*/ |
*/ |
26 |
|
|
27 |
#include "display.hh" |
#include "display.hh" |
31 |
|
|
32 |
#include "px/sdl.hh" |
#include "px/sdl.hh" |
33 |
#include "px/px.hh" |
#include "px/px.hh" |
34 |
|
#include "px/tools.hh" |
35 |
|
|
36 |
#include <vector> |
#include <vector> |
37 |
#include <algorithm> |
#include <algorithm> |
46 |
using namespace enigma; |
using namespace enigma; |
47 |
|
|
48 |
#include "d_engine.hh" |
#include "d_engine.hh" |
49 |
|
#include "d_models.hh" |
50 |
#include "d_statusbar.hh" |
#include "d_statusbar.hh" |
51 |
|
|
52 |
//---------------------------------------- |
//---------------------------------------- |
69 |
static int TileHeight = 32; |
static int TileHeight = 32; |
70 |
|
|
71 |
static GameDisplay *gamedpy = 0; |
static GameDisplay *gamedpy = 0; |
|
// static DisplayEngine *engine = 0; |
|
|
|
|
|
static DL_Lines *line_layer = 0; |
|
|
static DL_Sprites *sprite_layer = 0; |
|
|
static DL_Shadows *shadow_layer = 0; |
|
|
|
|
|
namespace |
|
|
{ |
|
|
const SpriteId MAGIC_SPRITEID = 1000000; |
|
|
|
|
|
// Do not change the order of the following two variables! |
|
|
FieldArray fields(0,0); |
|
|
|
|
|
// Screen layout |
|
|
} |
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------- |
|
|
// HELPER FUNCTIONS |
|
|
//---------------------------------------------------------------------- |
|
|
|
|
|
void |
|
|
ModelLayer::maybe_redraw_model(Model *m) |
|
|
{ |
|
|
WorldArea wa; |
|
|
if (m->has_changed(wa)) { |
|
|
get_engine()->mark_update_area(wa); |
|
|
} |
|
|
} |
|
|
|
|
|
void |
|
|
ModelLayer::activate (Model *m) |
|
|
{ |
|
|
list<Model*> &am = m_active_models; |
|
|
if (find(am.begin(), am.end(), m) == am.end()) |
|
|
am.push_back(m); |
|
|
} |
|
|
|
|
|
void |
|
|
ModelLayer::new_world (int, int) |
|
|
{ |
|
|
m_active_models.clear(); |
|
|
} |
|
|
|
|
|
void |
|
|
ModelLayer::deactivate (Model *m) |
|
|
{ |
|
|
m_active_models.remove(m); |
|
|
} |
|
|
|
|
|
void |
|
|
ModelLayer::tick (double dtime) |
|
|
{ |
|
|
ModelList &am = m_active_models; |
|
|
am.remove_if(mem_fun(&Model::is_garbage)); |
|
|
|
|
|
/* for_each does not work; animation may remove itself during a |
|
|
tick. This may happen for example when a model callback |
|
|
decides to replace the old model by another one. */ |
|
|
for (ModelList::iterator i=am.begin(); i!=am.end(); ) { |
|
|
ModelList::iterator n=next(i); |
|
|
(*i)->tick(dtime); |
|
|
i=n; |
|
|
} |
|
|
for (ModelList::iterator i=am.begin(); i!=am.end(); ++i) { |
|
|
maybe_redraw_model (*i); |
|
|
} |
|
|
} |
|
72 |
|
|
73 |
|
|
74 |
//====================================================================== |
//====================================================================== |
156 |
m_width = w; |
m_width = w; |
157 |
m_height = h; |
m_height = h; |
158 |
m_offset = V2(); |
m_offset = V2(); |
159 |
m_fields = Field2Array(w, h); |
m_fields.resize(w, h); |
160 |
|
|
161 |
for (unsigned i=0; i<m_layers.size(); ++i) |
for (unsigned i=0; i<m_layers.size(); ++i) |
162 |
m_layers[i]->new_world(w,h); |
m_layers[i]->new_world(w,h); |
173 |
} |
} |
174 |
|
|
175 |
void |
void |
|
DisplayEngine::world_to_screen (const V3 & pos, int *x, int *y) |
|
|
{ |
|
|
*x = int((pos[0] - m_offset[0])*m_tilew); |
|
|
*y = int((pos[1] - m_offset[1])*m_tileh); |
|
|
} |
|
|
|
|
|
void |
|
176 |
DisplayEngine::world_to_screen (const V2 & pos, int *x, int *y) |
DisplayEngine::world_to_screen (const V2 & pos, int *x, int *y) |
177 |
{ |
{ |
178 |
*x = int((pos[0] - m_offset[0])*m_tilew); |
*x = int((pos[0] - m_offset[0])*m_tilew); |
191 |
WorldArea |
WorldArea |
192 |
DisplayEngine::screen_to_world (const ScreenArea &a) |
DisplayEngine::screen_to_world (const ScreenArea &a) |
193 |
{ |
{ |
|
int worldw = m_width; |
|
|
int worldh = m_height; |
|
|
|
|
194 |
int sx = int(m_offset[0] * m_tilew); |
int sx = int(m_offset[0] * m_tilew); |
195 |
int sy = int(m_offset[1] * m_tileh); |
int sy = int(m_offset[1] * m_tileh); |
196 |
|
|
197 |
int x1 = Max(0, (sx + a.x) / m_tilew); |
int x1 = Max(0, (sx + a.x) / m_tilew); |
198 |
int y1 = Max(0, (sy + a.y) / m_tileh); |
int y1 = Max(0, (sy + a.y) / m_tileh); |
199 |
int x2 = Min(worldw, (sx + a.x+a.w+m_tilew-1) / m_tilew); |
int x2 = Min(m_width, (sx + a.x+a.w+m_tilew-1) / m_tilew); |
200 |
int y2 = Min(worldh, (sy + a.y+a.h+m_tileh-1) / m_tileh); |
int y2 = Min(m_height, (sy + a.y+a.h+m_tileh-1) / m_tileh); |
201 |
|
|
202 |
return WorldArea (x1, y1, x2-x1, y2-y1); |
return WorldArea (x1, y1, x2-x1, y2-y1); |
203 |
} |
} |
204 |
|
|
205 |
|
V2 |
206 |
|
DisplayEngine::to_screen (const V2 &pos) |
207 |
|
{ |
208 |
|
return V2 ((pos[0] - m_offset[0])*m_tilew, |
209 |
|
(pos[1] - m_offset[1])*m_tileh); |
210 |
|
} |
211 |
|
|
212 |
|
V2 |
213 |
|
DisplayEngine::to_world (const V2 &pos) |
214 |
|
{ |
215 |
|
return V2(pos[0]/m_tilew, pos[1]/m_tileh) + m_offset; |
216 |
|
} |
217 |
|
|
218 |
void |
void |
219 |
DisplayEngine::mark_redraw_area (const WorldArea &wa) |
DisplayEngine::mark_redraw_area (const WorldArea &wa) |
220 |
{ |
{ |
270 |
for (int y=wa.y; y<y2; y++) { |
for (int y=wa.y; y<y2; y++) { |
271 |
Field2 &f2 = m_fields(x,y); |
Field2 &f2 = m_fields(x,y); |
272 |
if (f2.updatep) { |
if (f2.updatep) { |
273 |
shadow_layer->update(x,y); |
// shadow_layer->update(x,y); |
274 |
f2.redrawp = true; |
f2.redrawp = true; |
275 |
f2.updatep = false; |
f2.updatep = false; |
276 |
} |
} |
283 |
draw_field(gc, x,y); |
draw_field(gc, x,y); |
284 |
} |
} |
285 |
} |
} |
|
line_layer->draw_lines (gc); |
|
286 |
} |
} |
287 |
|
|
288 |
void |
void |
294 |
clip(gc, area); |
clip(gc, area); |
295 |
WorldArea wa = screen_to_world (area); |
WorldArea wa = screen_to_world (area); |
296 |
|
|
297 |
int x2 = wa.x+wa.w; |
// Fill screen area not covered by world |
298 |
int y2 = wa.y+wa.h; |
{ |
299 |
for (int x=wa.x; x<x2; x++) { |
RectList rl; |
300 |
for (int y=wa.y; y<y2; y++) { |
rl.push_back (get_area()); |
301 |
|
rl.sub (world_to_screen (WorldArea (0,0, m_width, m_height))); |
302 |
|
set_color (gc, 200, 0, 200); |
303 |
|
for (RectList::iterator i=rl.begin(); i!=rl.end(); ++i) |
304 |
|
{ |
305 |
|
box (gc, *i); |
306 |
|
m_screen->update_rect (*i); |
307 |
|
} |
308 |
|
} |
309 |
|
|
310 |
|
|
311 |
|
int x2 = Min(m_width, wa.x+wa.w); |
312 |
|
int y2 = Min(m_height, wa.y+wa.h); |
313 |
|
for (int x=Max(0, wa.x); x<x2; x++) { |
314 |
|
for (int y=Max(0,wa.y); y<y2; y++) { |
315 |
Field2 &f2 = m_fields(x,y); |
Field2 &f2 = m_fields(x,y); |
316 |
if (f2.updatep) { |
if (f2.updatep) { |
317 |
shadow_layer->update(x,y); |
// shadow_layer->update(x,y); |
318 |
f2.redrawp = true; |
f2.redrawp = true; |
319 |
f2.updatep = false; |
f2.updatep = false; |
320 |
} |
} |
331 |
} |
} |
332 |
} |
} |
333 |
} |
} |
|
line_layer->draw_lines (gc); |
|
334 |
} |
} |
335 |
|
|
336 |
|
|
337 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
338 |
|
// Model layer |
339 |
|
//---------------------------------------------------------------------- |
340 |
|
|
341 |
|
void |
342 |
|
ModelLayer::maybe_redraw_model(Model *m) |
343 |
|
{ |
344 |
|
WorldArea wa; |
345 |
|
if (m->has_changed(wa)) { |
346 |
|
get_engine()->mark_update_area(wa); |
347 |
|
} |
348 |
|
} |
349 |
|
|
350 |
|
void |
351 |
|
ModelLayer::activate (Model *m) |
352 |
|
{ |
353 |
|
list<Model*> &am = m_active_models; |
354 |
|
if (find(am.begin(), am.end(), m) == am.end()) |
355 |
|
am.push_back(m); |
356 |
|
} |
357 |
|
|
358 |
|
void |
359 |
|
ModelLayer::new_world (int, int) |
360 |
|
{ |
361 |
|
m_active_models.clear(); |
362 |
|
} |
363 |
|
|
364 |
|
void |
365 |
|
ModelLayer::deactivate (Model *m) |
366 |
|
{ |
367 |
|
m_active_models.remove(m); |
368 |
|
} |
369 |
|
|
370 |
|
void |
371 |
|
ModelLayer::tick (double dtime) |
372 |
|
{ |
373 |
|
ModelList &am = m_active_models; |
374 |
|
am.remove_if(mem_fun(&Model::is_garbage)); |
375 |
|
|
376 |
|
/* for_each does not work; animation may remove itself during a |
377 |
|
tick. This may happen for example when a model callback |
378 |
|
decides to replace the old model by another one. */ |
379 |
|
for (ModelList::iterator i=am.begin(); i!=am.end(); ) { |
380 |
|
ModelList::iterator n=next(i); |
381 |
|
(*i)->tick(dtime); |
382 |
|
i=n; |
383 |
|
} |
384 |
|
for (ModelList::iterator i=am.begin(); i!=am.end(); ++i) { |
385 |
|
maybe_redraw_model (*i); |
386 |
|
} |
387 |
|
} |
388 |
|
|
389 |
|
|
390 |
|
//---------------------------------------------------------------------- |
391 |
|
// Grid Layer |
392 |
|
//---------------------------------------------------------------------- |
393 |
|
|
394 |
|
DL_Grid::DL_Grid() |
395 |
|
: m_models (0, 0) |
396 |
|
{ |
397 |
|
} |
398 |
|
|
399 |
|
DL_Grid::~DL_Grid() |
400 |
|
{ |
401 |
|
delete_sequence (m_models.begin(), m_models.end()); |
402 |
|
} |
403 |
|
|
404 |
|
void |
405 |
|
DL_Grid::new_world (int w, int h) |
406 |
|
{ |
407 |
|
ModelLayer::new_world (w, h); |
408 |
|
delete_sequence (m_models.begin(), m_models.end()); |
409 |
|
m_models.resize (w, h, 0); |
410 |
|
} |
411 |
|
|
412 |
|
void |
413 |
|
DL_Grid::mark_update (int x, int y) |
414 |
|
{ |
415 |
|
get_engine()->mark_update_area (WorldArea (x, y, 2, 2)); |
416 |
|
} |
417 |
|
|
418 |
|
void |
419 |
|
DL_Grid::set_model (int x, int y, Model *m) |
420 |
|
{ |
421 |
|
if (!(x >= 0 && y >= 0 && |
422 |
|
(unsigned)x<m_models.width() && |
423 |
|
(unsigned)y<m_models.height())) |
424 |
|
{ |
425 |
|
cout << "ouch, trying to set model somewhere it doesn't belong.\n"; |
426 |
|
delete m; |
427 |
|
return; |
428 |
|
} |
429 |
|
|
430 |
|
if (m_models(x,y) != m) { |
431 |
|
if (Model *mm = m_models(x,y)) { |
432 |
|
mm->remove(this); |
433 |
|
delete mm; |
434 |
|
} |
435 |
|
m_models(x,y) = m; |
436 |
|
mark_update(x,y); |
437 |
|
if (m) |
438 |
|
m->expose (this, V2(x, y)); |
439 |
|
} |
440 |
|
} |
441 |
|
|
442 |
|
Model * |
443 |
|
DL_Grid::get_model (int x, int y) |
444 |
|
{ |
445 |
|
return m_models(x,y); |
446 |
|
} |
447 |
|
|
448 |
|
Model * |
449 |
|
DL_Grid::yield_model (int x, int y) |
450 |
|
{ |
451 |
|
Model *m = get_model (x, y); |
452 |
|
if (m) |
453 |
|
m->remove (this); |
454 |
|
m_models(x,y) = 0; |
455 |
|
mark_update(x,y); |
456 |
|
return m; |
457 |
|
} |
458 |
|
|
459 |
|
|
460 |
|
void |
461 |
|
DL_Grid::draw (px::GC &gc, const WorldArea &a, int destx, int desty) |
462 |
|
{ |
463 |
|
int x2 = a.x+a.w; |
464 |
|
int y2 = a.y+a.h; |
465 |
|
for (int x=a.x; x<x2; ++x) |
466 |
|
for (int y=a.y; y<y2; ++y) |
467 |
|
if (Model *m = m_models(x,y)) |
468 |
|
m->draw(gc, destx, desty); |
469 |
|
} |
470 |
|
|
471 |
|
|
472 |
|
|
473 |
|
//====================================================================== |
474 |
// SPRITES |
// SPRITES |
475 |
|
//====================================================================== |
476 |
|
|
477 |
|
void |
478 |
|
SpriteHandle::kill() |
479 |
|
{ |
480 |
|
layer->kill_sprite (id); |
481 |
|
layer = 0; |
482 |
|
id = 0; |
483 |
|
} |
484 |
|
|
485 |
|
void |
486 |
|
SpriteHandle::move (const px::V2 &newpos) const |
487 |
|
{ |
488 |
|
if (layer) |
489 |
|
layer->move_sprite (id, newpos); |
490 |
|
} |
491 |
|
|
492 |
|
void |
493 |
|
SpriteHandle::replace_model (Model *m) const |
494 |
|
{ |
495 |
|
if (layer) |
496 |
|
layer->replace_sprite (id, m); |
497 |
|
else |
498 |
|
delete m; |
499 |
|
} |
500 |
|
|
501 |
|
Model * |
502 |
|
SpriteHandle::get_model () const |
503 |
|
{ |
504 |
|
return layer ? layer->get_model (id) : 0; |
505 |
|
} |
506 |
|
|
507 |
|
void |
508 |
|
SpriteHandle::set_callback (ModelCallback *cb) const |
509 |
|
{ |
510 |
|
if (Model *m = get_model()) |
511 |
|
m->set_callback(cb); |
512 |
|
} |
513 |
|
|
514 |
|
//---------------------------------------------------------------------- |
515 |
|
// Sprite layer |
516 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
517 |
|
|
518 |
DL_Sprites::DL_Sprites() |
DL_Sprites::DL_Sprites() |
524 |
delete_sequence(sprites.begin(), sprites.end()); |
delete_sequence(sprites.begin(), sprites.end()); |
525 |
} |
} |
526 |
|
|
|
|
|
527 |
void |
void |
528 |
DL_Sprites::new_world (int w, int h) |
DL_Sprites::new_world (int w, int h) |
529 |
{ |
{ |
530 |
|
ModelLayer::new_world (w,h); |
531 |
delete_sequence (sprites.begin(), sprites.end()); |
delete_sequence (sprites.begin(), sprites.end()); |
532 |
sprites.clear(); |
sprites.clear(); |
533 |
numsprites = 0; |
numsprites = 0; |
|
ModelLayer::new_world (w,h); |
|
534 |
} |
} |
535 |
|
|
536 |
void |
void |
537 |
DL_Sprites::move_sprite (SpriteId id, const px::V3& newpos) |
DL_Sprites::move_sprite (SpriteId id, const px::V2& newpos) |
538 |
{ |
{ |
|
if (id == MAGIC_SPRITEID) |
|
|
return; |
|
539 |
Sprite *sprite = sprites[id]; |
Sprite *sprite = sprites[id]; |
540 |
|
|
541 |
int oldx, oldy; |
int oldx, oldy; |
560 |
} |
} |
561 |
|
|
562 |
SpriteList &sl = sprites; |
SpriteList &sl = sprites; |
563 |
SpriteId id = MAGIC_SPRITEID; |
SpriteId id = 0; |
564 |
|
|
565 |
// Find the first empty slot |
// Find the first empty slot |
566 |
SpriteList::iterator i = find(sl.begin(), sl.end(), (Sprite*)0); |
SpriteList::iterator i = find(sl.begin(), sl.end(), (Sprite*)0); |
572 |
id = distance(sl.begin(), i); |
id = distance(sl.begin(), i); |
573 |
*i = sprite; |
*i = sprite; |
574 |
} |
} |
575 |
if (Model *m = sprite->model) { |
if (Model *m = sprite->model) |
576 |
m->expose (this, V2 (sprite->pos[0], sprite->pos[1])); |
m->expose (this, V2 (sprite->pos[0], sprite->pos[1])); |
|
} |
|
577 |
redraw_sprite_region(id); |
redraw_sprite_region(id); |
578 |
numsprites += 1; |
numsprites += 1; |
579 |
return id; |
return id; |
582 |
void |
void |
583 |
DL_Sprites::replace_sprite (SpriteId id, Model *m) |
DL_Sprites::replace_sprite (SpriteId id, Model *m) |
584 |
{ |
{ |
|
if (id == MAGIC_SPRITEID) { |
|
|
delete m; |
|
|
return; |
|
|
} |
|
|
|
|
585 |
Sprite *sprite = sprites[id]; |
Sprite *sprite = sprites[id]; |
586 |
|
|
587 |
if (Model *m = sprite->model) { |
if (Model *m = sprite->model) { |
598 |
void |
void |
599 |
DL_Sprites::kill_sprite (SpriteId id) |
DL_Sprites::kill_sprite (SpriteId id) |
600 |
{ |
{ |
|
if (id == MAGIC_SPRITEID) |
|
|
return; |
|
601 |
if (Sprite *sprite = sprites[id]) { |
if (Sprite *sprite = sprites[id]) { |
602 |
if (Model *m = sprite->model) { |
if (Model *m = sprite->model) { |
603 |
m->remove (this); |
m->remove (this); |
653 |
|
|
654 |
|
|
655 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
|
// GRID LAYER |
|
|
//---------------------------------------------------------------------- |
|
|
|
|
|
DL_Grid::DL_Grid() |
|
|
{ |
|
|
} |
|
|
|
|
|
void |
|
|
DL_Grid::new_world (int w, int h) |
|
|
{ |
|
|
m_models = ModelArray (w, h); |
|
|
ModelLayer::new_world (w, h); |
|
|
} |
|
|
|
|
|
void |
|
|
DL_Grid::mark_update (int x, int y) |
|
|
{ |
|
|
get_engine()->mark_update_area (WorldArea (x, y, 2, 2)); |
|
|
} |
|
|
|
|
|
void |
|
|
DL_Grid::set_model (int x, int y, Model *m) |
|
|
{ |
|
|
if (m_models(x,y) != m) { |
|
|
if (Model *mm = m_models(x,y)) { |
|
|
mm->remove(this); |
|
|
delete mm; |
|
|
} |
|
|
m_models(x,y) = m; |
|
|
mark_update(x,y); |
|
|
if (m) |
|
|
m->expose (this, V2(x, y)); |
|
|
} |
|
|
} |
|
|
|
|
|
Model * |
|
|
DL_Grid::get_model (int x, int y) |
|
|
{ |
|
|
return m_models(x,y); |
|
|
} |
|
|
|
|
|
Model * |
|
|
DL_Grid::yield_model (int x, int y) |
|
|
{ |
|
|
Model *m = m_models(x,y); |
|
|
m_models(x,y) = 0; |
|
|
mark_update(x,y); |
|
|
return m; |
|
|
} |
|
|
|
|
|
|
|
|
void |
|
|
DL_Grid::draw (px::GC &gc, const WorldArea &a, int destx, int desty) |
|
|
{ |
|
|
int x2 = a.x+a.w; |
|
|
int y2 = a.y+a.h; |
|
|
for (int x=a.x; x<x2; ++x) |
|
|
for (int y=a.y; y<y2; ++y) |
|
|
if (Model *m = m_models(x,y)) |
|
|
m->draw(gc, destx, desty); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------- |
|
656 |
// RUBBER BANDS |
// RUBBER BANDS |
657 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
658 |
|
|
741 |
{ |
{ |
742 |
m_rubbers[m_id] = Line(p1, p2); |
m_rubbers[m_id] = Line(p1, p2); |
743 |
mark_redraw_line (m_rubbers[m_id]); |
mark_redraw_line (m_rubbers[m_id]); |
744 |
return RubberHandle(m_id++); |
return RubberHandle(this, m_id++); |
745 |
} |
} |
746 |
|
|
747 |
void |
void |
769 |
m_rubbers.erase(i); |
m_rubbers.erase(i); |
770 |
} |
} |
771 |
|
|
772 |
|
RubberHandle::RubberHandle(DL_Lines *ll, unsigned id_) |
773 |
RubberHandle |
: line_layer (ll), id(id_) |
|
display::AddRubber (const V2 &p1, const V2 &p2) |
|
|
{ |
|
|
return line_layer->add_line (p1, p2); |
|
|
} |
|
|
|
|
|
|
|
|
RubberHandle::RubberHandle(unsigned id_): id(id_) |
|
774 |
{ |
{ |
775 |
} |
} |
776 |
|
|
794 |
// SHADOWS |
// SHADOWS |
795 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
796 |
|
|
797 |
DL_Shadows::DL_Shadows(DL_Grid *grid, DL_Sprites *sprites) |
/* |
798 |
: m_grid(grid), m_sprites(sprites), |
** Drawing the shadows is a lot more difficult than drawing any of the |
799 |
m_gridcache() |
** other layers. There are a couple of reasons for this: |
800 |
|
** |
801 |
|
** 1. Both Stones and actors cast a shadow. Not a real problem, but |
802 |
|
** it makes the implementation more complex. |
803 |
|
** |
804 |
|
** 2. Shadows can overlap. Not only can the shadows of stones and |
805 |
|
** actors overlap, but also the shadows of two adjacent stones can. |
806 |
|
** Since we are using alpha blending for the shadows, this means |
807 |
|
** that we cannot blit the invidual shadows to the screen, but we |
808 |
|
** have to use a intermediate buffer. |
809 |
|
** |
810 |
|
** 3. Performance is critical. Drawing the shadows is time-consuming, |
811 |
|
** firstly because alpha blending is costly and secondly because of |
812 |
|
** the intermediate buffer. So we should try to cache shadows *and* |
813 |
|
** avoid the buffer if possible. |
814 |
|
** |
815 |
|
** So, how do we approach these problems? We handle stone and actor |
816 |
|
** shadows separately: The stone shadows do not change very often so |
817 |
|
** it's easy to cache them, one tile at a time. If there is no actor |
818 |
|
** on this tile, we can blit the cached image directly to the screen, |
819 |
|
** otherwise we have no choice but to use buffer. |
820 |
|
** |
821 |
|
** The remaining problem is the shadow cache. The easiest solution |
822 |
|
** would be to use one huge image for the whole level and keep it in |
823 |
|
** memory all the time. But then the cache would consume roughly 20mb |
824 |
|
** for a 100x100 landscape. That is excessive, considering that there |
825 |
|
** are probably no more than 40 different shadow tiles in each |
826 |
|
** landscape. |
827 |
|
*/ |
828 |
|
|
829 |
|
namespace display |
830 |
{ |
{ |
831 |
SDL_Surface *ss = SDL_CreateRGBSurface(SDL_SWSURFACE, |
struct ImageQuad { |
832 |
TileWidth, TileHeight, |
Image *images[4]; |
833 |
video::GetColorDepth(), |
|
834 |
0,0,0,0); |
ImageQuad() { /* do not initialize fields. */ } |
835 |
SDL_SetColorKey(ss, SDL_SRCCOLORKEY, |
|
836 |
SDL_MapRGB(ss->format, 255,255,255)); |
ImageQuad (Image *i1, Image *i2, Image *i3, Image *i4) { |
837 |
SDL_SetAlpha(ss, SDL_SRCALPHA, 128); |
images[0] = i1; |
838 |
buffer = new Surface(ss); |
images[1] = i2; |
839 |
|
images[2] = i3; |
840 |
|
images[3] = i4; |
841 |
|
} |
842 |
|
bool operator == (const ImageQuad &q) { |
843 |
|
return (images[0]==q.images[0] && |
844 |
|
images[1]==q.images[1] && |
845 |
|
images[2]==q.images[2] && |
846 |
|
images[3]==q.images[3]); |
847 |
|
} |
848 |
|
Image *operator[] (int idx) { return images[idx]; } |
849 |
|
}; |
850 |
|
|
851 |
|
inline bool is_image (Model *m) { |
852 |
|
return m==0 || dynamic_cast<ImageModel*>(m); |
853 |
|
} |
854 |
|
|
855 |
|
inline bool only_images (Model *models[4], ImageQuad &q) { |
856 |
|
int nimages=4; |
857 |
|
|
858 |
|
for (int i=0; i<4; ++i) { |
859 |
|
if (models[i] == 0) |
860 |
|
q.images[i] = 0; |
861 |
|
else if (ImageModel *im = dynamic_cast<ImageModel*>(models[i])) |
862 |
|
q.images[i] = im->get_image(); |
863 |
|
else |
864 |
|
nimages--; |
865 |
|
} |
866 |
|
return nimages==4; |
867 |
|
} |
868 |
|
|
869 |
|
|
870 |
|
struct StoneShadow { |
871 |
|
ImageQuad images; |
872 |
|
Surface *image; |
873 |
|
bool in_cache; |
874 |
|
|
875 |
|
StoneShadow (ImageQuad iq, bool cached) |
876 |
|
: images(iq), image(0), in_cache(cached) |
877 |
|
{} |
878 |
|
}; |
879 |
|
|
880 |
|
class StoneShadowCache : public px::Nocopy { |
881 |
|
public: |
882 |
|
StoneShadowCache(int tilew, int tileh); |
883 |
|
~StoneShadowCache(); |
884 |
|
|
885 |
|
StoneShadow *retrieve (Model *models[4]); |
886 |
|
void release (StoneShadow *s); |
887 |
|
void clear(); |
888 |
|
private: |
889 |
|
typedef std::list<StoneShadow*> CacheList; |
890 |
|
|
891 |
|
// Variables |
892 |
|
size_t m_max_size; |
893 |
|
CacheList m_cache; |
894 |
|
int m_tilew, m_tileh; |
895 |
|
vector<Surface *> m_surface_avail; |
896 |
|
|
897 |
|
// Private methods. |
898 |
|
Surface *new_surface (); |
899 |
|
StoneShadow *find_in_cache (const ImageQuad &images); |
900 |
|
|
901 |
|
void fill_image (StoneShadow *s); |
902 |
|
void fill_image (StoneShadow *sh, Model *models[4]); |
903 |
|
}; |
904 |
} |
} |
905 |
|
|
906 |
DL_Shadows::~DL_Shadows() |
StoneShadowCache::StoneShadowCache(int tilew, int tileh) |
907 |
|
: m_max_size(50), m_cache() |
908 |
|
{ |
909 |
|
m_tilew=tilew; m_tileh=tileh; |
910 |
|
} |
911 |
|
|
912 |
|
StoneShadowCache::~StoneShadowCache() |
913 |
{ |
{ |
914 |
delete_sequence(m_gridcache.begin(), m_gridcache.end()); |
clear(); |
|
delete_sequence(m_surface_avail.begin(), m_surface_avail.end()); |
|
|
delete buffer; |
|
915 |
} |
} |
916 |
|
|
917 |
void |
void |
918 |
DL_Shadows::new_world(int w, int h) |
StoneShadowCache::clear() |
919 |
{ |
{ |
920 |
Array2<Surface*>::iterator i; |
CacheList::iterator i=m_cache.begin(); |
921 |
for (i=m_gridcache.begin();i!=m_gridcache.end(); ++i) |
for (; i!=m_cache.end(); ++i) |
922 |
dispose_surface(*i); |
{ |
923 |
m_gridcache.resize(w,h); |
delete (*i)->image; |
924 |
has_shadow.resize(w,h,false); |
} |
925 |
|
m_cache.clear(); |
926 |
|
delete_sequence (m_surface_avail.begin(), m_surface_avail.end()); |
927 |
} |
} |
928 |
|
|
929 |
Surface * |
void |
930 |
DL_Shadows::new_surface() |
StoneShadowCache::fill_image (StoneShadow *sh) |
931 |
|
{ |
932 |
|
// Special case: no shadows at all: |
933 |
|
if (sh->images[0] == 0 && sh->images[1] == 0 && |
934 |
|
sh->images[2] == 0 && sh->images[3] == 0) |
935 |
|
{ |
936 |
|
sh->image = 0; |
937 |
|
return; |
938 |
|
} |
939 |
|
|
940 |
|
Surface *s = new_surface(); |
941 |
|
GC gc(s); |
942 |
|
set_color (gc, 255,255,255); |
943 |
|
box(gc, s->size()); |
944 |
|
|
945 |
|
if (Image *i = sh->images[0]) |
946 |
|
i->draw (gc, -m_tilew, -m_tileh); |
947 |
|
if (Image *i = sh->images[1]) |
948 |
|
i->draw (gc, 0, -m_tileh); |
949 |
|
if (Image *i = sh->images[2]) |
950 |
|
i->draw (gc, -m_tilew, 0); |
951 |
|
if (Image *i = sh->images[3]) |
952 |
|
i->draw (gc, 0, 0); |
953 |
|
sh->image = s; |
954 |
|
} |
955 |
|
|
956 |
|
void |
957 |
|
StoneShadowCache::fill_image (StoneShadow *sh, Model *models[4]) |
958 |
|
{ |
959 |
|
Surface *s = new_surface(); |
960 |
|
GC gc(s); |
961 |
|
set_color (gc, 255,255,255); |
962 |
|
box(gc, s->size()); |
963 |
|
if (models[0]) models[0]->draw (gc, -m_tilew, -m_tileh); |
964 |
|
if (models[1]) models[1]->draw (gc, 0, -m_tileh); |
965 |
|
if (models[2]) models[2]->draw (gc, -m_tilew, 0); |
966 |
|
if (models[3]) models[3]->draw (gc, 0,0); |
967 |
|
sh->image = s; |
968 |
|
} |
969 |
|
|
970 |
|
|
971 |
|
StoneShadow * |
972 |
|
StoneShadowCache::find_in_cache (const ImageQuad &images) |
973 |
|
{ |
974 |
|
CacheList::iterator i=m_cache.begin(); |
975 |
|
for (; i!=m_cache.end(); ++i) { |
976 |
|
if ((*i)->images == images) { |
977 |
|
StoneShadow *sh = *i; |
978 |
|
// Move entry to front of list |
979 |
|
m_cache.splice (m_cache.begin(), m_cache, i); |
980 |
|
return sh; |
981 |
|
} |
982 |
|
} |
983 |
|
return 0; |
984 |
|
} |
985 |
|
|
986 |
|
|
987 |
|
StoneShadow * |
988 |
|
StoneShadowCache::retrieve (Model *models[4]) |
989 |
|
{ |
990 |
|
StoneShadow *shadow = 0; |
991 |
|
|
992 |
|
ImageQuad images; |
993 |
|
if (only_images (models, images)) { |
994 |
|
shadow = find_in_cache(images); |
995 |
|
if (shadow) { |
996 |
|
} else { |
997 |
|
shadow = new StoneShadow (images, true); |
998 |
|
fill_image (shadow); |
999 |
|
m_cache.push_front (shadow); |
1000 |
|
// cout << "new cache entry #" << m_cache.size() << endl; |
1001 |
|
} |
1002 |
|
} |
1003 |
|
else { |
1004 |
|
shadow = new StoneShadow (images, false); |
1005 |
|
fill_image (shadow); |
1006 |
|
} |
1007 |
|
return shadow; |
1008 |
|
} |
1009 |
|
|
1010 |
|
void |
1011 |
|
StoneShadowCache::release (StoneShadow *s) |
1012 |
{ |
{ |
1013 |
|
if (s->in_cache) { |
1014 |
|
} |
1015 |
|
else { |
1016 |
|
m_surface_avail.push_back(s->image); |
1017 |
|
delete s; |
1018 |
|
} |
1019 |
|
} |
1020 |
|
|
1021 |
|
|
1022 |
|
Surface * |
1023 |
|
StoneShadowCache::new_surface () { |
1024 |
Surface *s = 0; |
Surface *s = 0; |
1025 |
if (m_surface_avail.empty()) { |
if (m_surface_avail.empty()) { |
1026 |
SDL_Surface *ss = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_RLEACCEL, |
SDL_Surface *ss = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_RLEACCEL, |
1027 |
TileWidth, TileHeight, |
m_tilew, m_tileh, 16, |
|
video::GetColorDepth(), |
|
1028 |
0,0,0,0); |
0,0,0,0); |
1029 |
s = new Surface(SDL_DisplayFormat(ss)); |
s = new Surface(SDL_DisplayFormat(ss)); |
1030 |
SDL_FreeSurface(ss); |
SDL_FreeSurface(ss); |
1032 |
s = m_surface_avail.back(); |
s = m_surface_avail.back(); |
1033 |
m_surface_avail.pop_back(); |
m_surface_avail.pop_back(); |
1034 |
} |
} |
1035 |
return s; |
return s; |
1036 |
} |
} |
1037 |
|
|
1038 |
void |
|
1039 |
DL_Shadows::dispose_surface(Surface *s) |
//---------------------------------------- |
1040 |
|
// DL_Shadows |
1041 |
|
//---------------------------------------- |
1042 |
|
|
1043 |
|
DL_Shadows::DL_Shadows (DL_Grid *grid, DL_Sprites *sprites) |
1044 |
|
: m_grid(grid), m_sprites(sprites) |
1045 |
{ |
{ |
1046 |
if (s) |
int tilew=32, tileh=32; |
1047 |
m_surface_avail.push_back(s); |
m_cache = new StoneShadowCache(tilew, tileh); |
1048 |
|
SDL_Surface *ss = SDL_CreateRGBSurface(SDL_SWSURFACE, |
1049 |
|
tilew, tileh, |
1050 |
|
video::GetColorDepth(), |
1051 |
|
0,0,0,0); |
1052 |
|
SDL_SetColorKey(ss, SDL_SRCCOLORKEY, |
1053 |
|
SDL_MapRGB(ss->format, 255,255,255)); |
1054 |
|
SDL_SetAlpha(ss, SDL_SRCALPHA, 128); |
1055 |
|
buffer = new Surface(ss); |
1056 |
} |
} |
1057 |
|
|
1058 |
|
DL_Shadows::~DL_Shadows() |
1059 |
|
{ |
1060 |
|
delete m_cache; |
1061 |
|
delete buffer; |
1062 |
|
} |
1063 |
|
|
1064 |
Surface * |
void |
1065 |
DL_Shadows::get_cache(int x, int y) |
DL_Shadows::new_world(int w, int h) |
1066 |
{ |
{ |
1067 |
Surface *s= m_gridcache(x,y); |
m_cache->clear(); |
|
if (!s) |
|
|
m_gridcache(x,y) = s = new_surface(); |
|
|
return s; |
|
1068 |
} |
} |
1069 |
|
|
1070 |
bool |
void |
1071 |
DL_Shadows::draw_stone_shade(GC &gc, int x, int y, Field &f) |
DL_Shadows::set_model (int x, int y, Model *m) |
1072 |
{ |
{ |
1073 |
Model *m=f.layers[enigma::GRID_STONES]; |
// FieldInfo &f = m_fieldinfo(x,y); |
1074 |
if (m) |
// if (m != f.model) { |
1075 |
m->draw_shade(gc, x, y); |
// f.model = m; |
1076 |
return m!=0; |
// clear_flags (f.flags, HAS_SHADOW); |
1077 |
|
// set_flags (f.flags, MUST_UPDATE | (m ? HAS_SHADOW : 0)); |
1078 |
|
// } |
1079 |
} |
} |
1080 |
|
|
1081 |
void |
void |
1082 |
DL_Shadows::update (int x, int y) |
DL_Shadows::update (int x, int y) |
1083 |
{ |
{ |
1084 |
int has_sh = false; |
// set_flags (m_fieldinfo(x,y).flags, MUST_UPDATE); |
|
|
|
|
Surface *s=get_cache(x,y); |
|
|
|
|
|
GC gc(s); |
|
|
set_color (gc, 255,255,255); |
|
|
box(gc, s->size()); |
|
|
|
|
|
if (x>0&&y>0) |
|
|
has_sh |= draw_stone_shade(gc, -TileWidth, -TileHeight, |
|
|
fields(x-1,y-1)); |
|
|
if (x>0) |
|
|
has_sh |= draw_stone_shade(gc, -TileWidth, 0, fields(x-1,y)); |
|
|
if (y>0) |
|
|
has_sh |= draw_stone_shade(gc, 0, -TileHeight, fields(x,y-1)); |
|
|
has_sh |= draw_stone_shade(gc, 0, 0, fields(x,y)); |
|
|
has_shadow (x,y) = has_sh; |
|
|
|
|
|
if (!has_sh) { |
|
|
// m_gridcache(x,y) = 0; |
|
|
// dispose(s); |
|
|
} |
|
1085 |
} |
} |
1086 |
|
|
1087 |
void |
void |
1088 |
DL_Shadows::draw (px::GC &gc, const WorldArea &a, int x, int y) |
DL_Shadows::draw (px::GC &gc, const WorldArea &a, int x, int y) |
1089 |
{ |
{ |
1090 |
draw (gc, x, y, a.x, a. y); |
draw (gc, x, y, a.x, a.y); |
1091 |
} |
} |
1092 |
|
|
1093 |
|
bool |
1094 |
void |
DL_Shadows::has_actor (int x, int y) |
|
DL_Shadows::draw(GC &gc, int xpos, int ypos, int x, int y) |
|
1095 |
{ |
{ |
1096 |
bool has_actor = false; |
// Is any actor at least partially inside this field? |
1097 |
|
for (unsigned i=0; i<m_sprites->sprites.size(); ++i) { |
1098 |
// Is there an actor that is partially inside this field? |
Sprite *s = m_sprites->sprites[i]; |
|
for (unsigned i=0; i<sprite_layer->sprites.size(); ++i) { |
|
|
Sprite *s = sprite_layer->sprites[i]; |
|
1099 |
if (s && s->layer == SPRITE_ACTOR) { |
if (s && s->layer == SPRITE_ACTOR) { |
1100 |
Rect r(int(s->pos[0]-0.3), int(s->pos[1]-0.3),2,2); |
Rect r(int(s->pos[0]-0.3), int(s->pos[1]-0.3),2,2); |
1101 |
if (r.contains(x,y)) { |
if (r.contains(x,y)) { |
1102 |
has_actor = true; |
return true; |
|
break; |
|
1103 |
} |
} |
1104 |
} |
} |
1105 |
} |
} |
1106 |
|
return false; |
1107 |
|
} |
1108 |
|
|
1109 |
if (has_actor || has_shadow(x,y)) { |
Model * |
1110 |
Surface *s=get_cache(x,y); |
DL_Shadows::get_shadow_model(int x, int y) |
1111 |
|
{ |
1112 |
if (!has_actor) { |
if (x >= 0 && y >= 0) { |
1113 |
|
Model *m = m_grid->get_model(x,y); |
1114 |
|
if (ShadedModel *sm = dynamic_cast<ShadedModel*>(m)) |
1115 |
|
return sm->get_shadow(); |
1116 |
|
} |
1117 |
|
return 0; |
1118 |
|
} |
1119 |
|
|
1120 |
|
|
1121 |
|
void |
1122 |
|
DL_Shadows::draw(GC &gc, int xpos, int ypos, int x, int y) |
1123 |
|
{ |
1124 |
|
Model *models[4]; |
1125 |
|
models[0] = get_shadow_model (x-1, y-1); |
1126 |
|
models[1] = get_shadow_model (x, y-1); |
1127 |
|
models[2] = get_shadow_model (x-1, y); |
1128 |
|
models[3] = get_shadow_model (x, y); |
1129 |
|
|
1130 |
|
StoneShadow *sh = m_cache->retrieve (models); |
1131 |
|
|
1132 |
|
bool has_actor = this->has_actor (x, y); |
1133 |
|
if (has_actor || sh->image) |
1134 |
|
{ |
1135 |
|
Surface *s = sh->image; |
1136 |
|
if (has_actor) { |
1137 |
|
GC gc2(buffer); |
1138 |
|
if (s) |
1139 |
|
blit (gc2, 0,0,s); |
1140 |
|
else { |
1141 |
|
set_color (gc2, 255, 255, 255); |
1142 |
|
box (gc2, buffer->size()); |
1143 |
|
} |
1144 |
|
for (unsigned i=0; i<m_sprites->sprites.size(); ++i) { |
1145 |
|
if (Sprite *s = m_sprites->sprites[i]) { |
1146 |
|
int sx = int(s->pos[0]*32) - x*32; |
1147 |
|
int sy = int(s->pos[1]*32) - y*32; |
1148 |
|
s->model->draw_shade(gc2, sx, sy); |
1149 |
|
} |
1150 |
|
} |
1151 |
|
blit(gc, xpos, ypos, buffer); |
1152 |
|
} |
1153 |
|
else { |
1154 |
SDL_Surface *ss = s->get_surface(); |
SDL_Surface *ss = s->get_surface(); |
1155 |
SDL_SetColorKey(ss, SDL_SRCCOLORKEY, |
SDL_SetColorKey(ss, SDL_SRCCOLORKEY, |
1156 |
SDL_MapRGB(ss->format, 255,255,255)); |
SDL_MapRGB(ss->format, 255,255,255)); |
1157 |
SDL_SetAlpha (ss, SDL_SRCALPHA, 128); |
SDL_SetAlpha (ss, SDL_SRCALPHA, 128); |
1158 |
blit (gc, xpos,ypos,s); |
blit (gc, xpos,ypos,s); |
1159 |
SDL_SetAlpha (ss, 0, 0); |
SDL_SetAlpha (ss, 0, 0); |
1160 |
SDL_SetColorKey(ss, 0,0); |
SDL_SetColorKey (ss, 0,0); |
|
} |
|
|
else { |
|
|
GC gc2(buffer); |
|
|
blit (gc2, 0,0,s); |
|
|
for (unsigned i=0; i<sprite_layer->sprites.size(); ++i) { |
|
|
Sprite *s = sprite_layer->sprites[i]; |
|
|
if (s && s->layer == SPRITE_ACTOR){ |
|
|
int sx = int(s->pos[0]*TileWidth) - x*TileWidth; |
|
|
int sy = int(s->pos[1]*TileWidth) - y*TileHeight; |
|
|
s->model->draw_shade(gc2, sx, sy); |
|
|
} |
|
|
} |
|
|
blit(gc, xpos, ypos, buffer); |
|
1161 |
} |
} |
1162 |
} |
} |
1163 |
|
|
1164 |
|
m_cache->release (sh); |
1165 |
} |
} |
1166 |
|
|
1167 |
void |
void |
1168 |
DL_Shadows::shadow_blit (px::Surface *scr, int x, int y, |
DL_Shadows::shadow_blit (px::Surface *scr, int x, int y, |
1169 |
px::Surface *shadows, px::Rect r) |
px::Surface *shadows, px::Rect r) |
1170 |
{ |
{ |
1171 |
r.intersect(scr->size()); |
// r.intersect(scr->size()); |
1172 |
x=r.x; |
// x=r.x; |
1173 |
y=r.y; |
// y=r.y; |
1174 |
|
|
1175 |
SDL_Surface *s = shadows->get_surface(); // source |
// SDL_Surface *s = shadows->get_surface(); // source |
1176 |
SDL_Surface *d = scr->get_surface(); |
// SDL_Surface *d = scr->get_surface(); |
1177 |
|
|
1178 |
SDL_LockSurface(s); |
// SDL_LockSurface(s); |
1179 |
SDL_LockSurface(d); |
// SDL_LockSurface(d); |
1180 |
|
|
1181 |
assert (s->format->BytesPerPixel==2 && |
// assert (s->format->BytesPerPixel==2 && |
1182 |
d->format->BytesPerPixel==2); |
// d->format->BytesPerPixel==2); |
|
|
|
|
|
|
|
/* This bitmask is used to erase the highest bit in every color |
|
|
field. Every color value can be effectively halved by (a) |
|
|
shifting everything one bit to the right, and (b) applying the |
|
|
mask to the resulting value. */ |
|
|
Uint32 mask; |
|
|
mask = (d->format->Rmask >> d->format->Rshift+1) << d->format->Rshift; |
|
|
mask |= (d->format->Gmask >> d->format->Gshift+1) << d->format->Gshift; |
|
|
mask |= (d->format->Bmask >> d->format->Bshift+1) << d->format->Bshift; |
|
|
|
|
|
register Uint16 skey = (Uint16)shadow_ckey; |
|
|
for (int h=r.h; h; --h) |
|
|
{ |
|
|
Uint16 *sp = static_cast<Uint16*>(shadows->pixel_pointer(r.x, r.y)); |
|
|
Uint16 *dp = static_cast<Uint16*>(scr->pixel_pointer(x, y)); |
|
|
for (int w=r.w; w; --w) |
|
|
{ |
|
|
if (*sp != skey) |
|
|
*dp = (*dp >> 1) & mask; |
|
|
dp++; |
|
|
sp++; |
|
|
} |
|
|
y++; |
|
|
r.y++; |
|
|
} |
|
|
|
|
|
SDL_UnlockSurface(s); |
|
|
SDL_UnlockSurface(d); |
|
|
} |
|
|
|
|
|
Model * |
|
|
DL_Shadows::get_shadow_model (Model *stone_models[4]) |
|
|
{ |
|
|
return 0; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------- |
|
|
// GLOBAL FUNCTIONS |
|
|
//---------------------------------------------------------------------- |
|
|
|
|
|
void |
|
|
display::Init() |
|
|
{ |
|
|
InitModels(); |
|
1183 |
|
|
|
ScreenArea gamearea(0,0,640, 480-64); |
|
|
gamedpy = new GameDisplay (gamearea); |
|
|
} |
|
|
|
|
|
void |
|
|
display::Shutdown() |
|
|
{ |
|
|
delete gamedpy; |
|
|
ShutdownModels(); |
|
|
} |
|
1184 |
|
|
1185 |
void display::Tick (double dtime) { |
// /* This bitmask is used to erase the highest bit in every color |
1186 |
gamedpy->tick(dtime); |
// field. Every color value can be effectively halved by (a) |
1187 |
} |
// shifting everything one bit to the right, and (b) applying the |
1188 |
|
// mask to the resulting value. */ |
1189 |
|
// Uint32 mask; |
1190 |
|
// mask = (d->format->Rmask >> d->format->Rshift+1) << d->format->Rshift; |
1191 |
|
// mask |= (d->format->Gmask >> d->format->Gshift+1) << d->format->Gshift; |
1192 |
|
// mask |= (d->format->Bmask >> d->format->Bshift+1) << d->format->Bshift; |
1193 |
|
|
1194 |
|
// register Uint16 skey = (Uint16)shadow_ckey; |
1195 |
|
// for (int h=r.h; h; --h) |
1196 |
|
// { |
1197 |
|
// Uint16 *sp = static_cast<Uint16*>(shadows->pixel_pointer(r.x, r.y)); |
1198 |
|
// Uint16 *dp = static_cast<Uint16*>(scr->pixel_pointer(x, y)); |
1199 |
|
// for (int w=r.w; w; --w) |
1200 |
|
// { |
1201 |
|
// if (*sp != skey) |
1202 |
|
// *dp = (*dp >> 1) & mask; |
1203 |
|
// dp++; |
1204 |
|
// sp++; |
1205 |
|
// } |
1206 |
|
// y++; |
1207 |
|
// r.y++; |
1208 |
|
// } |
1209 |
|
|
1210 |
StatusBar * display::GetStatusBar() { |
// SDL_UnlockSurface(s); |
1211 |
return gamedpy->get_status_bar(); |
// SDL_UnlockSurface(d); |
|
} |
|
|
|
|
|
void display::NewWorld(int w, int h) { |
|
|
gamedpy->new_world (w, h); |
|
1212 |
} |
} |
1213 |
|
|
1214 |
|
|
1319 |
} |
} |
1320 |
} |
} |
1321 |
|
|
|
void display::FollowSprite(SpriteId id) { |
|
|
gamedpy->set_follow_sprite (id); |
|
|
} |
|
|
|
|
|
FollowMode display::SetFollowMode(FollowMode m) { |
|
|
return gamedpy->set_follow_mode(m); |
|
|
} |
|
|
|
|
|
Model *display::SetModel (const GridLoc &l, Model *m) { |
|
|
return gamedpy->set_model (l, m); |
|
|
} |
|
|
|
|
|
Model *display::SetModel (const GridLoc &l, const string &modelname) { |
|
|
return SetModel(l, MakeModel(modelname)); |
|
|
} |
|
|
|
|
|
void display::KillModel(const GridLoc & l) { |
|
|
delete YieldModel(l); |
|
|
} |
|
|
|
|
|
Model *display::GetModel(const GridLoc &l) { |
|
|
return gamedpy->get_model (l); |
|
|
} |
|
|
|
|
|
Model *display::YieldModel(const GridLoc &l) { |
|
|
return gamedpy->yield_model (l); |
|
|
} |
|
|
|
|
|
void display::AddEffect (const V3& pos, const char *modelname) { |
|
|
gamedpy->add_effect (pos, MakeModel(modelname)); |
|
|
} |
|
|
|
|
|
SpriteId |
|
|
display::AddSprite (const V3& pos, const char *modelname) |
|
|
{ |
|
|
Model *m = modelname ? MakeModel(modelname) : 0; |
|
|
return sprite_layer->add_sprite(new Sprite (pos, SPRITE_ACTOR, m)); |
|
|
} |
|
|
|
|
|
void |
|
|
display::MoveSprite(SpriteId id, const px::V3& newpos) |
|
|
{ |
|
|
sprite_layer->move_sprite (id, newpos); |
|
|
} |
|
|
|
|
|
void |
|
|
display::ReplaceSprite (SpriteId id, const char *modelname) |
|
|
{ |
|
|
sprite_layer->replace_sprite (id, MakeModel(modelname)); |
|
|
} |
|
|
|
|
|
void |
|
|
display::KillSprite(SpriteId id) |
|
|
{ |
|
|
sprite_layer->kill_sprite(id); |
|
|
} |
|
|
|
|
|
void |
|
|
display::SetCallback(SpriteId id, ModelCallback *cb) |
|
|
{ |
|
|
if (Model *m = GetModel(id)) |
|
|
m->set_callback(cb); |
|
|
} |
|
|
|
|
|
Model * |
|
|
display::GetModel(SpriteId id) |
|
|
{ |
|
|
if (id == MAGIC_SPRITEID) |
|
|
return 0; |
|
|
return sprite_layer->sprites[id]->model; |
|
|
} |
|
|
|
|
|
void |
|
|
display::SetTileSize(int w, int h) |
|
|
{ |
|
|
TileWidth = w; |
|
|
TileHeight = h; |
|
|
// engine->set_tilesize(w,h); |
|
|
} |
|
|
|
|
|
void |
|
|
display::ToggleFlag(DisplayFlags flag) |
|
|
{ |
|
|
display_flags = DisplayFlags(display_flags ^ flag); |
|
|
} |
|
|
|
|
|
void display::DrawAll (GC &gc) { |
|
|
gamedpy->draw_all(gc); |
|
|
} |
|
|
|
|
|
void display::RedrawAll(Screen *screen) { |
|
|
gamedpy->redraw_all(screen); |
|
|
} |
|
|
|
|
|
void display::Redraw(Screen *screen) { |
|
|
gamedpy->redraw(screen); |
|
|
} |
|
1322 |
|
|
1323 |
|
|
1324 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
1331 |
|
|
1332 |
engine->add_layer (floor_layer = new DL_Grid); |
engine->add_layer (floor_layer = new DL_Grid); |
1333 |
engine->add_layer (item_layer = new DL_Grid); |
engine->add_layer (item_layer = new DL_Grid); |
1334 |
engine->add_layer (shadow_layer = new DL_Shadows(0,0)); |
sprite_layer = new DL_Sprites; |
1335 |
engine->add_layer (sprite_layer = new DL_Sprites); |
stone_layer = new DL_Grid; |
1336 |
engine->add_layer (stone_layer = new DL_Grid); |
shadow_layer = new DL_Shadows(stone_layer, sprite_layer); |
1337 |
|
engine->add_layer (shadow_layer); |
1338 |
|
engine->add_layer (sprite_layer); |
1339 |
|
engine->add_layer (stone_layer); |
1340 |
engine->add_layer (line_layer = new DL_Lines); |
engine->add_layer (line_layer = new DL_Lines); |
1341 |
engine->add_layer (effects_layer = new DL_Sprites); |
engine->add_layer (effects_layer = new DL_Sprites); |
1342 |
effects_layer->set_maxsprites(10); |
effects_layer->set_maxsprites(10); |
1361 |
case GRID_STONES: |
case GRID_STONES: |
1362 |
stone_layer->set_model (x, y, m); |
stone_layer->set_model (x, y, m); |
1363 |
// shadow_layer->set_model (x, y, m); |
// shadow_layer->set_model (x, y, m); |
1364 |
|
shadow_layer->update (x, y); |
1365 |
break; |
break; |
1366 |
case GRID_COUNT: break; |
case GRID_COUNT: break; |
1367 |
} |
} |
|
Field& f = fields(x, y); |
|
|
f.layers[l.layer] = m; |
|
1368 |
return m; |
return m; |
1369 |
} |
} |
1370 |
|
|
1385 |
CommonDisplay::yield_model (const GridLoc &l) |
CommonDisplay::yield_model (const GridLoc &l) |
1386 |
{ |
{ |
1387 |
int x = l.pos.x, y=l.pos.y; |
int x = l.pos.x, y=l.pos.y; |
|
fields(x, y).layers[l.layer] = 0; |
|
1388 |
switch (l.layer) { |
switch (l.layer) { |
1389 |
case GRID_FLOOR: return floor_layer->yield_model (x, y); |
case GRID_FLOOR: return floor_layer->yield_model (x, y); |
1390 |
case GRID_ITEMS: return item_layer->yield_model (x, y); |
case GRID_ITEMS: return item_layer->yield_model (x, y); |
1394 |
return 0; |
return 0; |
1395 |
} |
} |
1396 |
|
|
1397 |
|
|
1398 |
|
RubberHandle |
1399 |
|
CommonDisplay::add_line (V2 p1, V2 p2) |
1400 |
|
{ |
1401 |
|
return line_layer->add_line (p1, p2); |
1402 |
|
} |
1403 |
|
|
1404 |
SpriteHandle |
SpriteHandle |
1405 |
CommonDisplay::add_effect (const V3& pos, Model *m) |
CommonDisplay::add_effect (const V2& pos, Model *m) |
1406 |
{ |
{ |
1407 |
Sprite *spr = new Sprite (pos, SPRITE_EFFECT, m); |
Sprite *spr = new Sprite (pos, SPRITE_EFFECT, m); |
1408 |
return SpriteHandle (effects_layer, effects_layer->add_sprite(spr)); |
return SpriteHandle (effects_layer, effects_layer->add_sprite(spr)); |
1409 |
} |
} |
1410 |
|
|
1411 |
|
SpriteHandle |
1412 |
|
CommonDisplay::add_sprite (const V2 &pos, Model *m) |
1413 |
|
{ |
1414 |
|
Sprite *spr = new Sprite (pos, SPRITE_ACTOR, m); |
1415 |
|
return SpriteHandle (sprite_layer, sprite_layer->add_sprite(spr)); |
1416 |
|
} |
1417 |
|
|
1418 |
void |
void |
1419 |
CommonDisplay::new_world (int w, int h) |
CommonDisplay::new_world (int w, int h) |
1420 |
{ |
{ |
1421 |
fields = FieldArray(w, h); |
// fields.resize(w, h); |
1422 |
get_engine()->new_world (w, h); |
get_engine()->new_world (w, h); |
1423 |
} |
} |
1424 |
|
|
1445 |
: CommonDisplay(a), |
: CommonDisplay(a), |
1446 |
last_frame_time (0), |
last_frame_time (0), |
1447 |
redraw_everything(false), |
redraw_everything(false), |
1448 |
follow_sprite (MAGIC_SPRITEID), |
m_reference_point (), |
1449 |
follow_mode (FOLLOW_NONE), |
m_follower (0), |
|
follower (0), |
|
1450 |
inventoryarea(0, 480-64, 640, 64) |
inventoryarea(0, 480-64, 640, 64) |
1451 |
{ |
{ |
1452 |
status_bar = new StatusBarImpl (inventoryarea); |
status_bar = new StatusBarImpl (inventoryarea); |
1463 |
get_engine()->tick (dtime); |
get_engine()->tick (dtime); |
1464 |
status_bar->tick (dtime); |
status_bar->tick (dtime); |
1465 |
|
|
1466 |
if (follow_sprite != MAGIC_SPRITEID) { |
if (m_follower) |
1467 |
V3 point = sprite_layer->sprites[follow_sprite]->pos; |
m_follower->tick (dtime, m_reference_point); |
|
follower->tick(dtime, V2(point[0], point[1])); |
|
|
} |
|
1468 |
} |
} |
1469 |
|
|
1470 |
void |
void |
1472 |
{ |
{ |
1473 |
CommonDisplay::new_world (w, h); |
CommonDisplay::new_world (w, h); |
1474 |
status_bar->new_world(); |
status_bar->new_world(); |
1475 |
SetFollowMode(FOLLOW_NONE); |
set_follow_mode (FOLLOW_NONE); |
1476 |
|
|
1477 |
// shadow_layer->new_world(w,h); |
// shadow_layer->new_world(w,h); |
1478 |
ScrollX = ScrollY = 0; |
ScrollX = ScrollY = 0; |
1488 |
// Scrolling |
// Scrolling |
1489 |
//---------------------------------------- |
//---------------------------------------- |
1490 |
|
|
1491 |
|
void |
|
FollowMode |
|
1492 |
GameDisplay::set_follow_mode (FollowMode m) |
GameDisplay::set_follow_mode (FollowMode m) |
1493 |
{ |
{ |
1494 |
FollowMode old=follow_mode; |
switch (m) { |
1495 |
if (m != follow_mode) |
case FOLLOW_NONE: set_follower(0); break; |
1496 |
{ |
case FOLLOW_SCROLLING: set_follower (new Follower_Scrolling); break; |
1497 |
follow_mode = m; |
case FOLLOW_SCREEN: set_follower (new Follower_Screen); break; |
1498 |
switch (follow_mode) { |
}; |
|
case FOLLOW_NONE: |
|
|
set_follower(0); |
|
|
break; |
|
|
case FOLLOW_SCROLLING: |
|
|
set_follower (new Follower_Scrolling); |
|
|
break; |
|
|
case FOLLOW_SCREEN: |
|
|
set_follower (new Follower_Screen); |
|
|
break; |
|
|
}; |
|
|
} |
|
|
return old; |
|
1499 |
} |
} |
1500 |
|
|
1501 |
void |
void |
1502 |
GameDisplay::set_follower (Follower *f) |
GameDisplay::set_follower (Follower *f) |
1503 |
{ |
{ |
1504 |
delete follower; |
delete m_follower; |
1505 |
follower = f; |
if ((m_follower = f)) { |
1506 |
if (follower) { |
m_follower->set_engine (get_engine()); |
1507 |
follower->set_engine (get_engine()); |
follow_center(); |
1508 |
} |
} |
1509 |
} |
} |
1510 |
|
|
1511 |
void |
void |
1512 |
GameDisplay::follow_center() |
GameDisplay::follow_center() |
1513 |
{ |
{ |
1514 |
if (follow_mode == FOLLOW_NONE) |
if (m_follower) |
1515 |
set_follow_mode (FOLLOW_SCREEN); |
m_follower->center (m_reference_point); |
|
if (follow_sprite != MAGIC_SPRITEID) { |
|
|
V3 point = sprite_layer->sprites[follow_sprite]->pos; |
|
|
follower->center (V2(point[0], point[1])); |
|
|
} |
|
1516 |
} |
} |
1517 |
|
|
1518 |
void |
void |
1519 |
GameDisplay::set_follow_sprite(SpriteId id) |
GameDisplay::set_reference_point (const V2 &point) |
1520 |
{ |
{ |
1521 |
follow_sprite = id; |
m_reference_point = point; |
|
follow_center(); |
|
1522 |
} |
} |
1523 |
|
|
1524 |
//---------------------------------------- |
//---------------------------------------- |
1526 |
//---------------------------------------- |
//---------------------------------------- |
1527 |
|
|
1528 |
void |
void |
1529 |
GameDisplay::redraw_all(Screen *scr) |
GameDisplay::redraw_all (Screen *scr) |
1530 |
{ |
{ |
1531 |
get_engine()->mark_redraw_screen(); |
get_engine()->mark_redraw_screen(); |
1532 |
redraw_everything = true; |
redraw_everything = true; |
1567 |
status_bar->redraw (gc, inventoryarea); |
status_bar->redraw (gc, inventoryarea); |
1568 |
} |
} |
1569 |
|
|
1570 |
|
|
1571 |
|
//---------------------------------------------------------------------- |
1572 |
|
// GLOBAL FUNCTIONS |
1573 |
|
//---------------------------------------------------------------------- |
1574 |
|
|
1575 |
|
void |
1576 |
|
display::Init() |
1577 |
|
{ |
1578 |
|
InitModels(); |
1579 |
|
|
1580 |
|
ScreenArea gamearea(0,0,640, 480-64); |
1581 |
|
gamedpy = new GameDisplay (gamearea); |
1582 |
|
} |
1583 |
|
|
1584 |
|
void |
1585 |
|
display::Shutdown() |
1586 |
|
{ |
1587 |
|
delete gamedpy; |
1588 |
|
ShutdownModels(); |
1589 |
|
} |
1590 |
|
|
1591 |
|
void display::Tick (double dtime) { |
1592 |
|
gamedpy->tick(dtime); |
1593 |
|
} |
1594 |
|
|
1595 |
|
StatusBar * display::GetStatusBar() { |
1596 |
|
return gamedpy->get_status_bar(); |
1597 |
|
} |
1598 |
|
|
1599 |
|
void display::NewWorld(int w, int h) { |
1600 |
|
gamedpy->new_world (w, h); |
1601 |
|
} |
1602 |
|
|
1603 |
|
void display::FocusReferencePoint() { |
1604 |
|
gamedpy->follow_center(); |
1605 |
|
} |
1606 |
|
|
1607 |
|
void display::SetReferencePoint (const px::V2 &point) { |
1608 |
|
gamedpy->set_reference_point (point); |
1609 |
|
} |
1610 |
|
|
1611 |
|
void display::SetFollowMode(FollowMode m) { |
1612 |
|
gamedpy->set_follow_mode(m); |
1613 |
|
} |
1614 |
|
|
1615 |
|
Model *display::SetModel (const GridLoc &l, Model *m) { |
1616 |
|
return gamedpy->set_model (l, m); |
1617 |
|
} |
1618 |
|
|
1619 |
|
Model *display::SetModel (const GridLoc &l, const string &modelname) { |
1620 |
|
return SetModel(l, MakeModel(modelname)); |
1621 |
|
} |
1622 |
|
|
1623 |
|
void display::KillModel(const GridLoc & l) { |
1624 |
|
delete YieldModel(l); |
1625 |
|
} |
1626 |
|
|
1627 |
|
Model *display::GetModel(const GridLoc &l) { |
1628 |
|
return gamedpy->get_model (l); |
1629 |
|
} |
1630 |
|
|
1631 |
|
Model *display::YieldModel(const GridLoc &l) { |
1632 |
|
return gamedpy->yield_model (l); |
1633 |
|
} |
1634 |
|
|
1635 |
|
void display::AddEffect (const V2& pos, const char *modelname) { |
1636 |
|
gamedpy->add_effect (pos, MakeModel(modelname)); |
1637 |
|
} |
1638 |
|
|
1639 |
|
SpriteHandle |
1640 |
|
display::AddSprite (const V2& pos, const char *modelname) |
1641 |
|
{ |
1642 |
|
Model *m = modelname ? MakeModel(modelname) : 0; |
1643 |
|
return gamedpy->add_sprite (pos, m); |
1644 |
|
} |
1645 |
|
|
1646 |
|
|
1647 |
|
void |
1648 |
|
display::SetTileSize(int w, int h) |
1649 |
|
{ |
1650 |
|
TileWidth = w; |
1651 |
|
TileHeight = h; |
1652 |
|
// engine->set_tilesize(w,h); |
1653 |
|
} |
1654 |
|
|
1655 |
|
void |
1656 |
|
display::ToggleFlag(DisplayFlags flag) |
1657 |
|
{ |
1658 |
|
toggle_flags (display_flags, flag); |
1659 |
|
} |
1660 |
|
|
1661 |
|
void display::DrawAll (GC &gc) { |
1662 |
|
gamedpy->draw_all(gc); |
1663 |
|
} |
1664 |
|
|
1665 |
|
void display::RedrawAll(Screen *screen) { |
1666 |
|
gamedpy->redraw_all(screen); |
1667 |
|
} |
1668 |
|
|
1669 |
|
void display::Redraw(Screen *screen) { |
1670 |
|
gamedpy->redraw(screen); |
1671 |
|
} |
1672 |
|
|
1673 |
|
RubberHandle |
1674 |
|
display::AddRubber (const V2 &p1, const V2 &p2) |
1675 |
|
{ |
1676 |
|
return gamedpy->add_line (p1, p2); |
1677 |
|
} |