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 /*
10 Code for handling 'screen' structures.
11 (Memory allocation and copy functions)
12 Last update: 10 feb 2003
13 */
14 #include <stdio.h>
15 #include <string.h>
16 #include "types.h"
17 #include "transform.h"
18 #include "screen.h"
19
allocscreen(int width,int height,int pixelformat)20 s_screen *allocscreen(int width, int height, int pixelformat)
21 {
22 s_screen *screen;
23 int psize;
24 width &= (0xFFFFFFFF - 3);
25 psize = width * height * pixelbytes[pixelformat];
26 if(pixelformat == PIXEL_x8)
27 {
28 screen = (s_screen *)malloc(sizeof(s_screen) + psize + PAL_BYTES + ANYNUMBER);
29 }
30 else
31 {
32 screen = (s_screen *)malloc(sizeof(s_screen) + psize + ANYNUMBER);
33 }
34 if(screen == NULL)
35 {
36 return NULL;
37 }
38 screen->width = width;
39 screen->height = height;
40 screen->pixelformat = pixelformat;
41 screen->magic = screen_magic;
42 if(pixelformat == PIXEL_x8)
43 {
44 screen->palette = ((unsigned char *)screen->data) + width * height * pixelbytes[(int)pixelformat];
45 }
46 else
47 {
48 screen->palette = NULL;
49 }
50 return screen;
51 }
52
freescreen(s_screen ** screen)53 void freescreen(s_screen **screen)
54 {
55 if((*screen) != NULL)
56 {
57 free((*screen));
58 }
59 (*screen) = NULL;
60 }
61
62 // Screen copy func. Supports clipping.
copyscreen(s_screen * dest,s_screen * src)63 void copyscreen(s_screen *dest, s_screen *src)
64 {
65 unsigned char *sp, *dp;
66 int width = src->width;
67 int height = src->height;
68 int pixelformat = src->pixelformat;
69
70 if(pixelformat != dest->pixelformat)
71 {
72 return;
73 }
74
75 if(height > dest->height)
76 {
77 height = dest->height;
78 }
79 if(width > dest->width)
80 {
81 width = dest->width;
82 }
83
84 dp = dest->data;
85 sp = src->data;
86 // Copy unclipped
87 if(dest->width == src->width)
88 {
89 memcpy(dest->data, src->data, width * height * pixelbytes[(int)pixelformat]);
90 return;
91 }
92
93 // Copy clipped
94 do
95 {
96 memcpy(dp, sp, width * pixelbytes[(int)pixelformat]);
97 sp += src->width * pixelbytes[(int)pixelformat];
98 dp += dest->width * pixelbytes[(int)pixelformat];
99 }
100 while(--height);
101 }
102
clearscreen(s_screen * s)103 void clearscreen(s_screen *s)
104 {
105 if(s == NULL)
106 {
107 return;
108 }
109 memset(s->data, 0, s->width * s->height * pixelbytes[(int)s->pixelformat]);
110 }
111
112 // Screen copy function with offset options. Supports clipping.
copyscreen_o(s_screen * dest,s_screen * src,int x,int y)113 void copyscreen_o(s_screen *dest, s_screen *src, int x, int y)
114 {
115 unsigned char *sp, *dp;
116 int pixelformat = src->pixelformat;
117 int sw = src->width;
118 int sh = src->height;
119 int dw = dest->width;
120 int cw = sw, ch = sh;
121 int linew, slinew, dlinew;
122 int sox, soy;
123
124 int xmin = useclip ? clipx1 : 0,
125 xmax = useclip ? clipx2 : dest->width,
126 ymin = useclip ? clipy1 : 0,
127 ymax = useclip ? clipy2 : dest->height;
128
129 // Copy anything at all?
130 if(x >= xmax)
131 {
132 return;
133 }
134 if(sw + x <= xmin)
135 {
136 return;
137 }
138 if(y >= ymax)
139 {
140 return;
141 }
142 if(sh + y <= ymin)
143 {
144 return;
145 }
146
147 sox = 0;
148 soy = 0;
149
150 // Clip?
151 if(x < xmin)
152 {
153 sox = xmin - x;
154 cw -= sox;
155 }
156 if(y < ymin)
157 {
158 soy = ymin - y;
159 ch -= soy;
160 }
161
162 if(x + sw > xmax)
163 {
164 cw -= (x + sw) - xmax;
165 }
166 if(y + sh > ymax)
167 {
168 ch -= (y + sh) - ymax;
169 }
170
171 if(x < xmin)
172 {
173 x = xmin;
174 }
175 if(y < ymin)
176 {
177 y = ymin;
178 }
179
180 if(dest->pixelformat != src->pixelformat)
181 {
182 return;
183 }
184
185 sp = src->data + (soy * sw + sox) * pixelbytes[(int)pixelformat];
186 dp = dest->data + (y * dw + x) * pixelbytes[(int)pixelformat];
187 linew = cw * pixelbytes[(int)pixelformat];
188 slinew = sw * pixelbytes[(int)pixelformat];
189 dlinew = dw * pixelbytes[(int)pixelformat];
190 // Copy data
191 do
192 {
193 memcpy(dp, sp, linew);
194 sp += slinew;
195 dp += dlinew;
196 }
197 while(--ch);
198 }
199
200 // same as above, with color key
copyscreen_trans(s_screen * dest,s_screen * src,int x,int y)201 void copyscreen_trans(s_screen *dest, s_screen *src, int x, int y)
202 {
203 unsigned char *sp, *dp;
204 int sw = src->width;
205 int sh = src->height;
206 int dw = dest->width;
207 int cw = sw, ch = sh;
208 int sox, soy;
209 int i;
210
211 int xmin = useclip ? clipx1 : 0,
212 xmax = useclip ? clipx2 : dest->width,
213 ymin = useclip ? clipy1 : 0,
214 ymax = useclip ? clipy2 : dest->height;
215
216 // Copy anything at all?
217 if(x >= xmax)
218 {
219 return;
220 }
221 if(sw + x <= xmin)
222 {
223 return;
224 }
225 if(y >= ymax)
226 {
227 return;
228 }
229 if(sh + y <= ymin)
230 {
231 return;
232 }
233
234 sox = 0;
235 soy = 0;
236
237 // Clip?
238 if(x < xmin)
239 {
240 sox = xmin - x;
241 cw -= sox;
242 }
243 if(y < ymin)
244 {
245 soy = ymin - y;
246 ch -= soy;
247 }
248
249 if(x + sw > xmax)
250 {
251 cw -= (x + sw) - xmax;
252 }
253 if(y + sh > ymax)
254 {
255 ch -= (y + sh) - ymax;
256 }
257
258 if(x < xmin)
259 {
260 x = xmin;
261 }
262 if(y < ymin)
263 {
264 y = ymin;
265 }
266
267 sp = src->data + (soy * sw + sox);
268 dp = dest->data + (y * dw + x);
269 // Copy data
270 do
271 {
272 i = cw - 1;
273 do
274 {
275 if(sp[i] == 0)
276 {
277 continue;
278 }
279 dp[i] = sp[i];
280 }
281 while(i--);
282 sp += sw;
283 dp += dw;
284 }
285 while(--ch);
286 }
287
288 //same as above, with remap, work only under 8bit pixel format
copyscreen_remap(s_screen * dest,s_screen * src,int x,int y,unsigned char * remap)289 void copyscreen_remap(s_screen *dest, s_screen *src, int x, int y, unsigned char *remap)
290 {
291 unsigned char *sp = src->data;
292 unsigned char *dp = dest->data;
293 int i;
294 int sw = src->width;
295 int sh = src->height;
296 int dw = dest->width;
297 int cw = sw, ch = sh;
298 int sox, soy;
299
300 int xmin = useclip ? clipx1 : 0,
301 xmax = useclip ? clipx2 : dest->width,
302 ymin = useclip ? clipy1 : 0,
303 ymax = useclip ? clipy2 : dest->height;
304
305 // Copy anything at all?
306 if(x >= xmax)
307 {
308 return;
309 }
310 if(sw + x <= xmin)
311 {
312 return;
313 }
314 if(y >= ymax)
315 {
316 return;
317 }
318 if(sh + y <= ymin)
319 {
320 return;
321 }
322
323 sox = 0;
324 soy = 0;
325
326 // Clip?
327 if(x < xmin)
328 {
329 sox = xmin - x;
330 cw -= sox;
331 }
332 if(y < ymin)
333 {
334 soy = ymin - y;
335 ch -= soy;
336 }
337
338 if(x + sw > xmax)
339 {
340 cw -= (x + sw) - xmax;
341 }
342 if(y + sh > ymax)
343 {
344 ch -= (y + sh) - ymax;
345 }
346
347 if(x < xmin)
348 {
349 x = xmin;
350 }
351 if(y < ymin)
352 {
353 y = ymin;
354 }
355
356 sp += (soy * sw + sox);
357 dp += (y * dw + x);
358
359 // Copy data
360 do
361 {
362 i = cw - 1;
363 do
364 {
365 if(!sp[i])
366 {
367 continue;
368 }
369 dp[i] = remap[sp[i]];
370 }
371 while(i--);
372 sp += sw;
373 dp += dw;
374 }
375 while(--ch);
376 }
377
378 //same as above, with alpha blend
blendscreen(s_screen * dest,s_screen * src,int x,int y,unsigned char * lut)379 void blendscreen(s_screen *dest, s_screen *src, int x, int y, unsigned char *lut)
380 {
381 unsigned char *sp = src->data;
382 unsigned char *dp = dest->data;
383 int i;
384 int sw = src->width;
385 int sh = src->height;
386 int dw = dest->width;
387 int cw = sw, ch = sh;
388 int sox, soy;
389 unsigned char *d, *s;
390
391 int xmin = useclip ? clipx1 : 0,
392 xmax = useclip ? clipx2 : dest->width,
393 ymin = useclip ? clipy1 : 0,
394 ymax = useclip ? clipy2 : dest->height;
395
396 // Copy anything at all?
397 if(x >= xmax)
398 {
399 return;
400 }
401 if(sw + x <= xmin)
402 {
403 return;
404 }
405 if(y >= ymax)
406 {
407 return;
408 }
409 if(sh + y <= ymin)
410 {
411 return;
412 }
413
414 sox = 0;
415 soy = 0;
416
417 // Clip?
418 if(x < xmin)
419 {
420 sox = xmin - x;
421 cw -= sox;
422 }
423 if(y < ymin)
424 {
425 soy = ymin - y;
426 ch -= soy;
427 }
428
429 if(x + sw > xmax)
430 {
431 cw -= (x + sw) - xmax;
432 }
433 if(y + sh > ymax)
434 {
435 ch -= (y + sh) - ymax;
436 }
437
438 if(x < xmin)
439 {
440 x = xmin;
441 }
442 if(y < ymin)
443 {
444 y = ymin;
445 }
446
447 sp += soy * sw + sox;
448 dp += y * dw + x;
449
450 // Copy data
451 do
452 {
453 i = cw;
454 do
455 {
456 d = dp + i - 1;
457 s = sp + i - 1;
458 if(!(*s))
459 {
460 continue;
461 }
462 *d = lut[(*s) << 8 | (*d)];
463 }
464 while(--i);
465 sp += sw;
466 dp += dw;
467 }
468 while(--ch);
469 }
470
471
_putscreen(s_screen * dest,s_screen * src,int x,int y,s_drawmethod * drawmethod)472 static void _putscreen(s_screen *dest, s_screen *src, int x, int y, s_drawmethod *drawmethod)
473 {
474 unsigned char *table;
475 int alpha, transbg;
476 gfx_entry gfx;
477
478 if(!drawmethod || drawmethod->flag == 0)
479 {
480 table = NULL;
481 alpha = 0;
482 transbg = 0;
483 }
484 else if(drawmethod->water.watermode && drawmethod->water.amplitude)
485 {
486 gfx.screen = src;
487 if(drawmethod->water.watermode == 3)
488 {
489 gfx_draw_plane(dest, &gfx, x, y, 0, 0, drawmethod);
490 }
491 else
492 {
493 gfx_draw_water(dest, &gfx, x, y, 0, 0, drawmethod);
494 }
495 return ;
496 }
497 else if(drawmethod->rotate)
498 {
499 gfx.screen = src;
500 gfx_draw_rotate(dest, &gfx, x, y, 0, 0, drawmethod);
501 return;
502 }
503 else if(drawmethod->scalex != 256 || drawmethod->scaley != 256 || drawmethod->shiftx)
504 {
505 gfx.screen = src;
506 gfx_draw_scale(dest, &gfx, x, y, 0, 0, drawmethod);
507 return;
508 }
509 else
510 {
511 table = drawmethod->table;
512 alpha = drawmethod->alpha;
513 transbg = drawmethod->transbg;
514 x -= drawmethod->centerx;
515 y -= drawmethod->centery;
516 }
517
518 if(!table && alpha <= 0 && !transbg && !usechannel)
519 {
520 if(dest->pixelformat == src->pixelformat && dest->width == src->width && dest->height == src->height && !x && !y)
521 {
522 copyscreen(dest, src);
523 return;
524 }
525 }
526
527 if(dest->pixelformat == PIXEL_8)
528 {
529 if(table)
530 {
531 copyscreen_remap(dest, src, x, y, drawmethod->table);
532 }
533 else if(alpha > 0)
534 {
535 blendscreen(dest, src, x, y, blendtables[drawmethod->alpha - 1]);
536 }
537 else if(transbg)
538 {
539 copyscreen_trans(dest, src, x, y);
540 }
541 else
542 {
543 copyscreen_o(dest, src, x, y);
544 }
545 }
546 else if(dest->pixelformat == PIXEL_16)
547 {
548 if(src->pixelformat == PIXEL_x8)
549 {
550 putscreenx8p16(dest, src, x, y, transbg, (unsigned short *)table, getblendfunction16(alpha));
551 }
552 else if(src->pixelformat == PIXEL_16)
553 {
554 blendscreen16(dest, src, x, y, transbg, getblendfunction16(alpha));
555 }
556 }
557 else if(dest->pixelformat == PIXEL_32)
558 {
559 if(src->pixelformat == PIXEL_x8)
560 {
561 putscreenx8p32(dest, src, x, y, transbg, (unsigned *)table, getblendfunction32(alpha));
562 }
563 else if(src->pixelformat == PIXEL_32)
564 {
565 blendscreen32(dest, src, x, y, transbg, getblendfunction32(alpha));
566 }
567 }
568 }
569
putscreen(s_screen * dest,s_screen * src,int x,int y,s_drawmethod * drawmethod)570 void putscreen(s_screen *dest, s_screen *src, int x, int y, s_drawmethod *drawmethod)
571 {
572 int xrepeat, yrepeat, xspan, yspan, i, j, dx, dy;
573
574 drawmethod_global_init(drawmethod);
575
576 if(drawmethod && drawmethod->flag)
577 {
578 xrepeat = drawmethod->xrepeat;
579 yrepeat = drawmethod->yrepeat;
580 xspan = drawmethod->xspan;
581 yspan = drawmethod->yspan;
582 }
583 else
584 {
585 xrepeat = yrepeat = 1;
586 xspan = yspan = 0;
587 }
588
589 for(j = 0, dy = y; j < yrepeat; j++, dy += yspan)
590 {
591 for(i = 0, dx = x; i < xrepeat; i++, dx += xspan)
592 {
593 _putscreen(dest, src, dx, dy, drawmethod);
594 }
595 }
596
597 }
598
599 // Scale screen
scalescreen(s_screen * dest,s_screen * src)600 void scalescreen(s_screen *dest, s_screen *src)
601 {
602 int sw, sh;
603 int dw, dh;
604 int dx, dy;
605 unsigned char *sp;
606 unsigned char *dp;
607 unsigned char *lineptr;
608 unsigned int xstep, ystep, xpos, ypos;
609 int pixelformat = src->pixelformat;
610
611 if(dest->pixelformat != pixelformat)
612 {
613 return;
614 }
615
616 if(src == NULL || dest == NULL)
617 {
618 return;
619 }
620 sp = src->data;
621 dp = dest->data;
622
623 sw = src->width * pixelbytes[(int)pixelformat];
624 sh = src->height;
625 dw = dest->width * pixelbytes[(int)pixelformat];
626 dh = dest->height;
627
628 xstep = (sw << 16) / dw;
629 ystep = (sh << 16) / dh;
630
631 ypos = 0;
632 for(dy = 0; dy < dh; dy++)
633 {
634 lineptr = sp + ((ypos >> 16) * sw);
635 ypos += ystep;
636 xpos = 0;
637 for(dx = 0; dx < dw; dx++)
638 {
639 *dp = lineptr[xpos >> 16];
640 ++dp;
641 xpos += xstep;
642 }
643 }
644 }
645
646 /*
647 * Zooms in or out on the screen.
648 * Parameters:
649 * centerx - x coord of zoom center on unclipped, unscaled screen
650 * centery - y coord of zoom center on unclipped, unscaled screen
651 * scalex - x scale factor
652 * scaley - y scale factor
653 */
zoomscreen(s_screen * dest,s_screen * src,int centerx,int centery,int scalex,int scaley)654 void zoomscreen(s_screen *dest, s_screen *src, int centerx, int centery, int scalex, int scaley)
655 {
656 s_screen *frame;
657 int screenwidth = src->width;
658 int screenheight = src->height;
659 int width = (screenwidth << 8) / scalex; // width of clipped, unscaled screen
660 int height = (screenheight << 8) / scaley; // height of clipped, unscaled screen
661 int xmin = (width >> 1) - centerx; // x coord before clipping corresponding to x=0 after clipping
662 int ymin = (height >> 1) - centery; // y coord before clipping corresponding to y=0 after clipping
663 int pixelformat = dest->pixelformat;
664
665 if(src->pixelformat != pixelformat)
666 {
667 return;
668 }
669 if(xmin >= screenwidth || xmin + ((width * scalex) >> 8) < 0)
670 {
671 return; // out of left or right border
672 }
673 if(ymin >= screenheight)
674 {
675 return;
676 }
677
678 frame = allocscreen(width, height, pixelformat); // the part of the screen that will be zoomed
679 copyscreen_o(frame, src, xmin, ymin);
680
681 if(pixelbytes[pixelformat] == 1)
682 {
683 scalescreen(dest, frame);
684 }
685 else if(pixelbytes[pixelformat] == 2)
686 {
687 scalescreen16(dest, frame);
688 }
689 else if(pixelbytes[pixelformat] == 4)
690 {
691 scalescreen32(dest, frame);
692 }
693
694 freescreen(&frame);
695 }
696