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