support screenshots in the nogl patch
[supertux.git] / contrib / supertux-nogl.diff
1 #
2 #  SuperTux -nogl patch
3 #  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
4 #
5 #  This program is free software; you can redistribute it and/or
6 #  modify it under the terms of the GNU General Public License
7 #  as published by the Free Software Foundation; either version 2
8 #  of the License, or (at your option) any later version.
9 #
10 #  This program is distributed in the hope that it will be useful,
11 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #  GNU General Public License for more details.
14 #
15 #  You should have received a copy of the GNU General Public License
16 #  along with this program; if not, write to the Free Software
17 #  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 #
19 # -----------------------------------------------------------------------------
20 #
21 #  This patch allows running the game on systems without OpenGL support. 
22 #
23 #  It modifies the video portion of the SuperTux engine to render all graphics
24 #  with SDL functions only. Many features are removed from the video engine,
25 #  so don't expect much.
26 #
27 #  Installing the patch should be pretty straightforward. Simply run the
28 #  following command prior to running autogen.sh and configure:
29 #
30 #  patch -p0 < contrib/supertux-nogl.diff
31 #
32 #  This patch works for revision 5068. It may break for later revisions.
33 #
34 # -----------------------------------------------------------------------------
35 Index: src/gameconfig.hpp
36 ===================================================================
37 --- src/gameconfig.hpp  (revision 5067)
38 +++ src/gameconfig.hpp  (working copy)
39 @@ -39,6 +39,7 @@
40    float aspect_ratio;
41  
42    bool use_fullscreen;
43 +  bool use_opengl;
44    bool try_vsync;
45    bool show_fps;
46    bool sound_enabled;
47 Index: src/video/drawing_context.cpp
48 ===================================================================
49 --- src/video/drawing_context.cpp       (revision 5067)
50 +++ src/video/drawing_context.cpp       (working copy)
51 @@ -308,28 +308,38 @@
52  void
53  DrawingContext::get_light(const Vector& position, Color* color)
54  {
55 -  if( ambient_color.red == 1.0f && ambient_color.green == 1.0f
56 -      && ambient_color.blue  == 1.0f ) {
57 -    *color = Color( 1.0f, 1.0f, 1.0f);
58 -    return;
59 -  }
60 +  if(config->use_opengl) {
61 +    if( ambient_color.red == 1.0f && ambient_color.green == 1.0f
62 +        && ambient_color.blue  == 1.0f ) {
63 +      *color = Color( 1.0f, 1.0f, 1.0f);
64 +      return;
65 +    }
66  
67 -  DrawingRequest* request = new(obst) DrawingRequest();
68 -  request->type = GETLIGHT;
69 -  request->pos = transform.apply(position);
70 +    DrawingRequest* request = new(obst) DrawingRequest();
71 +    request->type = GETLIGHT;
72 +    request->pos = transform.apply(position);
73  
74 -  //There is no light offscreen.
75 -  if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
76 -      || request->pos.x < 0 || request->pos.y < 0){
77 -    *color = Color( 0, 0, 0);
78 -    return;
79 +    //There is no light offscreen.
80 +    if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
81 +        || request->pos.x < 0 || request->pos.y < 0){
82 +      *color = Color( 0, 0, 0);
83 +      return;
84 +    }
85 +
86 +    request->layer = LAYER_GUI; //make sure all get_light requests are handled last.
87 +    GetLightRequest* getlightrequest = new(obst) GetLightRequest();
88 +    getlightrequest->color_ptr = color;
89 +    request->request_data = getlightrequest;
90 +    lightmap_requests.push_back(request);
91 +  } else {
92 +    static int i = 0;
93 +    i += 1; i &= 0xFFFF;
94 +    if (i & 0x8000) {
95 +      *color = Color(0.0f, 0.0f, 0.0f);
96 +    } else {
97 +      *color = Color(1.0f, 1.0f, 1.0f);
98 +    }
99    }
100 -
101 -  request->layer = LAYER_GUI; //make sure all get_light requests are handled last.
102 -  GetLightRequest* getlightrequest = new(obst) GetLightRequest();
103 -  getlightrequest->color_ptr = color;
104 -  request->request_data = getlightrequest;
105 -  lightmap_requests.push_back(request);
106  }
107  
108  void
109 @@ -370,16 +380,47 @@
110    const Color& top = gradientrequest->top;
111    const Color& bottom = gradientrequest->bottom;
112  
113 -  glDisable(GL_TEXTURE_2D);
114 -  glBegin(GL_QUADS);
115 -  glColor4f(top.red, top.green, top.blue, top.alpha);
116 -  glVertex2f(0, 0);
117 -  glVertex2f(SCREEN_WIDTH, 0);
118 -  glColor4f(bottom.red, bottom.green, bottom.blue, bottom.alpha);
119 -  glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
120 -  glVertex2f(0, SCREEN_HEIGHT);
121 -  glEnd();
122 -  glEnable(GL_TEXTURE_2D);
123 +  if(config->use_opengl)
124 +  {
125 +    glDisable(GL_TEXTURE_2D);
126 +    glBegin(GL_QUADS);
127 +    glColor4f(top.red, top.green, top.blue, top.alpha);
128 +    glVertex2f(0, 0);
129 +    glVertex2f(SCREEN_WIDTH, 0);
130 +    glColor4f(bottom.red, bottom.green, bottom.blue, bottom.alpha);
131 +    glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
132 +    glVertex2f(0, SCREEN_HEIGHT);
133 +    glEnd();
134 +    glEnable(GL_TEXTURE_2D);
135 +  }
136 +  else
137 +  {
138 +    for(int y = 0;y < screen->h;++y)
139 +    {
140 +      Uint8 r = (Uint8)((((float)(top.red-bottom.red)/(0-screen->h)) * y + top.red) * 255);
141 +      Uint8 g = (Uint8)((((float)(top.green-bottom.green)/(0-screen->h)) * y + top.green) * 255);
142 +      Uint8 b = (Uint8)((((float)(top.blue-bottom.blue)/(0-screen->h)) * y + top.blue) * 255);
143 +      Uint8 a = (Uint8)((((float)(top.alpha-bottom.alpha)/(0-screen->h)) * y + top.alpha) * 255);
144 +      Uint32 color = SDL_MapRGB(screen->format, r, g, b);
145 +
146 +      SDL_Rect rect;
147 +      rect.x = 0;
148 +      rect.y = y;
149 +      rect.w = screen->w;
150 +      rect.h = 1;
151 +
152 +      if(a == SDL_ALPHA_OPAQUE) {
153 +        SDL_FillRect(screen, &rect, color);
154 +      } else if(a != SDL_ALPHA_TRANSPARENT) {
155 +        SDL_Surface *temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
156 +
157 +        SDL_FillRect(temp, 0, color);
158 +        SDL_SetAlpha(temp, SDL_SRCALPHA, a);
159 +        SDL_BlitSurface(temp, 0, screen, &rect);
160 +        SDL_FreeSurface(temp);
161 +      }
162 +    }
163 +  }
164    glColor4f(1, 1, 1, 1);
165  }
166  
167 @@ -398,22 +439,48 @@
168    const FillRectRequest* fillrectrequest
169      = (FillRectRequest*) request.request_data;
170  
171 -  float x = request.pos.x;
172 -  float y = request.pos.y;
173 -  float w = fillrectrequest->size.x;
174 -  float h = fillrectrequest->size.y;
175 +  if(config->use_opengl)
176 +  {
177 +    float x = request.pos.x;
178 +    float y = request.pos.y;
179 +    float w = fillrectrequest->size.x;
180 +    float h = fillrectrequest->size.y;
181  
182 -  glDisable(GL_TEXTURE_2D);
183 -  glColor4f(fillrectrequest->color.red, fillrectrequest->color.green,
184 -            fillrectrequest->color.blue, fillrectrequest->color.alpha);
185 +    glDisable(GL_TEXTURE_2D);
186 +    glColor4f(fillrectrequest->color.red, fillrectrequest->color.green,
187 +              fillrectrequest->color.blue, fillrectrequest->color.alpha);
188  
189 -  glBegin(GL_QUADS);
190 -  glVertex2f(x, y);
191 -  glVertex2f(x+w, y);
192 -  glVertex2f(x+w, y+h);
193 -  glVertex2f(x, y+h);
194 -  glEnd();
195 -  glEnable(GL_TEXTURE_2D);
196 +    glBegin(GL_QUADS);
197 +    glVertex2f(x, y);
198 +    glVertex2f(x+w, y);
199 +    glVertex2f(x+w, y+h);
200 +    glVertex2f(x, y+h);
201 +    glEnd();
202 +    glEnable(GL_TEXTURE_2D);
203 +  }
204 +  else
205 +  {
206 +    SDL_Rect rect;
207 +    rect.x = (Sint16)request.pos.x;
208 +    rect.y = (Sint16)request.pos.y;
209 +    rect.w = (Uint16)fillrectrequest->size.x;
210 +    rect.h = (Uint16)fillrectrequest->size.y;
211 +    Uint8 r = static_cast<Uint8>(fillrectrequest->color.red * 255);
212 +    Uint8 g = static_cast<Uint8>(fillrectrequest->color.green * 255);
213 +    Uint8 b = static_cast<Uint8>(fillrectrequest->color.blue * 255);
214 +    Uint8 a = static_cast<Uint8>(fillrectrequest->color.alpha * 255);
215 +    Uint32 color = SDL_MapRGB(screen->format, r, g, b);
216 +    if(a == SDL_ALPHA_OPAQUE) {
217 +      SDL_FillRect(screen, &rect, color);
218 +    } else if(a != SDL_ALPHA_TRANSPARENT) {
219 +      SDL_Surface *temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
220 +
221 +      SDL_FillRect(temp, 0, color);
222 +      SDL_SetAlpha(temp, SDL_SRCALPHA, a);
223 +      SDL_BlitSurface(temp, 0, screen, &rect);
224 +      SDL_FreeSurface(temp);
225 +    }
226 +  }
227    
228    glColor4f(1, 1, 1, 1);
229  }
230 @@ -462,29 +529,36 @@
231  
232    // PART1: create lightmap
233    if(use_lightmap) {
234 -    glViewport(0, screen->h - lightmap_height, lightmap_width, lightmap_height);
235 -    glMatrixMode(GL_PROJECTION);
236 -    glLoadIdentity();
237 -    glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
238 -    glMatrixMode(GL_MODELVIEW);
239 -    glLoadIdentity();
240 +    if(config->use_opengl)
241 +    {
242 +      glViewport(0, screen->h - lightmap_height, lightmap_width, lightmap_height);
243 +      glMatrixMode(GL_PROJECTION);
244 +      glLoadIdentity();
245 +      glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
246 +      glMatrixMode(GL_MODELVIEW);
247 +      glLoadIdentity();
248  
249 -    glClearColor( ambient_color.red, ambient_color.green, ambient_color.blue, 1 );
250 -    glClear(GL_COLOR_BUFFER_BIT);
251 -    handle_drawing_requests(lightmap_requests);
252 -    lightmap_requests.clear();
253 +      glClearColor( ambient_color.red, ambient_color.green, ambient_color.blue, 1 );
254 +      glClear(GL_COLOR_BUFFER_BIT);
255 +      handle_drawing_requests(lightmap_requests);
256 +      lightmap_requests.clear();
257  
258 -    glDisable(GL_BLEND);
259 -    glBindTexture(GL_TEXTURE_2D, lightmap->get_handle());
260 -    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, screen->h - lightmap_height, lightmap_width, lightmap_height);
261 +      glDisable(GL_BLEND);
262 +      glBindTexture(GL_TEXTURE_2D, lightmap->get_handle());
263 +      glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, screen->h - lightmap_height, lightmap_width, lightmap_height);
264  
265 -    glViewport(0, 0, screen->w, screen->h);
266 -    glMatrixMode(GL_PROJECTION);
267 -    glLoadIdentity();
268 -    glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
269 -    glMatrixMode(GL_MODELVIEW);
270 -    glLoadIdentity();
271 -    glEnable(GL_BLEND);
272 +      glViewport(0, 0, screen->w, screen->h);
273 +      glMatrixMode(GL_PROJECTION);
274 +      glLoadIdentity();
275 +      glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
276 +      glMatrixMode(GL_MODELVIEW);
277 +      glLoadIdentity();
278 +      glEnable(GL_BLEND);
279 +    }
280 +    else
281 +    {
282 +      // FIXME: SDL alternative
283 +    }
284  
285      // add a lightmap drawing request into the queue
286      DrawingRequest* request = new(obst) DrawingRequest();
287 @@ -499,7 +573,10 @@
288    drawing_requests.clear();
289    obstack_free(&obst, NULL);
290    obstack_init(&obst);
291 -  assert_gl("drawing");
292 +  if(config->use_opengl)
293 +  {
294 +    assert_gl("drawing");
295 +  }
296  
297    // if a screenshot was requested, take one
298    if (screenshot_requested) {
299 @@ -507,7 +584,14 @@
300      screenshot_requested = false;
301    }
302  
303 -  SDL_GL_SwapBuffers();
304 +  if(config->use_opengl)
305 +  {
306 +    SDL_GL_SwapBuffers();
307 +  }
308 +  else
309 +  {
310 +    SDL_Flip(screen);
311 +  }
312  }
313  
314  class RequestPtrCompare
315 @@ -644,36 +728,42 @@
316  {
317    // [Christoph] TODO: Yes, this method also takes care of the actual disk I/O. Split it?
318  
319 -  // create surface to hold screenshot
320 -  #if SDL_BYTEORDER == SDL_BIG_ENDIAN
321 -  SDL_Surface* shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x00FF0000, 0x0000FF00, 0x000000FF, 0);
322 -  #else
323 -  SDL_Surface* shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0);
324 -  #endif
325 -  if (!shot_surf) {
326 -    log_warning << "Could not create RGB Surface to contain screenshot" << std::endl;
327 -    return;
328 -  }
329 +  SDL_Surface *shot_surf;
330 +  if(config->use_opengl) {
331 +    // create surface to hold screenshot
332 +    #if SDL_BYTEORDER == SDL_BIG_ENDIAN
333 +    shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x00FF0000, 0x0000FF00, 0x000000FF, 0);
334 +    #else
335 +    shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0);
336 +    #endif
337 +    if (!shot_surf) {
338 +      log_warning << "Could not create RGB Surface to contain screenshot" << std::endl;
339 +      return;
340 +    }
341  
342 -  // read pixels into array
343 -  char* pixels = new char[3 * SCREEN_WIDTH * SCREEN_HEIGHT];
344 -  if (!pixels) {
345 -    log_warning << "Could not allocate memory to store screenshot" << std::endl;
346 -    SDL_FreeSurface(shot_surf);
347 -    return;
348 -  }
349 -  glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels);
350 +    // read pixels into array
351 +    char* pixels = new char[3 * SCREEN_WIDTH * SCREEN_HEIGHT];
352 +    if (!pixels) {
353 +      log_warning << "Could not allocate memory to store screenshot" << std::endl;
354 +      SDL_FreeSurface(shot_surf);
355 +      return;
356 +    }
357 +    glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels);
358  
359 -  // copy array line-by-line
360 -  for (int i = 0; i < SCREEN_HEIGHT; i++) {
361 -    char* src = pixels + (3 * SCREEN_WIDTH * (SCREEN_HEIGHT - i - 1));
362 -    char* dst = ((char*)shot_surf->pixels) + i * shot_surf->pitch;
363 -    memcpy(dst, src, 3 * SCREEN_WIDTH);
364 +    // copy array line-by-line
365 +    for (int i = 0; i < SCREEN_HEIGHT; i++) {
366 +      char* src = pixels + (3 * SCREEN_WIDTH * (SCREEN_HEIGHT - i - 1));
367 +      char* dst = ((char*)shot_surf->pixels) + i * shot_surf->pitch;
368 +      memcpy(dst, src, 3 * SCREEN_WIDTH);
369 +    }
370 +
371 +    // free array
372 +    delete[](pixels);
373 +  } else {
374 +    shot_surf = SDL_GetVideoSurface();
375 +    shot_surf->refcount++;
376    }
377  
378 -  // free array
379 -  delete[](pixels);
380 -
381    // save screenshot
382    static const std::string writeDir = PHYSFS_getWriteDir();
383    static const std::string dirSep = PHYSFS_getDirSeparator();
384 Index: src/video/texture.cpp
385 ===================================================================
386 --- src/video/texture.cpp       (revision 5067)
387 +++ src/video/texture.cpp       (working copy)
388 @@ -20,6 +20,7 @@
389  #include <config.h>
390  
391  #include "texture.hpp"
392 +#include "gameconfig.hpp"
393  
394  #include <GL/gl.h>
395  #include <assert.h>
396 @@ -34,24 +35,32 @@
397  {
398    assert(is_power_of_2(w));
399    assert(is_power_of_2(h));
400 +  use_opengl = config->use_opengl;
401  
402 -  this->width = w;
403 -  this->height = h;
404 +  if(use_opengl)
405 +  {
406 +    surface.opengl.width = w;
407 +    surface.opengl.height = h;
408  
409 -  assert_gl("before creating texture");
410 -  glGenTextures(1, &handle);
411 +    assert_gl("before creating texture");
412 +    glGenTextures(1, &surface.opengl.handle);
413  
414 -  try {
415 -    glBindTexture(GL_TEXTURE_2D, handle);
416 +    try {
417 +      glBindTexture(GL_TEXTURE_2D, surface.opengl.handle);
418  
419 -    glTexImage2D(GL_TEXTURE_2D, 0, glformat, width, height, 0, GL_RGBA,
420 -                 GL_UNSIGNED_BYTE, 0);
421 +      glTexImage2D(GL_TEXTURE_2D, 0, glformat, surface.opengl.width,
422 +                   surface.opengl.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
423  
424 -    set_texture_params();
425 -  } catch(...) {
426 -    glDeleteTextures(1, &handle);
427 -    throw;
428 +      set_texture_params();
429 +    } catch(...) {
430 +      glDeleteTextures(1, &surface.opengl.handle);
431 +      throw;
432 +    }
433    }
434 +  else
435 +  {
436 +    surface.sdl = 0;
437 +  }
438  }
439  
440  Texture::Texture(SDL_Surface* image, GLenum glformat)
441 @@ -61,49 +70,62 @@
442      throw std::runtime_error("image has no power of 2 size");
443    if(format->BitsPerPixel != 24 && format->BitsPerPixel != 32)
444      throw std::runtime_error("image has no 24 or 32 bit color depth");
445 +  use_opengl = config->use_opengl;
446  
447 -  this->width = image->w;
448 -  this->height = image->h;
449 +  if(use_opengl)
450 +  {
451 +    surface.opengl.width = image->w;
452 +    surface.opengl.height = image->h;
453  
454 -  assert_gl("before creating texture");
455 -  glGenTextures(1, &handle);
456 +    assert_gl("before creating texture");
457 +    glGenTextures(1, &surface.opengl.handle);
458  
459 -  try {
460 -    GLenum sdl_format;
461 -    if(format->BytesPerPixel == 3)
462 -      sdl_format = GL_RGB;
463 -    else if(format->BytesPerPixel == 4)
464 -      sdl_format = GL_RGBA;
465 -    else
466 -      assert(false);
467 +    try {
468 +      GLenum sdl_format;
469 +      if(format->BytesPerPixel == 3)
470 +        sdl_format = GL_RGB;
471 +      else if(format->BytesPerPixel == 4)
472 +        sdl_format = GL_RGBA;
473 +      else
474 +        assert(false);
475  
476 -    glBindTexture(GL_TEXTURE_2D, handle);
477 -    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
478 -    glPixelStorei(GL_UNPACK_ROW_LENGTH, image->pitch/format->BytesPerPixel);
479 -    glTexImage2D(GL_TEXTURE_2D, 0, glformat, width, height, 0, sdl_format,
480 -            GL_UNSIGNED_BYTE, image->pixels);
481 +      glBindTexture(GL_TEXTURE_2D, surface.opengl.handle);
482 +      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
483 +      glPixelStorei(GL_UNPACK_ROW_LENGTH, image->pitch/format->BytesPerPixel);
484 +      glTexImage2D(GL_TEXTURE_2D, 0, glformat, surface.opengl.width,
485 +              surface.opengl.height, 0, sdl_format,
486 +              GL_UNSIGNED_BYTE, image->pixels);
487  
488 -    assert_gl("creating texture");
489 +      assert_gl("creating texture");
490  
491 -    set_texture_params();
492 -  } catch(...) {
493 -    glDeleteTextures(1, &handle);
494 -    throw;
495 +      set_texture_params();
496 +    } catch(...) {
497 +      glDeleteTextures(1, &surface.opengl.handle);
498 +      throw;
499 +    }
500 +  } else {
501 +    surface.sdl = SDL_DisplayFormatAlpha(image);
502    }
503  }
504  
505  Texture::~Texture()
506  {
507 -  glDeleteTextures(1, &handle);
508 +  if(use_opengl) {
509 +    glDeleteTextures(1, &surface.opengl.handle);
510 +  } else {
511 +    SDL_FreeSurface(surface.sdl);
512 +  }
513  }
514  
515  void
516  Texture::set_texture_params()
517  {
518 -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
519 -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
520 -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
521 -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
522 +  if(use_opengl) {
523 +    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
524 +    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
525 +    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
526 +    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
527  
528 -  assert_gl("set texture params");
529 +    assert_gl("set texture params");
530 +  }
531  }
532 Index: src/video/texture.hpp
533 ===================================================================
534 --- src/video/texture.hpp       (revision 5067)
535 +++ src/video/texture.hpp       (working copy)
536 @@ -20,9 +20,13 @@
537  #ifndef __TEXTURE_HPP__
538  #define __TEXTURE_HPP__
539  
540 +#include <assert.h>
541 +
542  #include <SDL.h>
543  #include <GL/gl.h>
544  
545 +#include "gameconfig.hpp"
546 +
547  /**
548   * This class is a wrapper around a texture handle. It stores the texture width
549   * and height and provides convenience functions for uploading SDL_Surfaces
550 @@ -31,29 +35,57 @@
551  class Texture
552  {
553  protected:
554 -  friend class TextureManager;
555 -  GLuint handle;
556 -  unsigned int width;
557 -  unsigned int height;
558 +  bool use_opengl;
559 +  union {
560 +    struct {
561 +      GLuint handle;
562 +      unsigned int width;
563 +      unsigned int height;
564 +    } opengl;
565 +    SDL_Surface *sdl;
566 +  } surface;
567  
568  public:
569    Texture(unsigned int width, unsigned int height, GLenum glformat);
570 -  Texture(SDL_Surface* surface, GLenum glformat);
571 +  Texture(SDL_Surface* sdlsurface, GLenum glformat);
572    virtual ~Texture();
573  
574 -  GLuint get_handle() const
575 -  {
576 -    return handle;
577 +  const GLuint &get_handle() const {
578 +    assert(use_opengl);
579 +    return surface.opengl.handle;
580    }
581  
582 +  void set_handle(GLuint handle) {
583 +    assert(use_opengl);
584 +    surface.opengl.handle = handle;
585 +  }
586 +
587 +  SDL_Surface *get_surface() const {
588 +    assert(!use_opengl);
589 +    return surface.sdl;
590 +  }
591 +
592 +  void set_surface(SDL_Surface *sdlsurface) {
593 +    assert(!use_opengl);
594 +    surface.sdl = sdlsurface;
595 +  }
596 +
597    unsigned int get_width() const
598    {
599 -    return width;
600 +    if(use_opengl) {
601 +      return surface.opengl.width;
602 +    } else {
603 +      return surface.sdl->w;
604 +    }
605    }
606  
607    unsigned int get_height() const
608    {
609 -    return height;
610 +    if(use_opengl) {
611 +      return surface.opengl.height;
612 +    } else {
613 +      return surface.sdl->h;
614 +    }
615    }
616  
617  private:
618 Index: src/video/surface.cpp
619 ===================================================================
620 --- src/video/surface.cpp       (revision 5067)
621 +++ src/video/surface.cpp       (working copy)
622 @@ -41,13 +41,27 @@
623  {
624    texture = texture_manager->get(file);
625    texture->ref();
626 -  uv_left = 0;
627 -  uv_top = 0;
628 -  uv_right = texture->get_uv_right();
629 -  uv_bottom = texture->get_uv_bottom();
630  
631 -  width = texture->get_image_width();
632 -  height = texture->get_image_height();
633 +  use_opengl = config->use_opengl;
634 +
635 +  if(use_opengl) {
636 +    surface.opengl.uv_left = 0;
637 +    surface.opengl.uv_top = 0;
638 +    surface.opengl.uv_right = texture->get_uv_right();
639 +    surface.opengl.uv_bottom = texture->get_uv_bottom();
640 +
641 +    surface.opengl.width = texture->get_image_width();
642 +    surface.opengl.height = texture->get_image_height();
643 +  } else {
644 +    memset(transforms, 0, NUM_EFFECTS * sizeof(SDL_Surface *));
645 +
646 +    surface.sdl.offsetx = 0;
647 +    surface.sdl.offsety = 0;
648 +    surface.sdl.width = static_cast<int>(texture->get_image_width());
649 +    surface.sdl.height = static_cast<int>(texture->get_image_height());
650 +
651 +    surface.sdl.flipx = false;
652 +  }
653  }
654  
655  Surface::Surface(const std::string& file, int x, int y, int w, int h)
656 @@ -55,15 +69,28 @@
657    texture = texture_manager->get(file);
658    texture->ref();
659  
660 -  float tex_w = static_cast<float> (texture->get_width());
661 -  float tex_h = static_cast<float> (texture->get_height());
662 -  uv_left = static_cast<float>(x) / tex_w;
663 -  uv_top = static_cast<float>(y) / tex_h;
664 -  uv_right = static_cast<float>(x+w) / tex_w;
665 -  uv_bottom = static_cast<float>(y+h) / tex_h;
666 +  use_opengl = config->use_opengl;
667  
668 -  width = w;
669 -  height = h;
670 +  if(use_opengl) {
671 +    float tex_w = static_cast<float> (texture->get_width());
672 +    float tex_h = static_cast<float> (texture->get_height());
673 +    surface.opengl.uv_left = static_cast<float>(x) / tex_w;
674 +    surface.opengl.uv_top = static_cast<float>(y) / tex_h;
675 +    surface.opengl.uv_right = static_cast<float>(x+w) / tex_w;
676 +    surface.opengl.uv_bottom = static_cast<float>(y+h) / tex_h;
677 +
678 +    surface.opengl.width = w;
679 +    surface.opengl.height = h;
680 +  } else {
681 +    memset(transforms, 0, NUM_EFFECTS * sizeof(SDL_Surface *));
682 +
683 +    surface.sdl.offsetx = x;
684 +    surface.sdl.offsety = y;
685 +    surface.sdl.width = w;
686 +    surface.sdl.height = h;
687 +
688 +    surface.sdl.flipx = false;
689 +  }
690  }
691  
692  Surface::Surface(const Surface& other)
693 @@ -71,12 +98,25 @@
694    texture = other.texture;
695    texture->ref();
696  
697 -  uv_left = other.uv_left;
698 -  uv_top = other.uv_top;
699 -  uv_right = other.uv_right;
700 -  uv_bottom = other.uv_bottom;
701 -  width = other.width;
702 -  height = other.height;
703 +  use_opengl = config->use_opengl;
704 +
705 +  if(use_opengl) {
706 +    surface.opengl.uv_left = other.surface.opengl.uv_left;
707 +    surface.opengl.uv_top = other.surface.opengl.uv_top;
708 +    surface.opengl.uv_right = other.surface.opengl.uv_right;
709 +    surface.opengl.uv_bottom = other.surface.opengl.uv_bottom;
710 +    surface.opengl.width = other.surface.opengl.width;
711 +    surface.opengl.height = other.surface.opengl.height;
712 +  } else {
713 +    memset(transforms, 0, NUM_EFFECTS * sizeof(SDL_Surface *));
714 +
715 +    surface.sdl.offsetx = other.surface.sdl.offsetx;
716 +    surface.sdl.offsety = other.surface.sdl.offsety;
717 +    surface.sdl.width = other.surface.sdl.width;
718 +    surface.sdl.height = other.surface.sdl.height;
719 +
720 +    surface.sdl.flipx = other.surface.sdl.flipx;
721 +  }
722  }
723  
724  const Surface&
725 @@ -86,25 +126,46 @@
726    texture->unref();
727    texture = other.texture;
728  
729 -  uv_left = other.uv_left;
730 -  uv_top = other.uv_top;
731 -  uv_right = other.uv_right;
732 -  uv_bottom = other.uv_bottom;
733 -  width = other.width;
734 -  height = other.height;
735 +  use_opengl = config->use_opengl;
736  
737 +  if(use_opengl) {
738 +    surface.opengl.uv_left = other.surface.opengl.uv_left;
739 +    surface.opengl.uv_top = other.surface.opengl.uv_top;
740 +    surface.opengl.uv_right = other.surface.opengl.uv_right;
741 +    surface.opengl.uv_bottom = other.surface.opengl.uv_bottom;
742 +    surface.opengl.width = other.surface.opengl.width;
743 +    surface.opengl.height = other.surface.opengl.height;
744 +  } else {
745 +    memset(transforms, 0, NUM_EFFECTS * sizeof(SDL_Surface *));
746 +
747 +    surface.sdl.offsetx = other.surface.sdl.offsetx;
748 +    surface.sdl.offsety = other.surface.sdl.offsety;
749 +    surface.sdl.width = other.surface.sdl.width;
750 +    surface.sdl.height = other.surface.sdl.height;
751 +
752 +    surface.sdl.flipx = other.surface.sdl.flipx;
753 +  }
754 +
755    return *this;
756  }
757  
758  Surface::~Surface()
759  {
760    texture->unref();
761 +
762 +  if(!use_opengl) {
763 +    std::for_each(transforms, transforms + NUM_EFFECTS, SDL_FreeSurface);
764 +  }
765  }
766  
767  void
768  Surface::hflip()
769  {
770 -  std::swap(uv_left, uv_right);
771 +  if(use_opengl) {
772 +    std::swap(surface.opengl.uv_left, surface.opengl.uv_right);
773 +  } else {
774 +    surface.sdl.flipx = !surface.sdl.flipx;
775 +  }
776  }
777  
778  static inline void intern_draw(float left, float top, float right, float bottom,                               float uv_left, float uv_top,
779 @@ -186,28 +247,99 @@
780  void
781  Surface::draw(float x, float y, float alpha, float angle, const Color& color, const Blend& blend, DrawingEffect effect) const
782  {
783 -  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
784 -
785 -  intern_draw2(x, y,
786 -               x + width, y + height,
787 -               uv_left, uv_top, uv_right, uv_bottom,
788 -               angle,
789 -               alpha,
790 -               color,
791 -               blend,
792 -               effect);
793 +  if(use_opengl) {
794 +    glBindTexture(GL_TEXTURE_2D, texture->get_handle());
795 +    intern_draw2(x, y,
796 +                 x + surface.opengl.width, y + surface.opengl.height,
797 +                 surface.opengl.uv_left, surface.opengl.uv_top,
798 +                 surface.opengl.uv_right, surface.opengl.uv_bottom,
799 +                 angle,
800 +                 alpha,
801 +                 color,
802 +                 blend,
803 +                 effect);
804 +  } else {
805 +    draw_part(0, 0, x, y, surface.sdl.width, surface.sdl.height, alpha, effect);
806 +  }
807  }
808  
809  void
810  Surface::draw(float x, float y, float alpha, DrawingEffect effect) const
811  {
812 -  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
813 +  if(use_opengl) {
814 +    glBindTexture(GL_TEXTURE_2D, texture->get_handle());
815 +    glColor4f(1, 1, 1, alpha);
816 +    intern_draw(x, y,
817 +                x + surface.opengl.width, y + surface.opengl.height,
818 +                surface.opengl.uv_left, surface.opengl.uv_top,
819 +                surface.opengl.uv_right, surface.opengl.uv_bottom, effect);
820 +    glColor4f(1, 1, 1, 1);
821 +  } else {
822 +    draw_part(0, 0, x, y, surface.sdl.width, surface.sdl.height, alpha, effect);
823 +  }
824 +}
825  
826 -  glColor4f(1, 1, 1, alpha);
827 -  intern_draw(x, y,
828 -              x + width, y + height,
829 -              uv_left, uv_top, uv_right, uv_bottom, effect);
830 -  glColor4f(1, 1, 1, 1);
831 +namespace
832 +{
833 +  SDL_Surface *horz_flip(SDL_Surface *src)
834 +  {
835 +    SDL_Surface *dst = SDL_ConvertSurface(src, src->format, src->flags);
836 +    int bpp = dst->format->BytesPerPixel;
837 +    for(int y = 0;y < dst->h;y++) {
838 +      Uint8 *line = (Uint8 *) dst->pixels + y * dst->pitch;
839 +      for(int x = 0;x < (dst->w / 2);x++) {
840 +        switch(bpp) {
841 +          case 4:
842 +            line[3 + x * bpp] ^= line[3 + (dst->w - x - 1) * bpp];
843 +            line[3 + (dst->w - x - 1) * bpp] ^= line[3 + x * bpp];
844 +            line[3 + x * bpp] ^= line[3 + (dst->w - x - 1) * bpp];
845 +          case 3:
846 +            line[2 + x * bpp] ^= line[2 + (dst->w - x - 1) * bpp];
847 +            line[2 + (dst->w - x - 1) * bpp] ^= line[2 + x * bpp];
848 +            line[2 + x * bpp] ^= line[2 + (dst->w - x - 1) * bpp];
849 +          case 2:
850 +            line[1 + x * bpp] ^= line[1 + (dst->w - x - 1) * bpp];
851 +            line[1 + (dst->w - x - 1) * bpp] ^= line[1 + x * bpp];
852 +            line[1 + x * bpp] ^= line[1 + (dst->w - x - 1) * bpp];
853 +          case 1:
854 +            line[0 + x * bpp] ^= line[0 + (dst->w - x - 1) * bpp];
855 +            line[0 + (dst->w - x - 1) * bpp] ^= line[0 + x * bpp];
856 +            line[0 + x * bpp] ^= line[0 + (dst->w - x - 1) * bpp];
857 +        }
858 +      }
859 +    }
860 +    return dst;
861 +  }
862 +
863 +  SDL_Surface *vert_flip(SDL_Surface *src)
864 +  {
865 +    SDL_Surface *dst = SDL_ConvertSurface(src, src->format, src->flags);
866 +    int bpp = dst->format->BytesPerPixel;
867 +    for(int x = 0;x < dst->w;x++) {
868 +      Uint8 *rank = (Uint8 *) dst->pixels + x * bpp;
869 +      for(int y = 0;y < (dst->h / 2);y++) {
870 +        switch(bpp) {
871 +          case 4:
872 +            rank[3 + y * dst->pitch] ^= rank[3 + (dst->h - y - 1) * dst->pitch];
873 +            rank[3 + (dst->h - y - 1) * dst->pitch] ^= rank[3 + y * dst->pitch];
874 +            rank[3 + y * dst->pitch] ^= rank[3 + (dst->h - y - 1) * dst->pitch];
875 +          case 3:
876 +            rank[2 + y * dst->pitch] ^= rank[2 + (dst->h - y - 1) * dst->pitch];
877 +            rank[2 + (dst->h - y - 1) * dst->pitch] ^= rank[2 + y * dst->pitch];
878 +            rank[2 + y * dst->pitch] ^= rank[2 + (dst->h - y - 1) * dst->pitch];
879 +          case 2:
880 +            rank[1 + y * dst->pitch] ^= rank[1 + (dst->h - y - 1) * dst->pitch];
881 +            rank[1 + (dst->h - y - 1) * dst->pitch] ^= rank[1 + y * dst->pitch];
882 +            rank[1 + y * dst->pitch] ^= rank[1 + (dst->h - y - 1) * dst->pitch];
883 +          case 1:
884 +            rank[0 + y * dst->pitch] ^= rank[0 + (dst->h - y - 1) * dst->pitch];
885 +            rank[0 + (dst->h - y - 1) * dst->pitch] ^= rank[0 + y * dst->pitch];
886 +            rank[0 + y * dst->pitch] ^= rank[0 + (dst->h - y - 1) * dst->pitch];
887 +        }
888 +      }
889 +    }
890 +    return dst;
891 +  }
892  }
893  
894  void
895 @@ -215,19 +347,65 @@
896                     float width, float height, float alpha,
897                     DrawingEffect effect) const
898  {
899 -  float uv_width = uv_right - uv_left;
900 -  float uv_height = uv_bottom - uv_top;
901 +  if(use_opengl) {
902 +    float uv_width = surface.opengl.uv_right - surface.opengl.uv_left;
903 +    float uv_height = surface.opengl.uv_bottom - surface.opengl.uv_top;
904  
905 -  float uv_left = this->uv_left + (uv_width * src_x) / this->width;
906 -  float uv_top = this->uv_top + (uv_height * src_y) / this->height;
907 -  float uv_right = this->uv_left + (uv_width * (src_x + width)) / this->width;
908 -  float uv_bottom = this->uv_top + (uv_height * (src_y + height)) / this->height;
909 +    float uv_left = surface.opengl.uv_left + (uv_width * src_x) / surface.opengl.width;
910 +    float uv_top = surface.opengl.uv_top + (uv_height * src_y) / surface.opengl.height;
911 +    float uv_right = surface.opengl.uv_left + (uv_width * (src_x + width)) / surface.opengl.width;
912 +    float uv_bottom = surface.opengl.uv_top + (uv_height * (src_y + height)) / surface.opengl.height;
913  
914 -  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
915 +    glBindTexture(GL_TEXTURE_2D, texture->get_handle());
916 +    glColor4f(1, 1, 1, alpha);
917 +    intern_draw(dst_x, dst_y,
918 +                dst_x + width, dst_y + height,
919 +                uv_left, uv_top, uv_right, uv_bottom, effect);
920 +    glColor4f(1, 1, 1, 1);
921 +  } else {
922 +    //FIXME: support parameter "alpha"
923
924 +    // get and check SDL_Surface
925 +    if (texture->get_surface() == 0) {
926 +      std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
927 +      return;
928 +    }  
929  
930 -  glColor4f(1, 1, 1, alpha);
931 -  intern_draw(dst_x, dst_y,
932 -              dst_x + width, dst_y + height,
933 -              uv_left, uv_top, uv_right, uv_bottom, effect);
934 -  glColor4f(1, 1, 1, 1);
935 +    if (surface.sdl.flipx) effect = HORIZONTAL_FLIP;
936 +
937 +    if(transforms[effect] == 0) {
938 +      switch(effect) {
939 +        case NO_EFFECT:
940 +          transforms[NO_EFFECT] = texture->get_surface();
941 +          transforms[NO_EFFECT]->refcount++;
942 +          break;
943 +        case HORIZONTAL_FLIP:
944 +          transforms[HORIZONTAL_FLIP] = horz_flip(texture->get_surface());
945 +          break;
946 +        case VERTICAL_FLIP:
947 +          transforms[VERTICAL_FLIP] = vert_flip(texture->get_surface());
948 +          break;
949 +        default:
950 +          std::cerr << "Warning: No known transformation applies to surface, skipped draw" << std::endl;
951 +          return;
952 +      }
953 +    }
954 +
955 +    int ox = surface.sdl.offsetx; if (effect == HORIZONTAL_FLIP) ox = static_cast<int>(transforms[effect]->w) - (ox+static_cast<int>(width));
956 +    int oy = surface.sdl.offsety; if (effect == VERTICAL_FLIP) oy = static_cast<int>(transforms[effect]->h) - (oy+static_cast<int>(height));
957 +    // draw surface to screen
958 +    SDL_Surface* screen = SDL_GetVideoSurface();
959 +
960 +    SDL_Rect srcRect;
961 +    srcRect.x = static_cast<int>(ox+src_x);
962 +    srcRect.y = static_cast<int>(oy+src_y);
963 +    srcRect.w = static_cast<int>(width);
964 +    srcRect.h = static_cast<int>(height);
965 +
966 +    SDL_Rect dstRect;
967 +    dstRect.x = static_cast<int>(dst_x);
968 +    dstRect.y = static_cast<int>(dst_y);
969 +
970 +    SDL_BlitSurface(transforms[effect], &srcRect, screen, &dstRect);
971 +  }
972  }
973 Index: src/video/texture_manager.cpp
974 ===================================================================
975 --- src/video/texture_manager.cpp       (revision 5067)
976 +++ src/video/texture_manager.cpp       (working copy)
977 @@ -32,6 +32,7 @@
978  #include "physfs/physfs_sdl.hpp"
979  #include "image_texture.hpp"
980  #include "glutil.hpp"
981 +#include "gameconfig.hpp"
982  #include "file_system.hpp"
983  #include "log.hpp"
984  
985 @@ -149,12 +150,14 @@
986  void
987  TextureManager::save_textures()
988  {
989 -  glPixelStorei(GL_PACK_ROW_LENGTH, 0);
990 -  glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
991 -  glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
992 -  glPixelStorei(GL_PACK_SKIP_ROWS, 0);
993 -  glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
994 -  glPixelStorei(GL_PACK_ALIGNMENT, 1);
995 +  if(config->use_opengl) {
996 +    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
997 +    glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
998 +    glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
999 +    glPixelStorei(GL_PACK_SKIP_ROWS, 0);
1000 +    glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
1001 +    glPixelStorei(GL_PACK_ALIGNMENT, 1);
1002 +  }
1003    for(Textures::iterator i = textures.begin(); i != textures.end(); ++i) {
1004      save_texture(*i);
1005    }
1006 @@ -169,73 +172,81 @@
1007  {
1008    SavedTexture saved_texture;
1009    saved_texture.texture = texture;
1010 -  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
1011 -  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,
1012 -                           &saved_texture.width);
1013 -  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT,
1014 -                           &saved_texture.height);
1015 -  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER,
1016 -                           &saved_texture.border);
1017 -  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
1018 -                      &saved_texture.min_filter);
1019 -  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
1020 -                      &saved_texture.mag_filter);
1021 -  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
1022 -                      &saved_texture.wrap_s);
1023 -  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
1024 -                      &saved_texture.wrap_t);
1025 +  if(config->use_opengl) {
1026 +    glBindTexture(GL_TEXTURE_2D, texture->get_handle());
1027 +    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,
1028 +                             &saved_texture.width);
1029 +    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT,
1030 +                             &saved_texture.height);
1031 +    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER,
1032 +                             &saved_texture.border);
1033 +    glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
1034 +                        &saved_texture.min_filter);
1035 +    glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
1036 +                        &saved_texture.mag_filter);
1037 +    glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
1038 +                        &saved_texture.wrap_s);
1039 +    glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
1040 +                        &saved_texture.wrap_t);
1041 +  }
1042  
1043    size_t pixelssize = saved_texture.width * saved_texture.height * 4;
1044    saved_texture.pixels = new char[pixelssize];
1045  
1046 -  glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1047 -                saved_texture.pixels);
1048 +  if(config->use_opengl) {
1049 +    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1050 +                  saved_texture.pixels);
1051 +  }
1052  
1053    saved_textures.push_back(saved_texture);
1054  
1055 -  glDeleteTextures(1, &(texture->handle));
1056 -  texture->handle = 0;
1057 +  if(config->use_opengl) {
1058 +    glDeleteTextures(1, &(texture->get_handle()));
1059 +    texture->set_handle(0);
1060  
1061 -  assert_gl("retrieving texture for save");
1062 +    assert_gl("retrieving texture for save");
1063 +  }
1064  }
1065  
1066  void
1067  TextureManager::reload_textures()
1068  {
1069 -  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1070 -  glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
1071 -  glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
1072 -  glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
1073 -  glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
1074 -  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1075 +  if(config->use_opengl) {
1076 +    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1077 +    glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
1078 +    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
1079 +    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
1080 +    glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
1081 +    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1082  
1083 -  for(std::vector<SavedTexture>::iterator i = saved_textures.begin();
1084 -      i != saved_textures.end(); ++i) {
1085 -    SavedTexture& saved_texture = *i;
1086 +    for(std::vector<SavedTexture>::iterator i = saved_textures.begin();
1087 +        i != saved_textures.end(); ++i) {
1088 +      SavedTexture& saved_texture = *i;
1089  
1090 -    GLuint handle;
1091 -    glGenTextures(1, &handle);
1092 -    assert_gl("creating texture handle");
1093 +      GLuint handle;
1094 +      glGenTextures(1, &handle);
1095 +      assert_gl("creating texture handle");
1096  
1097 -    glBindTexture(GL_TEXTURE_2D, handle);
1098 -    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1099 -                 saved_texture.width, saved_texture.height,
1100 -                 saved_texture.border, GL_RGBA,
1101 -                 GL_UNSIGNED_BYTE, saved_texture.pixels);
1102 -    delete[] saved_texture.pixels;
1103 -    assert_gl("uploading texture pixel data");
1104 +      glBindTexture(GL_TEXTURE_2D, handle);
1105 +      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1106 +                   saved_texture.width, saved_texture.height,
1107 +                   saved_texture.border, GL_RGBA,
1108 +                   GL_UNSIGNED_BYTE, saved_texture.pixels);
1109 +      delete[] saved_texture.pixels;
1110 +      assert_gl("uploading texture pixel data");
1111  
1112 -    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
1113 -                    saved_texture.min_filter);
1114 -    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
1115 -                    saved_texture.mag_filter);
1116 -    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
1117 -                    saved_texture.wrap_s);
1118 -    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
1119 -                    saved_texture.wrap_t);
1120 +      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
1121 +                      saved_texture.min_filter);
1122 +      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
1123 +                      saved_texture.mag_filter);
1124 +      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
1125 +                      saved_texture.wrap_s);
1126 +      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
1127 +                      saved_texture.wrap_t);
1128  
1129 -    assert_gl("setting texture_params");
1130 -    saved_texture.texture->handle = handle;
1131 +      assert_gl("setting texture_params");
1132 +      saved_texture.texture->set_handle(handle);
1133 +    }
1134    }
1135  
1136    saved_textures.clear();
1137 Index: src/video/surface.hpp
1138 ===================================================================
1139 --- src/video/surface.hpp       (revision 5067)
1140 +++ src/video/surface.hpp       (working copy)
1141 @@ -21,6 +21,8 @@
1142  #define __SURFACE_HPP__
1143  
1144  #include <string>
1145 +#include <SDL.h>
1146 +#include "gameconfig.hpp"
1147  #include "math/vector.hpp"
1148  
1149  class Color;
1150 @@ -30,11 +32,12 @@
1151  /// bitset for drawing effects
1152  enum DrawingEffect {
1153    /** Don't apply anything */
1154 -  NO_EFFECT       = 0x0000,
1155 +  NO_EFFECT,
1156    /** Draw the Surface upside down */
1157 -  VERTICAL_FLIP     = 0x0001,
1158 +  VERTICAL_FLIP,
1159    /** Draw the Surface from left to down */
1160 -  HORIZONTAL_FLIP   = 0x0002,
1161 +  HORIZONTAL_FLIP,
1162 +  NUM_EFFECTS
1163  };
1164  
1165  /**
1166 @@ -47,21 +50,38 @@
1167  private:
1168    friend class DrawingContext;
1169    friend class Font;
1170 -  ImageTexture* texture;
1171  
1172 -  float uv_left;
1173 -  float uv_top;
1174 -  float uv_right;
1175 -  float uv_bottom;
1176 -
1177    void draw(float x, float y, float alpha, float angle, const Color& color, const Blend& blend, DrawingEffect effect) const;
1178    void draw(float x, float y, float alpha, DrawingEffect effect) const;
1179    void draw_part(float src_x, float src_y, float dst_x, float dst_y,
1180                   float width, float height,
1181                   float alpha, DrawingEffect effect) const;
1182  
1183 -  float width;
1184 -  float height;
1185 +  ImageTexture* texture;
1186 +  bool use_opengl;
1187 +  union
1188 +  {
1189 +    struct
1190 +    {
1191 +      float uv_left;
1192 +      float uv_top;
1193 +      float uv_right;
1194 +      float uv_bottom;
1195 +
1196 +      float width;
1197 +      float height;
1198 +    } opengl;
1199 +    struct
1200 +    {
1201 +      bool flipx;
1202 +      int offsetx; /**< Region in ::surface to be used for blitting */
1203 +      int offsety; /**< Region in ::surface to be used for blitting */
1204 +      int width;   /**< Region in ::surface to be used for blitting */
1205 +      int height;  /**< Region in ::surface to be used for blitting */
1206 +    } sdl;
1207 +  } surface;
1208 +  mutable SDL_Surface *transforms[NUM_EFFECTS]; /**< Cache for pre-transformed surfaces */
1209 +
1210  public:
1211    Surface(const std::string& file);
1212    Surface(const std::string& file, int x, int y, int w, int h);
1213 @@ -75,12 +95,20 @@
1214  
1215    float get_width() const
1216    {
1217 -    return width;
1218 +    if(use_opengl) {
1219 +      return surface.opengl.width;
1220 +    } else {
1221 +      return surface.sdl.width;
1222 +    }
1223    }
1224  
1225    float get_height() const
1226    {
1227 -    return height;
1228 +    if(use_opengl) {
1229 +      return surface.opengl.height;
1230 +    } else {
1231 +      return surface.sdl.height;
1232 +    }
1233    }
1234  
1235    /**
1236 Index: src/gameconfig.cpp
1237 ===================================================================
1238 --- src/gameconfig.cpp  (revision 5067)
1239 +++ src/gameconfig.cpp  (working copy)
1240 @@ -36,6 +36,7 @@
1241  Config::Config()
1242  {
1243    use_fullscreen = true;
1244 +  use_opengl = true;
1245    try_vsync = true;
1246    show_fps = false;
1247    sound_enabled = true;
1248 @@ -70,7 +71,8 @@
1249    const lisp::Lisp* config_video_lisp = config_lisp->get_lisp("video");
1250    if(config_video_lisp) {
1251      config_video_lisp->get("fullscreen", use_fullscreen);
1252 -       config_video_lisp->get("vsync", try_vsync);
1253 +    config_video_lisp->get("opengl", use_opengl);
1254 +    config_video_lisp->get("vsync", try_vsync);
1255      config_video_lisp->get("width", screenwidth);
1256      config_video_lisp->get("height", screenheight);
1257      config_video_lisp->get("aspect_ratio", aspect_ratio);
1258 @@ -100,6 +102,7 @@
1259  
1260    writer.start_list("video");
1261    writer.write_bool("fullscreen", use_fullscreen);
1262 +  writer.write_bool("opengl", use_opengl);
1263    writer.write_bool("vsync", try_vsync);
1264    writer.write_int("width", screenwidth);
1265    writer.write_int("height", screenheight);
1266 Index: src/main.cpp
1267 ===================================================================
1268 --- src/main.cpp        (revision 5067)
1269 +++ src/main.cpp        (working copy)
1270 @@ -383,7 +383,7 @@
1271    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
1272    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
1273  
1274 -  int flags = SDL_OPENGL;
1275 +  int flags = config->use_opengl ? SDL_OPENGL : SDL_SWSURFACE;
1276    if(config->use_fullscreen)
1277      flags |= SDL_FULLSCREEN;
1278    int width = config->screenwidth;
1279 @@ -437,23 +437,26 @@
1280  
1281    log_info << (config->use_fullscreen?"fullscreen ":"window ") << SCREEN_WIDTH << "x" << SCREEN_HEIGHT << " Ratio: " << aspect_ratio << "\n";
1282  
1283 -  // setup opengl state and transform
1284 -  glDisable(GL_DEPTH_TEST);
1285 -  glDisable(GL_CULL_FACE);
1286 -  glEnable(GL_TEXTURE_2D);
1287 -  glEnable(GL_BLEND);
1288 -  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1289 +  if(config->use_opengl)
1290 +  {
1291 +    // setup opengl state and transform
1292 +    glDisable(GL_DEPTH_TEST);
1293 +    glDisable(GL_CULL_FACE);
1294 +    glEnable(GL_TEXTURE_2D);
1295 +    glEnable(GL_BLEND);
1296 +    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1297  
1298 -  glViewport(0, 0, screen->w, screen->h);
1299 -  glMatrixMode(GL_PROJECTION);
1300 -  glLoadIdentity();
1301 -  // logical resolution here not real monitor resolution
1302 -  glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
1303 -  glMatrixMode(GL_MODELVIEW);
1304 -  glLoadIdentity();
1305 -  glTranslatef(0, 0, 0);
1306 +    glViewport(0, 0, screen->w, screen->h);
1307 +    glMatrixMode(GL_PROJECTION);
1308 +    glLoadIdentity();
1309 +    // logical resolution here not real monitor resolution
1310 +    glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
1311 +    glMatrixMode(GL_MODELVIEW);
1312 +    glLoadIdentity();
1313 +    glTranslatef(0, 0, 0);
1314  
1315 -  check_gl_error("Setting up view matrices");
1316 +    check_gl_error("Setting up view matrices");
1317 +  }
1318  
1319    if(texture_manager != NULL)
1320      texture_manager->reload_textures();