Update for -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 #  Note that the patched sources will need an additional library, SDL_gfx, to 
28 #  compile.
29 #
30 #  Installing the patch should be pretty straightforward. Simply run the
31 #  following command prior to running autogen.sh and configure:
32 #
33 #  patch -p0 < contrib/supertux-nogl.diff
34 #
35 #  This patch works for revision 5051. It may break for later revisions.
36 #
37 # -----------------------------------------------------------------------------
38 Index: src/video/drawing_context.cpp
39 ===================================================================
40 --- src/video/drawing_context.cpp       (revision 5051)
41 +++ src/video/drawing_context.cpp       (working copy)
42 @@ -23,7 +23,7 @@
43  #include <cassert>
44  #include <iostream>
45  #include <SDL_image.h>
46 -#include <GL/gl.h>
47 +
48  #include <sstream>
49  #include <iomanip>
50  #include <physfs.h>
51 @@ -113,17 +113,7 @@
52  {
53    screen = SDL_GetVideoSurface();
54  
55 -  lightmap_width = screen->w / LIGHTMAP_DIV;
56 -  lightmap_height = screen->h / LIGHTMAP_DIV;
57 -  unsigned int width = next_po2(lightmap_width);
58 -  unsigned int height = next_po2(lightmap_height);
59 -
60 -  lightmap = new Texture(width, height, GL_RGB);
61 -
62 -  lightmap_uv_right = static_cast<float>(lightmap_width) / static_cast<float>(width);
63 -  lightmap_uv_bottom = static_cast<float>(lightmap_height) / static_cast<float>(height);
64 -  texture_manager->register_texture(lightmap);
65 -
66 +  target = NORMAL;
67    requests = &drawing_requests;
68  
69    obstack_init(&obst);
70 @@ -132,9 +122,6 @@
71  DrawingContext::~DrawingContext()
72  {
73    obstack_free(&obst, NULL);
74 -
75 -  texture_manager->remove_texture(lightmap);
76 -  delete lightmap;
77  }
78  
79  void
80 @@ -142,6 +129,8 @@
81                               float angle, const Color& color, const Blend& blend,
82                               int layer)
83  {
84 +  if(target != NORMAL) return;
85 +
86    assert(surface != 0);
87  
88    DrawingRequest* request = new(obst) DrawingRequest();
89 @@ -177,6 +166,8 @@
90  DrawingContext::draw_surface_part(const Surface* surface, const Vector& source,
91      const Vector& size, const Vector& dest, int layer)
92  {
93 +  if(target != NORMAL) return;
94 +
95    assert(surface != 0);
96  
97    DrawingRequest* request = new(obst) DrawingRequest();
98 @@ -216,6 +207,8 @@
99  DrawingContext::draw_text(const Font* font, const std::string& text,
100      const Vector& position, FontAlignment alignment, int layer)
101  {
102 +  if(target != NORMAL) return;
103 +
104    DrawingRequest* request = new(obst) DrawingRequest();
105  
106    request->type = TEXT;
107 @@ -237,6 +230,8 @@
108  DrawingContext::draw_center_text(const Font* font, const std::string& text,
109      const Vector& position, int layer)
110  {
111 +  if(target != NORMAL) return;
112 +
113    draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y),
114        ALIGN_CENTER, layer);
115  }
116 @@ -244,6 +239,8 @@
117  void
118  DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
119  {
120 +  if(target != NORMAL) return;
121 +
122    DrawingRequest* request = new(obst) DrawingRequest();
123  
124    request->type = GRADIENT;
125 @@ -265,6 +262,8 @@
126  DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
127                                   const Color& color, int layer)
128  {
129 +  if(target != NORMAL) return;
130 +
131    DrawingRequest* request = new(obst) DrawingRequest();
132  
133    request->type = FILLRECT;
134 @@ -287,6 +286,8 @@
135  DrawingContext::draw_filled_rect(const Rect& rect, const Color& color,
136                                   int layer)
137  {
138 +  if(target != NORMAL) return;
139 +
140    DrawingRequest* request = new(obst) DrawingRequest();
141  
142    request->type = FILLRECT;
143 @@ -306,47 +307,20 @@
144  }
145  
146  void
147 -DrawingContext::get_light(const Vector& position, Color* color)
148 +DrawingContext::get_light(const Vector& , Color* color)
149  {
150 -  if( ambient_color.red == 1.0f && ambient_color.green == 1.0f
151 -      && ambient_color.blue  == 1.0f ) {
152 -    *color = Color( 1.0f, 1.0f, 1.0f);
153 -    return;
154 -  }
155 -
156 -  DrawingRequest* request = new(obst) DrawingRequest();
157 -  request->type = GETLIGHT;
158 -  request->pos = transform.apply(position);
159 -
160 -  //There is no light offscreen.
161 -  if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
162 -      || request->pos.x < 0 || request->pos.y < 0){
163 -    *color = Color( 0, 0, 0);
164 -    return;
165 -  }
166 -
167 -  request->layer = LAYER_GUI; //make sure all get_light requests are handled last.
168 -  GetLightRequest* getlightrequest = new(obst) GetLightRequest();
169 -  getlightrequest->color_ptr = color;
170 -  request->request_data = getlightrequest;
171 -  lightmap_requests.push_back(request);
172 +   static int i = 0;
173 +   i += 1; i &= 0xFFFF;
174 +   if (i & 0x8000) {
175 +     *color = Color(0.0f, 0.0f, 0.0f);
176 +   } else {
177 +     *color = Color(1.0f, 1.0f, 1.0f);
178 +   }
179  }
180  
181  void
182 -DrawingContext::get_light(const DrawingRequest& request) const
183 +DrawingContext::get_light(const DrawingRequest& ) const
184  {
185 -  const GetLightRequest* getlightrequest 
186 -    = (GetLightRequest*) request.request_data;
187 -
188 -  float pixels[3];
189 -  for( int i = 0; i<3; i++)
190 -    pixels[i] = 0.0f; //set to black
191 -
192 -  float posX = request.pos.x * lightmap_width / SCREEN_WIDTH;
193 -  float posY = screen->h - request.pos.y * lightmap_height / SCREEN_HEIGHT;
194 -  glReadPixels((GLint) posX, (GLint) posY , 1, 1, GL_RGB, GL_FLOAT, pixels);
195 -    *(getlightrequest->color_ptr) = Color( pixels[0], pixels[1], pixels[2]);
196 -  //printf("get_light %f/%f =>%f/%f r%f g%f b%f\n", request.pos.x, request.pos.y, posX, posY, pixels[0], pixels[1], pixels[2]);
197  }
198  
199  void
200 @@ -362,6 +336,45 @@
201        request.alpha, request.drawing_effect);
202  }
203  
204 +namespace
205 +{
206 +  void fillrect(SDL_Surface* screen, float x, float y, float w, float h, int r, int g, int b, int a)
207 +  {
208 +    if(w < 0) {
209 +      x += w;
210 +      w = -w;
211 +    }
212 +    if(h < 0) {
213 +      y += h;
214 +      h = -h;
215 +    }
216 +
217 +    SDL_Rect src, rect;
218 +    SDL_Surface *temp = NULL;
219 +
220 +    rect.x = (int)x;
221 +    rect.y = (int)y;
222 +    rect.w = (int)w;
223 +    rect.h = (int)h;
224 +
225 +    if(a != 255) {
226 +      temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
227 +
228 +      src.x = 0;
229 +      src.y = 0;
230 +      src.w = rect.w;
231 +      src.h = rect.h;
232 +
233 +      SDL_FillRect(temp, &src, SDL_MapRGB(screen->format, r, g, b));
234 +      SDL_SetAlpha(temp, SDL_SRCALPHA, a);
235 +      SDL_BlitSurface(temp,0,screen,&rect);
236 +      SDL_FreeSurface(temp);
237 +    } else {
238 +      SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, r, g, b));
239 +    }
240 +  }
241 +}
242 +
243  void
244  DrawingContext::draw_gradient(const DrawingRequest& request) const
245  {
246 @@ -370,16 +383,10 @@
247    const Color& top = gradientrequest->top;
248    const Color& bottom = gradientrequest->bottom;
249  
250 -  glDisable(GL_TEXTURE_2D);
251 -  glBegin(GL_QUADS);
252 -  glColor4f(top.red, top.green, top.blue, top.alpha);
253 -  glVertex2f(0, 0);
254 -  glVertex2f(SCREEN_WIDTH, 0);
255 -  glColor4f(bottom.red, bottom.green, bottom.blue, bottom.alpha);
256 -  glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
257 -  glVertex2f(0, SCREEN_HEIGHT);
258 -  glEnd();
259 -  glEnable(GL_TEXTURE_2D);
260 +  int width = 800;
261 +  int height = 600;
262 +  for(float y = 0; y < height; y += 2) ::fillrect(screen, 0, (int)y, width, 2, (int)(((float)(top.red-bottom.red)/(0-height)) * y + top.red), (int)(((float)(top.green-bottom.green)/(0-height)) * y + top.green), (int)(((float)(top.blue-bottom.blue)/(0-height)) * y + top.blue), 255);
263
264  }
265  
266  void
267 @@ -402,45 +409,17 @@
268    float w = fillrectrequest->size.x;
269    float h = fillrectrequest->size.y;
270  
271 -  glDisable(GL_TEXTURE_2D);
272 -  glColor4f(fillrectrequest->color.red, fillrectrequest->color.green,
273 -            fillrectrequest->color.blue, fillrectrequest->color.alpha);
274 -
275 -  glBegin(GL_QUADS);
276 -  glVertex2f(x, y);
277 -  glVertex2f(x+w, y);
278 -  glVertex2f(x+w, y+h);
279 -  glVertex2f(x, y+h);
280 -  glEnd();
281 -  glEnable(GL_TEXTURE_2D);
282 +  int r = static_cast<int>(fillrectrequest->color.red);
283 +  int g = static_cast<int>(fillrectrequest->color.green);
284 +  int b = static_cast<int>(fillrectrequest->color.blue);
285 +  int a = static_cast<int>(fillrectrequest->color.alpha);
286
287 +   ::fillrect(screen, x, y, w, h, r, g, b, a);
288  }
289  
290  void
291 -DrawingContext::draw_lightmap(const DrawingRequest& request) const
292 +DrawingContext::draw_lightmap(const DrawingRequest& ) const
293  {
294 -  const Texture* texture = reinterpret_cast<Texture*> (request.request_data);
295 -
296 -  // multiple the lightmap with the framebuffer
297 -  glBlendFunc(GL_DST_COLOR, GL_ZERO);
298 -
299 -  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
300 -  glBegin(GL_QUADS);
301 -
302 -  glTexCoord2f(0, lightmap_uv_bottom);
303 -  glVertex2f(0, 0);
304 -
305 -  glTexCoord2f(lightmap_uv_right, lightmap_uv_bottom);
306 -  glVertex2f(SCREEN_WIDTH, 0);
307 -
308 -  glTexCoord2f(lightmap_uv_right, 0);
309 -  glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
310 -
311 -  glTexCoord2f(0, 0);
312 -  glVertex2f(0, SCREEN_HEIGHT);
313 -
314 -  glEnd();
315 -
316 -  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
317  }
318  
319  void
320 @@ -453,50 +432,12 @@
321    transformstack.clear();
322    target_stack.clear();
323  
324 -  //Use Lightmap if ambient color is not white.
325 -  bool use_lightmap = ( ambient_color.red != 1.0f   || ambient_color.green != 1.0f ||
326 -                        ambient_color.blue  != 1.0f );
327 -
328 -  // PART1: create lightmap
329 -  if(use_lightmap) {
330 -    glViewport(0, screen->h - lightmap_height, lightmap_width, lightmap_height);
331 -    glMatrixMode(GL_PROJECTION);
332 -    glLoadIdentity();
333 -    glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
334 -    glMatrixMode(GL_MODELVIEW);
335 -    glLoadIdentity();
336 -
337 -    glClearColor( ambient_color.red, ambient_color.green, ambient_color.blue, 1 );
338 -    glClear(GL_COLOR_BUFFER_BIT);
339 -    handle_drawing_requests(lightmap_requests);
340 -    lightmap_requests.clear();
341 -
342 -    glDisable(GL_BLEND);
343 -    glBindTexture(GL_TEXTURE_2D, lightmap->get_handle());
344 -    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, screen->h - lightmap_height, lightmap_width, lightmap_height);
345 -
346 -    glViewport(0, 0, screen->w, screen->h);
347 -    glMatrixMode(GL_PROJECTION);
348 -    glLoadIdentity();
349 -    glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
350 -    glMatrixMode(GL_MODELVIEW);
351 -    glLoadIdentity();
352 -    glEnable(GL_BLEND);
353 -
354 -    // add a lightmap drawing request into the queue
355 -    DrawingRequest* request = new(obst) DrawingRequest();
356 -    request->type = LIGHTMAPREQUEST;
357 -    request->layer = LAYER_HUD - 1;
358 -    request->request_data = lightmap;
359 -    requests->push_back(request);
360 -  }
361 -
362 -  //glClear(GL_COLOR_BUFFER_BIT);
363    handle_drawing_requests(drawing_requests);
364    drawing_requests.clear();
365    obstack_free(&obst, NULL);
366    obstack_init(&obst);
367 -  assert_gl("drawing");
368 +  
369 +  SDL_Flip(screen);
370  
371    // if a screenshot was requested, take one
372    if (screenshot_requested) {
373 @@ -622,12 +563,6 @@
374  DrawingContext::set_target(Target target)
375  {
376    this->target = target;
377 -  if(target == LIGHTMAP) {
378 -    requests = &lightmap_requests;
379 -  } else {
380 -    assert(target == NORMAL);
381 -    requests = &drawing_requests;
382 -  }
383  }
384  
385  void
386 @@ -659,7 +594,7 @@
387      SDL_FreeSurface(shot_surf);
388      return;
389    }
390 -  glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels);
391 +  //glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels); //TODO: Screenshot
392  
393    // copy array line-by-line
394    for (int i = 0; i < SCREEN_HEIGHT; i++) {
395 Index: src/video/texture_manager.hpp
396 ===================================================================
397 --- src/video/texture_manager.hpp       (revision 5051)
398 +++ src/video/texture_manager.hpp       (working copy)
399 @@ -20,7 +20,7 @@
400  #ifndef __IMAGE_TEXTURE_MANAGER_HPP__
401  #define __IMAGE_TEXTURE_MANAGER_HPP__
402  
403 -#include <GL/gl.h>
404 +#include "video/glutil.hpp"
405  #include <string>
406  #include <vector>
407  #include <map>
408 Index: src/video/texture.cpp
409 ===================================================================
410 --- src/video/texture.cpp       (revision 5051)
411 +++ src/video/texture.cpp       (working copy)
412 @@ -21,7 +21,6 @@
413  
414  #include "texture.hpp"
415  
416 -#include <GL/gl.h>
417  #include <assert.h>
418  #include "glutil.hpp"
419  
420 @@ -30,7 +29,7 @@
421    return (v & (v-1)) == 0;
422  }
423  
424 -Texture::Texture(unsigned int w, unsigned int h, GLenum glformat)
425 +Texture::Texture(unsigned int w, unsigned int h, GLenum)
426  {
427    assert(is_power_of_2(w));
428    assert(is_power_of_2(h));
429 @@ -38,23 +37,10 @@
430    this->width = w;
431    this->height = h;
432  
433 -  assert_gl("before creating texture");
434 -  glGenTextures(1, &handle);
435 -
436 -  try {
437 -    glBindTexture(GL_TEXTURE_2D, handle);
438 -
439 -    glTexImage2D(GL_TEXTURE_2D, 0, glformat, width, height, 0, GL_RGBA,
440 -                 GL_UNSIGNED_BYTE, 0);
441 -
442 -    set_texture_params();
443 -  } catch(...) {
444 -    glDeleteTextures(1, &handle);
445 -    throw;
446 -  }
447 +  surface = 0;
448  }
449  
450 -Texture::Texture(SDL_Surface* image, GLenum glformat)
451 +Texture::Texture(SDL_Surface* image, GLenum)
452  {
453    const SDL_PixelFormat* format = image->format;
454    if(!is_power_of_2(image->w) || !is_power_of_2(image->h))
455 @@ -65,45 +51,14 @@
456    this->width = image->w;
457    this->height = image->h;
458  
459 -  assert_gl("before creating texture");
460 -  glGenTextures(1, &handle);
461 -
462 -  try {
463 -    GLenum sdl_format;
464 -    if(format->BytesPerPixel == 3)
465 -      sdl_format = GL_RGB;
466 -    else if(format->BytesPerPixel == 4)
467 -      sdl_format = GL_RGBA;
468 -    else
469 -      assert(false);
470 -
471 -    glBindTexture(GL_TEXTURE_2D, handle);
472 -    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
473 -    glPixelStorei(GL_UNPACK_ROW_LENGTH, image->pitch/format->BytesPerPixel);
474 -    glTexImage2D(GL_TEXTURE_2D, 0, glformat, width, height, 0, sdl_format,
475 -            GL_UNSIGNED_BYTE, image->pixels);
476 -
477 -    assert_gl("creating texture");
478 -
479 -    set_texture_params();
480 -  } catch(...) {
481 -    glDeleteTextures(1, &handle);
482 -    throw;
483 -  }
484 +  surface = SDL_DisplayFormatAlpha(image);
485  }
486  
487  Texture::~Texture()
488  {
489 -  glDeleteTextures(1, &handle);
490  }
491  
492  void
493  Texture::set_texture_params()
494  {
495 -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
496 -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
497 -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
498 -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
499 -
500 -  assert_gl("set texture params");
501  }
502 Index: src/video/drawing_context.hpp
503 ===================================================================
504 --- src/video/drawing_context.hpp       (revision 5051)
505 +++ src/video/drawing_context.hpp       (working copy)
506 @@ -25,7 +25,6 @@
507  
508  #include <stdint.h>
509  
510 -#include <GL/gl.h>
511  #include <SDL_video.h>
512  
513  #include "obstack/obstack.h"
514 @@ -35,8 +34,9 @@
515  #include "font.hpp"
516  #include "color.hpp"
517  
518 +#include "glutil.hpp"
519 +
520  class Surface;
521 -class Texture;
522  struct DrawingRequest;
523  
524  // some constants for predefined layer values
525 @@ -182,7 +182,6 @@
526    void do_take_screenshot();
527  
528    DrawingRequests drawing_requests;
529 -  DrawingRequests lightmap_requests;
530  
531    DrawingRequests* requests;
532    Color ambient_color;
533 @@ -190,9 +189,6 @@
534    SDL_Surface* screen;
535    Target target;
536    std::vector<Target> target_stack;
537 -  Texture* lightmap;
538 -  int lightmap_width, lightmap_height;
539 -  float lightmap_uv_right, lightmap_uv_bottom;
540  
541    /* obstack holding the memory of the drawing requests */
542    struct obstack obst;
543 Index: src/video/glutil.hpp
544 ===================================================================
545 --- src/video/glutil.hpp        (revision 5051)
546 +++ src/video/glutil.hpp        (working copy)
547 @@ -21,60 +21,17 @@
548  
549  #include <sstream>
550  #include <stdexcept>
551 -#include <GL/gl.h>
552  
553 -static inline void check_gl_error(const char* message)
554 -{
555 -#ifdef DEBUG
556 -  GLenum error = glGetError();
557 -  if(error != GL_NO_ERROR) {
558 -    std::ostringstream msg;
559 -    msg << "OpenGLError while '" << message << "': ";
560 -    switch(error) {
561 -      case GL_INVALID_ENUM:
562 -        msg << "INVALID_ENUM: An unacceptable value is specified for an "
563 -               "enumerated argument.";
564 -        break;
565 -      case GL_INVALID_VALUE:
566 -        msg << "INVALID_VALUE: A numeric argument is out of range.";
567 -        break;
568 -      case GL_INVALID_OPERATION:
569 -        msg << "INVALID_OPERATION: The specified operation is not allowed "
570 -               "in the current state.";
571 -        break;
572 -      case GL_STACK_OVERFLOW:
573 -        msg << "STACK_OVERFLOW: This command would cause a stack overflow.";
574 -        break;
575 -      case GL_STACK_UNDERFLOW:
576 -        msg << "STACK_UNDERFLOW: This command would cause a stack underflow.";
577 -        break;
578 -      case GL_OUT_OF_MEMORY:
579 -        msg << "OUT_OF_MEMORY: There is not enough memory left to execute the "
580 -               "command.";
581 -        break;
582 -#ifdef GL_TABLE_TOO_LARGE
583 -      case GL_TABLE_TOO_LARGE:
584 -        msg << "TABLE_TOO_LARGE: table is too large";
585 -        break;
586 -#endif
587 -      default:
588 -        msg << "Unknown error (code " << error << ")";
589 -    }
590 -
591 -    throw std::runtime_error(msg.str());
592 -  }
593 -#else
594 -  (void) message;
595 -#endif
596 -}
597 -
598 +#define GLenum int
599 +#define GLint int
600 +#define GL_SRC_ALPHA 0
601 +#define GL_ONE_MINUS_SRC_ALPHA 1
602 +#define GL_RGBA 2
603 +#define GL_ONE 3
604 +  
605  static inline void assert_gl(const char* message)
606  {
607 -#ifdef DEBUG
608 -  check_gl_error(message);
609 -#else
610    (void) message;
611 -#endif
612  }
613  
614  #endif
615 Index: src/video/texture.hpp
616 ===================================================================
617 --- src/video/texture.hpp       (revision 5051)
618 +++ src/video/texture.hpp       (working copy)
619 @@ -21,7 +21,7 @@
620  #define __TEXTURE_HPP__
621  
622  #include <SDL.h>
623 -#include <GL/gl.h>
624 +#include "glutil.hpp"
625  
626  /**
627   * This class is a wrapper around a texture handle. It stores the texture width
628 @@ -31,8 +31,9 @@
629  class Texture
630  {
631  protected:
632 +  SDL_Surface* surface; /**< non-GL branch stores optimized surface */
633 +
634    friend class TextureManager;
635 -  GLuint handle;
636    unsigned int width;
637    unsigned int height;
638  
639 @@ -41,11 +42,6 @@
640    Texture(SDL_Surface* surface, GLenum glformat);
641    virtual ~Texture();
642  
643 -  GLuint get_handle() const
644 -  {
645 -    return handle;
646 -  }
647 -
648    unsigned int get_width() const
649    {
650      return width;
651 @@ -56,6 +52,14 @@
652      return height;
653    }
654  
655 +  SDL_Surface* getSurface() {
656 +    return surface;
657 +  }
658 +
659 +  void setSurface(SDL_Surface* surface) {
660 +    this->surface = surface;
661 +  }
662 +
663  private:
664    void set_texture_params();
665  };
666 Index: src/video/surface.cpp
667 ===================================================================
668 --- src/video/surface.cpp       (revision 5051)
669 +++ src/video/surface.cpp       (working copy)
670 @@ -28,6 +28,7 @@
671  
672  #include <SDL.h>
673  #include <SDL_image.h>
674 +#include <SDL_rotozoom.h>
675  
676  #include "gameconfig.hpp"
677  #include "physfs/physfs_sdl.hpp"
678 @@ -41,13 +42,13 @@
679  {
680    texture = texture_manager->get(file);
681    texture->ref();
682 -  uv_left = 0;
683 -  uv_top = 0;
684 -  uv_right = texture->get_uv_right();
685 -  uv_bottom = texture->get_uv_bottom();
686  
687 -  width = texture->get_image_width();
688 -  height = texture->get_image_height();
689 +  offsetx = 0;
690 +  offsety = 0;
691 +  width = static_cast<int>(texture->get_image_width());
692 +  height = static_cast<int>(texture->get_image_height());
693 +
694 +  flipx = false;
695  }
696  
697  Surface::Surface(const std::string& file, int x, int y, int w, int h)
698 @@ -55,15 +56,12 @@
699    texture = texture_manager->get(file);
700    texture->ref();
701  
702 -  float tex_w = static_cast<float> (texture->get_width());
703 -  float tex_h = static_cast<float> (texture->get_height());
704 -  uv_left = static_cast<float>(x) / tex_w;
705 -  uv_top = static_cast<float>(y) / tex_h;
706 -  uv_right = static_cast<float>(x+w) / tex_w;
707 -  uv_bottom = static_cast<float>(y+h) / tex_h;
708 -
709 +  offsetx = x;
710 +  offsety = y;
711    width = w;
712    height = h;
713 +
714 +  flipx = false;
715  }
716  
717  Surface::Surface(const Surface& other)
718 @@ -71,12 +69,12 @@
719    texture = other.texture;
720    texture->ref();
721  
722 -  uv_left = other.uv_left;
723 -  uv_top = other.uv_top;
724 -  uv_right = other.uv_right;
725 -  uv_bottom = other.uv_bottom;
726 +  offsetx = other.offsetx;
727 +  offsety = other.offsety;
728    width = other.width;
729    height = other.height;
730 +
731 +  flipx = other.flipx;
732  }
733  
734  const Surface&
735 @@ -86,52 +84,33 @@
736    texture->unref();
737    texture = other.texture;
738  
739 -  uv_left = other.uv_left;
740 -  uv_top = other.uv_top;
741 -  uv_right = other.uv_right;
742 -  uv_bottom = other.uv_bottom;
743 +  offsetx = other.offsetx;
744 +  offsety = other.offsety;
745    width = other.width;
746    height = other.height;
747  
748 +  flipx = other.flipx;
749 +
750    return *this;
751  }
752  
753  Surface::~Surface()
754  {
755    texture->unref();
756 +
757 +  for (std::list<TransformedSurface*>::iterator i = transformedSurfaces.begin(); i != transformedSurfaces.end(); i++) {
758 +    SDL_FreeSurface((*i)->surface);
759 +    delete (*i);
760 +  }
761  }
762  
763  void
764  Surface::hflip()
765  {
766 -  std::swap(uv_left, uv_right);
767 +  flipx = !flipx;
768  }
769  
770 -static inline void intern_draw(float left, float top, float right, float bottom,                               float uv_left, float uv_top,
771 -                               float uv_right, float uv_bottom,
772 -                               DrawingEffect effect)
773 -{
774 -  if(effect & HORIZONTAL_FLIP)
775 -    std::swap(uv_left, uv_right);
776 -  if(effect & VERTICAL_FLIP) {
777 -    std::swap(uv_top, uv_bottom);
778 -  }
779 -
780 -  glBegin(GL_QUADS);
781 -  glTexCoord2f(uv_left, uv_top);
782 -  glVertex2f(left, top);
783 -
784 -  glTexCoord2f(uv_right, uv_top);
785 -  glVertex2f(right, top);
786 -
787 -  glTexCoord2f(uv_right, uv_bottom);
788 -  glVertex2f(right, bottom);
789 -
790 -  glTexCoord2f(uv_left, uv_bottom);
791 -  glVertex2f(left, bottom);
792 -  glEnd();
793 -}
794 -
795 +/*
796  static inline void intern_draw2(float left, float top, float right, float bottom,
797                                  float uv_left, float uv_top,
798                                  float uv_right, float uv_bottom,
799 @@ -182,50 +161,76 @@
800    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
801    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
802  }
803 +*/
804  
805  void
806 -Surface::draw(float x, float y, float alpha, float angle, const Color& color, const Blend& blend, DrawingEffect effect) const
807 +Surface::draw(float x, float y, float alpha, float, const Color&, const Blend&, DrawingEffect effect) const
808  {
809 -  glColor4f(1.0f, 1.0f, 1.0f, alpha);
810 -  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
811 -
812 -  intern_draw2(x, y,
813 -               x + width, y + height,
814 -               uv_left, uv_top, uv_right, uv_bottom,
815 -               angle,
816 -               color,
817 -               blend,
818 -               effect);
819 +  draw_part(0, 0, x, y, width, height, alpha, effect);
820  }
821  
822  void
823  Surface::draw(float x, float y, float alpha, DrawingEffect effect) const
824  {
825 -  glColor4f(1.0f, 1.0f, 1.0f, alpha);
826 -  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
827 -
828 -  intern_draw(x, y,
829 -              x + width, y + height,
830 -              uv_left, uv_top, uv_right, uv_bottom, effect);
831 +  draw_part(0, 0, x, y, width, height, alpha, effect);
832  }
833  
834  void
835  Surface::draw_part(float src_x, float src_y, float dst_x, float dst_y,
836 -                   float width, float height, float alpha,
837 +                   float width, float height, float ,
838                     DrawingEffect effect) const
839  {
840 -  float uv_width = uv_right - uv_left;
841 -  float uv_height = uv_bottom - uv_top;
842 +  //FIXME: support parameter "alpha"
843 +  SDL_Surface* surface = texture->getSurface();
844  
845 -  float uv_left = this->uv_left + (uv_width * src_x) / this->width;
846 -  float uv_top = this->uv_top + (uv_height * src_y) / this->height;
847 -  float uv_right = this->uv_left + (uv_width * (src_x + width)) / this->width;
848 -  float uv_bottom = this->uv_top + (uv_height * (src_y + height)) / this->height;
849 +  // get and check SDL_Surface
850 +  if (surface == 0) {
851 +    std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
852 +    return;
853 +  }    
854  
855 -  glColor4f(1.0f, 1.0f, 1.0f, alpha);
856 -  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
857 +  SDL_Surface* transformedSurface = surface;
858  
859 -  intern_draw(dst_x, dst_y,
860 -              dst_x + width, dst_y + height,
861 -              uv_left, uv_top, uv_right, uv_bottom, effect);
862 +  if (flipx) effect = HORIZONTAL_FLIP;
863 +
864 +  if (effect != NO_EFFECT) {
865 +    transformedSurface = 0;
866 +
867 +    // check if we have this effect buffered
868 +    for (std::list<TransformedSurface*>::const_iterator i = transformedSurfaces.begin(); i != transformedSurfaces.end(); i++) {
869 +      if ((*i)->effect == effect) transformedSurface = (*i)->surface;
870 +    }
871 +
872 +    // if not: transform and buffer
873 +    if (!transformedSurface) {
874 +      if (effect == HORIZONTAL_FLIP) transformedSurface = zoomSurface(surface, -1, 1, 0);
875 +      if (effect == VERTICAL_FLIP) transformedSurface = zoomSurface(surface, 1, -1, 0);
876 +      if (transformedSurface == 0) {
877 +        std::cerr << "Warning: No known transformation applies to surface, skipped draw" << std::endl;
878 +        return;
879 +      }        
880 +      TransformedSurface* su = new TransformedSurface();
881 +      su->surface = transformedSurface;
882 +      su->effect = effect;
883 +
884 +      transformedSurfaces.push_front(su);
885 +    }
886 +  }
887 +
888 +  int ox = offsetx; if (effect == HORIZONTAL_FLIP) ox = static_cast<int>(surface->w) - (ox+static_cast<int>(width));
889 +  int oy = offsety; if (effect == VERTICAL_FLIP) oy = static_cast<int>(surface->h) - (oy+static_cast<int>(height));
890 +  // draw surface to screen
891 +  SDL_Surface* screen = SDL_GetVideoSurface();
892 +
893 +  SDL_Rect srcRect;
894 +  srcRect.x = static_cast<int>(ox+src_x);
895 +  srcRect.y = static_cast<int>(oy+src_y);
896 +  srcRect.w = static_cast<int>(width);
897 +  srcRect.h = static_cast<int>(height);
898 +
899 +  SDL_Rect dstRect;
900 +  dstRect.x = static_cast<int>(dst_x);
901 +  dstRect.y = static_cast<int>(dst_y);
902 +
903 +  SDL_BlitSurface(transformedSurface, &srcRect, screen, &dstRect);
904  }
905 Index: src/video/texture_manager.cpp
906 ===================================================================
907 --- src/video/texture_manager.cpp       (revision 5051)
908 +++ src/video/texture_manager.cpp       (working copy)
909 @@ -24,8 +24,6 @@
910  #include <assert.h>
911  #include <SDL.h>
912  #include <SDL_image.h>
913 -#include <GL/gl.h>
914 -#include <GL/glext.h>
915  #include <iostream>
916  #include <sstream>
917  #include <stdexcept>
918 @@ -149,12 +147,6 @@
919  void
920  TextureManager::save_textures()
921  {
922 -  glPixelStorei(GL_PACK_ROW_LENGTH, 0);
923 -  glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
924 -  glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
925 -  glPixelStorei(GL_PACK_SKIP_ROWS, 0);
926 -  glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
927 -  glPixelStorei(GL_PACK_ALIGNMENT, 1);
928    for(Textures::iterator i = textures.begin(); i != textures.end(); ++i) {
929      save_texture(*i);
930    }
931 @@ -169,74 +161,15 @@
932  {
933    SavedTexture saved_texture;
934    saved_texture.texture = texture;
935 -  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
936 -  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,
937 -                           &saved_texture.width);
938 -  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT,
939 -                           &saved_texture.height);
940 -  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER,
941 -                           &saved_texture.border);
942 -  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
943 -                      &saved_texture.min_filter);
944 -  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
945 -                      &saved_texture.mag_filter);
946 -  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
947 -                      &saved_texture.wrap_s);
948 -  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
949 -                      &saved_texture.wrap_t);
950  
951    size_t pixelssize = saved_texture.width * saved_texture.height * 4;
952    saved_texture.pixels = new char[pixelssize];
953  
954 -  glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE,
955 -                saved_texture.pixels);
956 -
957    saved_textures.push_back(saved_texture);
958 -
959 -  glDeleteTextures(1, &(texture->handle));
960 -  texture->handle = 0;
961 -
962 -  assert_gl("retrieving texture for save");
963  }
964  
965  void
966  TextureManager::reload_textures()
967  {
968 -  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
969 -  glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
970 -  glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
971 -  glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
972 -  glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
973 -  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
974 -
975 -  for(std::vector<SavedTexture>::iterator i = saved_textures.begin();
976 -      i != saved_textures.end(); ++i) {
977 -    SavedTexture& saved_texture = *i;
978 -
979 -    GLuint handle;
980 -    glGenTextures(1, &handle);
981 -    assert_gl("creating texture handle");
982 -
983 -    glBindTexture(GL_TEXTURE_2D, handle);
984 -    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
985 -                 saved_texture.width, saved_texture.height,
986 -                 saved_texture.border, GL_RGBA,
987 -                 GL_UNSIGNED_BYTE, saved_texture.pixels);
988 -    delete[] saved_texture.pixels;
989 -    assert_gl("uploading texture pixel data");
990 -
991 -    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
992 -                    saved_texture.min_filter);
993 -    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
994 -                    saved_texture.mag_filter);
995 -    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
996 -                    saved_texture.wrap_s);
997 -    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
998 -                    saved_texture.wrap_t);
999 -
1000 -    assert_gl("setting texture_params");
1001 -    saved_texture.texture->handle = handle;
1002 -  }
1003 -
1004    saved_textures.clear();
1005  }
1006 Index: src/video/surface.hpp
1007 ===================================================================
1008 --- src/video/surface.hpp       (revision 5051)
1009 +++ src/video/surface.hpp       (working copy)
1010 @@ -20,7 +20,9 @@
1011  #ifndef __SURFACE_HPP__
1012  #define __SURFACE_HPP__
1013  
1014 +#include <SDL_image.h>
1015  #include <string>
1016 +#include <list>
1017  #include "math/vector.hpp"
1018  
1019  class Color;
1020 @@ -38,6 +40,15 @@
1021  };
1022  
1023  /**
1024 + * Helper class to buffer a pre-transformed SDL_Surface
1025 + */
1026 +class TransformedSurface {
1027 +    public:
1028 +       SDL_Surface* surface;
1029 +       DrawingEffect effect;
1030 +};
1031 +
1032 +/**
1033   * A rectangular image.
1034   * The class basically holds a reference to a texture with additional UV
1035   * coordinates that specify a rectangular area on this texture
1036 @@ -49,19 +60,26 @@
1037    friend class Font;
1038    ImageTexture* texture;
1039  
1040 -  float uv_left;
1041 -  float uv_top;
1042 -  float uv_right;
1043 -  float uv_bottom;
1044 +  bool flipx;
1045  
1046 +  /** draw the surface on the screen, applying a ::DrawingEffect on-the-fly. Transformed Surfaces will be cached in ::transformedSurfaces */
1047    void draw(float x, float y, float alpha, float angle, const Color& color, const Blend& blend, DrawingEffect effect) const;
1048 +  
1049 +  /** draw the surface on the screen, applying a ::DrawingEffect on-the-fly. Transformed Surfaces will be cached in ::transformedSurfaces */
1050    void draw(float x, float y, float alpha, DrawingEffect effect) const;
1051 +  
1052 +  /** draw the surface on the screen, applying a ::DrawingEffect on-the-fly. Transformed Surfaces will be cached in ::transformedSurfaces */
1053    void draw_part(float src_x, float src_y, float dst_x, float dst_y,
1054                   float width, float height,
1055                   float alpha, DrawingEffect effect) const;
1056  
1057 -  float width;
1058 -  float height;
1059 +  int offsetx; /**< Region in ::surface to be used for blitting */
1060 +  int offsety; /**< Region in ::surface to be used for blitting */
1061 +  int width;   /**< Region in ::surface to be used for blitting */
1062 +  int height;  /**< Region in ::surface to be used for blitting */
1063 +
1064 +  mutable std::list<TransformedSurface*> transformedSurfaces; /**< Cache for pre-transformed surfaces */
1065 +
1066  public:
1067    Surface(const std::string& file);
1068    Surface(const std::string& file, int x, int y, int w, int h);
1069 Index: src/main.cpp
1070 ===================================================================
1071 --- src/main.cpp        (revision 5051)
1072 +++ src/main.cpp        (working copy)
1073 @@ -33,7 +33,6 @@
1074  #include <physfs.h>
1075  #include <SDL.h>
1076  #include <SDL_image.h>
1077 -#include <GL/gl.h>
1078  
1079  #include "gameconfig.hpp"
1080  #include "resources.hpp"
1081 @@ -383,7 +382,7 @@
1082    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
1083    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
1084  
1085 -  int flags = SDL_OPENGL;
1086 +  int flags = SDL_SWSURFACE;
1087    if(config->use_fullscreen)
1088      flags |= SDL_FULLSCREEN;
1089    int width = config->screenwidth;
1090 @@ -437,24 +436,6 @@
1091  
1092    log_info << (config->use_fullscreen?"fullscreen ":"window ") << SCREEN_WIDTH << "x" << SCREEN_HEIGHT << " Ratio: " << aspect_ratio << "\n";
1093  
1094 -  // setup opengl state and transform
1095 -  glDisable(GL_DEPTH_TEST);
1096 -  glDisable(GL_CULL_FACE);
1097 -  glEnable(GL_TEXTURE_2D);
1098 -  glEnable(GL_BLEND);
1099 -  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1100 -
1101 -  glViewport(0, 0, screen->w, screen->h);
1102 -  glMatrixMode(GL_PROJECTION);
1103 -  glLoadIdentity();
1104 -  // logical resolution here not real monitor resolution
1105 -  glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
1106 -  glMatrixMode(GL_MODELVIEW);
1107 -  glLoadIdentity();
1108 -  glTranslatef(0, 0, 0);
1109 -
1110 -  check_gl_error("Setting up view matrices");
1111 -
1112    if(texture_manager != NULL)
1113      texture_manager->reload_textures();
1114    else
1115 Index: src/Jamfile
1116 ===================================================================
1117 --- src/Jamfile (revision 5051)
1118 +++ src/Jamfile (working copy)
1119 @@ -28,7 +28,7 @@
1120  Application supertux2 : $(sources) $(wrapper_objects) : linkerfile ;
1121  C++Flags supertux2 : -DAPPDATADIR=\'\"$(appdatadir)\"\' ;
1122  LinkWith supertux2 : squirrel ;
1123 -ExternalLibs supertux2 : SDL SDLIMAGE GL OPENAL VORBIS VORBISFILE OGG ICONV PHYSFS BINRELOC LIBCURL ;
1124 +ExternalLibs supertux2 : SDL SDLIMAGE SDLGFX OPENAL VORBIS VORBISFILE OGG ICONV PHYSFS BINRELOC LIBCURL ;
1125  Help supertux2 : "Build the supertux2 executable" ;
1126  IncludeDir supertux2 : squirrel/include squirrel ;
1127  Package [ Wildcard scripting : *.cpp *.hpp ] ;
1128 Index: README
1129 ===================================================================
1130 --- README      (revision 5051)
1131 +++ README      (working copy)
1132 @@ -2,7 +2,8 @@
1133  - An introduction for SuperTux -
1134  http://supertux.lethargik.org/
1135  
1136 -Last update: December 17, 2006
1137 +Last update: May 27, 2007
1138 +using -nogl patch by Christoph Sommer 
1139  
1140  DESCRIPTION
1141  -----------
1142 @@ -69,12 +70,10 @@
1143    Also, notice that SuperTux saves the options, so it's often enough to
1144    specify them once.
1145  
1146 -  The game uses OpenGL to render the graphics. You will either need a CPU
1147 -  with about 10 GHz or an accelerated video card with the vendor's drivers.
1148 -  (On Linux, the team recommends using cards from NVidia with the proprietary
1149 -  drivers, but ATI or another vendor should do.)
1150 +  The game uses SDL to render the graphics. You will either need a CPU
1151 +  with about 1 GHz or go get the original version of SuperTux which uses
1152 +  OpenGL.
1153  
1154 -
1155  PLAYING THE GAME
1156  ----------------
1157    Controls
1158 Index: configure.ac
1159 ===================================================================
1160 --- configure.ac        (revision 5051)
1161 +++ configure.ac        (working copy)
1162 @@ -11,7 +11,7 @@
1163  
1164  dnl Process this file with autoconf to produce a configure script.
1165  AC_PREREQ([2.54])
1166 -AC_INIT(supertux2, 0.3.0-SVN)
1167 +AC_INIT(supertux2, 0.3.0-nogl-SVN)
1168  AC_CONFIG_SRCDIR([src/main.cpp])
1169  AC_CONFIG_AUX_DIR([mk/autoconf])
1170  AC_CANONICAL_TARGET
1171 @@ -129,6 +129,14 @@
1172          [AC_MSG_ERROR([Please install SDLImage >= 1.2.1])],
1173          [$SDL_CFLAGS], [$SDL_LIBS])
1174  
1175 +dnl FIXME: This is far from perfect
1176 +NP_FINDLIB([SDLGFX], [SDL_gfx], [SDL_gfx >= 2.0.13],
1177 +        NP_LANG_PROGRAM([#include <SDL_rotozoom.h>], [0;]),
1178 +        [], [-lSDL_gfx],
1179 +        [],
1180 +        [AC_MSG_ERROR([Please install SDL_gfx >= 2.0.13])],
1181 +        [$SDL_CFLAGS], [$SDL_LIBS])
1182 +
1183  NP_FINDLIB([PHYSFS], [physfs], [physfs >= 1.0.0],
1184          NP_LANG_PROGRAM([
1185  #include <stdio.h>
1186 @@ -154,11 +162,6 @@
1187           [AC_MSG_ERROR([Please intall OpenAL])],
1188           [], [])
1189  
1190 -AX_CHECK_GL
1191 -if test "$no_gl" = "yes"; then
1192 -  AC_MSG_ERROR([Please install opengl libraries and headers])
1193 -fi
1194 -
1195  dnl Checks for library functions.
1196  AC_CHECK_FUNCS(mkdir strdup strstr)
1197  
1198 Index: INSTALL
1199 ===================================================================
1200 --- INSTALL     (revision 5051)
1201 +++ INSTALL     (working copy)
1202 @@ -1,7 +1,7 @@
1203  - Install instructions for SuperTux -
1204  http://supertux.lethargik.org/
1205  
1206 -Last update: October 11, 2005 by Ondra Hosek
1207 +Last update: March 4, 2006 by Christoph Sommer
1208  
1209  BINARIES
1210  --------
1211 @@ -34,17 +34,15 @@
1212      Download: ftp://ftp.perforce.com/pub/jam
1213      Homepage: http://www.perforce.com/jam/jam.html
1214  
1215 -* OpenGL headers and libraries
1216 -    opengl libraries and headers are specific to your graphics card. Make sure
1217 -    that you have hardware accelerated opengl drivers installed. Software
1218 -    renderers like Mesa will make supertux unplayable slow.
1219 -
1220  * SDL 1.2.5 or later (1.2.8 is recommended on MacOS/X)
1221      http://www.libsdl.org
1222  
1223  * SDL_image (any version)
1224      http://www.libsdl.org/projects/SDL_image
1225  
1226 +* SDL_gfx (2.0.13 or later)
1227 +    http://www.ferzkopp.net/Software/SDL_gfx-2.0/
1228 +
1229  * PhysicsFS (1.0.0, the development branch 1.1.x is buggy and does not work,
1230               1.2.0 and later should work when it is released)
1231      http://www.icculus.org/physfs