- Fixed gradient not working when cached (SDL mode);
[supertux.git] / lib / video / surface.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 //  02111-1307, USA.
20
21 #include <cassert>
22 #include <iostream>
23 #include <algorithm>
24
25 #include "SDL.h"
26 #include "SDL_image.h"
27
28 #include "../video/surface.h"
29 #include "../app/globals.h"
30 #include "../app/setup.h"
31
32 using namespace SuperTux;
33
34 Surface::Surfaces Surface::surfaces;
35
36 SurfaceData::SurfaceData(SDL_Surface* temp, bool use_alpha_)
37     : type(SURFACE), surface(0), use_alpha(use_alpha_)
38 {
39   // Copy the given surface and make sure that it is not stored in
40   // video memory
41   surface = SDL_CreateRGBSurface(temp->flags & (~SDL_HWSURFACE),
42                                  temp->w, temp->h,
43                                  temp->format->BitsPerPixel,
44                                  temp->format->Rmask,
45                                  temp->format->Gmask,
46                                  temp->format->Bmask,
47                                  temp->format->Amask);
48   if(!surface)
49     Termination::abort("No memory left.", "");
50   SDL_SetAlpha(temp,0,0);
51   SDL_BlitSurface(temp, NULL, surface, NULL);
52 }
53
54 SurfaceData::SurfaceData(const std::string& file_, bool use_alpha_)
55     : type(LOAD), surface(0), file(file_), use_alpha(use_alpha_)
56 {}
57
58 SurfaceData::SurfaceData(const std::string& file_, int x_, int y_, int w_, int h_, bool use_alpha_)
59     : type(LOAD_PART), surface(0), file(file_), use_alpha(use_alpha_),
60     x(x_), y(y_), w(w_), h(h_)
61 {}
62
63 SurfaceData::SurfaceData(Color top_gradient_, Color bottom_gradient_, int w_, int h_)
64     : type(GRADIENT), surface(0), use_alpha(false), w(w_), h(h_)
65 {
66 top_gradient = top_gradient_;
67 bottom_gradient = bottom_gradient_;
68 }
69
70
71 SurfaceData::~SurfaceData()
72 {
73   SDL_FreeSurface(surface);
74 }
75
76 SurfaceImpl*
77 SurfaceData::create()
78 {
79 #ifndef NOOPENGL
80   if (use_gl)
81     return create_SurfaceOpenGL();
82   else
83     return create_SurfaceSDL();
84 #else
85   return create_SurfaceSDL();
86 #endif
87 }
88
89 SurfaceSDL*
90 SurfaceData::create_SurfaceSDL()
91 {
92   switch(type)
93   {
94   case LOAD:
95     return new SurfaceSDL(file, use_alpha);
96   case LOAD_PART:
97     return new SurfaceSDL(file, x, y, w, h, use_alpha);
98   case SURFACE:
99     return new SurfaceSDL(surface, use_alpha);
100   case GRADIENT:
101     return new SurfaceSDL(top_gradient, bottom_gradient, w, h);
102   }
103   assert(0);
104 }
105
106 SurfaceOpenGL*
107 SurfaceData::create_SurfaceOpenGL()
108 {
109 #ifndef NOOPENGL
110   switch(type)
111   {
112   case LOAD:
113     return new SurfaceOpenGL(file, use_alpha);
114   case LOAD_PART:
115     return new SurfaceOpenGL(file, x, y, w, h, use_alpha);
116   case SURFACE:
117     return new SurfaceOpenGL(surface, use_alpha);
118   case GRADIENT:
119     return new SurfaceOpenGL(top_gradient, bottom_gradient, w, h);
120   }
121 #endif
122   assert(0);
123 }
124
125 #ifndef NOOPENGL
126 /* Quick utility function for texture creation */
127 static int power_of_two(int input)
128 {
129   int value = 1;
130
131   while ( value < input )
132   {
133     value <<= 1;
134   }
135   return value;
136 }
137 #endif
138
139 Surface::Surface(SDL_Surface* surf, bool use_alpha)
140     : data(surf, use_alpha), w(0), h(0)
141 {
142   impl = data.create();
143   if (impl)
144   {
145     w = impl->w;
146     h = impl->h;
147   }
148   surfaces.push_back(this);
149 }
150
151 Surface::Surface(const std::string& file, bool use_alpha)
152     : data(file, use_alpha), w(0), h(0)
153 {
154   impl = data.create();
155   if (impl)
156   {
157     w = impl->w;
158     h = impl->h;
159   }
160   surfaces.push_back(this);
161 }
162
163 Surface::Surface(const std::string& file, int x, int y, int w, int h, bool use_alpha)
164     : data(file, x, y, w, h, use_alpha), w(0), h(0)
165 {
166   impl = data.create();
167   if (impl)
168   {
169     w = impl->w;
170     h = impl->h;
171   }
172   surfaces.push_back(this);
173 }
174
175 Surface::Surface(Color top_background, Color bottom_background, int w_, int h_)
176     : data(top_background, bottom_background, w_, h_), w(0), h(0)
177 {
178   // FIXME: Gradient surfaces currently don't accept width/height
179   //        If nonzero values are passed to data.create(), supertux
180   //        crashes.
181   impl = data.create();
182   if (impl)
183   {
184     w = impl->w;
185     h = impl->h;
186   }
187   surfaces.push_back(this);
188 }
189
190 void
191 Surface::reload()
192 {
193   delete impl;
194   impl = data.create();
195   if (impl)
196   {
197     w = impl->w;
198     h = impl->h;
199   }
200 }
201
202 Surface::~Surface()
203 {
204 #ifdef DEBUG
205   bool found = false;
206   for(std::list<Surface*>::iterator i = surfaces.begin(); i != surfaces.end();
207       ++i)
208   {
209     if(*i == this)
210     {
211       found = true; break;
212     }
213   }
214   if(!found)
215     printf("Error: Surface freed twice!!!\n");
216 #endif
217   surfaces.remove(this);
218   delete impl;
219 }
220
221 void
222 Surface::reload_all()
223 {
224   for(Surfaces::iterator i = surfaces.begin(); i != surfaces.end(); ++i)
225   {
226     (*i)->reload();
227   }
228 }
229
230 void
231 Surface::debug_check()
232 {
233   for(Surfaces::iterator i = surfaces.begin(); i != surfaces.end(); ++i)
234   {
235     printf("Surface not freed: T:%d F:%s.\n", (*i)->data.type,
236            (*i)->data.file.c_str());
237   }
238 }
239
240 void
241 Surface::resize(int w_, int h_)
242 {
243   if (impl)
244   {
245     w = w_;
246     h = h_;
247     if (impl->resize(w_,h_) == -2)
248       reload();
249   }
250 }
251
252 SDL_Surface*
253 sdl_surface_part_from_file(const std::string& file, int x, int y, int w, int h,  bool use_alpha)
254 {
255   SDL_Rect src;
256   SDL_Surface * sdl_surface;
257   SDL_Surface * temp;
258   SDL_Surface * conv;
259
260   temp = IMG_Load(file.c_str());
261
262   if (temp == NULL)
263     Termination::abort("Can't load", file);
264
265   /* Set source rectangle for conv: */
266
267   src.x = x;
268   src.y = y;
269   src.w = w;
270   src.h = h;
271
272   conv = SDL_CreateRGBSurface(temp->flags, w, h, temp->format->BitsPerPixel,
273                               temp->format->Rmask,
274                               temp->format->Gmask,
275                               temp->format->Bmask,
276                               temp->format->Amask);
277
278   /* #if SDL_BYTEORDER == SDL_BIG_ENDIAN
279      0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
280      #else
281
282      0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
283      #endif*/
284
285   SDL_SetAlpha(temp,0,0);
286
287   SDL_BlitSurface(temp, &src, conv, NULL);
288   if(use_alpha == false && !use_gl)
289     sdl_surface = SDL_DisplayFormat(conv);
290   else
291     sdl_surface = SDL_DisplayFormatAlpha(conv);
292
293   if (sdl_surface == NULL)
294     Termination::abort("Can't covert to display format", file);
295
296   if (use_alpha == false && !use_gl)
297     SDL_SetAlpha(sdl_surface, 0, 0);
298
299   SDL_FreeSurface(temp);
300   SDL_FreeSurface(conv);
301
302   return sdl_surface;
303 }
304
305 SDL_Surface*
306 sdl_surface_from_file(const std::string& file, bool use_alpha)
307 {
308   SDL_Surface* sdl_surface;
309   SDL_Surface* temp;
310
311   temp = IMG_Load(file.c_str());
312
313   if (temp == NULL)
314     Termination::abort("Can't load", file);
315
316   if(use_alpha == false && !use_gl)
317     sdl_surface = SDL_DisplayFormat(temp);
318   else
319     sdl_surface = SDL_DisplayFormatAlpha(temp);
320
321   if (sdl_surface == NULL)
322     Termination::abort("Can't covert to display format", file);
323
324   if (use_alpha == false && !use_gl)
325     SDL_SetAlpha(sdl_surface, 0, 0);
326
327   SDL_FreeSurface(temp);
328
329   return sdl_surface;
330 }
331
332 SDL_Surface*
333 SuperTux::sdl_surface_from_sdl_surface(SDL_Surface* sdl_surf, bool use_alpha)
334 {
335   SDL_Surface* sdl_surface;
336   Uint32 saved_flags;
337   Uint8  saved_alpha;
338
339   /* Save the alpha blending attributes */
340   saved_flags = sdl_surf->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
341   saved_alpha = sdl_surf->format->alpha;
342   if ( (saved_flags & SDL_SRCALPHA)
343        == SDL_SRCALPHA )
344   {
345     SDL_SetAlpha(sdl_surf, 0, 0);
346   }
347
348   if(use_alpha == false && !use_gl)
349     sdl_surface = SDL_DisplayFormat(sdl_surf);
350   else
351     sdl_surface = SDL_DisplayFormatAlpha(sdl_surf);
352
353   /* Restore the alpha blending attributes */
354   if ( (saved_flags & SDL_SRCALPHA)
355        == SDL_SRCALPHA )
356   {
357     SDL_SetAlpha(sdl_surface, saved_flags, saved_alpha);
358   }
359
360   if (sdl_surface == NULL)
361     Termination::abort("Can't covert to display format", "SURFACE");
362
363   if (use_alpha == false && !use_gl)
364     SDL_SetAlpha(sdl_surface, 0, 0);
365
366   return sdl_surface;
367 }
368
369 SDL_Surface*
370 sdl_surface_from_gradient(Color top, Color bottom, int w, int h)
371 {
372   SDL_Surface* sdl_surface;
373
374   sdl_surface = SDL_CreateRGBSurface(screen->flags, w, h,
375                     screen->format->BitsPerPixel, screen->format->Rmask,
376                     screen->format->Gmask, screen->format->Bmask, 0);
377
378   if(sdl_surface == NULL)
379       Termination::abort("Cannot create surface for the gradient", "SURFACE");
380
381   if(top == bottom)
382     {
383     SDL_FillRect(sdl_surface, NULL, SDL_MapRGB(sdl_surface->format,
384         top.red, top.green, top.blue));
385     }
386   else
387     {
388     float redstep = (float(bottom.red)-float(top.red)) / float(h);
389     float greenstep = (float(bottom.green)-float(top.green)) / float(h);
390     float bluestep = (float(bottom.blue) - float(top.blue)) / float(h);
391
392     SDL_Rect rect;
393     rect.x = 0;
394     rect.w = w;
395     rect.h = 1;
396     for(float y = 0; y < h; y++)
397       {
398       rect.y = (int)y;
399       SDL_FillRect(sdl_surface, &rect, SDL_MapRGB(sdl_surface->format,
400           int(float(top.red) + redstep * y),
401           int(float(top.green) + greenstep * y),
402           int(float(top.blue) + bluestep * y)));
403       }
404     }
405
406   return sdl_surface;
407 }
408
409 //---------------------------------------------------------------------------
410
411 SurfaceImpl::SurfaceImpl()
412 {}
413
414 SurfaceImpl::~SurfaceImpl()
415 {
416   SDL_FreeSurface(sdl_surface);
417 }
418
419 SDL_Surface* SurfaceImpl::get_sdl_surface() const
420 {
421   return sdl_surface;
422 }
423
424 int SurfaceImpl::resize(int w_, int h_)
425 {
426   w = w_;
427   h = h_;
428   SDL_Rect dest;
429   dest.x = 0;
430   dest.y = 0;
431   dest.w = w;
432   dest.h = h;
433   int ret = SDL_SoftStretch(sdl_surface, NULL,
434                             sdl_surface, &dest);
435   return ret;
436 }
437
438 #ifndef NOOPENGL
439 SurfaceOpenGL::SurfaceOpenGL(SDL_Surface* surf, bool use_alpha)
440 {
441   sdl_surface = sdl_surface_from_sdl_surface(surf, use_alpha);
442   create_gl(sdl_surface,&gl_texture);
443
444   w = sdl_surface->w;
445   h = sdl_surface->h;
446 }
447
448 SurfaceOpenGL::SurfaceOpenGL(const std::string& file, bool use_alpha)
449 {
450   sdl_surface = sdl_surface_from_file(file, use_alpha);
451   create_gl(sdl_surface,&gl_texture);
452
453   w = sdl_surface->w;
454   h = sdl_surface->h;
455 }
456
457 SurfaceOpenGL::SurfaceOpenGL(const std::string& file_, int x_, int y_, int w_, int h_, bool use_alpha_)
458 {
459   sdl_surface = sdl_surface_part_from_file(file_,x_,y_,w_,h_,use_alpha_);
460   
461   create_gl(sdl_surface, &gl_texture);
462
463   w = sdl_surface->w;
464   h = sdl_surface->h;
465 }
466
467 SurfaceOpenGL::SurfaceOpenGL(Color top_gradient, Color bottom_gradient, int w, int h)
468 {
469   sdl_surface = sdl_surface_from_gradient(top_gradient, bottom_gradient, w, h);
470   create_gl(sdl_surface, &gl_texture);
471
472   w = sdl_surface->w;
473   h = sdl_surface->h;
474 }
475
476 SurfaceOpenGL::~SurfaceOpenGL()
477 {
478   glDeleteTextures(1, &gl_texture);
479 }
480
481 void
482 SurfaceOpenGL::create_gl(SDL_Surface * surf, GLuint * tex)
483 {
484   Uint32 saved_flags;
485   Uint8  saved_alpha;
486   int w, h;
487   SDL_Surface *conv;
488
489   w = power_of_two(surf->w);
490   h = power_of_two(surf->h),
491
492 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
493       conv = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, surf->format->BitsPerPixel,
494                                   0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
495 #else
496       conv = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, surf->format->BitsPerPixel,
497                                   0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
498 #endif
499
500   /* Save the alpha blending attributes */
501   saved_flags = surf->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
502   saved_alpha = surf->format->alpha;
503   if ( (saved_flags & SDL_SRCALPHA)
504        == SDL_SRCALPHA )
505   {
506     SDL_SetAlpha(surf, 0, 0);
507   }
508
509   SDL_BlitSurface(surf, 0, conv, 0);
510
511   /* Restore the alpha blending attributes */
512   if ( (saved_flags & SDL_SRCALPHA)
513        == SDL_SRCALPHA )
514   {
515     SDL_SetAlpha(surf, saved_flags, saved_alpha);
516   }
517
518   // We check all the pixels of the surface to figure out which
519   // internal format OpenGL should use for storing it, ie. if no alpha
520   // is present store in RGB instead of RGBA, this saves a few bytes
521   // of memory, but much more importantly it makes the game look
522   // *much* better in 16bit color mode
523   int internal_format = GL_RGB10_A2;
524   bool has_alpha = false;
525
526   unsigned char* buf = static_cast<unsigned char*>(conv->pixels);
527   for (int y = 0; y < surf->h; ++y)
528     for (int x = 0; x < surf->w; ++x)
529       {
530         if (buf[(conv->pitch*y + x*4) + 3] != 255)
531           {
532             has_alpha = true;
533             break;
534           }
535       }
536
537   if (!has_alpha)
538     {
539       internal_format = GL_RGB;
540     }
541
542   glGenTextures(1, &*tex);
543   glBindTexture(GL_TEXTURE_2D , *tex);
544   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
545   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
546   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
547   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
548   glPixelStorei(GL_UNPACK_ROW_LENGTH, conv->pitch / conv->format->BytesPerPixel);
549   glTexImage2D(GL_TEXTURE_2D, 0, internal_format, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, conv->pixels);
550   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
551
552   SDL_FreeSurface(conv);
553 }
554
555 int
556 SurfaceOpenGL::draw(float x, float y, Uint8 alpha, Uint32 effect)
557 {
558   float pw = power_of_two(w);
559   float ph = power_of_two(h);
560
561   if(effect & SEMI_TRANSPARENT)
562     alpha = 128;
563
564   glEnable(GL_TEXTURE_2D);
565   glEnable(GL_BLEND);
566   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
567
568   glColor4ub(alpha, alpha, alpha, alpha);
569
570   glBindTexture(GL_TEXTURE_2D, gl_texture);
571
572   glBegin(GL_QUADS);
573
574   if(effect & VERTICAL_FLIP)
575     {
576     glTexCoord2f(0, 0);
577     glVertex2f(x, (float)h+y);
578
579     glTexCoord2f((float)w / pw, 0);
580     glVertex2f((float)w+x, (float)h+y);
581
582     glTexCoord2f((float)w / pw, (float)h / ph);
583     glVertex2f((float)w+x, y);
584     
585     glTexCoord2f(0, (float)h / ph);
586     glVertex2f(x, y);
587     }
588   else
589     {
590     glTexCoord2f(0, 0);
591     glVertex2f(x, y);
592
593     glTexCoord2f((float)w / pw, 0);
594     glVertex2f((float)w+x, y);
595
596     glTexCoord2f((float)w / pw, (float)h / ph);
597     glVertex2f((float)w+x, (float)h+y);
598
599     glTexCoord2f(0, (float)h / ph);
600     glVertex2f(x, (float)h+y);
601     }
602   glEnd();
603
604   glDisable(GL_TEXTURE_2D);
605   glDisable(GL_BLEND);
606
607   return 0;
608 }
609
610 int
611 SurfaceOpenGL::draw_part(float sx, float sy, float x, float y, float w, float h, Uint8 alpha, Uint32 effect)
612 {
613   float pw = power_of_two(int(this->w));
614   float ph = power_of_two(int(this->h));
615
616   if(effect & SEMI_TRANSPARENT)
617     alpha = 128;
618
619   glBindTexture(GL_TEXTURE_2D, gl_texture);
620
621   glEnable(GL_BLEND);
622   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
623
624   glColor4ub(alpha, alpha, alpha, alpha);
625
626   glEnable(GL_TEXTURE_2D);
627
628
629   glBegin(GL_QUADS);
630
631   if(effect & VERTICAL_FLIP)
632     {
633     glTexCoord2f(sx / pw, sy / ph);
634     glVertex2f(x, y);
635
636     glTexCoord2f((float)(sx + w) / pw, sy / ph);
637     glVertex2f(w+x, y);
638
639     glTexCoord2f((sx+w) / pw, (sy+h) / ph);
640     glVertex2f(w +x, h+y);
641
642     glTexCoord2f(sx / pw, (float)(sy+h) / ph);
643     glVertex2f(x, h+y);
644     }
645   else
646     {
647     glTexCoord2f(sx / pw, (float)(sy+h) / ph);
648     glVertex2f(x, h+y);
649
650     glTexCoord2f((sx+w) / pw, (sy+h) / ph);
651     glVertex2f(w +x, h+y);
652
653     glTexCoord2f((float)(sx + w) / pw, sy / ph);
654     glVertex2f(w+x, y);
655
656     glTexCoord2f(sx / pw, sy / ph);
657     glVertex2f(x, y);
658     }
659
660   glEnd();
661
662   glDisable(GL_TEXTURE_2D);
663   glDisable(GL_BLEND);
664
665   return 0;
666 }
667
668 int
669 SurfaceOpenGL::draw_stretched(float x, float y, int sw, int sh, Uint8 alpha, Uint32 effect)
670 {
671   if(effect & SEMI_TRANSPARENT)
672     alpha = 128;
673
674   float pw = power_of_two(sw);
675   float ph = power_of_two(sh);
676
677   if(effect & SEMI_TRANSPARENT)
678     alpha = 128;
679
680   glEnable(GL_TEXTURE_2D);
681   glEnable(GL_BLEND);
682   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
683
684   glColor4ub(alpha, alpha, alpha, alpha);
685
686   glBindTexture(GL_TEXTURE_2D, gl_texture);
687
688   glBegin(GL_QUADS);
689
690   if(effect & VERTICAL_FLIP)
691     {
692     glTexCoord2f(0, 0);
693     glVertex2f(x, (float)sh+y);
694
695     glTexCoord2f((float)w / pw, 0);
696     glVertex2f((float)sw+x, (float)sh+y);
697
698     glTexCoord2f((float)w / pw, (float)h / ph);
699     glVertex2f((float)sw+x, y);
700     
701     glTexCoord2f(0, (float)h / ph);
702     glVertex2f(x, y);
703     }
704   else
705     {
706     glTexCoord2f(0, 0);
707     glVertex2f(x, y);
708
709     glTexCoord2f((float)w / pw, 0);
710     glVertex2f((float)sw+x, y);
711
712     glTexCoord2f((float)w / pw, (float)h / ph);
713     glVertex2f((float)sw+x, (float)sh+y);
714
715     glTexCoord2f(0, (float)h / ph);
716     glVertex2f(x, (float)sh+y);
717     }
718   glEnd();
719
720   glDisable(GL_TEXTURE_2D);
721   glDisable(GL_BLEND);
722
723   return 0;
724 }
725
726 #endif
727
728 SurfaceSDL::SurfaceSDL(SDL_Surface* surf, bool use_alpha)
729 {
730   sdl_surface = sdl_surface_from_sdl_surface(surf, use_alpha);
731   w = sdl_surface->w;
732   h = sdl_surface->h;
733 }
734
735 SurfaceSDL::SurfaceSDL(const std::string& file, bool use_alpha)
736 {
737   sdl_surface = sdl_surface_from_file(file, use_alpha);
738   w = sdl_surface->w;
739   h = sdl_surface->h;
740 }
741
742 SurfaceSDL::SurfaceSDL(const std::string& file, int x, int y, int w, int h,  bool use_alpha)
743 {
744   sdl_surface = sdl_surface_part_from_file(file, x, y, w, h, use_alpha);
745   w = sdl_surface->w;
746   h = sdl_surface->h;
747 }
748
749 SurfaceSDL::SurfaceSDL(Color top_gradient, Color bottom_gradient, int w, int h)
750 {
751   sdl_surface = sdl_surface_from_gradient(top_gradient, bottom_gradient, w, h);
752   w = sdl_surface->w;
753   h = sdl_surface->h;
754 }
755
756 int
757 SurfaceSDL::draw(float x, float y, Uint8 alpha, Uint32 effect)
758 {
759   SDL_Rect dest;
760
761   dest.x = (int)x;
762   dest.y = (int)y;
763   dest.w = w;
764   dest.h = h;
765
766   if(effect & SEMI_TRANSPARENT)
767     alpha = 128;
768
769   if(effect & VERTICAL_FLIP)    // FIXME: feel free to replace this hack
770     {
771     for(float sy = 0; sy < h; sy++)
772       if(draw_part(0, sy, x, y+(h-sy), w, 1, alpha, NONE_EFFECT) == -2)
773         return -2;
774     return 0;
775     }
776
777   if(alpha != 255)
778     {
779     /* Create a Surface, make it using colorkey, blit surface into temp, apply alpha
780       to temp sur, blit the temp into the screen */
781     /* Note: this has to be done, since SDL doesn't allow to set alpha to surfaces that
782       already have an alpha mask yet... */
783
784     SDL_Surface* sdl_surface_copy = SDL_CreateRGBSurface (sdl_surface->flags,
785                                     sdl_surface->w, sdl_surface->h, sdl_surface->format->BitsPerPixel,
786                                     sdl_surface->format->Rmask, sdl_surface->format->Gmask,
787                                     sdl_surface->format->Bmask,
788                                     0);
789     int colorkey = SDL_MapRGB(sdl_surface_copy->format, 255, 0, 255);
790     SDL_FillRect(sdl_surface_copy, NULL, colorkey);
791     SDL_SetColorKey(sdl_surface_copy, SDL_SRCCOLORKEY, colorkey);
792
793
794     SDL_BlitSurface(sdl_surface, NULL, sdl_surface_copy, NULL);
795     SDL_SetAlpha(sdl_surface_copy ,SDL_SRCALPHA,alpha);
796
797     int ret = SDL_BlitSurface(sdl_surface_copy, NULL, screen, &dest);
798
799     SDL_FreeSurface (sdl_surface_copy);
800     return ret;
801     }
802
803   int ret = SDL_BlitSurface(sdl_surface, NULL, screen, &dest);
804
805   return ret;
806 }
807
808 int
809 SurfaceSDL::draw_part(float sx, float sy, float x, float y, float w, float h, Uint8 alpha, Uint32 effect)
810 {
811   SDL_Rect src, dest;
812
813   src.x = (int)sx;
814   src.y = (int)sy;
815   src.w = (int)w;
816   src.h = (int)h;
817
818   dest.x = (int)x;
819   dest.y = (int)y;
820   dest.w = (int)w;
821   dest.h = (int)h;
822
823   if(effect & SEMI_TRANSPARENT)
824     alpha = 128;
825
826   if(effect & VERTICAL_FLIP)    // FIXME: feel free to replace this hack
827     {
828     for(float sy_ = sy; sy_ < h; sy_++)
829       if(draw_part(sx, sy_, x, y+(h-sy_), w, 1, alpha, NONE_EFFECT) == -2)
830         return -2;
831     return 0;
832     }
833
834   if(alpha != 255)
835     {
836     /* Create a Surface, make it using colorkey, blit surface into temp, apply alpha
837       to temp sur, blit the temp into the screen */
838     /* Note: this has to be done, since SDL doesn't allow to set alpha to surfaces that
839       already have an alpha mask yet... */
840
841     SDL_Surface* sdl_surface_copy = SDL_CreateRGBSurface (sdl_surface->flags,
842                                     sdl_surface->w, sdl_surface->h, sdl_surface->format->BitsPerPixel,
843                                     sdl_surface->format->Rmask, sdl_surface->format->Gmask,
844                                     sdl_surface->format->Bmask,
845                                     0);
846     int colorkey = SDL_MapRGB(sdl_surface_copy->format, 255, 0, 255);
847     SDL_FillRect(sdl_surface_copy, NULL, colorkey);
848     SDL_SetColorKey(sdl_surface_copy, SDL_SRCCOLORKEY, colorkey);
849
850
851     SDL_BlitSurface(sdl_surface, NULL, sdl_surface_copy, NULL);
852     SDL_SetAlpha(sdl_surface_copy ,SDL_SRCALPHA,alpha);
853
854     int ret = SDL_BlitSurface(sdl_surface_copy, NULL, screen, &dest);
855
856     SDL_FreeSurface (sdl_surface_copy);
857     return ret;
858     }
859
860   int ret = SDL_BlitSurface(sdl_surface, &src, screen, &dest);
861
862   return ret;
863 }
864
865 int
866 SurfaceSDL::draw_stretched(float x, float y, int sw, int sh, Uint8 alpha, Uint32 effect)
867 {
868   SDL_Rect dest;
869
870   dest.x = (int)x;
871   dest.y = (int)y;
872   dest.w = (int)sw;
873   dest.h = (int)sh;
874
875   if(effect & SEMI_TRANSPARENT)
876     alpha = 128;
877
878   SDL_Surface* sdl_surface_copy = SDL_CreateRGBSurface (sdl_surface->flags,
879                                   sw, sh, sdl_surface->format->BitsPerPixel,
880                                   sdl_surface->format->Rmask, sdl_surface->format->Gmask,
881                                   sdl_surface->format->Bmask,
882                                   0);
883
884   SDL_BlitSurface(sdl_surface, NULL, sdl_surface_copy, NULL);
885   SDL_SoftStretch(sdl_surface_copy, NULL, sdl_surface_copy, &dest);
886
887   if(alpha != 255)
888     SDL_SetAlpha(sdl_surface_copy,SDL_SRCALPHA,alpha);
889
890   int ret = SDL_BlitSurface(sdl_surface_copy,NULL,screen,&dest);
891   SDL_FreeSurface(sdl_surface_copy);
892
893   return ret;
894 }
895
896 SurfaceSDL::~SurfaceSDL()
897 {}
898
899 /* EOF */