1 /*
2 * GNUjump
3 * =======
4 *
5 * Copyright (C) 2005-2008, Juan Pedro Bolivar Puente
6 *
7 * GNUjump is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * GNUjump is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21
22 #include "gnujump.h"
23 #include "surface.h"
24
25 #include "SDL_rotozoom.h"
26
27 extern SDL_Surface *screen;
28 extern L_gblOptions gblOps;
29
30 #define applyAlpha(alpha, bc, c) ((alpha)*(bc) + (1-(alpha))*(c))
31
32 void
JPB_drawLine(Uint8 r,Uint8 g,Uint8 b,Uint8 a,int x0,int y0,int x1,int y1)33 JPB_drawLine (Uint8 r, Uint8 g, Uint8 b, Uint8 a, int x0, int y0, int x1,
34 int y1)
35 {
36 if (gblOps.useGL)
37 {
38 GL2D_DrawLine (r, g, b, a, x0, y0, x1, y1);
39 }
40 else
41 {
42 drawLine (screen, r, g, b, a, x0, y0, x1, y1);
43 }
44 }
45
46 /* Interesting article on line drawing:
47 http://www.cs.unc.edu/~mcmillan/comp136/Lecture6/Lines.html */
48 void
drawLine(SDL_Surface * dest,Uint8 dr,Uint8 dg,Uint8 db,Uint8 alpha,int x0,int y0,int x1,int y1)49 drawLine (SDL_Surface * dest, Uint8 dr, Uint8 dg, Uint8 db, Uint8 alpha,
50 int x0, int y0, int x1, int y1)
51 {
52 int dy = y1 - y0;
53 int dx = x1 - x0;
54 int stepx, stepy;
55 int fraction;
56 Uint8 r, g, b;
57 Uint32 pixel;
58 float a = (float) alpha / 255;
59
60 if (dy < 0)
61 {
62 dy = -dy;
63 stepy = -1;
64 }
65 else
66 {
67 stepy = 1;
68 }
69 if (dx < 0)
70 {
71 dx = -dx;
72 stepx = -1;
73 }
74 else
75 {
76 stepx = 1;
77 }
78 dy <<= 1;
79 dx <<= 1;
80
81 /* We dont draw the first pixel, because it would overlap with another
82 trail segment */
83 if (dx > dy)
84 {
85 fraction = dy - (dx >> 1);
86 while (x0 != x1)
87 {
88 if (fraction >= 0)
89 {
90 y0 += stepy;
91 fraction -= dx;
92 }
93 x0 += stepx;
94 fraction += dy;
95
96 /* TODO: We should create a function for this */
97 pixel = getpixel (dest, x0, y0);
98 SDL_GetRGB (pixel, dest->format, &r, &g, &b);
99 r = applyAlpha (a, dr, r);
100 g = applyAlpha (a, dg, g);
101 b = applyAlpha (a, db, b);
102 pixel = SDL_MapRGB (dest->format, r, g, b);
103 putpixel (dest, x0, y0, pixel);
104 }
105 }
106 else
107 {
108 fraction = dx - (dy >> 1);
109 while (y0 != y1)
110 {
111 if (fraction >= 0)
112 {
113 x0 += stepx;
114 fraction -= dy;
115 }
116 y0 += stepy;
117 fraction += dx;
118
119 pixel = getpixel (dest, x0, y0);
120 SDL_GetRGB (pixel, dest->format, &r, &g, &b);
121 r = applyAlpha (a, dr, r);
122 g = applyAlpha (a, dg, g);
123 b = applyAlpha (a, db, b);
124 pixel = SDL_MapRGB (dest->format, r, g, b);
125 putpixel (dest, x0, y0, pixel);
126 }
127 }
128 }
129
130 void
JPB_drawSquare(Uint32 color,Uint8 alpha,int x,int y,int w,int h)131 JPB_drawSquare (Uint32 color, Uint8 alpha, int x, int y, int w, int h)
132 {
133 Uint8 r, g, b;
134 if (gblOps.useGL)
135 {
136 SDL_GetRGB (color, screen->format, &r, &g, &b);
137 GL2D_DrawRect (r, g, b, alpha, x, y, w, h);
138 }
139 else
140 {
141 drawSquareAlpha (screen, color, alpha, x, y, w, h);
142 }
143 }
144
145 JPB_surfaceRot *
JPB_LoadImgRot(char * file,Uint8 gl,Uint8 alpha,Uint8 trans,Uint8 rev)146 JPB_LoadImgRot (char *file, Uint8 gl, Uint8 alpha, Uint8 trans, Uint8 rev)
147 {
148 SDL_Surface *temp1 = NULL, *temp2 = NULL;
149 JPB_surfaceRot *surface = NULL;
150
151 temp1 = LoadImg (file, alpha, trans);
152 if (temp1 != NULL)
153 {
154 if (rev)
155 {
156 temp2 = temp1;
157 temp1 = ReversePic (temp1);
158 SDL_FreeSurface (temp2);
159 }
160 surface = JPB_CreateSurfaceRot (temp1, gl);
161 SDL_FreeSurface (temp1);
162 }
163
164 return surface;
165 }
166
167 JPB_surfaceRot *
JPB_CreateSurfaceRot(SDL_Surface * src,Uint8 gl)168 JPB_CreateSurfaceRot (SDL_Surface * src, Uint8 gl)
169 {
170 JPB_surfaceRot *surface = NULL;
171
172 surface = malloc (sizeof (JPB_surfaceRot));
173
174 if (gl)
175 {
176 surface->gl = TRUE;
177 surface->surfGL = GL2D_CreateSurfaceGL (src, gblOps.texFilter);
178 surface->w = surface->surfGL->w;
179 surface->h = surface->surfGL->h;
180 }
181 else
182 {
183 if ((src->flags & SDL_SRCALPHA) == SDL_SRCALPHA)
184 surface->surf = SDL_DisplayFormatAlpha (src);
185 else
186 surface->surf = SDL_DisplayFormat (src);
187 if (gblOps.texFilter == GL_NEAREST)
188 surface->rSurf = rotozoomSurface (surface->surf, 0, 1, 0);
189 else
190 surface->rSurf = rotozoomSurface (surface->surf, 0, 1, 1);
191
192 surface->w = surface->surf->w;
193 surface->h = surface->surf->h;
194 surface->gl = FALSE;
195 }
196 surface->alpha = -1;
197
198 return surface;
199 }
200
201
202 JPB_surface *
JPB_LoadImg(char * file,Uint8 gl,Uint8 alpha,Uint8 trans,Uint8 rev)203 JPB_LoadImg (char *file, Uint8 gl, Uint8 alpha, Uint8 trans, Uint8 rev)
204 {
205 SDL_Surface *temp1 = NULL, *temp2 = NULL;
206 JPB_surface *surface = NULL;
207
208 temp1 = LoadImg (file, alpha, trans);
209 if (temp1 != NULL)
210 {
211 if (rev)
212 {
213 temp2 = temp1;
214 temp1 = ReversePic (temp1);
215 SDL_FreeSurface (temp2);
216 }
217 surface = JPB_CreateSurface (temp1, gl);
218 SDL_FreeSurface (temp1);
219 }
220
221 return surface;
222 }
223
224 JPB_surface *
JPB_CreateSurface(SDL_Surface * src,Uint8 gl)225 JPB_CreateSurface (SDL_Surface * src, Uint8 gl)
226 {
227 JPB_surface *surface = NULL;
228 GLint texSize;
229
230 surface = malloc (sizeof (JPB_surface));
231
232 if (gl)
233 {
234 glGetIntegerv (GL_MAX_TEXTURE_SIZE, &texSize);
235 //texSize = 1024;
236 if (texSize < src->w)
237 {
238 surface->gl = LARGE_GL;
239 surface->LsurfGL =
240 GL2D_CreateLargeSurfaceGL (src, gblOps.texFilter);
241 surface->w = surface->LsurfGL->w;
242 surface->h = surface->LsurfGL->h;
243 }
244 else
245 {
246 surface->gl = TRUE;
247 surface->surfGL = GL2D_CreateSurfaceGL (src, gblOps.texFilter);
248 surface->w = surface->surfGL->w;
249 surface->h = surface->surfGL->h;
250 }
251 }
252 else
253 {
254 if ((src->flags & SDL_SRCALPHA) == SDL_SRCALPHA)
255 surface->surf = SDL_DisplayFormatAlpha (src);
256 else
257 surface->surf = SDL_DisplayFormat (src);
258
259 surface->w = surface->surf->w;
260 surface->h = surface->surf->h;
261 surface->gl = FALSE;
262 }
263 surface->alpha = -1;
264
265 return surface;
266 }
267
268 void
JPB_FreeSurface(JPB_surface * surface)269 JPB_FreeSurface (JPB_surface * surface)
270 {
271 if (surface->gl == LARGE_GL)
272 GL2D_FreeLargeSurfaceGL (surface->LsurfGL);
273 else if (surface->gl == TRUE)
274 GL2D_FreeSurfaceGL (surface->surfGL);
275 else if (surface->gl == FALSE)
276 SDL_FreeSurface (surface->surf);
277
278 free (surface);
279 }
280
281 void
JPB_FreeSurfaceRot(JPB_surfaceRot * surface)282 JPB_FreeSurfaceRot (JPB_surfaceRot * surface)
283 {
284 if (surface->gl == TRUE)
285 GL2D_FreeSurfaceGL (surface->surfGL);
286 else if (surface->gl == FALSE)
287 {
288 SDL_FreeSurface (surface->surf);
289 SDL_FreeSurface (surface->rSurf);
290 }
291 free (surface);
292 }
293
294 void
JPB_PrintSurfaceRot(JPB_surfaceRot * src,SDL_Rect * src_r,SDL_Rect * dest_r,float angle)295 JPB_PrintSurfaceRot (JPB_surfaceRot * src, SDL_Rect * src_r,
296 SDL_Rect * dest_r, float angle)
297 {
298
299 if (src->gl == TRUE)
300 {
301 GL2D_BlitGLrot (src->surfGL, dest_r->x, dest_r->y, angle, src->alpha);
302 src->angle = angle;
303 }
304 else if (src->gl == FALSE)
305 {
306 if (angle != src->angle)
307 {
308 SDL_FreeSurface (src->rSurf);
309 if (gblOps.texFilter == GL_NEAREST)
310 src->rSurf = rotozoomSurface (src->surf, angle, 1, 0);
311 else
312 src->rSurf = rotozoomSurface (src->surf, angle, 1, 1);
313 src->angle = angle;
314 }
315 dest_r->x -= src->rSurf->w / 2;
316 dest_r->y -= src->rSurf->h / 2;
317 BlitSurface (src->rSurf, src_r, screen, dest_r, src->alpha);
318 }
319 }
320
321 void
JPB_PrintSurface(JPB_surface * src,SDL_Rect * src_r,SDL_Rect * dest_r)322 JPB_PrintSurface (JPB_surface * src, SDL_Rect * src_r, SDL_Rect * dest_r)
323 {
324
325 if (src->gl == TRUE)
326 GL2D_BlitSurfaceGL (src->surfGL, src_r, dest_r, src->alpha);
327 else if (src->gl == FALSE)
328 BlitSurface (src->surf, src_r, screen, dest_r, src->alpha);
329 else if (src->gl == LARGE_GL)
330 GL2D_BlitLargeSurfaceGL (src->LsurfGL, src_r, dest_r, src->alpha);
331
332 }
333
334
335
336 /* Probably not very fast, but enough for my needs*/
337 void
drawSquareAlpha(SDL_Surface * dest,Uint32 color,Uint8 alpha,int x,int y,int w,int h)338 drawSquareAlpha (SDL_Surface * dest, Uint32 color, Uint8 alpha,
339 int x, int y, int w, int h)
340 {
341 int i, j;
342 Uint32 pixel;
343 Uint8 r, g, b, dr, dg, db;
344 float alphaF = (float) alpha / 255;
345
346 if (x + w > dest->w)
347 w = dest->w - x;
348 if (y + h > dest->h)
349 h = dest->h - y;
350
351 /* Negative width/height values do reverse drawing */
352 if (w < 0)
353 {
354 w = -w;
355 x -= w;
356 }
357 if (h < 0)
358 {
359 h = -h;
360 y -= h;
361 }
362
363 SDL_GetRGB (color, dest->format, &dr, &dg, &db);
364 Slock (dest);
365 for (i = 0; i < w; i++)
366 {
367 for (j = 0; j < h; j++)
368 {
369 pixel = getpixel (dest, i + x, j + y);
370 SDL_GetRGB (pixel, dest->format, &r, &g, &b);
371 r = applyAlpha (alphaF, dr, r);
372 g = applyAlpha (alphaF, dg, g);
373 b = applyAlpha (alphaF, db, b);
374 pixel = SDL_MapRGB (dest->format, r, g, b);
375 putpixel (dest, i + x, j + y, pixel);
376 }
377 }
378 Sulock (dest);
379 }
380
381 int
BlitSurface(SDL_Surface * src,SDL_Rect * src_r,SDL_Surface * dest,SDL_Rect * dest_r,Uint8 alpha)382 BlitSurface (SDL_Surface * src, SDL_Rect * src_r,
383 SDL_Surface * dest, SDL_Rect * dest_r, Uint8 alpha)
384 {
385 //SDL_Surface * sdl_surface_copy = NULL;
386 int ret;
387
388 if (alpha == 0)
389 return FALSE;
390
391 if (alpha != 255)
392 {
393 /*if ((src->flags & SDL_SRCALPHA)==SDL_SRCALPHA)
394 {
395 sdl_surface_copy = SDL_CreateRGBSurface (src->flags,
396 src->w, src->h, src->format->BitsPerPixel,
397 src->format->Rmask, src->format->Gmask,
398 src->format->Bmask,
399 0);
400
401 //colorkey = SDL_MapRGB(sdl_surface_copy->format, 255, 0, 255);
402
403 //SDL_FillRect(sdl_surface_copy, NULL, colorkey);
404 //SDL_SetColorKey(sdl_surface_copy, SDL_SRCCOLORKEY, colorkey);
405
406 SDL_BlitSurface(src, NULL, sdl_surface_copy, NULL);
407
408 SDL_SetAlpha(sdl_surface_copy, SDL_SRCALPHA, alpha);
409
410 ret = SDL_BlitSurface(sdl_surface_copy, src_r, dest, dest_r);
411
412 SDL_FreeSurface (sdl_surface_copy);
413 return ret;
414 return FALSE;
415 }else
416 { */
417 SDL_SetAlpha (src, SDL_SRCALPHA, alpha);
418 ret = SDL_BlitSurface (src, src_r, dest, dest_r);
419 SDL_SetAlpha (src, 0, alpha);
420 return ret;
421 //}
422 }
423 else
424 {
425 ret = SDL_BlitSurface (src, src_r, dest, dest_r);
426 return ret;
427 }
428 }
429
430 int
BlitRot(SDL_Surface * src,SDL_Surface * dest,SDL_Rect * dest_r,Sint16 angle,Uint8 alpha)431 BlitRot (SDL_Surface * src, SDL_Surface * dest, SDL_Rect * dest_r,
432 Sint16 angle, Uint8 alpha)
433 {
434 SDL_Surface *rot = NULL;
435 int ret;
436
437 rot = rotozoomSurface (src, angle, 1, 0);
438 ret = BlitSurface (rot, NULL, dest, dest_r, alpha);
439 SDL_FreeSurface (rot);
440 return ret;
441 }
442
443 void
FlipScreen()444 FlipScreen ()
445 {
446 if (gblOps.useGL)
447 {
448 SDL_GL_SwapBuffers ();
449 #ifdef GLFINISH
450 glFinish ();
451 #endif
452 //glClear(GL_COLOR_BUFFER_BIT);
453 }
454 else
455 SDL_Flip (screen);
456 }
457
458 Uint32
getpixel(SDL_Surface * surface,int x,int y)459 getpixel (SDL_Surface * surface, int x, int y)
460 {
461 int bpp = surface->format->BytesPerPixel;
462 /* Here p is the address to the pixel we want to retrieve */
463 Uint8 *p = (Uint8 *) surface->pixels + y * surface->pitch + x * bpp;
464
465 if (x >= surface->w || y >= surface->h || x < 0 || y < 0)
466 return 0;
467
468 switch (bpp)
469 {
470 case 1:
471 return *p;
472
473 case 2:
474 return *(Uint16 *) p;
475
476 case 3:
477 if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
478 return p[0] << 16 | p[1] << 8 | p[2];
479 else
480 return p[0] | p[1] << 8 | p[2] << 16;
481
482 case 4:
483 return *(Uint32 *) p;
484
485 default:
486 return 0; /* shouldn't happen, but avoids warnings */
487 }
488 }
489
490
491 void
putpixel(SDL_Surface * surface,int x,int y,Uint32 pixel)492 putpixel (SDL_Surface * surface, int x, int y, Uint32 pixel)
493 {
494 int bpp = surface->format->BytesPerPixel;
495 /* Here p is the address to the pixel we want to set */
496 Uint8 *p = (Uint8 *) surface->pixels + y * surface->pitch + x * bpp;
497
498 if (x >= surface->w || y >= surface->h || x < 0 || y < 0)
499 return;
500
501 switch (bpp)
502 {
503 case 1:
504 *p = pixel;
505 break;
506
507 case 2:
508 *(Uint16 *) p = pixel;
509 break;
510
511 case 3:
512 if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
513 {
514 p[0] = (pixel >> 16) & 0xff;
515 p[1] = (pixel >> 8) & 0xff;
516 p[2] = pixel & 0xff;
517 }
518 else
519 {
520 p[0] = pixel & 0xff;
521 p[1] = (pixel >> 8) & 0xff;
522 p[2] = (pixel >> 16) & 0xff;
523 }
524 break;
525
526 case 4:
527 *(Uint32 *) p = pixel;
528 break;
529 }
530 }
531
532
533 void
Slock(SDL_Surface * door)534 Slock (SDL_Surface * door)
535 {
536 if (SDL_MUSTLOCK (door))
537 {
538 if (SDL_LockSurface (door) < 0)
539 {
540 fprintf (stderr, "Can't lock screen: %s\n", SDL_GetError ());
541 }
542 }
543 }
544
545
546 void
Sulock(SDL_Surface * door)547 Sulock (SDL_Surface * door)
548 {
549 if (SDL_MUSTLOCK (door))
550 {
551 SDL_UnlockSurface (door);
552 }
553 }
554
555
556 void
SetTrans(SDL_Surface * src,int x,int y)557 SetTrans (SDL_Surface * src, int x, int y)
558 {
559 Uint32 pixel;
560
561 Slock (src);
562 pixel = getpixel (src, x, y);
563 Sulock (src);
564 SDL_SetColorKey (src, SDL_SRCCOLORKEY | SDL_RLEACCEL, pixel);
565 }
566
567 void
SetRLE(SDL_Surface * src)568 SetRLE (SDL_Surface * src)
569 {
570 SDL_SetColorKey (src, SDL_RLEACCEL, 0);
571 }
572
573 SDL_Surface *
LoadImg(char * file,Uint8 Use_Alpha,Uint8 trans)574 LoadImg (char *file, Uint8 Use_Alpha, Uint8 trans)
575 {
576 SDL_Surface *temp1 = NULL, *temp2 = NULL;
577
578 temp1 = IMG_Load (file);
579 if (trans)
580 SetTrans (temp1, 0, 0);
581
582 if (!Use_Alpha && !gblOps.useGL)
583 {
584 temp2 = SDL_DisplayFormat (temp1);
585 SDL_FreeSurface (temp1);
586 }
587 else
588 {
589 SDL_SetAlpha (temp1, SDL_RLEACCEL | SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
590 temp2 = SDL_DisplayFormatAlpha (temp1);
591 SDL_FreeSurface (temp1);
592 }
593
594 return temp2;
595 }
596
597
598 SDL_Surface *
ReversePic(SDL_Surface * source)599 ReversePic (SDL_Surface * source)
600 {
601 SDL_Surface *destiny = NULL;
602 Uint32 pixel;
603 int i, j, w, h;
604
605 //Generates a surface dor the destiny and makes the pinter aim to it...
606 if ((source->flags & SDL_SRCALPHA) == SDL_SRCALPHA)
607 destiny = SDL_DisplayFormatAlpha (source);
608 else
609 destiny = SDL_DisplayFormat (source);
610
611 w = source->w;
612 h = source->h;
613 //locks the surfaces...
614 Slock (source);
615 Slock (destiny);
616
617 for (j = 0; j < h; j++)
618 {
619
620 for (i = 0; i < w; i++)
621 {
622 pixel = getpixel (source, i, j); //Gets the pixel...
623 putpixel (destiny, ((w - 1) - i), j, pixel);
624 //And puts it in the other side.
625 }
626 }
627
628 //unlocking surfaces...
629 Sulock (destiny);
630 Sulock (source);
631
632 return destiny; //Here we go!
633
634 }
635