Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1806 | yogev_ezra | 1 | /* |
2 | ------------------------------------------------------------ |
||
3 | Fixed Rate Pig - a fixed logic frame rate demo |
||
4 | ------------------------------------------------------------ |
||
5 | * Copyright (C) 2004 David Olofson |
||
6 | * |
||
7 | * This software is released under the terms of the GPL. |
||
8 | * |
||
9 | * Contact author for permission if you want to use this |
||
10 | * software, or work derived from it, under other terms. |
||
11 | */ |
||
12 | |||
13 | #ifndef PIG_ENGINE_H |
||
14 | #define PIG_ENGINE_H |
||
15 | |||
16 | #include "SDL.h" |
||
17 | #include |
||
18 | #ifndef M_PI |
||
19 | # define M_PI 3.14159265358979323846 /* pi */ |
||
20 | #endif |
||
21 | #include "dirty.h" |
||
22 | |||
23 | |||
24 | /*---------------------------------------------------------- |
||
25 | Game Engine |
||
26 | ----------------------------------------------------------*/ |
||
27 | |||
28 | typedef struct PIG_object PIG_object; |
||
29 | typedef struct PIG_engine PIG_engine; |
||
30 | |||
31 | |||
32 | /* Interpolated point */ |
||
33 | typedef struct PIG_ipoint |
||
34 | { |
||
35 | /* From the last logic frame: */ |
||
36 | float ox, oy; /* Position */ |
||
37 | |||
38 | /* From the last/current rendered frame: */ |
||
39 | int gimage; /* Sprite frame index */ |
||
40 | float gx, gy; /* Interpolated position */ |
||
41 | } PIG_ipoint; |
||
42 | |||
43 | |||
44 | /* |
||
45 | * Game logic events |
||
46 | * |
||
47 | * PREFRAME: |
||
48 | * Occurs once per logic frame, before collision and |
||
49 | * off-screen detection, and before timer handlers. |
||
50 | * |
||
51 | * TIMERx: |
||
52 | * Occurs whenever timer x expires. Timers are one- |
||
53 | * shot, but can be reloaded by the handler for |
||
54 | * periodic action. Timer events are handled before |
||
55 | * before collision and off-screen detection. |
||
56 | * |
||
57 | * HIT_TILE: |
||
58 | * Occurs when the hot-spot of an object hits a |
||
59 | * marked side of a tile, and the corresponding bit |
||
60 | * in 'tilemask' is set. |
||
61 | * |
||
62 | * HIT_OBJECT: |
||
63 | * Occurs when the collision circle of an object |
||
64 | * intersects the collision circle of another object, |
||
65 | * provided one or more bits in 'hitgroup' of the |
||
66 | * other object matches bits in 'hitmask'. |
||
67 | * |
||
68 | * OFFSCREEN: |
||
69 | * Occurs when an object is off-screen. This takes |
||
70 | * in account the hot-spot and bounding rectangle of |
||
71 | * the current sprite frame. |
||
72 | * |
||
73 | * POSTFRAME: |
||
74 | * Occurs once per logic frame, after collision |
||
75 | * detection, off-screen detection and all other |
||
76 | * events. |
||
77 | * |
||
78 | */ |
||
79 | #define PIG_TIMERS 3 |
||
80 | typedef enum |
||
81 | { |
||
82 | PIG_PREFRAME, |
||
83 | PIG_TIMER0, |
||
84 | PIG_TIMER1, |
||
85 | PIG_TIMER2, |
||
86 | PIG_HIT_TILE, |
||
87 | PIG_HIT_OBJECT, |
||
88 | PIG_OFFSCREEN, |
||
89 | PIG_POSTFRAME |
||
90 | } PIG_events; |
||
91 | |||
92 | |||
93 | typedef enum |
||
94 | { |
||
95 | PIG_NONE = 0, |
||
96 | |||
97 | /* Bit positions */ |
||
98 | PIG_TOP_B = 0, |
||
99 | PIG_BOTTOM_B = 1, |
||
100 | PIG_LEFT_B = 2, |
||
101 | PIG_RIGHT_B = 3, |
||
102 | |||
103 | /* Masks */ |
||
104 | PIG_TOP = 1 << PIG_TOP_B, |
||
105 | PIG_BOTTOM = 1 << PIG_BOTTOM_B, |
||
106 | PIG_LEFT = 1 << PIG_LEFT_B, |
||
107 | PIG_RIGHT = 1 << PIG_RIGHT_B, |
||
108 | |||
109 | /* Combined masks */ |
||
110 | PIG_TL = PIG_TOP | PIG_LEFT, |
||
111 | PIG_TR = PIG_TOP | PIG_RIGHT, |
||
112 | PIG_BL = PIG_BOTTOM | PIG_LEFT, |
||
113 | PIG_BR = PIG_BOTTOM | PIG_RIGHT, |
||
114 | PIG_ALL = 0xf, |
||
115 | } PIG_sides; |
||
116 | |||
117 | |||
118 | typedef enum |
||
119 | { |
||
120 | PIG_UNCHANGED = -10000000, |
||
121 | PIG_MIN = -10000001, |
||
122 | PIG_CENTER = -10000002, |
||
123 | PIG_MAX = -10000003 |
||
124 | } PIG_values; |
||
125 | |||
126 | |||
127 | /* Collision info */ |
||
128 | typedef struct |
||
129 | { |
||
130 | float ff; /* Fractional frame */ |
||
131 | int x, y; /* Exact position */ |
||
132 | PIG_sides sides; /* Side of tile hit */ |
||
133 | } PIG_cinfo; |
||
134 | |||
135 | |||
136 | typedef struct PIG_event |
||
137 | { |
||
138 | PIG_events type; |
||
139 | |||
140 | /* For HIT_TILE, HIT_OBJECT and OFFSCREEN: */ |
||
141 | PIG_cinfo cinfo; /* Detailed collision info */ |
||
142 | |||
143 | /* For HIT_OBJECT: */ |
||
144 | PIG_object *obj; /* Which object? */ |
||
145 | } PIG_event; |
||
146 | |||
147 | |||
148 | /* Logic object */ |
||
149 | struct PIG_object |
||
150 | { |
||
151 | PIG_engine *owner; |
||
152 | PIG_object *next, *prev; |
||
153 | |||
154 | int id; /* Unique ID. 0 means "free". */ |
||
155 | |||
156 | int ibase; /* Sprite frame base index */ |
||
157 | int image; /* Sprite frame offset */ |
||
158 | float x, y; /* Position */ |
||
159 | float vx, vy; /* Speed */ |
||
160 | float ax, ay; /* Acceleration */ |
||
161 | PIG_ipoint ip; |
||
162 | int tilemask; /* Sprite/tile mask [PIG_ALL] */ |
||
163 | |||
164 | int hitmask; /* Sprite/sprite mask [0] */ |
||
165 | int hitgroup; /* Sprite/sprite group [0] */ |
||
166 | |||
167 | int timer[PIG_TIMERS]; /* Down-counting timers */ |
||
168 | int age; /* Age timer (logic frames) */ |
||
169 | |||
170 | int score; |
||
171 | int power; |
||
172 | int target; |
||
173 | int state; |
||
174 | |||
175 | void (*handler)(PIG_object *po, const PIG_event *ev); |
||
176 | |||
177 | void *userdata; |
||
178 | }; |
||
179 | |||
180 | |||
181 | /* Level map */ |
||
182 | typedef struct PIG_map |
||
183 | { |
||
184 | PIG_engine *owner; |
||
185 | |||
186 | int w, h; /* Size of map (tiles) */ |
||
187 | unsigned char *map; /* 2D aray of tile indices */ |
||
188 | unsigned char *hit; /* 2D aray of collision flags */ |
||
189 | |||
190 | int tw, th; /* Size of one tile (pixels) */ |
||
191 | SDL_Surface *tiles; /* Tile palette image */ |
||
192 | unsigned char hitinfo[256]; /* Collision info for the tiles */ |
||
193 | } PIG_map; |
||
194 | |||
195 | |||
196 | /* Sprite frame */ |
||
197 | typedef struct PIG_sprite |
||
198 | { |
||
199 | int w, h; /* Size of sprite (pixels) */ |
||
200 | int hotx, hoty; /* Hot-spot offset (pixels) */ |
||
201 | int radius; /* Collision zone radius (pixels) */ |
||
202 | SDL_Surface *surface; |
||
203 | } PIG_sprite; |
||
204 | |||
205 | /* Engine */ |
||
206 | struct PIG_engine |
||
207 | { |
||
208 | /* Video stuff */ |
||
209 | SDL_Surface *screen; |
||
210 | SDL_Surface *buffer; /* For h/w surface displays */ |
||
211 | SDL_Surface *surface; /* Where to render to */ |
||
212 | int pages; /* # of display VRAM buffers */ |
||
213 | SDL_Rect view; /* Viewport pos & size (pixels) */ |
||
214 | int page; /* Current page (double buffer) */ |
||
215 | PIG_dirtytable *pagedirty[2]; /* One table for each page */ |
||
216 | PIG_dirtytable *workdirty; /* The work dirtytable */ |
||
217 | |||
218 | /* "Live" switches */ |
||
219 | int interpolation; |
||
220 | int direct; /* 1 ==> render directly to screen */ |
||
221 | int show_dirtyrects; |
||
222 | |||
223 | /* Time */ |
||
224 | double time; /* Logic time (frames) */ |
||
225 | int frame; /* Logic time; integer part */ |
||
226 | |||
227 | /* Background graphics */ |
||
228 | PIG_map *map; |
||
229 | |||
230 | /* Sprites and stuff */ |
||
231 | PIG_object *objects; |
||
232 | PIG_object *object_pool; |
||
233 | int object_id_counter; |
||
234 | int nsprites; |
||
235 | PIG_sprite **sprites; |
||
236 | |||
237 | /* Logic frame global handlers */ |
||
238 | void (*before_objects)(PIG_engine *pe); |
||
239 | void (*after_objects)(PIG_engine *pe); |
||
240 | |||
241 | /* Space for user data */ |
||
242 | void *userdata; |
||
243 | }; |
||
244 | |||
245 | |||
246 | /* |
||
247 | * Engine |
||
248 | */ |
||
249 | PIG_engine *pig_open(SDL_Surface *screen); |
||
250 | void pig_close(PIG_engine *pe); |
||
251 | |||
252 | /* Set viewport size and position */ |
||
253 | void pig_viewport(PIG_engine *pe, int x, int y, int w, int h); |
||
254 | |||
255 | /* Start engine at logic time 'frame' */ |
||
256 | void pig_start(PIG_engine *pe, int frame); |
||
257 | |||
258 | /* |
||
259 | * Load a sprite palette image. The image is chopped up into |
||
260 | * sprites, based on 'sw' and 'sh', and added as new frames |
||
261 | * in the sprite bank. Default values: |
||
262 | * Hot-spot: (sw/2, sh/2) |
||
263 | * Collision radius: 0.2 * (sw + sh) |
||
264 | * |
||
265 | * Passing 0 for 'sw' and/or 'sh' makes pig_sprites() take |
||
266 | * the respective value from the image width and/or height. |
||
267 | * |
||
268 | * Returns the index of the first frame loaded. |
||
269 | */ |
||
270 | int pig_sprites(PIG_engine *pe, const char *filename, int sw, int sh); |
||
271 | |||
272 | /* Set hot-spot of sprite 'frame' to (hotx, hoty) */ |
||
273 | int pig_hotspot(PIG_engine *pe, int frame, int hotx, int hoty); |
||
274 | |||
275 | /* Set sprite/sprite collision zone radius of 'frame' */ |
||
276 | int pig_radius(PIG_engine *pe, int frame, int radius); |
||
277 | |||
278 | /* Advance logic time by 'frames' logic frames */ |
||
279 | void pig_animate(PIG_engine *pe, float frames); |
||
280 | |||
281 | /* |
||
282 | * Manually add a dirtyrect for pig_refresh(). |
||
283 | * 'dr' can be outside the engine viewport. |
||
284 | */ |
||
285 | void pig_dirty(PIG_engine *pe, SDL_Rect *dr); |
||
286 | |||
287 | /* |
||
288 | * Do what's needed to deal with the dirtyrects |
||
289 | * and then make the new frame visible. |
||
290 | */ |
||
291 | void pig_flip(PIG_engine *pe); |
||
292 | |||
293 | /* |
||
294 | * Refresh the viewport and any additional dirtyrects. |
||
295 | * |
||
296 | * Note that this does not refresh the entire viewport; |
||
297 | * only the areas that have actually changed! |
||
298 | */ |
||
299 | void pig_refresh(PIG_engine *pe); |
||
300 | |||
301 | /* |
||
302 | * Refresh the whole viewport, including sprites. |
||
303 | */ |
||
304 | void pig_refresh_all(PIG_engine *pe); |
||
305 | |||
306 | /* Render a sprite "manually", bypassing the engine */ |
||
307 | void pig_draw_sprite(PIG_engine *pe, int frame, int x, int y); |
||
308 | |||
309 | /* |
||
310 | * Get the collision flags for the tile at (x, y), |
||
311 | * where the unit of x and y is pixels. The return |
||
312 | * is the PIG_sides flags for the tile, or PIG_NONE |
||
313 | * if (x, y) is outside the map. |
||
314 | */ |
||
315 | int pig_test_map(PIG_engine *pe, int x, int y); |
||
316 | |||
317 | /* |
||
318 | * Find the first "collidable" tile side when going from |
||
319 | * (x1, y1) to (x2, y2). 'mask' determines which tile sides |
||
320 | * are considered for collisions. |
||
321 | * |
||
322 | * Returns the side(s) hit, if any tile was hit. If the return |
||
323 | * is non-zero, the PIG_cinfo struct at 'ci' contains detailed |
||
324 | * information about the collision. |
||
325 | */ |
||
326 | int pig_test_map_vector(PIG_engine *pe, int x1, int y1, int x2, int y2, |
||
327 | int mask, PIG_cinfo *ci); |
||
328 | |||
329 | |||
330 | /* |
||
331 | * Map |
||
332 | */ |
||
333 | PIG_map *pig_map_open(PIG_engine *pe, int w, int h); |
||
334 | void pig_map_close(PIG_map *pm); |
||
335 | |||
336 | /* Load a tile palette image */ |
||
337 | int pig_map_tiles(PIG_map *pm, const char *filename, int tw, int th); |
||
338 | |||
339 | /* |
||
340 | * Set tile collision info for 'count' tiles, starting at |
||
341 | * 'first'. Each tile in the tile palette has a set of |
||
342 | * PIG_sides flags that determine which sides the tile are |
||
343 | * considered for sprite/map collisions. |
||
344 | */ |
||
345 | void pig_map_collisions(PIG_map *pm, unsigned first, unsigned count, |
||
346 | PIG_sides sides); |
||
347 | |||
348 | /* |
||
349 | * Load a map from a string (one byte/tile). 'trans' |
||
350 | * is a string used for translating 'data' into integer |
||
351 | * tile indices. Each position in 'trans' corresponds |
||
352 | * to one tile in the tile palette. |
||
353 | */ |
||
354 | int pig_map_from_string(PIG_map *pm, const char *trans, const char *data); |
||
355 | |||
356 | |||
357 | /* |
||
358 | * Object |
||
359 | */ |
||
360 | |||
361 | /* |
||
362 | * Create an object with the initial position (x, y). If |
||
363 | * 'last' is 1, the object will end up last in the |
||
364 | * processing and rendering order, otherwise, first. |
||
365 | * |
||
366 | * Note that relative processing order is very important |
||
367 | * to objects that chase each other and stuff like that! |
||
368 | * If they're placed in the "wrong" order, the tracking |
||
369 | * objects get an extra frame of reaction time, which is |
||
370 | * annoying if it's not what you intend. |
||
371 | */ |
||
372 | PIG_object *pig_object_open(PIG_engine *pe, int x, int y, int last); |
||
373 | |||
374 | /* |
||
375 | * Delete an object. |
||
376 | * |
||
377 | * Note that objects are never actually deleted. Instead, |
||
378 | * they are placed in a free pool, where pig_object_open() |
||
379 | * looks for objects to recycle. |
||
380 | * |
||
381 | * In fact, they are not even freed when you ask for it, |
||
382 | * but rather kept around until the next rendered frame, |
||
383 | * so they can be removed from the screen correctly. |
||
384 | */ |
||
385 | void pig_object_close(PIG_object *po); |
||
386 | |||
387 | /* |
||
388 | * Close all objects. |
||
389 | */ |
||
390 | void pig_object_close_all(PIG_engine *pe); |
||
391 | |||
392 | /* |
||
393 | * Find object by 'id', starting at object 'start'. |
||
394 | * |
||
395 | * The search starts at 'start' and is done in both |
||
396 | * directions in parallel, assuming that the matching |
||
397 | * object is near 'start' in the list. (It usually is |
||
398 | * when dealing with linked objects.) |
||
399 | * |
||
400 | * Returns NULL if the object was not found. |
||
401 | */ |
||
402 | PIG_object *pig_object_find(PIG_object *start, int id); |
||
403 | |||
404 | #endif /* PIG_ENGINE_H */><>><>><>><> |