1 /*
2 Copyright (c) 2009-2011 Tero Lindeman (kometbomb)
3 
4 Permission is hereby granted, free of charge, to any person
5 obtaining a copy of this software and associated documentation
6 files (the "Software"), to deal in the Software without
7 restriction, including without limitation the rights to use,
8 copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following
11 conditions:
12 
13 The above copyright notice and this permission notice shall be
14 included in all copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24 */
25 
26 #include <assert.h>
27 #include "gfx.h"
28 #include <math.h>
29 #include <stdlib.h>
30 
31 #ifdef WIN32
32 #define WIN32_LEAN_AND_MEAN
33 #include <windows.h>
34 #endif
35 
36 #ifdef USESDL_IMAGE
37 #include "SDL_image.h"
38 #endif
39 
40 
41 // gives the optimizer an opportunity to vectorize the second loop
42 
43 #define vechelper(width, block)\
44 	{\
45 		const int w = width & 0xffffff00;\
46 		int x;\
47 		for (x = 0 ; x < w ; ++x)\
48 		{\
49 			block;\
50 		}\
51 		for ( ; x < width ; ++x)\
52 		{\
53 			block;\
54 		}\
55 	}
56 
gfx_build_collision_mask(SDL_Surface * s)57 int * gfx_build_collision_mask(SDL_Surface *s)
58 {
59 	int * mask = malloc(sizeof(int) * s->w * s->h);
60 
61 #if SDL_VERSION_ATLEAST(1,3,0)
62 	Uint32 key;
63 	SDL_GetColorKey(s, &key);
64 #else
65 	const Uint32 key = s->format->colorkey;
66 #endif
67 
68 	my_lock(s);
69 	for (int y = 0 ; y < s->h ; ++y)
70 	{
71 		Uint8 *pa = (Uint8 *)s->pixels + y * s->pitch;
72 
73 		for (int x = 0 ; x < s->w ; ++x)
74 		{
75 			int p = 0;
76 
77 			switch (s->format->BytesPerPixel)
78 			{
79 				default:
80 				case 1: p = ((*((Uint8*)pa))) != key; break;
81 				case 2: p = ((*((Uint16*)pa))&0xffff) != key; break;
82 				case 3: p = ((*((Uint32*)pa))&0xffffff) != key; break;
83 				case 4: p = ((*((Uint32*)pa))&0xffffff) != key; break;
84 			}
85 
86 			mask[x + y * s->w] = p;
87 			pa += s->format->BytesPerPixel;
88 		}
89 	}
90 	my_unlock(s);
91 
92 	return mask;
93 }
94 
95 
gfx_load_surface(GfxDomain * domain,const char * filename,const int flags)96 GfxSurface* gfx_load_surface(GfxDomain *domain, const char* filename, const int flags)
97 {
98 	SDL_RWops * rw = SDL_RWFromFile(filename, "rb");
99 
100 	if (rw)
101 	{
102 		GfxSurface * s = gfx_load_surface_RW(domain, rw, flags);
103 		return s;
104 	}
105 	else
106 	{
107 		warning("Opening image '%s' failed", filename);
108 		return NULL;
109 	}
110 }
111 
112 
gfx_load_surface_RW(GfxDomain * domain,SDL_RWops * rw,const int flags)113 GfxSurface* gfx_load_surface_RW(GfxDomain *domain, SDL_RWops *rw, const int flags)
114 {
115 #ifdef USESDL_IMAGE
116 	SDL_Surface* loaded = IMG_Load_RW(rw, 1);
117 #else
118 	SDL_Surface* loaded = SDL_LoadBMP_RW(rw, 1);
119 #endif
120 
121 	if (!loaded)
122 	{
123 		warning("Loading surface failed: %s", SDL_GetError());
124 		return NULL;
125 	}
126 
127 	GfxSurface *gs = calloc(1, sizeof(GfxSurface));
128 
129 	if (flags & GFX_KEYED)
130 	{
131 		Uint32 c = SDL_MapRGB(loaded->format, 255, 0, 255);
132 		Uint8 r, g, b;
133 		SDL_GetRGB(c, loaded->format, &r, &g, &b);
134 
135 		if (r == 255 && g == 0 && b == 255)
136 			SDL_SetColorKey(loaded, SDL_TRUE, c);
137 
138 #ifdef USESDL_GPU
139 		SDL_Surface *conv = SDL_ConvertSurfaceFormat(loaded, SDL_PIXELFORMAT_ARGB8888, 0);
140 		SDL_FreeSurface(loaded);
141 		loaded = conv;
142 #endif
143 	}
144 
145 	gs->surface = loaded;
146 
147 	if (flags & GFX_COL_MASK) gs->mask = gfx_build_collision_mask(gs->surface);
148 
149 	gs->flags = flags;
150 
151 	gfx_update_texture(domain, gs);
152 
153 	return gs;
154 }
155 
156 
gfx_blit_2x(SDL_Surface * dest,SDL_Surface * src)157 void gfx_blit_2x(SDL_Surface *dest, SDL_Surface *src)
158 {
159 
160 	for (int y = 0 ; y < src->h ; y ++)
161 	{
162 		unsigned int *dptr1 = dest->pixels+dest->pitch*(y*2);
163 		unsigned int *dptr2 = dest->pixels+dest->pitch*(y*2+1);
164 		unsigned int *sptr = src->pixels+src->pitch*y;
165 		for (int x = src->w ; x != 0  ; --x)
166 		{
167 			*(dptr1++) = *sptr;
168 			*(dptr1++) = *sptr;
169 			*(dptr2++) = *sptr;
170 			*(dptr2++) = *(sptr++);
171 		}
172 	}
173 }
174 
175 
gfx_blit_3x(SDL_Surface * dest,SDL_Surface * src)176 void gfx_blit_3x(SDL_Surface *dest, SDL_Surface *src)
177 {
178 
179 	for (int y = 0 ; y < src->h ; y ++)
180 	{
181 		unsigned int *dptr1 = dest->pixels+dest->pitch*(y*3);
182 		unsigned int *dptr2 = dest->pixels+dest->pitch*(y*3+1);
183 		unsigned int *dptr3 = dest->pixels+dest->pitch*(y*3+2);
184 		unsigned int *sptr = src->pixels+src->pitch*y;
185 		for (int x = src->w ; x != 0  ; --x)
186 		{
187 			*(dptr1++) = *sptr;
188 			*(dptr1++) = *sptr;
189 			*(dptr1++) = *sptr;
190 			*(dptr2++) = *sptr;
191 			*(dptr2++) = *sptr;
192 			*(dptr2++) = *sptr;
193 			*(dptr3++) = *sptr;
194 			*(dptr3++) = *sptr;
195 			*(dptr3++) = *(sptr++);
196 		}
197 	}
198 }
199 
200 
gfx_blit_4x(SDL_Surface * dest,SDL_Surface * src)201 void gfx_blit_4x(SDL_Surface *dest, SDL_Surface *src)
202 {
203 
204 	for (int y = 0 ; y < src->h ; y ++)
205 	{
206 		unsigned int *dptr1 = dest->pixels+dest->pitch*(y*4);
207 		unsigned int *dptr2 = dest->pixels+dest->pitch*(y*4+1);
208 		unsigned int *dptr3 = dest->pixels+dest->pitch*(y*4+2);
209 		unsigned int *dptr4 = dest->pixels+dest->pitch*(y*4+3);
210 		unsigned int *sptr = src->pixels+src->pitch*y;
211 		for (int x = src->w ; x != 0  ; --x)
212 		{
213 			*(dptr1++) = *sptr;
214 			*(dptr1++) = *sptr;
215 			*(dptr1++) = *sptr;
216 			*(dptr1++) = *sptr;
217 			*(dptr2++) = *sptr;
218 			*(dptr2++) = *sptr;
219 			*(dptr2++) = *sptr;
220 			*(dptr2++) = *sptr;
221 			*(dptr3++) = *sptr;
222 			*(dptr3++) = *sptr;
223 			*(dptr3++) = *sptr;
224 			*(dptr3++) = *sptr;
225 			*(dptr4++) = *sptr;
226 			*(dptr4++) = *sptr;
227 			*(dptr4++) = *sptr;
228 			*(dptr4++) = *(sptr++);
229 		}
230 	}
231 }
232 
233 
gfx_raster(SDL_Surface * dest,const SDL_Rect * rect,const Uint32 * colors,int len)234 void gfx_raster(SDL_Surface *dest, const SDL_Rect *rect, const Uint32 *colors, int len)
235 {
236 	for (int y = rect ? rect->y : 0, i = 0 ; y < (rect ? rect->h+rect->y : dest->h) && i < len ; ++i, ++y)
237 	{
238 		SDL_Rect r = {rect ? rect->x : 0, y, rect ? rect->w : dest->w, 1};
239 		SDL_FillRect(dest, &r, colors[i]);
240 	}
241 }
242 
243 
gfx_generate_raster(Uint32 * dest,const Uint32 from,const Uint32 to,int len)244 void gfx_generate_raster(Uint32 *dest, const Uint32 from, const Uint32 to, int len)
245 {
246 	for (int i = 0 ; i < len ; ++i)
247 	{
248 		int from_r = ((Uint8*)&from)[0];
249 		int from_g = ((Uint8*)&from)[1];
250 		int from_b = ((Uint8*)&from)[2];
251 		int to_r = ((Uint8*)&to)[0];
252 		int to_g = ((Uint8*)&to)[1];
253 		int to_b = ((Uint8*)&to)[2];
254 
255 		*(dest++) = ((from_r + (to_r-from_r) * i / len) & 0xff)
256 					| (((from_g + (to_g-from_g) * i / len) & 0xff) << 8)
257 					| (((from_b + (to_b-from_b) * i / len) & 0xff) << 16)
258 					;
259 	}
260 }
261 
262 
has_pixels(TileDescriptor * desc)263 static int has_pixels(TileDescriptor *desc)
264 {
265 #if SDL_VERSION_ATLEAST(1,3,0)
266 	Uint32 key;
267 	SDL_GetColorKey(desc->surface->surface, &key);
268 #else
269 	const Uint32 key = desc->surface->surface->format->colorkey;
270 #endif
271 
272 	my_lock(desc->surface->surface);
273 
274 	int result = 0;
275 
276 	for (int y = 0 ; y < desc->rect.h && y + desc->rect.y < desc->surface->surface->h ; ++y)
277 	{
278 		Uint8 *p = (Uint8 *)desc->surface->surface->pixels + ((int)desc->rect.y + y) * desc->surface->surface->pitch + (int)desc->rect.x * desc->surface->surface->format->BytesPerPixel;
279 
280 		for (int x = 0 ; x < desc->rect.w && x + desc->rect.x < desc->surface->surface->w ; ++x)
281 		{
282 			Uint32 c = 0;
283 
284 			switch (desc->surface->surface->format->BytesPerPixel)
285 			{
286 				case 1:
287 					c = *((Uint8*)p);
288 					break;
289 
290 				case 2:
291 					c = *((Uint16*)p);
292 					break;
293 
294 				case 3:
295 					c = *((Uint8*)p) | (*((Uint16*)&p[1]) << 8);
296 					break;
297 
298 				default:
299 				case 4:
300 					c = *((Uint32*)p);
301 					break;
302 			}
303 
304 			if ((c & 0xffffff) != key)
305 			{
306 				++result;
307 			}
308 
309 			p+=desc->surface->surface->format->BytesPerPixel;
310 		}
311 	}
312 
313 	my_unlock(desc->surface->surface);
314 
315 	return result;
316 }
317 
318 
gfx_build_tiledescriptor(GfxSurface * tiles,const int cellwidth,const int cellheight,int * out_n_tiles)319 TileDescriptor *gfx_build_tiledescriptor(GfxSurface *tiles, const int cellwidth, const int cellheight, int *out_n_tiles)
320 {
321 	TileDescriptor *descriptor = calloc(sizeof(*descriptor), (tiles->surface->w/cellwidth)*(tiles->surface->h/cellheight));
322 
323 	int n_tiles = 0;
324 
325 	for (int i = 0 ; i < (tiles->surface->w/cellwidth)*(tiles->surface->h/cellheight) ; ++i)
326 	{
327 		descriptor[i].rect.x = i*cellwidth;
328 		descriptor[i].rect.y = 0;
329 
330 		while (descriptor[i].rect.x >= tiles->surface->w)
331 		{
332 			descriptor[i].rect.y += cellheight;
333 			descriptor[i].rect.x -= tiles->surface->w;
334 		}
335 
336 		descriptor[i].rect.w = cellwidth;
337 		descriptor[i].rect.h = cellheight;
338 		descriptor[i].surface = tiles;
339 
340 		int pixels = has_pixels(&descriptor[i]);
341 
342 		if (pixels == CELLSIZE*CELLSIZE || !(tiles->flags & GFX_COL_MASK))
343 			descriptor[i].flags = TILE_COL_NORMAL;
344 		else if (pixels > 0)
345 			descriptor[i].flags = TILE_COL_PIXEL;
346 		else descriptor[i].flags = TILE_COL_DISABLE;
347 
348 		n_tiles++;
349 	}
350 
351 	if (out_n_tiles)
352 		*out_n_tiles = n_tiles;
353 
354 	return descriptor;
355 }
356 
357 
358 #define SWAP(x,y) {int t = x; x = y; y=t;}
359 
gfx_line(GfxDomain * dest,int x0,int y0,int x1,int y1,Uint32 color)360 void gfx_line(GfxDomain *dest, int x0, int y0, int x1, int y1, Uint32 color)
361 {
362 #ifdef USESDL_GPU
363 	SDL_Color c = {(color >> 16) & 255, (color >> 8) & 255, color & 255, 255};
364 	GPU_Line(dest->screen, x0, y0, x1, y1, c);
365 #else
366 	SDL_SetRenderDrawColor(dest->renderer, (color >> 16) & 255, (color >> 8) & 255, color & 255, 255);
367 	SDL_RenderDrawLine(dest->renderer, x0, y0, x1, y1);
368 #endif
369 
370 }
371 
372 
scale2x(SDL_Surface * src,SDL_Surface * dst)373 static void scale2x(SDL_Surface *src, SDL_Surface *dst)
374 {
375 	int looph, loopw;
376 
377 	Uint8* srcpix = (Uint8*)src->pixels;
378 	Uint8* dstpix = (Uint8*)dst->pixels;
379 
380 	const int srcpitch = src->pitch;
381 	const int dstpitch = dst->pitch;
382 	const int width = src->w;
383 	const int height = src->h;
384 
385 	Uint32 *E0, *E1, *E2, *E3;
386 	Uint32 B, D, E, F, H;
387 	for(looph = 0; looph < height; ++looph)
388 	{
389 		E0 = (Uint32*)(dstpix + looph*2*dstpitch + 0*2*4);
390 		E1 = (Uint32*)(dstpix + looph*2*dstpitch + (0*2+1)*4);
391 		E2 = (Uint32*)(dstpix + (looph*2+1)*dstpitch + 0*2*4);
392 		E3 = (Uint32*)(dstpix + (looph*2+1)*dstpitch + (0*2+1)*4);
393 
394 		for(loopw = 0; loopw < width; ++ loopw)
395 		{
396 			B = *(Uint32*)(srcpix + (my_max(0,looph-1)*srcpitch) + (4*loopw));
397 			D = *(Uint32*)(srcpix + (looph*srcpitch) + (4*my_max(0,loopw-1)));
398 			E = *(Uint32*)(srcpix + (looph*srcpitch) + (4*loopw));
399 			F = *(Uint32*)(srcpix + (looph*srcpitch) + (4*my_min(width-1,loopw+1)));
400 			H = *(Uint32*)(srcpix + (my_min(height-1,looph+1)*srcpitch) + (4*loopw));
401 
402 			if (B != H && D != F)
403 			{
404 				*E0 = D == B ? D : E;
405 				*E1 = B == F ? F : E;
406 				*E2 = D == H ? D : E;
407 				*E3 = H == F ? F : E;
408 			}
409 			else
410 			{
411 				*E0 = E;
412 				*E1 = E;
413 				*E2 = E;
414 				*E3 = E;
415 			}
416 
417 
418 			E0 += 2;
419 			E1 += 2;
420 			E2 += 2;
421 			E3 += 2;
422 		}
423 	}
424 
425 }
426 
427 
scale3x(SDL_Surface * src,SDL_Surface * dst)428 static void scale3x(SDL_Surface *src, SDL_Surface *dst)
429 {
430 	int looph, loopw;
431 
432 	Uint8* srcpix = (Uint8*)src->pixels;
433 	Uint8* dstpix = (Uint8*)dst->pixels;
434 
435 	const int srcpitch = src->pitch;
436 	const int dstpitch = dst->pitch;
437 	const int width = src->w;
438 	const int height = src->h;
439 
440 	Uint32 *E0, *E1, *E2, *E3, *E4, *E5, *E6, *E7, *E8, A, B, C, D, E, F, G, H, I;
441 	for(looph = 0; looph < height; ++looph)
442 	{
443 		E0 = (Uint32*)(dstpix + looph*3*dstpitch + 0*3*4);
444 		E1 = (Uint32*)(dstpix + looph*3*dstpitch + (0*3+1)*4);
445 		E2 = (Uint32*)(dstpix + looph*3*dstpitch + (0*3+2)*4);
446 		E3 = (Uint32*)(dstpix + (looph*3+1)*dstpitch + 0*3*4);
447 		E4 = (Uint32*)(dstpix + (looph*3+1)*dstpitch + (0*3+1)*4);
448 		E5 = (Uint32*)(dstpix + (looph*3+1)*dstpitch + (0*3+2)*4);
449 		E6 = (Uint32*)(dstpix + (looph*3+2)*dstpitch + 0*3*4);
450 		E7 = (Uint32*)(dstpix + (looph*3+2)*dstpitch + (0*3+1)*4);
451 		E8 = (Uint32*)(dstpix + (looph*3+2)*dstpitch + (0*3+2)*4);
452 
453 		for(loopw = 0; loopw < width; ++ loopw)
454 		{
455 				A = *(Uint32*)(srcpix + (my_max(0,looph-1)*srcpitch) + (4*my_max(0,loopw-1)));
456 				B = *(Uint32*)(srcpix + (my_max(0,looph-1)*srcpitch) + (4*loopw));
457 				C = *(Uint32*)(srcpix + (my_max(0,looph-1)*srcpitch) + (4*my_min(width-1,loopw+1)));
458 				D = *(Uint32*)(srcpix + (looph*srcpitch) + (4*my_max(0,loopw-1)));
459 				E = *(Uint32*)(srcpix + (looph*srcpitch) + (4*loopw));
460 				F = *(Uint32*)(srcpix + (looph*srcpitch) + (4*my_min(width-1,loopw+1)));
461 				G = *(Uint32*)(srcpix + (my_min(height-1,looph+1)*srcpitch) + (4*my_max(0,loopw-1)));
462 				H = *(Uint32*)(srcpix + (my_min(height-1,looph+1)*srcpitch) + (4*loopw));
463 				I = *(Uint32*)(srcpix + (my_min(height-1,looph+1)*srcpitch) + (4*my_min(width-1,loopw+1)));
464 
465 			if (B != H && D != F) {
466 				*E0 = D == B ? D : E;
467 				*E1 = (D == B && E != C) || (B == F && E != A) ? B : E;
468 				*E2 = B == F ? F : E;
469 				*E3 = (D == B && E != G) || (D == H && E != A) ? D : E;
470 				*E4 = E;
471 				*E5 = (B == F && E != I) || (H == F && E != C) ? F : E;
472 				*E6 = D == H ? D : E;
473 				*E7 = (D == H && E != I) || (H == F && E != G) ? H : E;
474 				*E8 = H == F ? F : E;
475 			} else {
476 				*E0 = E;
477 				*E1 = E;
478 				*E2 = E;
479 				*E3 = E;
480 				*E4 = E;
481 				*E5 = E;
482 				*E6 = E;
483 				*E7 = E;
484 				*E8 = E;
485 			}
486 
487 
488 			E0 += 3;
489 			E1 += 3;
490 			E2 += 3;
491 			E3 += 3;
492 			E4 += 3;
493 			E5 += 3;
494 			E6 += 3;
495 			E7 += 3;
496 			E8 += 3;
497 		}
498 	}
499 }
500 
501 
gfx_blit_2x_resample(SDL_Surface * dest,SDL_Surface * src)502 void gfx_blit_2x_resample(SDL_Surface *dest, SDL_Surface *src)
503 {
504 	scale2x(src,dest);
505 }
506 
gfx_blit_3x_resample(SDL_Surface * dest,SDL_Surface * src)507 void gfx_blit_3x_resample(SDL_Surface *dest, SDL_Surface *src)
508 {
509 	scale3x(src,dest);
510 }
511 
512 
gfx_circle(SDL_Surface * dest,const int xc,const int yc,const int r,const Uint32 color)513 void gfx_circle(SDL_Surface *dest, const int xc, const int yc, const int r, const Uint32 color)
514 {
515 	const int h = my_min(yc+r+1, dest->h);
516 	for (int y=my_max(0,yc-r); y<h; ++y)
517 	{
518 		const int w = (int)(sqrt(SQR(r) - SQR(y - yc)));
519 		SDL_Rect r = {xc - w, y, w*2, 1};
520 		SDL_FillRect(dest, &r, color);
521 	}
522 }
523 
gfx_circle_inverted(SDL_Surface * dest,const int xc,const int yc,const int r,const Uint32 color)524 void gfx_circle_inverted(SDL_Surface *dest, const int xc, const int yc, const int r, const Uint32 color)
525 {
526 	const int h = my_min(yc+r+1, dest->h);
527 	for (int y=my_max(0,yc-r); y<h; ++y)
528 	{
529 		const int w = (int)(sqrt(SQR(r) - SQR(y - yc)));
530 
531 		{
532 			SDL_Rect rect = {xc - r, y, r - w, 1};
533 			SDL_FillRect(dest, &rect, color);
534 		}
535 
536 		{
537 			SDL_Rect rect = {xc + w, y, r - w, 1};
538 			SDL_FillRect(dest, &rect, color);
539 		}
540 	}
541 }
542 
543 
gfx_domain_set_framerate(GfxDomain * d)544 static void gfx_domain_set_framerate(GfxDomain *d)
545 {
546 #ifdef WIN32
547 	QueryPerformanceFrequency((LARGE_INTEGER*)&d->clock_resolution);
548 	QueryPerformanceCounter((LARGE_INTEGER*)&d->start_time);
549 #else
550 	d->clock_resolution = 1000;
551 	d->start_time = SDL_GetTicks();
552 #endif
553 
554 	d->dt = d->clock_resolution / d->fps;
555 	d->accumulator = 0;
556 }
557 
558 
559 #ifndef USESDL_GPU
create_scanlines_texture(GfxDomain * domain)560 static void create_scanlines_texture(GfxDomain *domain)
561 {
562 	if (domain->scanlines_texture)
563 		SDL_DestroyTexture(domain->scanlines_texture);
564 
565 	SDL_Surface *temp = SDL_CreateRGBSurface(0, 8, domain->screen_h * domain->scale, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000);
566 
567 	// alpha = 1.0
568 	SDL_FillRect(temp, NULL, 0x00ffffff);
569 
570 	debug("%d", domain->scale);
571 
572 	const int depth = 32 * domain->scale;
573 
574 	for (int y = 0 ; y < domain->screen_h * domain->scale ; ++y)
575 	{
576 		SDL_Rect r = {0, y, 8, 1};
577 		Uint8 c = fabs(sin((float)y * M_PI / domain->scale)) * depth + (255 - depth);
578 
579 		SDL_FillRect(temp, &r, (c << 8) | (c << 16) | c);
580 	}
581 
582 	domain->scanlines_texture = SDL_CreateTextureFromSurface(domain->renderer, temp);
583 
584 	SDL_SetTextureBlendMode(domain->scanlines_texture, SDL_BLENDMODE_MOD);
585 
586 	SDL_FreeSurface(temp);
587 }
588 #endif
589 
590 
gfx_domain_update(GfxDomain * domain,bool resize_window)591 void gfx_domain_update(GfxDomain *domain, bool resize_window)
592 {
593 	debug("Setting screen mode (scale = %d%s)", domain->scale, domain->fullscreen ? ", fullscreen" : "");
594 #ifdef USESDL_GPU
595 	GPU_SetWindowResolution(domain->screen_w * domain->scale, domain->screen_h * domain->scale);
596 	GPU_SetVirtualResolution(domain->screen, domain->screen_w, domain->screen_h);
597 
598 	domain->window_w = domain->screen_w * domain->scale;
599 	domain->window_h = domain->screen_h * domain->scale;
600 
601 #else
602 
603 	if (resize_window)
604 		SDL_SetWindowSize(domain->window, domain->screen_w * domain->scale, domain->screen_h * domain->scale);
605 
606 	if (domain->fullscreen)
607 	{
608 		debug("Setting fullscreen");
609 		if (SDL_SetWindowFullscreen(domain->window, SDL_WINDOW_FULLSCREEN_DESKTOP) != 0)
610 		{
611 			warning("Fullscreen failed: %s", SDL_GetError());
612 
613 			if (SDL_SetWindowFullscreen(domain->window, SDL_WINDOW_FULLSCREEN_DESKTOP) != 0)
614 				warning("Fake fullscreen failed: %s", SDL_GetError());
615 		}
616 	}
617 	else
618 		SDL_SetWindowFullscreen(domain->window, 0);
619 
620 	if (domain->render_to_texture && !(domain->flags & GFX_DOMAIN_DISABLE_RENDER_TO_TEXTURE) /* && domain->scale > 1*/)
621 	{
622 		debug("Rendering to texture enabled");
623 
624 		SDL_SetRenderTarget(domain->renderer, NULL);
625 
626 		if (domain->scale_texture)
627 			SDL_DestroyTexture(domain->scale_texture);
628 
629 		domain->scale_texture = SDL_CreateTexture(domain->renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, domain->screen_w, domain->screen_h);
630 
631 		if (!domain->scale_texture)
632 		{
633 			warning("Could not create texture: %s", SDL_GetError());
634 		}
635 		else
636 		{
637 			SDL_SetRenderTarget(domain->renderer, domain->scale_texture);
638 		}
639 	}
640 	else
641 	{
642 		debug("Rendering to texture disabled");
643 
644 		SDL_SetRenderTarget(domain->renderer, NULL);
645 		SDL_RenderSetScale(domain->renderer, domain->scale, domain->scale);
646 	}
647 
648 	if (domain->scale_type == GFX_SCALE_SCANLINES && domain->scale > 1)
649 		create_scanlines_texture(domain);
650 
651 	SDL_RenderSetViewport(domain->renderer, NULL);
652 
653 	SDL_SetWindowMinimumSize(domain->window, domain->window_min_w * domain->scale, domain->window_min_h * domain->scale);
654 	SDL_GetWindowSize(domain->window, &domain->window_w, &domain->window_h);
655 #endif
656 
657 	debug("Screen size is %dx%d", domain->screen_w, domain->screen_h);
658 	debug("Window size is %dx%d", domain->window_w, domain->window_h);
659 
660 	gfx_domain_set_framerate(domain);
661 }
662 
663 
gfx_domain_flip(GfxDomain * domain)664 void gfx_domain_flip(GfxDomain *domain)
665 {
666 #ifdef USESDL_GPU
667     GPU_Flip(domain->screen);
668 #else
669 	if (domain->render_to_texture && !(domain->flags & GFX_DOMAIN_DISABLE_RENDER_TO_TEXTURE) /*&& domain->scale > 1*/)
670 	{
671 		SDL_RenderPresent(domain->renderer);
672 
673 		SDL_SetRenderTarget(domain->renderer, NULL);
674 		SDL_RenderSetViewport(domain->renderer, NULL);
675 		SDL_RenderCopy(domain->renderer, domain->scale_texture, NULL, NULL);
676 
677 		if (domain->scale_type == GFX_SCALE_SCANLINES && domain->scale > 1)
678 		{
679 			SDL_RenderCopy(domain->renderer, domain->scanlines_texture, NULL, NULL);
680 		}
681 
682 		SDL_RenderPresent(domain->renderer);
683 
684 		SDL_SetRenderTarget(domain->renderer, domain->scale_texture);
685 		SDL_RenderSetViewport(domain->renderer, NULL);
686 	}
687 	else
688 	{
689 		if (domain->scale_type == GFX_SCALE_SCANLINES && domain->scale > 1)
690 		{
691 			SDL_RenderCopy(domain->renderer, domain->scanlines_texture, NULL, NULL);
692 		}
693 
694 		SDL_RenderPresent(domain->renderer);
695 	}
696 
697 #endif
698 
699 #ifdef DEBUG
700 	domain->calls_per_frame = 0;
701 #endif
702 }
703 
704 
gfx_domain_free(GfxDomain * domain)705 void gfx_domain_free(GfxDomain *domain)
706 {
707 #ifdef USESDL_GPU
708     GPU_Quit();
709 #else
710 	if (domain->scale_texture)
711 		SDL_DestroyTexture(domain->scale_texture);
712 
713 	if (domain->scanlines_texture)
714 		SDL_DestroyTexture(domain->scanlines_texture);
715 
716 	SDL_DestroyRenderer(domain->renderer);
717 	SDL_DestroyWindow(domain->window);
718 #endif
719 
720 	free(domain);
721 }
722 
723 
gfx_create_domain(const char * title,Uint32 window_flags,int window_w,int window_h,int scale)724 GfxDomain * gfx_create_domain(const char *title, Uint32 window_flags, int window_w, int window_h, int scale)
725 {
726 	GfxDomain *d = malloc(sizeof(GfxDomain));
727 	d->screen_w = window_w / scale;
728 	d->screen_h = window_h / scale;
729 	d->scale = scale;
730 	d->scale_type = GFX_SCALE_NEAREST;
731 	d->fullscreen = 0;
732 	d->fps = 50;
733 	d->flags = 0;
734 	d->window_min_w = d->screen_w;
735 	d->window_min_h = d->screen_h;
736 
737 #ifdef USESDL_GPU
738 	d->screen = GPU_Init(window_w, window_h, GPU_DEFAULT_INIT_FLAGS);
739 #else
740 	d->window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, window_w, window_h, window_flags);
741 	d->renderer = SDL_CreateRenderer(d->window, -1, SDL_RENDERER_PRESENTVSYNC|SDL_RENDERER_ACCELERATED|SDL_RENDERER_TARGETTEXTURE);
742 
743 	SDL_RendererInfo info;
744 	SDL_GetRendererInfo(d->renderer, &info);
745 
746 	if (!(info.flags & SDL_RENDERER_TARGETTEXTURE))
747 	{
748 		warning("Renderer doesn't support rendering to texture");
749 		d->render_to_texture = false;
750 	}
751 	else
752 	{
753 		d->render_to_texture = true;
754 	}
755 
756 	d->scale_texture = NULL;
757 	d->scanlines_texture = NULL;
758 #endif
759 
760 #ifdef DEBUG
761 
762 	d->calls_per_frame = 0;
763 
764 #ifndef USESDL_GPU
765 
766 	{
767 		SDL_RendererInfo info;
768 		SDL_GetRendererInfo(d->renderer, &info);
769 
770 		debug("Renderer: %s (%s)", info.name, (info.flags & SDL_RENDERER_ACCELERATED) ? "Accelerated" : "Not accelerated");
771 	}
772 
773 #endif
774 
775 #endif
776 
777 	gfx_domain_set_framerate(d);
778 
779 	return d;
780 }
781 
782 
gfx_domain_is_next_frame(GfxDomain * domain)783 int gfx_domain_is_next_frame(GfxDomain *domain)
784 {
785 #ifdef WIN32
786 	Uint64 ticks;
787 	QueryPerformanceCounter((LARGE_INTEGER*)&ticks);
788 #else
789 	Uint32 ticks = SDL_GetTicks();
790 #endif
791 
792 	FramerateTimer frameTime = ticks - domain->start_time;
793     domain->start_time = ticks;
794 	domain->accumulator += frameTime;
795 	int frames = 0;
796 
797     while ( domain->accumulator > domain->dt )
798     {
799         domain->accumulator -= domain->dt;
800 		++frames;
801     }
802 
803 	return frames;
804 }
805 
806 
gfx_create_surface(GfxDomain * domain,int w,int h)807 GfxSurface * gfx_create_surface(GfxDomain *domain, int w, int h)
808 {
809 	GfxSurface *gs = calloc(1, sizeof(GfxSurface));
810 	gs->surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
811 	return gs;
812 }
813 
814 
gfx_update_texture(GfxDomain * domain,GfxSurface * surface)815 void gfx_update_texture(GfxDomain *domain, GfxSurface *surface)
816 {
817 #ifdef USESDL_GPU
818 	if (!surface->texture)
819 		surface->texture = GPU_CreateImage(surface->surface->w, surface->surface->h, GPU_FORMAT_RGBA);
820 
821 	GPU_UpdateImage(surface->texture, surface->surface, NULL);
822 	GPU_SetImageFilter(surface->texture, GPU_FILTER_NEAREST);
823 	GPU_SetSnapMode(surface->texture, GPU_SNAP_POSITION_AND_DIMENSIONS);
824 	GPU_SetBlending(surface->texture, 1);
825 	GPU_SetBlendMode(surface->texture, GPU_BLEND_NORMAL);
826 #else
827 	if (surface->texture)
828 		SDL_DestroyTexture(surface->texture);
829 
830 	surface->texture = SDL_CreateTextureFromSurface(domain->renderer, surface->surface);
831 #endif
832 }
833 
834 
gfx_free_surface(GfxSurface * surface)835 void gfx_free_surface(GfxSurface *surface)
836 {
837 #ifdef USESDL_GPU
838 	if (surface->texture) GPU_FreeImage(surface->texture);
839 #else
840 	if (surface->texture) SDL_DestroyTexture(surface->texture);
841 #endif
842 	if (surface->surface) SDL_FreeSurface(surface->surface);
843 	if (surface->mask) free(surface->mask);
844 
845 	free(surface);
846 }
847 
848 
gfx_clear(GfxDomain * domain,Uint32 color)849 void gfx_clear(GfxDomain *domain, Uint32 color)
850 {
851 #ifdef USESDL_GPU
852 	GPU_ClearRGBA(domain->screen, (color >> 16) & 255, (color >> 8) & 255, color & 255, 255);
853 #else
854 	SDL_SetRenderDrawColor(domain->renderer, (color >> 16) & 255, (color >> 8) & 255, color & 255, 255);
855 	SDL_RenderClear(domain->renderer);
856 #endif
857 }
858 
859 
860 
861 #define SCALEHELPER(test) do {\
862 		for (int dy = dest_rect->y, sy = 256 * (int)src_rect->y ; dy < dest_rect->h + dest_rect->y ; ++dy, sy += yspd)\
863 		{\
864 			Uint32 * dptr = (Uint32*)((Uint8*)dest->pixels + dy * dest->pitch) + dest_rect->x;\
865 			Uint32 * sptr = (Uint32*)((Uint8*)src->pixels + sy/256 * src->pitch);\
866 			\
867 			for (int dx = dest_rect->w, sx = 256 * (int)src_rect->x ; dx > 0 ; --dx, sx += xspd)\
868 			{\
869 				if (test) *dptr = sptr[sx / 256];\
870 				++dptr;\
871 			}\
872 		}\
873 	} while(0)
874 
875 
gfx_blit(GfxSurface * _src,SDL_Rect * _src_rect,GfxDomain * domain,SDL_Rect * _dest_rect)876 void gfx_blit(GfxSurface *_src, SDL_Rect *_src_rect, GfxDomain *domain, SDL_Rect *_dest_rect)
877 {
878 #ifdef USESDL_GPU
879 	GPU_Rect rect;
880 
881 	if (_src_rect)
882 		rect = GPU_MakeRect(_src_rect->x, _src_rect->y, _src_rect->w, _src_rect->h);
883 	else
884 		rect = GPU_MakeRect(0, 0, _src->surface->w, _src->surface->h);
885 
886 	GPU_BlitScale(_src->texture, &rect, domain->screen, _dest_rect->x + (float)_dest_rect->w / 2, _dest_rect->y + (float)_dest_rect->h / 2, (float)_dest_rect->w / rect.w, (float)_dest_rect->h / rect.h);
887 #else
888 	SDL_RenderCopy(domain->renderer, _src->texture,  _src_rect, _dest_rect);
889 #endif
890 
891 #ifdef DEBUG
892 	domain->calls_per_frame++;
893 #endif
894 }
895 
896 
gfx_rect(GfxDomain * domain,SDL_Rect * dest,Uint32 color)897 void gfx_rect(GfxDomain *domain, SDL_Rect *dest, Uint32 color)
898 {
899 #ifdef USESDL_GPU
900 	SDL_Color rgb = { (color >> 16) & 255, (color >> 8) & 255, color & 255, 255 };
901 
902 	if (dest)
903 		GPU_RectangleFilled(domain->screen, dest->x, dest->y, dest->w + dest->x - 1, dest->y + dest->h - 1, rgb);
904 	else
905 		GPU_RectangleFilled(domain->screen, 0, 0, domain->screen_w, domain->screen_h, rgb);
906 #else
907 	SDL_SetRenderDrawColor(domain->renderer, (color >> 16) & 255, (color >> 8) & 255, color & 255, 255);
908 	SDL_RenderFillRect(domain->renderer, dest);
909 #endif
910 }
911 
912 
my_BlitSurface(GfxSurface * src,SDL_Rect * src_rect,GfxDomain * dest,SDL_Rect * dest_rect)913 void my_BlitSurface(GfxSurface *src, SDL_Rect *src_rect, GfxDomain *dest, SDL_Rect *dest_rect)
914 {
915 	gfx_blit(src, src_rect, dest, dest_rect);
916 }
917 
918 
gfx_domain_set_clip(GfxDomain * domain,const SDL_Rect * rect)919 void gfx_domain_set_clip(GfxDomain *domain, const SDL_Rect *rect)
920 {
921 #ifdef USESDL_GPU
922 	if (rect)
923 		memcpy(&domain->clip, rect, sizeof(*rect));
924 	else
925 	{
926 		domain->clip.x = 0;
927 		domain->clip.y = 0;
928 		domain->clip.w = domain->screen_w;
929 		domain->clip.h = domain->screen_h;
930 	}
931 
932 	GPU_SetClip(domain->screen, domain->clip.x, domain->clip.y, domain->clip.w, domain->clip.h);
933 #else
934 	SDL_RenderSetClipRect(domain->renderer, rect);
935 #endif
936 }
937 
938 
gfx_domain_get_clip(GfxDomain * domain,SDL_Rect * rect)939 void gfx_domain_get_clip(GfxDomain *domain, SDL_Rect *rect)
940 {
941 #ifdef USESDL_GPU
942 	memcpy(rect, &domain->clip, sizeof(*rect));
943 #else
944 	SDL_RenderGetClipRect(domain->renderer, rect);
945 #endif
946 }
947 
948 
gfx_surface_set_color(GfxSurface * surf,Uint32 color)949 void gfx_surface_set_color(GfxSurface *surf, Uint32 color)
950 {
951 #ifdef USESDL_GPU
952 	GPU_SetRGB(surf->texture, (color >> 16) & 255, (color >> 8) & 255, color & 255);
953 #else
954 	SDL_SetTextureColorMod(surf->texture, (color >> 16) & 255, (color >> 8) & 255, color & 255);
955 #endif
956 }
957 
958 
gfx_convert_mouse_coordinates(GfxDomain * domain,int * x,int * y)959 void gfx_convert_mouse_coordinates(GfxDomain *domain, int *x, int *y)
960 {
961 	if (domain->window_w)
962 		*x = *x * domain->screen_w / domain->window_w;
963 
964 	if (domain->window_h)
965 		*y = *y * domain->screen_h / domain->window_h;
966 }
967