1 /*
2 * OpenBOR - http://www.chronocrash.com
3 * -----------------------------------------------------------------------
4 * All rights reserved, see LICENSE in OpenBOR root for details.
5 *
6 * Copyright (c) 2004 - 2014 OpenBOR Team
7 */
8
9 // Sprite queueing and sorting
10
11 #include <stdio.h>
12 #include "types.h"
13 #include "screen.h"
14 #include "sprite.h"
15 #include "draw.h"
16 #include "globals.h"
17
18 // This should be enough for most games...
19 // But bear in mind that text is also composed of sprites!
20 #define MAXQSPRITES 5000 // DEFAULT 5000
21
22 #define SQT_SPRITE 0
23 #define SQT_DOT 1
24 #define SQT_LINE 2
25 #define SQT_BOX 3
26 #define SQT_CIRCLE 4
27 #define SQT_SHADOW 5 //current unused, use common sprite method instead
28 #define SQT_SCREEN 6
29
30 #define SQ_MAX_PARAMS 3
31
32 typedef struct
33 {
34 int x;
35 int y;
36 int z;
37 int sortid;
38 void *frame;
39 s_drawmethod drawmethod;
40 int params[SQ_MAX_PARAMS];
41 int type;
42 } qstruct;
43
44 static qstruct queue[MAXQSPRITES];
45 static qstruct *order[MAXQSPRITES];
46
47 static int spritequeue_len = 0;
48 static int spriteq_old_len = 0;
49 static int spriteq_locked = 0;
50
51 // Return the current sprite count.
spriteq_get_sprite_count()52 int spriteq_get_sprite_count()
53 {
54 return spritequeue_len;
55 }
56
57 // Return the current sprite .
spriteq_get_sprite_max()58 int spriteq_get_sprite_max()
59 {
60 return MAXQSPRITES;
61 }
62
spriteq_add_frame(int x,int y,int z,s_sprite * frame,s_drawmethod * pdrawmethod,int sortid)63 void spriteq_add_frame(int x, int y, int z, s_sprite *frame, s_drawmethod *pdrawmethod, int sortid)
64 {
65 if(frame == NULL)
66 {
67 return;
68 }
69 if(spritequeue_len >= MAXQSPRITES)
70 {
71 return;
72 }
73 queue[spritequeue_len].type = SQT_SPRITE;
74 queue[spritequeue_len].x = x;
75 queue[spritequeue_len].y = y;
76 queue[spritequeue_len].z = z;
77 queue[spritequeue_len].sortid = sortid;
78 queue[spritequeue_len].frame = frame;
79 if(pdrawmethod)
80 {
81 queue[spritequeue_len].drawmethod = *pdrawmethod;
82 }
83 else
84 {
85 queue[spritequeue_len].drawmethod.flag = 0;
86 }
87 queue[spritequeue_len].params[0] = 0; // determin if the sprite's center should be readjusted;
88 order[spritequeue_len] = &queue[spritequeue_len];
89 ++spritequeue_len;
90 }
91
spriteq_add_sprite(int x,int y,int z,int id,s_drawmethod * pdrawmethod,int sortid)92 void spriteq_add_sprite(int x, int y, int z, int id, s_drawmethod *pdrawmethod, int sortid)
93 {
94 extern s_sprite_map *sprite_map;
95 s_sprite *loadsprite2(char * filename, int * width, int * height);
96 s_sprite *frame = sprite_map[id].node->sprite;
97 if(frame == NULL)
98 {
99 sprite_map[id].node->sprite = frame = loadsprite2(sprite_map[id].node->filename, NULL, NULL);
100 }
101 if(spritequeue_len >= MAXQSPRITES)
102 {
103 return;
104 }
105 queue[spritequeue_len].type = SQT_SPRITE;
106 queue[spritequeue_len].x = x;
107 queue[spritequeue_len].y = y;
108 queue[spritequeue_len].z = z;
109 queue[spritequeue_len].sortid = sortid;
110 queue[spritequeue_len].frame = frame;
111 if(pdrawmethod)
112 {
113 queue[spritequeue_len].drawmethod = *pdrawmethod;
114 }
115 else
116 {
117 queue[spritequeue_len].drawmethod.flag = 0;
118 }
119 queue[spritequeue_len].params[0] = 1; // determin if the sprite's center should be readjusted;
120 queue[spritequeue_len].params[1] = sprite_map[id].centerx; // centerx
121 queue[spritequeue_len].params[2] = sprite_map[id].centery; // centery
122 order[spritequeue_len] = &queue[spritequeue_len];
123 ++spritequeue_len;
124 }
125
spriteq_add_screen(int x,int y,int z,s_screen * ps,s_drawmethod * pdrawmethod,int sortid)126 void spriteq_add_screen(int x, int y, int z, s_screen *ps, s_drawmethod *pdrawmethod, int sortid)
127 {
128 if(spritequeue_len >= MAXQSPRITES)
129 {
130 return;
131 }
132 if(ps == NULL)
133 {
134 return;
135 }
136 queue[spritequeue_len].type = SQT_SCREEN;
137 queue[spritequeue_len].x = x;
138 queue[spritequeue_len].y = y;
139 queue[spritequeue_len].z = z;
140 queue[spritequeue_len].sortid = sortid;
141 queue[spritequeue_len].frame = ps;
142 if(pdrawmethod)
143 {
144 queue[spritequeue_len].drawmethod = *pdrawmethod;
145 }
146 else
147 {
148 queue[spritequeue_len].drawmethod.flag = 0;
149 }
150 order[spritequeue_len] = &queue[spritequeue_len];
151 ++spritequeue_len;
152 }
153
spriteq_add_dot(int sx,int sy,int z,int colour,s_drawmethod * pdrawmethod)154 void spriteq_add_dot(int sx, int sy, int z, int colour, s_drawmethod *pdrawmethod)
155 {
156 if(spritequeue_len >= MAXQSPRITES)
157 {
158 return;
159 }
160 queue[spritequeue_len].type = SQT_DOT;
161 queue[spritequeue_len].x = sx;
162 queue[spritequeue_len].y = sy;
163 queue[spritequeue_len].z = z;
164 queue[spritequeue_len].sortid = 0;
165 queue[spritequeue_len].params[0] = colour;
166 queue[spritequeue_len].frame = NULL;
167 if(pdrawmethod)
168 {
169 queue[spritequeue_len].drawmethod = *pdrawmethod;
170 }
171 else
172 {
173 queue[spritequeue_len].drawmethod.flag = 0;
174 }
175 order[spritequeue_len] = &queue[spritequeue_len];
176 ++spritequeue_len;
177 }
178
spriteq_add_line(int sx,int sy,int ex,int ey,int z,int colour,s_drawmethod * pdrawmethod)179 void spriteq_add_line(int sx, int sy, int ex, int ey, int z, int colour, s_drawmethod *pdrawmethod)
180 {
181 if(spritequeue_len >= MAXQSPRITES)
182 {
183 return;
184 }
185 queue[spritequeue_len].type = SQT_LINE;
186 queue[spritequeue_len].x = sx;
187 queue[spritequeue_len].y = sy;
188 queue[spritequeue_len].params[0] = colour;
189 queue[spritequeue_len].params[1] = ex;
190 queue[spritequeue_len].params[2] = ey;
191 queue[spritequeue_len].z = z;
192 queue[spritequeue_len].sortid = 0;
193 queue[spritequeue_len].frame = NULL;
194 if(pdrawmethod)
195 {
196 queue[spritequeue_len].drawmethod = *pdrawmethod;
197 }
198 else
199 {
200 queue[spritequeue_len].drawmethod.flag = 0;
201 }
202 order[spritequeue_len] = &queue[spritequeue_len];
203 ++spritequeue_len;
204 }
205
spriteq_add_box(int x,int y,int width,int height,int z,int colour,s_drawmethod * pdrawmethod)206 void spriteq_add_box(int x, int y, int width, int height, int z, int colour, s_drawmethod *pdrawmethod)
207 {
208 if(spritequeue_len >= MAXQSPRITES)
209 {
210 return;
211 }
212 queue[spritequeue_len].type = SQT_BOX;
213 queue[spritequeue_len].x = x;
214 queue[spritequeue_len].y = y;
215 queue[spritequeue_len].params[0] = colour;
216 queue[spritequeue_len].params[1] = width;
217 queue[spritequeue_len].params[2] = height;
218 queue[spritequeue_len].z = z;
219 queue[spritequeue_len].sortid = 0;
220 queue[spritequeue_len].frame = NULL;
221 if(pdrawmethod)
222 {
223 queue[spritequeue_len].drawmethod = *pdrawmethod;
224 }
225 else
226 {
227 queue[spritequeue_len].drawmethod.flag = 0;
228 }
229 order[spritequeue_len] = &queue[spritequeue_len];
230 ++spritequeue_len;
231 }
232
233
234 // Double sort code (sorts high and low simultaneously from 2 directions)
235 // Can't get much faster than this - I think
spriteq_sort()236 static void spriteq_sort()
237 {
238 int i, lidx, hidx, lz, hz, start, end, lsid, hsid;
239 void *tempp;
240
241 start = 0;
242 end = spritequeue_len - 1;
243
244 while(start < end)
245 {
246 lidx = end;
247 hidx = start;
248
249 lz = order[lidx]->z;
250 hz = order[hidx]->z;
251 lsid = order[lidx]->sortid;
252 hsid = order[hidx]->sortid;
253
254 // Search for lowest and highest Z coord
255 for(i = start; i <= end; i++)
256 {
257 if(order[i]->z < lz || (order[i]->z == lz && order[i]->sortid < lsid))
258 {
259 lidx = i;
260 lz = order[i]->z;
261 lsid = order[i]->sortid;
262 }
263 if(order[i]->z > hz || (order[i]->z == hz && order[i]->sortid > hsid))
264 {
265 hidx = i;
266 hz = order[i]->z;
267 hsid = order[i]->sortid;
268 }
269 }
270
271 // No need to sort equal values!
272 if(hz == lz && hsid == lsid)
273 {
274 return;
275 }
276
277 // Exchange values (low)
278 tempp = order[start];
279 order[start] = order[lidx];
280 order[lidx] = tempp;
281
282 // Prevent confusion:
283 // This value may already have been exchanged!
284 if(hidx == start)
285 {
286 hidx = lidx;
287 }
288
289 // Exchange values (high)
290 tempp = order[end];
291 order[end] = order[hidx];
292 order[hidx] = tempp;
293
294 ++start;
295 --end;
296 }
297 }
298
299 // newonly is 1 means don't draw locked sprites
spriteq_draw(s_screen * screen,int newonly,int minz,int maxz,int dx,int dy)300 void spriteq_draw(s_screen *screen, int newonly, int minz, int maxz, int dx, int dy)
301 {
302 int i, x, y;
303
304 spriteq_sort();
305
306 for(i = 0; i < spritequeue_len; i++)
307 {
308 if((newonly && spriteq_locked && order[i] < queue + spriteq_old_len) || order[i]->z < minz || order[i]->z > maxz)
309 {
310 continue;
311 }
312
313 x = order[i]->x + dx;
314 y = order[i]->y + dy;
315
316 switch(order[i]->type)
317 {
318 case SQT_SPRITE: // sprite
319
320 if(order[i]->params[0])// determin if the sprite's center should be readjusted;
321 {
322 ((s_sprite *)(order[i]->frame))->centerx = order[i]->params[1];
323 ((s_sprite *)(order[i]->frame))->centery = order[i]->params[2];
324 }
325 putsprite(x, y, order[i]->frame, screen, &(order[i]->drawmethod));
326 break;
327 case SQT_SCREEN: // draw a screen instead of sprite
328 putscreen(screen, (s_screen *)(order[i]->frame), x, y, &(order[i]->drawmethod));
329 break;
330 case SQT_DOT:
331 putpixel(x, y, order[i]->params[0], screen, &(order[i]->drawmethod));
332 break;
333 case SQT_LINE:
334 putline(x, y, order[i]->params[1] + dx, order[i]->params[2] + dy, order[i]->params[0], screen, &(order[i]->drawmethod));
335 break;
336 case SQT_BOX:
337 putbox(x, y, order[i]->params[1], order[i]->params[2], order[i]->params[0], screen, &(order[i]->drawmethod));
338 break;
339 default:
340 continue;
341 }
342 }
343 }
344
345 // UT: lock the spriteq, don't clearn old sprites
spriteq_lock()346 void spriteq_lock()
347 {
348 spriteq_old_len = spritequeue_len;
349 spriteq_locked = 1;
350 }
351
352 // don't forget to unlock the queue, or we'll have troubles
353 // if the sprite is unloaded for some reason
spriteq_unlock()354 void spriteq_unlock()
355 {
356 spriteq_locked = 0;
357 }
358
spriteq_islocked()359 int spriteq_islocked()
360 {
361 return (spriteq_locked != 0);
362 }
363
spriteq_clear()364 void spriteq_clear()
365 {
366 int i;
367 if(spriteq_locked)
368 {
369 // when locked, always draw previous sprites,
370 // and only clear new sprites
371 spritequeue_len = spriteq_old_len;
372 for(i = 0; i < spriteq_old_len; i++)
373 {
374 order[i] = queue + i;
375 }
376 }
377 else
378 {
379 spriteq_old_len = spritequeue_len;
380 spritequeue_len = 0;
381 }
382 }
383
384
385
386
387