2 * Copyright (C) 2003 Daniel Heck
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "ecl_geom.hh"
23 #include "ecl_array2.hh"
24 #include "ecl_alist.hh"
30 /* -------------------- DisplayEngine -------------------- */
34 DisplayEngine (int tilew
=32, int tileh
=32);
37 /* ---------- Class configuration ---------- */
38 void add_layer (DisplayLayer
*l
);
39 void set_screen_area (const ecl::Rect
& r
);
40 void set_tilesize (int w
, int h
);
42 int get_tilew () const { return m_tilew
; }
43 int get_tileh () const { return m_tileh
; }
44 int get_width() const { return m_width
; }
45 int get_height() const { return m_height
; }
46 const ecl::Rect
&get_area() const { return m_area
; }
48 /* ---------- Scrolling / page flipping ---------- */
49 void set_offset (const ecl::V2
&off
);
50 void move_offset (const ecl::V2
&off
);
51 ecl::V2
get_offset () const { return m_offset
; }
53 /* ---------- Game-related stuff ---------- */
54 void new_world (int w
, int h
);
55 void tick (double dtime
);
57 /* ---------- Coordinate conversion ---------- */
58 void world_to_screen (const ecl::V2
& pos
, int *x
, int *y
);
59 WorldArea
screen_to_world (const ScreenArea
&a
);
60 ScreenArea
world_to_screen (const WorldArea
&a
);
62 /* "Video" coordinates are like screen coordinates, except the
63 origin coincides with the world origin, not the current
64 scrolling position. */
65 void world_to_video (const ecl::V2
&pos
, int *x
, int *y
);
66 void video_to_screen (int x
, int y
, int *xx
, int *yy
);
67 void video_to_world (const ecl::Rect
&r
, ecl::Rect
&s
);
69 V2
to_world (const V2
&pos
);
71 /* ---------- Screen upates ---------- */
73 void mark_redraw_screen();
74 void mark_redraw_area (const WorldArea
&wa
, int delay
=0);
76 void redraw_screen_area (const ScreenArea
&a
);
77 void redraw_world_area (const WorldArea
&a
);
80 void draw_all (ecl::GC
&gc
);
84 void update_layer (DisplayLayer
*l
, WorldArea wa
);
86 /* ---------- Variables ---------- */
88 std::vector
<DisplayLayer
*> m_layers
;
92 ecl::V2 m_offset
; // Offset in world units
93 ecl::V2 m_new_offset
; // New offset in world units
94 int m_screenoffset
[2]; // Offset in screen units
97 // Screen area occupied by level display
100 // Width and height of the world in tiles
101 int m_width
, m_height
;
103 ecl::Array2
<char> m_redrawp
;
107 /* -------------------- DisplayLayer -------------------- */
112 virtual ~DisplayLayer() {}
114 /* ---------- Class configuration ---------- */
115 void set_engine (DisplayEngine
*e
) { m_engine
= e
; }
116 DisplayEngine
*get_engine() const { return m_engine
; }
118 /* ---------- DisplayLayer interface ---------- */
119 virtual void prepare_draw (const WorldArea
&) {}
120 virtual void draw (ecl::GC
&gc
, const WorldArea
&a
, int x
, int y
) = 0;
121 virtual void draw_onepass (ecl::GC
&/*gc*/) {}
122 virtual void tick (double /*dtime*/) {}
123 virtual void new_world (int /*w*/, int /*h*/) {}
126 void mark_redraw_area (const ecl::Rect
&r
)
128 get_engine()->mark_redraw_area(r
);
131 DisplayEngine
*m_engine
;
135 /* -------------------- ModelLayer -------------------- */
137 /*! The base class for all layers that contains Models. */
138 class ModelLayer
: public DisplayLayer
{
142 // DisplayLayer interface
143 void tick (double dtime
);
144 void new_world (int, int);
147 void activate (Model
*m
);
148 void deactivate (Model
*m
);
149 void maybe_redraw_model(Model
*m
, bool immediately
=false);
151 virtual int redraw_size () const { return 2; }
155 ModelList m_active_models
;
156 ModelList m_active_models_new
;
160 /* -------------------- DL_Grid -------------------- */
162 /*! Layer for grid-aligned models (stones, floor tiles, items). */
164 class DL_Grid
: public ModelLayer
{
166 DL_Grid(int redrawsize
= 1);
169 void set_model (int x
, int y
, Model
*m
);
170 Model
*get_model (int x
, int y
);
171 Model
*yield_model (int x
, int y
);
174 // DL_Grid interface.
175 void mark_redraw (int x
, int y
);
177 // DisplayLayer interface.
178 void new_world (int w
, int h
);
179 void draw (ecl::GC
&gc
, const WorldArea
&a
, int x
, int y
);
181 // ModelLayer interface
182 virtual int redraw_size () const { return m_redrawsize
; }
185 typedef ecl::Array2
<Model
*> ModelArray
;
191 /* -------------------- Sprites -------------------- */
193 class Sprite
: public ecl::Nocopy
{
203 Sprite (const V2
& p
, SpriteLayer l
, Model
*m
)
204 : model(m
), pos(p
), layer(l
), visible(true)
206 screenpos
[0] = screenpos
[1] = 0;
207 above
[0] = above
[1] = above
[2] = NULL
;
208 beneath
[0] = beneath
[1] = beneath
[2] = NULL
;
210 ~Sprite() { delete model
; }
213 typedef std::vector
<Sprite
*> SpriteList
;
215 class DL_Sprites
: public ModelLayer
{
220 /* ---------- DisplayLayer interface ---------- */
221 void draw (ecl::GC
&gc
, const WorldArea
&a
, int x
, int y
);
222 void draw_onepass (ecl::GC
&gc
);
223 void new_world (int, int);
225 /* ---------- Member functions ---------- */
226 SpriteId
add_sprite (Sprite
*sprite
, bool isDispensible
= false);
227 void kill_sprite (SpriteId id
);
228 void move_sprite (SpriteId
, const ecl::V2
& newpos
);
229 void replace_sprite (SpriteId id
, Model
*m
);
231 void redraw_sprite_region (SpriteId id
);
232 void draw_sprites (bool shades
, ecl::GC
&gc
, const WorldArea
&a
);
234 Model
*get_model (SpriteId id
) { return sprites
[id
]->model
; }
236 void set_maxsprites (unsigned m
, unsigned c
) { maxsprites
= m
; dispensiblesprites
= c
;}
238 Sprite
*get_sprite(SpriteId id
);
240 static const SpriteId MAGIC_SPRITEID
= 1000000;
242 SpriteList bottomSprites
; // bottom sprite for each x
245 void update_sprite_region (Sprite
* s
, bool is_add
, bool is_redraw_only
= false);
247 // ModelLayer interface
248 virtual void tick (double /*dtime*/);
251 unsigned numsprites
; // Current number of sprites
252 unsigned maxsprites
; // Maximum number of sprites
253 unsigned dispensiblesprites
; // Threshold above which just critical sprites are accepted
257 /* -------------------- Shadows -------------------- */
259 struct StoneShadowCache
;
261 class DL_Shadows
: public DisplayLayer
{
263 DL_Shadows(DL_Grid
*grid
, DL_Sprites
*sprites
);
266 void new_world(int w
, int h
);
267 void draw (ecl::GC
&gc
, int xpos
, int ypos
, int x
, int y
);
269 void draw (ecl::GC
&gc
, const WorldArea
&a
, int x
, int y
);
271 /* ---------- Private functions ---------- */
272 void shadow_blit (ecl::Surface
*scr
, int x
, int y
,
273 ecl::Surface
*shadows
, ecl::Rect r
);
275 bool has_actor (int x
, int y
);
276 virtual void prepare_draw (const WorldArea
&);
278 Model
* get_shadow_model(int x
, int y
);
280 /* ---------- Variables ---------- */
281 DL_Grid
*m_grid
; // Stone models
282 DL_Sprites
*m_sprites
; // Sprite models
284 StoneShadowCache
*m_cache
;
286 Uint32 shadow_ckey
; // Color key
287 ecl::Surface
*buffer
;
289 ecl::Array2
<bool> m_hasactor
;
293 /* -------------------- Lines -------------------- */
298 unsigned short r
,g
,b
;
301 Line(const V2
&s
, const V2
&e
, unsigned short rc
, unsigned short gc
, unsigned short bc
, bool isThick
) :
302 start (s
), end (e
), r (rc
), g (gc
), b (bc
), thick (isThick
) {
308 typedef ecl::AssocList
<unsigned, Line
> LineMap
;
310 class DL_Lines
: public DisplayLayer
{
316 void draw (ecl::GC
&/*gc*/, const WorldArea
&/*a*/, int /*x*/, int /*y*/)
318 void draw_onepass (ecl::GC
&gc
);
320 RubberHandle
add_line (const V2
&p1
, const V2
&p2
, unsigned short rc
, unsigned short gc
, unsigned short bc
, bool isThick
);
321 void set_startpoint (unsigned id
, const V2
&p1
);
322 void set_endpoint (unsigned id
, const V2
&p2
);
323 void kill_line (unsigned id
);
324 void new_world (int w
, int h
);
328 void mark_redraw_line (const Line
&r
);
336 /* -------------------- CommonDisplay -------------------- */
338 /*! Parts of the display engine that are common to the game and
340 class CommonDisplay
{
342 CommonDisplay (const ScreenArea
&a
= ScreenArea (0, 0, 10, 10));
345 Model
*set_model (const GridLoc
&l
, Model
*m
);
346 Model
*get_model (const GridLoc
&l
);
347 Model
*yield_model (const GridLoc
&l
);
349 void set_floor (int x
, int y
, Model
*m
);
350 void set_item (int x
, int y
, Model
*m
);
351 void set_stone (int x
, int y
, Model
*m
);
353 DisplayEngine
*get_engine() const { return m_engine
; }
355 SpriteHandle
add_effect (const V2
& pos
, Model
*m
, bool isDispensible
= false);
356 SpriteHandle
add_sprite (const V2
&pos
, Model
*m
);
358 RubberHandle
add_line (V2 p1
, V2 p2
, unsigned short rc
, unsigned short gc
, unsigned short bc
, bool isThick
);
360 void new_world (int w
, int h
);
364 DL_Grid
*floor_layer
;
366 DL_Grid
*stone_layer
;
368 DL_Sprites
*effects_layer
;
370 DL_Lines
*line_layer
;
371 DL_Sprites
*sprite_layer
;
372 DL_Shadows
*shadow_layer
;
376 DisplayEngine
*m_engine
;
380 /* -------------------- Scrolling -------------------- */
385 Follower (DisplayEngine
*e
);
386 virtual ~Follower() {}
387 virtual void tick(double dtime
, const ecl::V2
&point
) = 0;
388 virtual void center(const ecl::V2
&point
);
390 void set_boundary (double b
) {
396 DisplayEngine
*get_engine() const { return m_engine
; }
397 bool set_offset (V2 offs
);
398 double get_hoff() const;
399 double get_voff() const;
400 ecl::V2
get_scrollpos(const ecl::V2
&point
);
406 DisplayEngine
*m_engine
;
409 /*! Follows a sprite by flipping to the next screen as soon as the
410 sprite reaches the border of the current screen. */
411 class Follower_Screen
: public Follower
{
413 Follower_Screen(DisplayEngine
*e
, double borderx
= 0.5, double bordery
= 0.5);
414 void tick(double dtime
, const ecl::V2
&point
);
417 /*! Follows a sprite by softly scrolling the visible area of the
418 screen as soon as the sprite reaches the border of the current
420 class Follower_Scrolling
: public Follower
{
422 Follower_Scrolling (DisplayEngine
*e
, bool screenwise
, double borderx
= 0.5, double bordery
= 0.5);
423 void tick(double dtime
, const ecl::V2
&point
);
424 void center(const ecl::V2
&point
);
426 bool currently_scrolling
;
434 class Follower_Smooth
: public Follower
{
436 Follower_Smooth (DisplayEngine
*e
);
437 void tick (double time
, const ecl::V2
&point
);
438 void center (const ecl::V2
&point
);
439 virtual void set_boundary (double b
) {}
441 ecl::V2
calc_offset (const ecl::V2
&point
);
445 /* -------------------- GameDisplay -------------------- */
447 class GameDisplay
: public CommonDisplay
{
449 GameDisplay (const ScreenArea
&gamearea
,
450 const ScreenArea
&inventoryarea
);
453 StatusBar
* get_status_bar() const;
455 void tick(double dtime
);
456 void new_world (int w
, int h
);
458 void resize_game_area (int w
, int h
);
460 /* ---------- Scrolling ---------- */
461 void set_follow_mode (FollowMode m
);
462 void updateFollowMode();
463 void follow_center();
464 void set_follow_sprite(SpriteId id
);
465 void set_reference_point (const ecl::V2
&point
);
466 void set_scroll_boundary (double d
);
468 // current screen coordinates of reference point
469 void get_reference_point_coordinates(int *x
, int *y
);
471 /* ---------- Screen updates ---------- */
472 void redraw (ecl::Screen
*scr
);
473 void redraw_all (ecl::Screen
*scr
);
474 void draw_all (ecl::GC
&gc
);
477 void set_follower (Follower
*f
);
478 void draw_borders (ecl::GC
&gc
);
480 /* ---------- Variables ---------- */
481 Uint32 last_frame_time
;
482 bool redraw_everything
;
483 StatusBarImpl
*status_bar
;
485 V2 m_reference_point
;
486 Follower
*m_follower
;
488 ScreenArea inventoryarea
;