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 /*
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 screen = (s_screen*)malloc(sizeof(s_screen) + psize + PAL_BYTES+ANYNUMBER);
28 else screen = (s_screen*)malloc(sizeof(s_screen) + psize + ANYNUMBER);
29 if(screen==NULL) return NULL;
30 screen->width = width;
31 screen->height = height;
32 screen->pixelformat = pixelformat;
33 if(pixelformat==PIXEL_x8) screen->palette = ((unsigned char*)screen->data)+width*height*pixelbytes[(int)pixelformat];
34 else screen->palette = NULL;
35 return screen;
36 }
37
freescreen(s_screen ** screen)38 void freescreen(s_screen **screen)
39 {
40 if((*screen) != NULL) free((*screen));
41 (*screen) = NULL;
42 }
43
44 // Screen copy func. Supports clipping.
copyscreen(s_screen * dest,s_screen * src)45 void copyscreen(s_screen * dest, s_screen * src)
46 {
47 unsigned char *sp, *dp;
48 int width = src->width;
49 int height = src->height;
50 int pixelformat = src->pixelformat;
51
52 if(pixelformat!=dest->pixelformat) return;
53
54 if(height > dest->height) height = dest->height;
55 if(width > dest->width) width = dest->width;
56
57 dp = dest->data; sp = src->data;
58 // Copy unclipped
59 if(dest->width == src->width){
60 memcpy(dest->data, src->data, width * height * pixelbytes[(int)pixelformat]);
61 return;
62 }
63
64 // Copy clipped
65 do{
66 memcpy(dp, sp, width * pixelbytes[(int)pixelformat]);
67 sp += src->width*pixelbytes[(int)pixelformat];
68 dp += dest->width*pixelbytes[(int)pixelformat];
69 }while(--height);
70 }
71
clearscreen(s_screen * s)72 void clearscreen(s_screen * s)
73 {
74 if(s == NULL) return;
75 memset(s->data, 0, s->width*s->height*pixelbytes[(int)s->pixelformat]);
76 }
77
78 // Screen copy function with offset options. Supports clipping.
copyscreen_o(s_screen * dest,s_screen * src,int x,int y)79 void copyscreen_o(s_screen * dest, s_screen * src, int x, int y)
80 {
81 unsigned char *sp, *dp;
82 int pixelformat = src->pixelformat;
83 int sw = src->width;
84 int sh = src->height;
85 int dw = dest->width;
86 int dh = dest->height;
87 int cw = sw, ch = sh;
88 int linew, slinew, dlinew;
89 int sox, soy;
90
91 if(dest->pixelformat != src->pixelformat) return;
92
93 // Copy anything at all?
94 if(x >= dw) return;
95 if(sw+x <= 0) return;
96 if(y >= dh) return;
97 if(sh+y <= 0) return;
98
99 sox = 0;
100 soy = 0;
101
102 // Clip?
103 if(x<0) {sox = -x; cw += x;}
104 if(y<0) {soy = -y; ch += y;}
105
106 if(x+sw > dw) cw -= (x+sw) - dw;
107 if(y+sh > dh) ch -= (y+sh) - dh;
108
109 if(x<0) x = 0;
110 if(y<0) y = 0;
111
112 sp = src->data + (soy*sw + sox)*pixelbytes[(int)pixelformat];
113 dp = dest->data + (y*dw + x)*pixelbytes[(int)pixelformat];
114 linew = cw*pixelbytes[(int)pixelformat];
115 slinew = sw*pixelbytes[(int)pixelformat];
116 dlinew = dw*pixelbytes[(int)pixelformat];
117 // Copy data
118 do{
119 memcpy(dp, sp, linew);
120 sp += slinew;
121 dp += dlinew;
122 }while(--ch);
123 }
124
125 // same as above, with color key
copyscreen_trans(s_screen * dest,s_screen * src,int x,int y)126 void copyscreen_trans(s_screen * dest, s_screen * src, int x, int y)
127 {
128 unsigned char *sp, *dp;
129 int sw = src->width;
130 int sh = src->height;
131 int dw = dest->width;
132 int dh = dest->height;
133 int cw = sw, ch = sh;
134 int sox, soy;
135 int i;
136
137 // Copy anything at all?
138 if(x >= dw) return;
139 if(sw+x <= 0) return;
140 if(y >= dh) return;
141 if(sh+y <= 0) return;
142
143 sox = 0;
144 soy = 0;
145
146 // Clip?
147 if(x<0) {sox = -x; cw += x;}
148 if(y<0) {soy = -y; ch += y;}
149
150 if(x+sw > dw) cw -= (x+sw) - dw;
151 if(y+sh > dh) ch -= (y+sh) - dh;
152
153 if(x<0) x = 0;
154 if(y<0) y = 0;
155
156 sp = src->data + (soy*sw + sox);
157 dp = dest->data + (y*dw + x);
158 // Copy data
159 do{
160 i=cw-1;
161 do{
162 if(sp[i]==0)continue;
163 dp[i] = sp[i];
164 }while(i--);
165 sp += sw;
166 dp += dw;
167 }while(--ch);
168 }
169
170 //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)171 void copyscreen_remap(s_screen * dest, s_screen * src, int x, int y, unsigned char* remap)
172 {
173 unsigned char *sp = src->data;
174 unsigned char *dp = dest->data;
175 int i;
176 int sw = src->width;
177 int sh = src->height;
178 int dw = dest->width;
179 int dh = dest->height;
180 int cw = sw, ch = sh;
181 int sox, soy;
182
183 // Copy anything at all?
184 if(x >= dw) return;
185 if(sw+x <= 0) return;
186 if(y >= dh) return;
187 if(sh+y <= 0) return;
188
189 sox = 0;
190 soy = 0;
191
192 // Clip?
193 if(x<0) {sox = -x; cw += x;}
194 if(y<0) {soy = -y; ch += y;}
195
196 if(x+sw > dw) cw -= (x+sw) - dw;
197 if(y+sh > dh) ch -= (y+sh) - dh;
198
199 if(x<0) x = 0;
200 if(y<0) y = 0;
201
202 sp += (soy*sw + sox);
203 dp += (y*dw + x);
204
205 // Copy data
206 do{
207 i=cw-1;
208 do{
209 if(!sp[i])continue;
210 dp[i] = remap[sp[i]];
211 }while(i--);
212 sp += sw;
213 dp += dw;
214 }while(--ch);
215 }
216
217 //same as above, with alpha blend
blendscreen(s_screen * dest,s_screen * src,int x,int y,unsigned char * lut)218 void blendscreen(s_screen * dest, s_screen * src, int x, int y, unsigned char* lut)
219 {
220 unsigned char *sp = src->data;
221 unsigned char *dp = dest->data;
222 int i;
223 int sw = src->width;
224 int sh = src->height;
225 int dw = dest->width;
226 int dh = dest->height;
227 int cw = sw, ch = sh;
228 int sox, soy;
229 unsigned char* d, *s;
230
231 // Copy anything at all?
232 if(x >= dw) return;
233 if(sw+x <= 0) return;
234 if(y >= dh) return;
235 if(sh+y <= 0) return;
236
237 sox = 0;
238 soy = 0;
239
240 // Clip?
241 if(x<0) {sox = -x; cw += x;}
242 if(y<0) {soy = -y; ch += y;}
243
244 if(x+sw > dw) cw -= (x+sw) - dw;
245 if(y+sh > dh) ch -= (y+sh) - dh;
246
247 if(x<0) x = 0;
248 if(y<0) y = 0;
249
250 sp += soy*sw + sox;
251 dp += y*dw + x;
252
253 // Copy data
254 do{
255 i=cw;
256 do{
257 d = dp+i-1;
258 s = sp+i-1;
259 if(!(*s)) continue;
260 *d = lut[(*s)<<8|(*d)];
261 }while(--i);
262 sp += sw;
263 dp += dw;
264 }while(--ch);
265 }
266
267
putscreen(s_screen * dest,s_screen * src,int x,int y,s_drawmethod * drawmethod)268 void putscreen(s_screen* dest, s_screen* src, int x, int y, s_drawmethod* drawmethod)
269 {
270 unsigned char* table;
271 int alpha, transbg;
272 gfx_entry gfx;
273 if(!drawmethod || drawmethod->flag==0)
274 {
275 table = NULL;
276 alpha = 0;
277 transbg = 0;
278 } else if(drawmethod->water.watermode) {
279 gfx.type = gfx_screen;
280 gfx.screen = src;
281 if(drawmethod->water.watermode==3)
282 gfx_draw_plane(dest, &gfx, x, y, 0, 0, drawmethod);
283 else gfx_draw_water(dest, &gfx, x, y, 0, 0, drawmethod);
284 return ;
285 }else{
286 table = drawmethod->table;
287 alpha = drawmethod->alpha;
288 transbg = drawmethod->transbg;
289 }
290
291 if(!table && alpha<=0 && !transbg)
292 {
293 if(dest->pixelformat==src->pixelformat && dest->width==src->width && dest->height==src->height)
294 {
295 copyscreen(dest, src);
296 return;
297 }
298 }
299
300 if(dest->pixelformat==PIXEL_8)
301 {
302 if(table)
303 {
304 copyscreen_remap(dest, src, x, y, drawmethod->table);
305 }
306 else if(alpha>0)
307 {
308 blendscreen(dest, src, x, y, blendtables[drawmethod->alpha-1]);
309 }
310 else if(transbg) copyscreen_trans(dest, src, x, y);
311 else copyscreen_o(dest, src, x, y);
312 }
313 else if(dest->pixelformat==PIXEL_16)
314 {
315 if(src->pixelformat==PIXEL_x8)
316 putscreenx8p16(dest, src, x, y, transbg, (unsigned short*)table, alpha>0?blendfunctions16[alpha-1]:NULL);
317 else if(src->pixelformat==PIXEL_16)
318 blendscreen16(dest, src, x, y, transbg, alpha>0?blendfunctions16[alpha-1]:NULL);
319 }
320 else if(dest->pixelformat==PIXEL_32)
321 {
322 if(src->pixelformat==PIXEL_x8)
323 putscreenx8p32(dest, src, x, y, transbg, (unsigned*)table, alpha>0?blendfunctions32[alpha-1]:NULL);
324 else if(src->pixelformat==PIXEL_32)
325 blendscreen32(dest, src, x, y, transbg, alpha>0?blendfunctions32[alpha-1]:NULL);
326 }
327 }
328
329
330 // Scale screen
scalescreen(s_screen * dest,s_screen * src)331 void scalescreen(s_screen * dest, s_screen * src)
332 {
333 int sw, sh;
334 int dw, dh;
335 int dx, dy;
336 unsigned char *sp;
337 unsigned char *dp;
338 unsigned char *lineptr;
339 unsigned int xstep, ystep, xpos, ypos;
340 int pixelformat = src->pixelformat;
341
342 if(dest->pixelformat!=pixelformat) return;
343
344 if(src==NULL || dest==NULL) return;
345 sp = src->data;
346 dp = dest->data;
347
348 sw = src->width*pixelbytes[(int)pixelformat];
349 sh = src->height;
350 dw = dest->width*pixelbytes[(int)pixelformat];
351 dh = dest->height;
352
353 xstep = (sw<<16) / dw;
354 ystep = (sh<<16) / dh;
355
356 ypos = 0;
357 for(dy=0; dy<dh; dy++)
358 {
359 lineptr = sp + ((ypos>>16) * sw);
360 ypos += ystep;
361 xpos = 0;
362 for(dx=0; dx<dw; dx++)
363 {
364 *dp = lineptr[xpos>>16];
365 ++dp;
366 xpos += xstep;
367 }
368 }
369 }
370
371 /*
372 * Zooms in or out on the screen.
373 * Parameters:
374 * centerx - x coord of zoom center on unclipped, unscaled screen
375 * centery - y coord of zoom center on unclipped, unscaled screen
376 * scalex - x scale factor
377 * scaley - y scale factor
378 */
zoomscreen(s_screen * dest,s_screen * src,int centerx,int centery,int scalex,int scaley)379 void zoomscreen(s_screen* dest, s_screen* src, int centerx, int centery, int scalex, int scaley)
380 {
381 s_screen* frame;
382 int screenwidth = src->width;
383 int screenheight = src->height;
384 int width = (screenwidth<<8)/scalex; // width of clipped, unscaled screen
385 int height = (screenheight<<8)/scaley; // height of clipped, unscaled screen
386 int xmin = (width>>1)-centerx; // x coord before clipping corresponding to x=0 after clipping
387 int ymin = (height>>1)-centery; // y coord before clipping corresponding to y=0 after clipping
388 int pixelformat = dest->pixelformat;
389
390 if(src->pixelformat!=pixelformat) return;
391 if(xmin>=screenwidth || xmin+((width*scalex)>>8)<0) return; // out of left or right border
392 if(ymin>=screenheight) return;
393
394 frame = allocscreen(width, height, pixelformat); // the part of the screen that will be zoomed
395 copyscreen_o(frame, src, xmin, ymin);
396
397 if(pixelbytes[pixelformat]==1)
398 {
399 scalescreen(dest, frame);
400 }
401 else if(pixelbytes[pixelformat]==2)
402 {
403 scalescreen16(dest, frame);
404 }
405 else if(pixelbytes[pixelformat]==4)
406 {
407 scalescreen32(dest, frame);
408 }
409
410 freescreen(&frame);
411 }
412