42 |
using namespace std; |
using namespace std; |
43 |
using namespace px; |
using namespace px; |
44 |
using namespace display; |
using namespace display; |
45 |
|
using namespace enigma; |
46 |
|
|
47 |
#include "d_engine.hh" |
#include "d_engine.hh" |
48 |
#include "d_statusbar.hh" |
#include "d_statusbar.hh" |
49 |
|
|
|
/* |
|
|
* Function prototypes |
|
|
*/ |
|
|
static void follow_center(); |
|
|
static void follow_doit(double dtime); |
|
|
|
|
|
namespace |
|
|
{ |
|
|
struct Field { |
|
|
static const int NUM_LAYERS = 3; |
|
|
|
|
|
Field() { |
|
|
fill_n(layers, NUM_LAYERS, (Model*)0); |
|
|
redrawp = updatep = false; |
|
|
} |
|
|
~Field() { delete_sequence(layers, layers+NUM_LAYERS); } |
|
|
|
|
|
Model* layers[NUM_LAYERS]; |
|
|
bool redrawp; |
|
|
bool updatep; |
|
|
}; |
|
|
|
|
|
typedef Array2<Field> FieldArray; |
|
|
typedef list<Model*> ModelList; |
|
|
} |
|
|
|
|
50 |
//---------------------------------------- |
//---------------------------------------- |
51 |
// Local variables |
// Local variables |
52 |
//---------------------------------------- |
//---------------------------------------- |
66 |
static int TileWidth = 32; |
static int TileWidth = 32; |
67 |
static int TileHeight = 32; |
static int TileHeight = 32; |
68 |
|
|
69 |
static bool RedrawEverything=false; |
static GameDisplay *gamedpy = 0; |
70 |
|
static DisplayEngine *engine = 0; |
71 |
|
|
72 |
static DisplayEngine *engine = 0; |
static DL_Lines *line_layer = 0; |
73 |
static DL_Lines *line_layer = 0; |
static DL_Sprites *sprite_layer = 0; |
74 |
static DL_Sprites *sprite_layer = 0; |
static DL_Shadows *shadow_layer = 0; |
|
static DL_Sprites *effects_layer = 0; |
|
|
static ShadowLayer *shadow_layer = 0; |
|
75 |
|
|
76 |
namespace |
namespace |
77 |
{ |
{ |
81 |
ModelList active_models; |
ModelList active_models; |
82 |
FieldArray fields(0,0); |
FieldArray fields(0,0); |
83 |
|
|
|
StatusBarImpl *status_bar = 0; |
|
|
|
|
84 |
// Screen layout |
// Screen layout |
85 |
ScreenArea gamearea(0,0,640, 480-64); |
ScreenArea gamearea(0,0,640, 480-64); |
|
ScreenArea inventoryarea(0, 480-64, 640, 64); |
|
86 |
} |
} |
87 |
|
|
88 |
|
|
116 |
} |
} |
117 |
} |
} |
118 |
|
|
119 |
static void |
void |
120 |
mark_change(const GridLoc &l) |
ModelLayer::activate (Model *m) |
121 |
{ |
{ |
122 |
if (l.layer == enigma::GRID_STONES) |
list<Model*> &am = m_active_models; |
123 |
engine->mark_update_area (Rect(l.pos.x, l.pos.y, 2,2)); |
if (find(am.begin(), am.end(), m) == am.end()) |
124 |
else |
am.push_back(m); |
|
engine->mark_redraw_area (Rect(l.pos.x,l.pos.y, 1,1)); |
|
125 |
} |
} |
126 |
|
|
127 |
|
void |
128 |
static inline void |
ModelLayer::deactivate (Model *m) |
|
draw_model(GC &gc, int x, int y, Model *m) |
|
129 |
{ |
{ |
130 |
if (m) |
m_active_models.remove(m); |
|
m->draw(gc, x, y); |
|
131 |
} |
} |
132 |
|
|
133 |
static void |
void |
134 |
draw_field(GC &gc, Field &f, int x, int y) |
ModelLayer::tick (double dtime) |
135 |
{ |
{ |
136 |
int xpos, ypos; |
ModelList &am = m_active_models; |
137 |
engine->world_to_screen (V2(x, y), &xpos, &ypos); |
am.remove_if(mem_fun(&Model::is_garbage)); |
|
|
|
|
using namespace enigma; |
|
138 |
|
|
139 |
if (display_flags & SHOW_FLOOR) draw_model(gc, xpos, ypos, f.layers[GRID_FLOOR]); |
/* for_each does not work; animation may remove itself during a |
140 |
if (display_flags & SHOW_ITEMS) draw_model(gc, xpos, ypos, f.layers[GRID_ITEMS]); |
tick. This may happen for example when a model callback |
141 |
if (display_flags & SHOW_SPRITES) sprite_layer->draw_sprites (false, gc); |
decides to replace the old model by another one. */ |
142 |
if (display_flags & SHOW_SHADES) shadow_layer->draw(gc, xpos, ypos, x, y); |
for (ModelList::iterator i=am.begin(); i!=am.end(); ) { |
143 |
if (display_flags & SHOW_SPRITES) sprite_layer->draw_sprites (false, gc); |
ModelList::iterator n=next(i); |
144 |
if (display_flags & SHOW_STONES) draw_model(gc, xpos, ypos, f.layers[GRID_STONES]); |
(*i)->tick(dtime); |
145 |
if (display_flags & SHOW_SPRITES) effects_layer->draw_sprites (false, gc); |
i=n; |
146 |
|
} |
147 |
|
for_each(am.begin(), am.end(), &maybe_redraw_model); |
148 |
} |
} |
149 |
|
|
150 |
|
|
151 |
|
|
152 |
|
|
153 |
//====================================================================== |
//====================================================================== |
154 |
// DISPLAY ENGINE |
// DISPLAY ENGINE |
155 |
//====================================================================== |
//====================================================================== |
156 |
|
|
157 |
DisplayEngine::DisplayEngine (px::Screen *scr) |
DisplayEngine::DisplayEngine (px::Screen *scr) |
158 |
: m_tilew(32), m_tileh(32), m_screen (scr) |
: m_tilew(32), m_tileh(32), m_screen (scr), |
159 |
, m_offset() |
m_offset(), |
160 |
, m_area (scr->size()) |
m_area (scr->size()), |
161 |
, m_width(0), m_height(0) |
m_width(0), m_height(0), |
162 |
, m_fields(0,0) |
m_fields(0,0) |
163 |
{ |
{ |
164 |
} |
} |
165 |
|
|
189 |
int newx = int(off[0] * m_tilew); |
int newx = int(off[0] * m_tilew); |
190 |
int newy = int(off[1] * m_tileh); |
int newy = int(off[1] * m_tileh); |
191 |
|
|
192 |
|
|
193 |
|
|
194 |
if (newx != oldx || newy != oldy) |
if (newx != oldx || newy != oldy) |
195 |
{ |
{ |
196 |
Rect newarea(newx, newy, gamearea.w, gamearea.h); |
Rect newarea(newx, newy, m_area.w, m_area.h); |
197 |
Rect oldarea(oldx, oldy, gamearea.w, gamearea.h); |
Rect oldarea(oldx, oldy, m_area.w, m_area.h); |
198 |
Rect common = intersect(newarea, oldarea); |
Rect common = intersect(newarea, oldarea); |
199 |
|
|
200 |
Rect blitrect(common.x-oldx+gamearea.x, |
Rect blitrect(common.x-oldx+m_area.x, |
201 |
common.y-oldy+gamearea.y, |
common.y-oldy+m_area.y, |
202 |
common.w, common.h); |
common.w, common.h); |
203 |
m_screen->blit(common.x-newx+gamearea.x, |
m_screen->blit(common.x-newx+m_area.x, |
204 |
common.y-newy+gamearea.y, |
common.y-newy+m_area.y, |
205 |
m_screen, |
m_screen, |
206 |
blitrect); |
blitrect); |
207 |
blitrect.x = common.x-newx+gamearea.x; |
blitrect.x = common.x-newx+m_area.x; |
208 |
blitrect.y = common.y-newy+gamearea.y; |
blitrect.y = common.y-newy+m_area.y; |
209 |
m_screen->update_rect(blitrect); |
m_screen->update_rect(blitrect); |
210 |
|
|
211 |
ScrollX = newx/double(TileWidth); |
ScrollX = newx/double(m_tilew); |
212 |
ScrollY = newy/double(TileHeight); |
ScrollY = newy/double(m_tileh); |
213 |
|
|
214 |
m_offset = V2(ScrollX, ScrollY); |
m_offset = V2(ScrollX, ScrollY); |
215 |
|
|
265 |
*y = int((pos[1] - m_offset[1])*m_tileh); |
*y = int((pos[1] - m_offset[1])*m_tileh); |
266 |
} |
} |
267 |
|
|
268 |
|
ScreenArea |
269 |
|
DisplayEngine::world_to_screen (const WorldArea &a) |
270 |
|
{ |
271 |
|
int x, y; |
272 |
|
world_to_screen (V2(a.x, a.y), &x, &y); |
273 |
|
return ScreenArea (x, y, a.w*m_tilew, a.h*m_tileh); |
274 |
|
} |
275 |
|
|
276 |
|
|
277 |
WorldArea |
WorldArea |
278 |
DisplayEngine::screen_to_world (const ScreenArea &a) |
DisplayEngine::screen_to_world (const ScreenArea &a) |
279 |
{ |
{ |
298 |
int y2 = Min(m_height, wa.y+wa.h); |
int y2 = Min(m_height, wa.y+wa.h); |
299 |
for (int x=Max(0,wa.x); x <x2; x++) |
for (int x=Max(0,wa.x); x <x2; x++) |
300 |
for (int y=Max(0,wa.y); y<y2; y++) |
for (int y=Max(0,wa.y); y<y2; y++) |
301 |
fields(x,y).redrawp = true; |
m_fields(x,y).redrawp = true; |
302 |
} |
} |
303 |
|
|
304 |
void |
void |
308 |
int y2 = Min(m_height, wa.y+wa.h); |
int y2 = Min(m_height, wa.y+wa.h); |
309 |
for (int x=Max(0,wa.x); x <x2; x++) |
for (int x=Max(0,wa.x); x <x2; x++) |
310 |
for (int y=Max(0,wa.y); y<y2; y++) |
for (int y=Max(0,wa.y); y<y2; y++) |
311 |
fields(x,y).updatep = true; |
m_fields(x,y).updatep = true; |
312 |
} |
} |
313 |
|
|
314 |
void |
void |
323 |
mark_redraw_area(screen_to_world(m_area)); |
mark_redraw_area(screen_to_world(m_area)); |
324 |
} |
} |
325 |
|
|
326 |
|
|
327 |
|
void |
328 |
|
DisplayEngine::draw_field (GC &gc, int x, int y) |
329 |
|
{ |
330 |
|
int xpos, ypos; |
331 |
|
world_to_screen (V2(x, y), &xpos, &ypos); |
332 |
|
|
333 |
|
for (unsigned i=0; i<m_layers.size(); ++i) { |
334 |
|
m_layers[i]->draw (gc, WorldArea(x,y,1,1), xpos, ypos); |
335 |
|
} |
336 |
|
} |
337 |
|
|
338 |
|
|
339 |
void |
void |
340 |
DisplayEngine::draw_all (px::GC &gc) |
DisplayEngine::draw_all (px::GC &gc) |
341 |
{ |
{ |
342 |
WorldArea wa = screen_to_world (gamearea); |
WorldArea wa = screen_to_world (m_area); |
343 |
|
|
344 |
int x2 = wa.x+wa.w; |
int x2 = wa.x+wa.w; |
345 |
int y2 = wa.y+wa.h; |
int y2 = wa.y+wa.h; |
346 |
for (int x=wa.x; x<x2; x++) { |
for (int x=wa.x; x<x2; x++) { |
347 |
for (int y=wa.y; y<y2; y++) { |
for (int y=wa.y; y<y2; y++) { |
348 |
Field &f = fields(x,y); |
Field2 &f2 = m_fields(x,y); |
349 |
if (f.updatep) { |
if (f2.updatep) { |
350 |
shadow_layer->update(x,y); |
shadow_layer->update(x,y); |
351 |
f.redrawp = true; |
f2.redrawp = true; |
352 |
f.updatep = false; |
f2.updatep = false; |
353 |
} |
} |
354 |
ScreenArea sa(int((x-m_offset[0])*m_tilew), |
ScreenArea sa(int((x-m_offset[0])*m_tilew), |
355 |
int((y-m_offset[1])*m_tileh), |
int((y-m_offset[1])*m_tileh), |
356 |
m_tilew, |
m_tilew, |
357 |
m_tileh); |
m_tileh); |
358 |
sa.intersect(gamearea); |
sa.intersect (m_area); |
359 |
clip(gc, sa); |
clip(gc, sa); |
360 |
draw_field(gc, f, x,y); |
draw_field(gc, x,y); |
361 |
} |
} |
362 |
} |
} |
363 |
line_layer->draw_lines (gc); |
line_layer->draw_lines (gc); |
376 |
int y2 = wa.y+wa.h; |
int y2 = wa.y+wa.h; |
377 |
for (int x=wa.x; x<x2; x++) { |
for (int x=wa.x; x<x2; x++) { |
378 |
for (int y=wa.y; y<y2; y++) { |
for (int y=wa.y; y<y2; y++) { |
379 |
Field &f = fields(x,y); |
Field2 &f2 = m_fields(x,y); |
380 |
if (f.updatep) { |
if (f2.updatep) { |
381 |
shadow_layer->update(x,y); |
shadow_layer->update(x,y); |
382 |
f.redrawp = true; |
f2.redrawp = true; |
383 |
f.updatep = false; |
f2.updatep = false; |
384 |
} |
} |
385 |
if (f.redrawp) { |
if (f2.redrawp) { |
386 |
ScreenArea sa(int((x-m_offset[0])*m_tilew), |
ScreenArea sa(int((x-m_offset[0])*m_tilew), |
387 |
int((y-m_offset[1])*m_tileh), |
int((y-m_offset[1])*m_tileh), |
388 |
m_tilew, |
m_tilew, |
389 |
m_tileh); |
m_tileh); |
390 |
sa.intersect(area); |
sa.intersect(area); |
391 |
clip(gc, sa); |
clip(gc, sa); |
392 |
draw_field(gc, f, x,y); |
draw_field(gc, x,y); |
393 |
f.redrawp = false; |
f2.redrawp = false; |
394 |
m_screen->update_rect(sa); |
m_screen->update_rect(sa); |
395 |
} |
} |
396 |
} |
} |
427 |
if (id == magic_spriteid) |
if (id == magic_spriteid) |
428 |
return; |
return; |
429 |
Sprite *sprite = sprites[id]; |
Sprite *sprite = sprites[id]; |
430 |
if ((fabs(newpos[0]-sprite->pos[0]) > 1.0/TileWidth) || |
|
431 |
(fabs(newpos[1]-sprite->pos[1]) > 1.0/TileHeight)) |
int oldx, oldy; |
432 |
{ |
int newx, newy; |
433 |
|
engine->world_to_screen (newpos, &newx, &newy); |
434 |
|
engine->world_to_screen (sprite->pos, &oldx, &oldy); |
435 |
|
|
436 |
|
if (oldx != newx || oldy != newy) { |
437 |
redraw_sprite_region(id); |
redraw_sprite_region(id); |
438 |
sprite->pos = newpos; |
sprite->pos = newpos; |
439 |
redraw_sprite_region(id); |
redraw_sprite_region(id); |
497 |
} |
} |
498 |
} |
} |
499 |
|
|
500 |
|
void |
501 |
|
DL_Sprites::draw (px::GC &gc, const WorldArea &a, int x, int y) |
502 |
|
{ |
503 |
|
clip (gc, get_engine()->world_to_screen(a)); |
504 |
|
draw_sprites (false, gc); |
505 |
|
} |
506 |
|
|
507 |
void |
void |
508 |
DL_Sprites::draw_sprites (bool shades, GC &gc) |
DL_Sprites::draw_sprites (bool shades, GC &gc) |
509 |
{ |
{ |
537 |
Sprite *s = sprites[id]; |
Sprite *s = sprites[id]; |
538 |
int x = int(s->pos[0]-0.5); |
int x = int(s->pos[0]-0.5); |
539 |
int y = int(s->pos[1]-0.5); |
int y = int(s->pos[1]-0.5); |
540 |
engine->mark_redraw_area (Rect(x, y, 3, 3)); |
get_engine()->mark_redraw_area (Rect(x, y, 3, 3)); |
541 |
} |
} |
542 |
|
|
543 |
|
|
544 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
545 |
// GRID MODELS |
// GRID LAYER |
546 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
547 |
|
|
548 |
|
DL_Grid::DL_Grid() |
549 |
|
{ |
550 |
|
} |
551 |
|
|
552 |
|
void |
553 |
|
DL_Grid::new_world (int w, int h) |
554 |
|
{ |
555 |
|
m_models = ModelArray (w, h); |
556 |
|
} |
557 |
|
|
558 |
|
void |
559 |
|
DL_Grid::mark_update (int x, int y) |
560 |
|
{ |
561 |
|
get_engine()->mark_update_area (WorldArea (x, y, 2, 2)); |
562 |
|
} |
563 |
|
|
564 |
|
void |
565 |
|
DL_Grid::set_model (int x, int y, Model *m) |
566 |
|
{ |
567 |
|
if (m_models(x,y) != m) { |
568 |
|
delete m_models(x,y); |
569 |
|
m_models(x,y) = m; |
570 |
|
mark_update(x,y); |
571 |
|
} |
572 |
|
} |
573 |
|
|
574 |
|
Model * |
575 |
|
DL_Grid::get_model (int x, int y) |
576 |
|
{ |
577 |
|
return m_models(x,y); |
578 |
|
} |
579 |
|
|
580 |
|
Model * |
581 |
|
DL_Grid::yield_model (int x, int y) |
582 |
|
{ |
583 |
|
Model *m = m_models(x,y); |
584 |
|
m_models(x,y) = 0; |
585 |
|
mark_update(x,y); |
586 |
|
return m; |
587 |
|
} |
588 |
|
|
589 |
|
|
590 |
|
void |
591 |
|
DL_Grid::draw (px::GC &gc, const WorldArea &a, int destx, int desty) |
592 |
|
{ |
593 |
|
int x2 = a.x+a.w; |
594 |
|
int y2 = a.y+a.h; |
595 |
|
for (int x=a.x; x<x2; ++x) |
596 |
|
for (int y=a.y; y<y2; ++y) |
597 |
|
if (Model *m = m_models(x,y)) |
598 |
|
m->draw(gc, destx, desty); |
599 |
|
} |
600 |
|
|
601 |
|
|
602 |
|
|
603 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
606 |
|
|
607 |
#include "SDL_gfxPrimitives.h" |
#include "SDL_gfxPrimitives.h" |
608 |
|
|
609 |
|
void |
610 |
|
DL_Lines::draw (px::GC &gc, const WorldArea &a, int x, int y) |
611 |
|
{ |
612 |
|
clip (gc, get_engine()->world_to_screen(a)); |
613 |
|
draw_lines(gc); |
614 |
|
} |
615 |
|
|
616 |
|
|
617 |
void |
void |
618 |
DL_Lines::draw_lines (GC &gc) |
DL_Lines::draw_lines (GC &gc) |
619 |
{ |
{ |
746 |
line_layer->kill_line(id); |
line_layer->kill_line(id); |
747 |
} |
} |
748 |
|
|
749 |
|
|
750 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
751 |
// SHADOWS |
// SHADOWS |
752 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
753 |
|
|
754 |
namespace |
DL_Shadows::DL_Shadows(DL_Grid *grid, DL_Sprites *sprites) |
755 |
{ |
: m_grid(grid), m_sprites(sprites), |
756 |
class ShadowLayer_Alpha : public ShadowLayer { |
m_gridcache() |
|
public: |
|
|
ShadowLayer_Alpha(); |
|
|
~ShadowLayer_Alpha(); |
|
|
|
|
|
void new_world(int w, int h); |
|
|
void update (int x, int y); |
|
|
void draw(GC &gc, int xpos, int ypos, int x, int y); |
|
|
private: |
|
|
void shadow_blit (px::Surface *scr, int x, int y, |
|
|
px::Surface *shadows, px::Rect r); |
|
|
|
|
|
Surface *new_surface(); |
|
|
void dispose_surface(Surface *s); |
|
|
Surface *get_cache(int x, int y); |
|
|
bool draw_stone_shade(GC &gc, int x, int y, Field &f); |
|
|
|
|
|
// Variables. |
|
|
Surface *shadow_surface; |
|
|
Uint32 shadow_ckey; // Color key |
|
|
Array2<Surface *> m_gridcache; |
|
|
Array2<bool> has_shadow; |
|
|
vector<Surface *> m_surface_avail; |
|
|
Surface *buffer; |
|
|
}; |
|
|
|
|
|
class ShadowLayer_Stippled : public ShadowLayer { |
|
|
public: |
|
|
ShadowLayer_Stippled() {} |
|
|
void update (int x, int y) {} |
|
|
void draw(GC &gc, int xpos, int ypos, int x, int y) |
|
|
{} |
|
|
private: |
|
|
|
|
|
}; |
|
|
} |
|
|
|
|
|
ShadowLayer_Alpha::ShadowLayer_Alpha() |
|
|
: m_gridcache() |
|
757 |
{ |
{ |
758 |
SDL_Surface *ss = SDL_CreateRGBSurface(SDL_SWSURFACE, |
SDL_Surface *ss = SDL_CreateRGBSurface(SDL_SWSURFACE, |
759 |
TileWidth, TileHeight, |
TileWidth, TileHeight, |
765 |
buffer = new Surface(ss); |
buffer = new Surface(ss); |
766 |
} |
} |
767 |
|
|
768 |
ShadowLayer_Alpha::~ShadowLayer_Alpha() |
DL_Shadows::~DL_Shadows() |
769 |
{ |
{ |
770 |
delete_sequence(m_gridcache.begin(), m_gridcache.end()); |
delete_sequence(m_gridcache.begin(), m_gridcache.end()); |
771 |
delete_sequence(m_surface_avail.begin(), m_surface_avail.end()); |
delete_sequence(m_surface_avail.begin(), m_surface_avail.end()); |
773 |
} |
} |
774 |
|
|
775 |
void |
void |
776 |
ShadowLayer_Alpha::new_world(int w, int h) |
DL_Shadows::new_world(int w, int h) |
777 |
{ |
{ |
778 |
Array2<Surface*>::iterator i; |
Array2<Surface*>::iterator i; |
779 |
for (i=m_gridcache.begin();i!=m_gridcache.end(); ++i) |
for (i=m_gridcache.begin();i!=m_gridcache.end(); ++i) |
783 |
} |
} |
784 |
|
|
785 |
Surface * |
Surface * |
786 |
ShadowLayer_Alpha::new_surface() |
DL_Shadows::new_surface() |
787 |
{ |
{ |
788 |
Surface *s = 0; |
Surface *s = 0; |
789 |
if (m_surface_avail.empty()) { |
if (m_surface_avail.empty()) { |
801 |
} |
} |
802 |
|
|
803 |
void |
void |
804 |
ShadowLayer_Alpha::dispose_surface(Surface *s) |
DL_Shadows::dispose_surface(Surface *s) |
805 |
{ |
{ |
806 |
if (s) |
if (s) |
807 |
m_surface_avail.push_back(s); |
m_surface_avail.push_back(s); |
809 |
|
|
810 |
|
|
811 |
Surface * |
Surface * |
812 |
ShadowLayer_Alpha::get_cache(int x, int y) |
DL_Shadows::get_cache(int x, int y) |
813 |
{ |
{ |
814 |
Surface *s= m_gridcache(x,y); |
Surface *s= m_gridcache(x,y); |
815 |
if (!s) |
if (!s) |
818 |
} |
} |
819 |
|
|
820 |
bool |
bool |
821 |
ShadowLayer_Alpha::draw_stone_shade(GC &gc, int x, int y, Field &f) |
DL_Shadows::draw_stone_shade(GC &gc, int x, int y, Field &f) |
822 |
{ |
{ |
823 |
Model *m=f.layers[enigma::GRID_STONES]; |
Model *m=f.layers[enigma::GRID_STONES]; |
824 |
if (m) |
if (m) |
827 |
} |
} |
828 |
|
|
829 |
void |
void |
830 |
ShadowLayer_Alpha::update (int x, int y) |
DL_Shadows::update (int x, int y) |
831 |
{ |
{ |
832 |
int has_sh = false; |
int has_sh = false; |
833 |
|
|
854 |
} |
} |
855 |
|
|
856 |
void |
void |
857 |
ShadowLayer_Alpha::draw(GC &gc, int xpos, int ypos, int x, int y) |
DL_Shadows::draw (px::GC &gc, const WorldArea &a, int x, int y) |
858 |
|
{ |
859 |
|
draw (gc, x, y, a.x, a. y); |
860 |
|
} |
861 |
|
|
862 |
|
|
863 |
|
void |
864 |
|
DL_Shadows::draw(GC &gc, int xpos, int ypos, int x, int y) |
865 |
{ |
{ |
866 |
bool has_actor = false; |
bool has_actor = false; |
867 |
|
|
906 |
} |
} |
907 |
|
|
908 |
void |
void |
909 |
ShadowLayer_Alpha::shadow_blit (px::Surface *scr, int x, int y, |
DL_Shadows::shadow_blit (px::Surface *scr, int x, int y, |
910 |
px::Surface *shadows, px::Rect r) |
px::Surface *shadows, px::Rect r) |
911 |
{ |
{ |
912 |
r.intersect(scr->size()); |
r.intersect(scr->size()); |
961 |
display::Init() |
display::Init() |
962 |
{ |
{ |
963 |
InitModels(); |
InitModels(); |
964 |
status_bar = new StatusBarImpl (inventoryarea); |
gamedpy = new GameDisplay; |
|
|
|
|
// Initialize display engine |
|
|
engine = new DisplayEngine (video::GetScreen()); |
|
|
engine->set_screen_area (gamearea); |
|
|
engine->add_layer (sprite_layer = new DL_Sprites); |
|
|
engine->add_layer (line_layer = new DL_Lines); |
|
|
engine->add_layer (effects_layer = new DL_Sprites); |
|
|
effects_layer->set_maxsprites(10); |
|
|
|
|
|
SetShadowType(SHADOW_ALPHA); |
|
965 |
} |
} |
966 |
|
|
967 |
void |
void |
968 |
display::Shutdown() |
display::Shutdown() |
969 |
{ |
{ |
970 |
active_models.clear(); |
active_models.clear(); |
971 |
delete status_bar; |
delete gamedpy; |
|
delete shadow_layer; |
|
|
delete engine; |
|
972 |
|
|
973 |
ShutdownModels(); |
ShutdownModels(); |
974 |
} |
} |
975 |
|
|
976 |
void |
void display::Tick (double dtime) { |
977 |
display::NewWorld(int w, int h) |
gamedpy->tick(dtime); |
|
{ |
|
|
SetFollowMode(FOLLOW_NONE); |
|
|
|
|
|
engine->new_world (w, h); |
|
|
|
|
|
active_models.clear(); |
|
|
|
|
|
fields = FieldArray(w, h); |
|
|
ScrollX = ScrollY = 0; |
|
|
|
|
|
status_bar->new_world(); |
|
|
shadow_layer->new_world(w,h); |
|
|
engine->mark_update_world(); |
|
978 |
} |
} |
979 |
|
|
980 |
void |
StatusBar * display::GetStatusBar() { |
981 |
display::Tick (double dtime) |
return gamedpy->get_status_bar(); |
|
{ |
|
|
engine->tick (dtime); |
|
|
|
|
|
ModelList &am = active_models; |
|
|
am.remove_if(mem_fun(&Model::is_garbage)); |
|
|
|
|
|
/* for_each does not work; animation may remove itself during |
|
|
tick() */ |
|
|
for (ModelList::iterator i=am.begin(); i!=am.end(); ) { |
|
|
ModelList::iterator n=next(i); |
|
|
(*i)->tick(dtime); |
|
|
i=n; |
|
|
} |
|
|
for_each(am.begin(), am.end(), &maybe_redraw_model); |
|
|
|
|
|
follow_doit(dtime); |
|
|
|
|
|
status_bar->tick (dtime); |
|
982 |
} |
} |
983 |
|
|
984 |
StatusBar * |
void display::NewWorld(int w, int h) { |
985 |
display::GetStatusBar() |
gamedpy->new_world (w, h); |
|
{ |
|
|
return status_bar; |
|
|
} |
|
|
|
|
|
void |
|
|
display::SetShadowType(ShadowType st) |
|
|
{ |
|
|
delete shadow_layer; |
|
|
if (options::BitsPerPixel == 16) |
|
|
shadow_layer = new ShadowLayer_Alpha; |
|
|
else |
|
|
shadow_layer = new ShadowLayer_Stippled; |
|
986 |
} |
} |
987 |
|
|
988 |
|
|
989 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
990 |
// Sprite following code |
// Sprite following code |
991 |
//---------------------------------------------------------------------- |
//---------------------------------------------------------------------- |
992 |
|
|
|
namespace |
|
|
{ |
|
|
class Follow { |
|
|
public: |
|
|
virtual ~Follow() {} |
|
|
virtual void tick(double dtime) = 0; |
|
|
virtual void center() =0; |
|
|
}; |
|
|
|
|
|
class Follow_Screen : public Follow { |
|
|
public: |
|
|
void tick(double dtime); |
|
|
void center(); |
|
|
}; |
|
|
|
|
|
class Follow_Scrolling : public Follow { |
|
|
public: |
|
|
Follow_Scrolling(); |
|
|
void tick(double dtime); |
|
|
void center(); |
|
|
private: |
|
|
bool currently_scrolling; |
|
|
V2 curpos, destpos; |
|
|
V2 dir; |
|
|
double scrollspeed; |
|
|
double resttime; |
|
|
}; |
|
|
} |
|
|
|
|
|
namespace |
|
|
{ |
|
|
SpriteId follow_sprite = magic_spriteid; |
|
|
FollowMode follow_mode = FOLLOW_NONE; |
|
|
Follow *follower = 0; |
|
|
} |
|
|
|
|
993 |
void |
void |
994 |
Follow_Screen::center() |
Follower_Screen::center(const px::V2 &point) |
995 |
{ |
{ |
996 |
tick(0); |
tick(0, point); |
997 |
} |
} |
998 |
|
|
999 |
/* Determine whether the screen must be scrolled or not, and change |
/* Determine whether the screen must be scrolled or not, and change |
1000 |
the coordinate origin of the screen accordingly. */ |
the coordinate origin of the screen accordingly. */ |
1001 |
void |
void |
1002 |
Follow_Screen::tick(double) |
Follower_Screen::tick(double, const px::V2 &point) |
1003 |
{ |
{ |
|
assert(follow_sprite != magic_spriteid); |
|
|
Sprite *s = sprite_layer->sprites[follow_sprite]; |
|
|
|
|
1004 |
for (;;) { |
for (;;) { |
1005 |
int sx, sy; |
int sx, sy; |
1006 |
engine->world_to_screen(s->pos, &sx, &sy); |
engine->world_to_screen(point, &sx, &sy); |
1007 |
|
|
1008 |
V2 screenoff = engine->get_offset(); |
V2 screenoff = engine->get_offset(); |
1009 |
|
|
1028 |
|
|
1029 |
|
|
1030 |
|
|
1031 |
Follow_Scrolling::Follow_Scrolling() |
Follower_Scrolling::Follower_Scrolling() |
1032 |
: currently_scrolling(false), |
: currently_scrolling(false), |
1033 |
scrollspeed(0), resttime(0) |
scrollspeed(0), resttime(0) |
1034 |
{} |
{} |
1035 |
|
|
1036 |
void |
void |
1037 |
Follow_Scrolling::center() |
Follower_Scrolling::center(const px::V2 &point) |
1038 |
{ |
{ |
1039 |
tick(1000); |
tick(1000, point); |
1040 |
tick(1000); |
tick(1000, point); |
1041 |
} |
} |
1042 |
|
|
1043 |
void |
void |
1044 |
Follow_Scrolling::tick(double dtime) |
Follower_Scrolling::tick(double dtime, const px::V2 &point) |
1045 |
{ |
{ |
|
assert(follow_sprite != magic_spriteid); |
|
|
Sprite *s = sprite_layer->sprites[follow_sprite]; |
|
|
|
|
|
V2 spritepos (s->pos[0], s->pos[1]); |
|
|
|
|
1046 |
int sx, sy; |
int sx, sy; |
1047 |
engine->world_to_screen(s->pos, &sx, &sy); |
engine->world_to_screen(point, &sx, &sy); |
1048 |
|
|
1049 |
if (currently_scrolling) { |
if (currently_scrolling) { |
1050 |
resttime -= dtime; |
resttime -= dtime; |
1067 |
{ |
{ |
1068 |
currently_scrolling = true; |
currently_scrolling = true; |
1069 |
curpos = V2(ScrollX, ScrollY); |
curpos = V2(ScrollX, ScrollY); |
1070 |
destpos = curpos + spritepos - V2(ScrollX+gamearea.w/TileWidth/2, |
destpos = curpos + point - V2(ScrollX+gamearea.w/TileWidth/2, |
1071 |
ScrollY+gamearea.h/TileHeight/2); |
ScrollY+gamearea.h/TileHeight/2); |
1072 |
destpos[0] = int(destpos[0]*TileWidth)/TileWidth; |
destpos[0] = int(destpos[0]*TileWidth)/TileWidth; |
1073 |
destpos[1] = int(destpos[1]*TileHeight)/TileHeight; |
destpos[1] = int(destpos[1]*TileHeight)/TileHeight; |
1074 |
destpos[0] = max(0, min((int) destpos[0], |
destpos[0] = max(0, min((int) destpos[0], |
1087 |
} |
} |
1088 |
} |
} |
1089 |
|
|
1090 |
static void |
void display::FollowSprite(SpriteId id) { |
1091 |
follow_doit(double dtime) |
gamedpy->set_follow_sprite (id); |
|
{ |
|
|
if (follow_sprite != magic_spriteid) { |
|
|
follower->tick(dtime); |
|
|
} |
|
|
} |
|
|
|
|
|
static void |
|
|
follow_center() |
|
|
{ |
|
|
if (follow_mode == FOLLOW_NONE) |
|
|
SetFollowMode(FOLLOW_SCREEN); |
|
|
if (follow_sprite != magic_spriteid) { |
|
|
follower->center(); |
|
|
} |
|
|
} |
|
|
|
|
|
static void |
|
|
set_follower (Follow *f) |
|
|
{ |
|
|
delete follower; |
|
|
follower = f; |
|
|
} |
|
|
|
|
|
|
|
|
void |
|
|
display::FollowSprite(SpriteId id) |
|
|
{ |
|
|
follow_sprite = id; |
|
|
follow_center(); |
|
1092 |
} |
} |
1093 |
|
|
1094 |
|
FollowMode display::SetFollowMode(FollowMode m) { |
1095 |
FollowMode |
return gamedpy->set_follow_mode(m); |
|
display::SetFollowMode(FollowMode m) |
|
|
{ |
|
|
FollowMode old=follow_mode; |
|
|
if (m != follow_mode) |
|
|
{ |
|
|
follow_mode = m; |
|
|
switch (follow_mode) { |
|
|
case FOLLOW_NONE: |
|
|
set_follower(0); |
|
|
break; |
|
|
case FOLLOW_SCROLLING: |
|
|
set_follower (new Follow_Scrolling); |
|
|
break; |
|
|
case FOLLOW_SCREEN: |
|
|
set_follower (new Follow_Screen); |
|
|
break; |
|
|
}; |
|
|
} |
|
|
return old; |
|
1096 |
} |
} |
1097 |
|
|
1098 |
//---------------------------------------- |
//---------------------------------------- |
1099 |
// Handling active models |
// Handling active models |
1100 |
//---------------------------------------- |
//---------------------------------------- |
1101 |
|
|
1102 |
Model* |
Model * |
1103 |
display::SetModel(const GridLoc &l, Model *m) |
CommonDisplay::set_model (const GridLoc &l, Model *m) |
1104 |
{ |
{ |
1105 |
int x = l.pos.x, y=l.pos.y; |
int x = l.pos.x, y=l.pos.y; |
1106 |
|
|
1107 |
|
switch (l.layer) { |
1108 |
|
case GRID_FLOOR: floor_layer->set_model (x, y, m); break; |
1109 |
|
case GRID_ITEMS: item_layer->set_model (x, y, m); break; |
1110 |
|
case GRID_STONES: |
1111 |
|
stone_layer->set_model (x, y, m); |
1112 |
|
// shadow_layer->set_model (x, y, m); |
1113 |
|
break; |
1114 |
|
case GRID_COUNT: break; |
1115 |
|
} |
1116 |
Field& f = fields(x, y); |
Field& f = fields(x, y); |
|
delete f.layers[l.layer]; |
|
1117 |
f.layers[l.layer] = m; |
f.layers[l.layer] = m; |
1118 |
if (m) |
if (m) |
1119 |
m->activate(double(x), double(y), false); |
m->activate(double(x), double(y), false); |
1120 |
mark_change(l); |
// mark_change(l); |
1121 |
return m; |
return m; |
1122 |
} |
} |
1123 |
|
|
1124 |
Model * |
Model * |
1125 |
display::SetModel(const GridLoc &l, const string &modelname) |
CommonDisplay::get_model (const GridLoc &l) |
1126 |
{ |
{ |
1127 |
return SetModel(l, MakeModel(modelname)); |
int x = l.pos.x, y=l.pos.y; |
1128 |
|
switch (l.layer) { |
1129 |
|
case GRID_FLOOR: return floor_layer->get_model (x, y); |
1130 |
|
case GRID_ITEMS: return item_layer->get_model (x, y); |
1131 |
|
case GRID_STONES: return stone_layer->get_model (x, y); |
1132 |
|
case GRID_COUNT: return 0; |
1133 |
|
} |
1134 |
|
return 0; |
1135 |
} |
} |
1136 |
|
|
1137 |
void |
Model * |
1138 |
display::KillModel(const GridLoc & l) |
CommonDisplay::yield_model (const GridLoc &l) |
1139 |
{ |
{ |
1140 |
|
int x = l.pos.x, y=l.pos.y; |
1141 |
|
fields(x, y).layers[l.layer] = 0; |
1142 |
|
switch (l.layer) { |
1143 |
|
case GRID_FLOOR: return floor_layer->yield_model (x, y); |
1144 |
|
case GRID_ITEMS: return item_layer->yield_model (x, y); |
1145 |
|
case GRID_STONES: return stone_layer->yield_model (x, y); |
1146 |
|
case GRID_COUNT: return 0; |
1147 |
|
} |
1148 |
|
return 0; |
1149 |
|
} |
1150 |
|
|
1151 |
|
Model *display::SetModel (const GridLoc &l, Model *m) { |
1152 |
|
return gamedpy->set_model (l, m); |
1153 |
|
} |
1154 |
|
|
1155 |
|
Model *display::SetModel (const GridLoc &l, const string &modelname) { |
1156 |
|
return SetModel(l, MakeModel(modelname)); |
1157 |
|
} |
1158 |
|
|
1159 |
|
void display::KillModel(const GridLoc & l) { |
1160 |
delete YieldModel(l); |
delete YieldModel(l); |
1161 |
} |
} |
1162 |
|
|
1163 |
Model * |
Model *display::GetModel(const GridLoc &l) { |
1164 |
display::GetModel(const GridLoc &l) |
return gamedpy->get_model (l); |
|
{ |
|
|
Field& f = fields(l.pos.x, l.pos.y); |
|
|
return f.layers[l.layer]; |
|
1165 |
} |
} |
1166 |
|
|
1167 |
Model * |
Model *display::YieldModel(const GridLoc &l) { |
1168 |
display::YieldModel(const GridLoc &l) |
return gamedpy->yield_model (l); |
|
{ |
|
|
Field& f = fields(l.pos.x, l.pos.y); |
|
|
Model *m = f.layers[l.layer]; |
|
|
f.layers[l.layer] = 0; |
|
|
mark_change(l); |
|
|
return m; |
|
1169 |
} |
} |
1170 |
|
|
1171 |
void |
void |
1172 |
display::AddEffect (const V3& pos, const char *modelname) |
display::AddEffect (const V3& pos, const char *modelname) |
1173 |
{ |
{ |
1174 |
Model *m = modelname ? MakeModel(modelname) : 0; |
gamedpy->add_effect (pos, MakeModel(modelname)); |
|
effects_layer->add_sprite(new Sprite (pos, SPRITE_EFFECT, m)); |
|
1175 |
} |
} |
1176 |
|
|
1177 |
SpriteId |
SpriteId |
1228 |
display_flags = DisplayFlags(display_flags ^ flag); |
display_flags = DisplayFlags(display_flags ^ flag); |
1229 |
} |
} |
1230 |
|
|
1231 |
static Uint32 last_frame_time = 0; |
void display::DrawAll (GC &gc) { |
1232 |
|
gamedpy->draw_all(gc); |
1233 |
|
} |
1234 |
|
|
1235 |
|
void display::RedrawAll(Screen *screen) { |
1236 |
|
gamedpy->redraw_all(screen); |
1237 |
|
} |
1238 |
|
|
1239 |
|
void display::Redraw(Screen *screen) { |
1240 |
|
gamedpy->redraw(screen); |
1241 |
|
} |
1242 |
|
|
1243 |
|
|
1244 |
|
|
1245 |
|
//---------------------------------------------------------------------- |
1246 |
|
// Game Display Engine |
1247 |
|
//---------------------------------------------------------------------- |
1248 |
|
|
1249 |
|
GameDisplay::GameDisplay() |
1250 |
|
: last_frame_time (0), |
1251 |
|
redraw_everything(false), |
1252 |
|
follow_sprite (magic_spriteid), |
1253 |
|
follow_mode (FOLLOW_NONE), |
1254 |
|
follower (0), |
1255 |
|
inventoryarea(0, 480-64, 640, 64) |
1256 |
|
{ |
1257 |
|
status_bar = new StatusBarImpl (inventoryarea); |
1258 |
|
|
1259 |
|
// Initialize display engine |
1260 |
|
engine = new DisplayEngine (video::GetScreen()); |
1261 |
|
engine->set_screen_area (gamearea); |
1262 |
|
|
1263 |
|
engine->add_layer (floor_layer = new DL_Grid); |
1264 |
|
engine->add_layer (item_layer = new DL_Grid); |
1265 |
|
engine->add_layer (shadow_layer = new DL_Shadows(0,0)); |
1266 |
|
engine->add_layer (sprite_layer = new DL_Sprites); |
1267 |
|
engine->add_layer (stone_layer = new DL_Grid); |
1268 |
|
engine->add_layer (line_layer = new DL_Lines); |
1269 |
|
engine->add_layer (effects_layer = new DL_Sprites); |
1270 |
|
effects_layer->set_maxsprites(10); |
1271 |
|
} |
1272 |
|
|
1273 |
|
GameDisplay::~GameDisplay() |
1274 |
|
{ |
1275 |
|
delete status_bar; |
1276 |
|
delete engine; |
1277 |
|
} |
1278 |
|
|
1279 |
|
void |
1280 |
|
GameDisplay::tick(double dtime) |
1281 |
|
{ |
1282 |
|
engine->tick (dtime); |
1283 |
|
status_bar->tick (dtime); |
1284 |
|
|
1285 |
|
ModelList &am = active_models; |
1286 |
|
am.remove_if(mem_fun(&Model::is_garbage)); |
1287 |
|
|
1288 |
|
/* for_each does not work; animation may remove itself during |
1289 |
|
tick() */ |
1290 |
|
for (ModelList::iterator i=am.begin(); i!=am.end(); ) { |
1291 |
|
ModelList::iterator n=next(i); |
1292 |
|
(*i)->tick(dtime); |
1293 |
|
i=n; |
1294 |
|
} |
1295 |
|
for_each(am.begin(), am.end(), &maybe_redraw_model); |
1296 |
|
|
1297 |
|
|
1298 |
|
if (follow_sprite != magic_spriteid) { |
1299 |
|
V3 point = sprite_layer->sprites[follow_sprite]->pos; |
1300 |
|
follower->tick(dtime, V2(point[0], point[1])); |
1301 |
|
} |
1302 |
|
} |
1303 |
|
|
1304 |
|
void |
1305 |
|
GameDisplay::new_world (int w, int h) |
1306 |
|
{ |
1307 |
|
active_models.clear(); |
1308 |
|
|
1309 |
|
status_bar->new_world(); |
1310 |
|
SetFollowMode(FOLLOW_NONE); |
1311 |
|
|
1312 |
|
fields = FieldArray(w, h); |
1313 |
|
engine->new_world (w, h); |
1314 |
|
shadow_layer->new_world(w,h); |
1315 |
|
engine->mark_update_world(); |
1316 |
|
|
1317 |
|
|
1318 |
|
ScrollX = ScrollY = 0; |
1319 |
|
} |
1320 |
|
|
1321 |
|
StatusBar * |
1322 |
|
GameDisplay::get_status_bar() const |
1323 |
|
{ |
1324 |
|
return status_bar; |
1325 |
|
} |
1326 |
|
|
1327 |
|
//---------------------------------------- |
1328 |
|
// Scrolling |
1329 |
|
//---------------------------------------- |
1330 |
|
|
1331 |
|
|
1332 |
|
FollowMode |
1333 |
|
GameDisplay::set_follow_mode (FollowMode m) |
1334 |
|
{ |
1335 |
|
FollowMode old=follow_mode; |
1336 |
|
if (m != follow_mode) |
1337 |
|
{ |
1338 |
|
follow_mode = m; |
1339 |
|
switch (follow_mode) { |
1340 |
|
case FOLLOW_NONE: |
1341 |
|
set_follower(0); |
1342 |
|
break; |
1343 |
|
case FOLLOW_SCROLLING: |
1344 |
|
set_follower (new Follower_Scrolling); |
1345 |
|
break; |
1346 |
|
case FOLLOW_SCREEN: |
1347 |
|
set_follower (new Follower_Screen); |
1348 |
|
break; |
1349 |
|
}; |
1350 |
|
} |
1351 |
|
return old; |
1352 |
|
} |
1353 |
|
|
1354 |
void |
void |
1355 |
display::DrawAll (GC &gc) |
GameDisplay::set_follower (Follower *f) |
1356 |
{ |
{ |
1357 |
engine->draw_all(gc); |
delete follower; |
1358 |
status_bar->redraw (gc, inventoryarea); |
follower = f; |
1359 |
} |
} |
1360 |
|
|
1361 |
void |
void |
1362 |
display::RedrawAll(Screen *scr) |
GameDisplay::follow_center() |
1363 |
{ |
{ |
1364 |
engine->mark_redraw_screen(); |
if (follow_mode == FOLLOW_NONE) |
1365 |
RedrawEverything = true; |
set_follow_mode (FOLLOW_SCREEN); |
1366 |
Redraw(scr); |
if (follow_sprite != magic_spriteid) { |
1367 |
|
V3 point = sprite_layer->sprites[follow_sprite]->pos; |
1368 |
|
follower->center (V2(point[0], point[1])); |
1369 |
|
} |
1370 |
} |
} |
1371 |
|
|
1372 |
void |
void |
1373 |
display::Redraw(Screen *screen) |
GameDisplay::set_follow_sprite(SpriteId id) |
1374 |
|
{ |
1375 |
|
follow_sprite = id; |
1376 |
|
follow_center(); |
1377 |
|
} |
1378 |
|
|
1379 |
|
//---------------------------------------- |
1380 |
|
// Screen updates |
1381 |
|
//---------------------------------------- |
1382 |
|
|
1383 |
|
void |
1384 |
|
GameDisplay::redraw_all(Screen *scr) |
1385 |
|
{ |
1386 |
|
engine->mark_redraw_screen(); |
1387 |
|
redraw_everything = true; |
1388 |
|
redraw (scr); |
1389 |
|
} |
1390 |
|
|
1391 |
|
void |
1392 |
|
GameDisplay::redraw(px::Screen *screen) |
1393 |
{ |
{ |
1394 |
GC gc(screen); |
GC gc(screen); |
1395 |
|
|
1396 |
engine->update_screen(); |
engine->update_screen(); |
1397 |
if (status_bar->has_changed() || RedrawEverything) { |
if (status_bar->has_changed() || redraw_everything) { |
1398 |
status_bar->redraw (gc, inventoryarea); |
status_bar->redraw (gc, inventoryarea); |
1399 |
screen->update_rect(inventoryarea); |
screen->update_rect(inventoryarea); |
1400 |
} |
} |
1413 |
screen->update_rect(area); |
screen->update_rect(area); |
1414 |
} |
} |
1415 |
screen->flush_updates(); |
screen->flush_updates(); |
1416 |
RedrawEverything = false; |
redraw_everything = false; |
1417 |
|
} |
1418 |
|
|
1419 |
|
void |
1420 |
|
GameDisplay::draw_all (GC &gc) |
1421 |
|
{ |
1422 |
|
engine->draw_all(gc); |
1423 |
|
status_bar->redraw (gc, inventoryarea); |
1424 |
} |
} |
1425 |
|
|