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