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 // Primitive drawing functions. Should really be done in ASM...
10 // Last update: 24-jun-2002
11
12 #include "types.h"
13 #include "draw.h"
14
15 #ifndef NULL
16 #define NULL ((void*)0)
17 #endif
18
19
20 #define abso(x) (x<0?-x:x)
21
22
23 // Not a particularly fast line function, but it works, and clips!
line(int sx,int sy,int ex,int ey,int colour,s_screen * screen,int alpha)24 void line(int sx, int sy, int ex, int ey, int colour, s_screen *screen, int alpha)
25 {
26
27 int diffx, diffy;
28 int absdiffx, absdiffy;
29 int xdir, ydir;
30 int thres;
31 int d;
32 unsigned char *lut;
33
34 // Some off-screen lines may slip through this test!
35 if(sx < 0 && ex < 0)
36 {
37 return;
38 }
39 if(sy < 0 && ey < 0)
40 {
41 return;
42 }
43 if(sx >= screen->width && ex >= screen->width)
44 {
45 return;
46 }
47 if(sy >= screen->height && ey >= screen->height)
48 {
49 return;
50 }
51
52
53 // Check clipping and calculate new coords if necessary
54
55 diffx = ex - sx;
56 diffy = ey - sy;
57
58 if(sx < 0)
59 {
60 sy -= (sx * diffy / diffx);
61 sx = 0;
62 }
63 if(sy < 0)
64 {
65 sx -= (sy * diffx / diffy);
66 sy = 0;
67 }
68 if(sx >= screen->width)
69 {
70 sy -= ((sx - screen->width) * diffy / diffx);
71 sx = screen->width - 1;
72 }
73 if(sy >= screen->height)
74 {
75 sx -= ((sy - screen->height) * diffx / diffy);
76 sy = screen->height - 1;
77 }
78
79 if(ex < 0)
80 {
81 ey -= (ex * diffy / diffx);
82 ex = 0;
83 }
84 if(ey < 0)
85 {
86 ex -= (ey * diffx / diffy);
87 ey = 0;
88 }
89 if(ex >= screen->width)
90 {
91 ey -= ((ex - screen->width) * diffy / diffx);
92 ex = screen->width - 1;
93 }
94 if(ey >= screen->height)
95 {
96 ex -= ((ey - screen->height) * diffx / diffy);
97 ey = screen->height - 1;
98 }
99
100
101 // Second test: the lines that passed test 1 won't pass this time!
102 if(sx < 0 || ex < 0)
103 {
104 return;
105 }
106 if(sy < 0 || ey < 0)
107 {
108 return;
109 }
110 if(sx >= screen->width || ex >= screen->width)
111 {
112 return;
113 }
114 if(sy >= screen->height || ey >= screen->height)
115 {
116 return;
117 }
118
119
120 // Recalculate directions
121 diffx = ex - sx;
122 diffy = ey - sy;
123
124 absdiffx = abso(diffx);
125 absdiffy = abso(diffy);
126
127 sy *= screen->width;
128 ey *= screen->width;
129
130 lut = alpha > 0 ? blendtables[alpha - 1] : NULL;
131
132 if(lut)
133 {
134 lut += (colour << 8);
135 }
136
137 if(absdiffx > absdiffy)
138 {
139 // Draw a flat line
140 thres = absdiffx >> 1;
141 xdir = 1;
142 if(diffx < 0)
143 {
144 xdir = -xdir;
145 }
146 ydir = screen->width;
147 if(diffy < 0)
148 {
149 ydir = -ydir;
150 }
151 while(sx != ex)
152 {
153 d = sx + sy;
154 screen->data[d] = (lut && screen->data[d]) ? (lut[screen->data[d]]) : colour;
155 sx += xdir;
156 if((thres -= absdiffy) <= 0)
157 {
158 sy += ydir;
159 thres += absdiffx;
160 }
161 }
162 d = ex + ey;
163 screen->data[d] = (lut && screen->data[d]) ? (lut[screen->data[d]]) : colour;
164 return;
165 }
166
167 // Draw a high line
168 thres = absdiffy >> 1;
169 xdir = 1;
170 if(diffx < 0)
171 {
172 xdir = -1;
173 }
174 ydir = screen->width;
175 if(diffy < 0)
176 {
177 ydir = -ydir;
178 }
179 while(sy != ey)
180 {
181 d = sx + sy;
182 screen->data[d] = (lut && screen->data[d]) ? (lut[screen->data[d]]) : colour;;
183 sy += ydir;
184 if((thres -= absdiffx) <= 0)
185 {
186 sx += xdir;
187 thres += absdiffy;
188 }
189 }
190 d = ex + ey;
191 screen->data[d] = (lut && screen->data[d]) ? (lut[screen->data[d]]) : colour;
192 }
193
194
195
196
197
drawbox(int x,int y,int width,int height,int colour,s_screen * screen,int alpha)198 void drawbox(int x, int y, int width, int height, int colour, s_screen *screen, int alpha)
199 {
200 unsigned char *cp;
201 unsigned char *lut;
202
203 if(width <= 0)
204 {
205 return;
206 }
207 if(height <= 0)
208 {
209 return;
210 }
211 if(screen == NULL)
212 {
213 return;
214 }
215
216 if(x < 0)
217 {
218 if((width += x) <= 0)
219 {
220 return;
221 }
222 x = 0;
223 }
224 else if(x >= screen->width)
225 {
226 return;
227 }
228 if(y < 0)
229 {
230 if((height += y) <= 0)
231 {
232 return;
233 }
234 y = 0;
235 }
236 else if(y >= screen->height)
237 {
238 return;
239 }
240 if(x + width > screen->width)
241 {
242 width = screen->width - x;
243 }
244 if(y + height > screen->height)
245 {
246 height = screen->height - y;
247 }
248
249 cp = (unsigned char *)screen->data + y * screen->width + x;
250 lut = alpha > 0 ? blendtables[alpha - 1] : NULL;
251 if(lut)
252 {
253 lut += (colour << 8);
254 }
255 while(--height >= 0)
256 {
257 for(x = 0; x < width; x++)
258 {
259 *cp = (lut && *cp) ? (lut[((int)(*cp)) & 0xFF]) : colour;
260 ++cp;
261 }
262 cp += screen->width - width;
263 }
264 }
265
266
267
268 // Putpixel used by circle function
_putpixel(int x,int y,int colour,s_screen * screen,int alpha)269 void _putpixel(int x, int y, int colour, s_screen *screen, int alpha)
270 {
271 int pixind;
272 unsigned char *lut;
273 if((unsigned)x > screen->width || (unsigned)y > screen->height)
274 {
275 return;
276 }
277 pixind = x + y * screen->width;
278 lut = alpha > 0 ? blendtables[alpha - 1] : NULL;
279 if(lut)
280 {
281 lut += (colour << 8);
282 }
283 screen->data[pixind] = (lut && screen->data[pixind]) ? (lut[(int)(screen->data[pixind]) & 0xFF]) : colour;
284 }
285
286
287
288
289 // Code to draw a circle.
290 // I ripped this, not sure how it works...
291 // It seems it devides the circle into 8 parts, which are drawn
292 // simultaneously.
293 // Not much optimization, though, since every pixel is clipped
294 // separately.
295
circle(int x,int y,int rad,int col,s_screen * screen,int alpha)296 void circle(int x, int y, int rad, int col, s_screen *screen, int alpha)
297 {
298 int cx = 0; // 'Circle X'
299 int cy = rad; // 'Circle Y'
300 int df = 1 - rad;
301 int d_e = 3;
302 int d_se = -2 * rad + 5;
303
304 do
305 {
306 _putpixel(x + cx, y + cy, col, screen, alpha);
307 if(cx)
308 {
309 _putpixel(x - cx, y + cy, col, screen, alpha);
310 }
311 if(cy)
312 {
313 _putpixel(x + cx, y - cy, col, screen, alpha);
314 }
315 if(cx && cy)
316 {
317 _putpixel(x - cx, y - cy, col, screen, alpha);
318 }
319
320 if(cx != cy)
321 {
322 _putpixel(x + cy, y + cx, col, screen, alpha);
323 if(cx)
324 {
325 _putpixel(x + cy, y - cx, col, screen, alpha);
326 }
327 if(cy)
328 {
329 _putpixel(x - cy, y + cx, col, screen, alpha);
330 }
331 if(cx && cy)
332 {
333 _putpixel(x - cy, y - cx, col, screen, alpha);
334 }
335 }
336
337 if(df < 0)
338 {
339 df += d_e;
340 d_e += 2;
341 d_se += 2;
342 }
343 else
344 {
345 df += d_se;
346 d_e += 2;
347 d_se += 4;
348 --cy;
349 }
350 ++cx;
351 }
352 while(cx <= cy);
353 }
354
355
356
draw_init(s_drawmethod * drawmethod)357 static int draw_init( s_drawmethod *drawmethod)
358 {
359 int alpha = 0;
360 drawmethod_global_init(drawmethod);
361
362 if (drawmethod && drawmethod->flag)
363 {
364 alpha = drawmethod->alpha;
365 }
366
367 return alpha;
368 }
369
370 //======================== root methods ==================================
371
putbox(int x,int y,int width,int height,int colour,s_screen * screen,s_drawmethod * drawmethod)372 void putbox(int x, int y, int width, int height, int colour, s_screen *screen, s_drawmethod *drawmethod)
373 {
374 int alpha = draw_init(drawmethod);
375
376 switch(screen->pixelformat)
377 {
378 case PIXEL_8:
379 drawbox(x, y, width, height, colour, screen, alpha);
380 break;
381 case PIXEL_16:
382 drawbox16(x, y, width, height, colour, screen, alpha);
383 break;
384 case PIXEL_32:
385 drawbox32(x, y, width, height, colour, screen, alpha);
386 break;
387 }
388 }
389
putline(int sx,int sy,int ex,int ey,int colour,s_screen * screen,s_drawmethod * drawmethod)390 void putline(int sx, int sy, int ex, int ey, int colour, s_screen *screen, s_drawmethod *drawmethod)
391 {
392 int alpha = draw_init(drawmethod);
393
394 switch(screen->pixelformat)
395 {
396 case PIXEL_8:
397 line(sx, sy, ex, ey, colour, screen, alpha);
398 break;
399 case PIXEL_16:
400 line16(sx, sy, ex, ey, colour, screen, alpha);
401 break;
402 case PIXEL_32:
403 line32(sx, sy, ex, ey, colour, screen, alpha);
404 break;
405 }
406 }
407
putpixel(unsigned x,unsigned y,int colour,s_screen * screen,s_drawmethod * drawmethod)408 void putpixel(unsigned x, unsigned y, int colour, s_screen *screen, s_drawmethod *drawmethod)
409 {
410 int alpha = draw_init(drawmethod);
411 switch(screen->pixelformat)
412 {
413 case PIXEL_8:
414 _putpixel(x, y, colour, screen, alpha);
415 break;
416 case PIXEL_16:
417 _putpixel16(x, y, colour, screen, alpha);
418 break;
419 case PIXEL_32:
420 _putpixel32(x, y, colour, screen, alpha);
421 break;
422 }
423 }
424
425
426