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