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