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