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