Refactored video/ subsystem to make adding other methods of rendering (in particular...
authorTim Goya <tuxdev103@gmail.com>
Wed, 15 Aug 2007 01:02:22 +0000 (01:02 +0000)
committerTim Goya <tuxdev103@gmail.com>
Wed, 15 Aug 2007 01:02:22 +0000 (01:02 +0000)
SVN-Revision: 5138

36 files changed:
configure.ac
src/gameconfig.cpp
src/gameconfig.hpp
src/main.cpp
src/mainloop.cpp
src/mainloop.hpp
src/sprite/sprite_data.cpp
src/video/color.hpp
src/video/drawing_context.cpp
src/video/drawing_context.hpp
src/video/drawing_request.hpp [new file with mode: 0644]
src/video/font.cpp
src/video/font.hpp
src/video/gl_lightmap.cpp [new file with mode: 0644]
src/video/gl_lightmap.hpp [new file with mode: 0644]
src/video/gl_renderer.cpp [new file with mode: 0644]
src/video/gl_renderer.hpp [new file with mode: 0644]
src/video/gl_texture.cpp [new file with mode: 0644]
src/video/gl_texture.hpp [new file with mode: 0644]
src/video/glutil.hpp
src/video/image_texture.cpp
src/video/image_texture.hpp
src/video/lightmap.hpp [new file with mode: 0644]
src/video/renderer.hpp [new file with mode: 0644]
src/video/sdl_lightmap.cpp [new file with mode: 0644]
src/video/sdl_lightmap.hpp [new file with mode: 0644]
src/video/sdl_renderer.cpp [new file with mode: 0644]
src/video/sdl_renderer.hpp [new file with mode: 0644]
src/video/sdl_texture.cpp [new file with mode: 0644]
src/video/sdl_texture.hpp [new file with mode: 0644]
src/video/surface.cpp [deleted file]
src/video/surface.hpp
src/video/texture.cpp [deleted file]
src/video/texture.hpp
src/video/texture_manager.cpp
src/video/texture_manager.hpp

index 0627bf2..f6aca78 100644 (file)
@@ -154,9 +154,15 @@ NP_FINDLIB([OPENAL], [OpenAL], [OpenAL],
          [AC_MSG_ERROR([Please intall OpenAL])],
          [], [])
 
-AX_CHECK_GL
-if test "$no_gl" = "yes"; then
-  AC_MSG_ERROR([Please install opengl libraries and headers])
+AC_ARG_ENABLE(opengl,
+              AC_HELP_STRING([--enable-opengl], [enable opengl support]),
+              [enable_opengl=$enableval], [enable_opengl=yes])
+
+if test "$enable_opengl" = "yes"; then
+  AX_CHECK_GL
+  if test "$no_gl" != "yes"; then
+    AC_DEFINE_UNQUOTED(HAVE_OPENGL, 1, Define if OpenGL is present on the system)
+  fi
 fi
 
 dnl Checks for library functions.
index 2373d70..80f27c0 100644 (file)
@@ -36,6 +36,11 @@ Config* config = 0;
 Config::Config()
 {
   use_fullscreen = true;
+#ifdef HAVE_OPENGL
+  video = "opengl";
+#else
+  video = "sdl";
+#endif
   try_vsync = true;
   show_fps = false;
   sound_enabled = true;
@@ -73,7 +78,8 @@ Config::load()
   const lisp::Lisp* config_video_lisp = config_lisp->get_lisp("video");
   if(config_video_lisp) {
     config_video_lisp->get("fullscreen", use_fullscreen);
-       config_video_lisp->get("vsync", try_vsync);
+    config_video_lisp->get("video", video);
+    config_video_lisp->get("vsync", try_vsync);
     config_video_lisp->get("width", screenwidth);
     config_video_lisp->get("height", screenheight);
     config_video_lisp->get("aspect_ratio", aspect_ratio);
@@ -104,6 +110,7 @@ Config::save()
 
   writer.start_list("video");
   writer.write_bool("fullscreen", use_fullscreen);
+  writer.write_string("video", video);
   writer.write_bool("vsync", try_vsync);
   writer.write_int("width", screenwidth);
   writer.write_int("height", screenheight);
index 4263bda..0efeacd 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef SUPERTUX_CONFIG_H
 #define SUPERTUX_CONFIG_H
 
+#include <config.h>
+
 #include <string>
 
 class Config
@@ -39,6 +41,7 @@ public:
   float aspect_ratio;
 
   bool use_fullscreen;
+  std::string video;
   bool try_vsync;
   bool show_fps;
   bool sound_enabled;
index 8780ddc..c3b6805 100644 (file)
@@ -33,7 +33,6 @@
 #include <physfs.h>
 #include <SDL.h>
 #include <SDL_image.h>
-#include <GL/gl.h>
 
 #include "gameconfig.hpp"
 #include "resources.hpp"
@@ -41,6 +40,7 @@
 #include "audio/sound_manager.hpp"
 #include "video/surface.hpp"
 #include "video/texture_manager.hpp"
+#include "video/drawing_context.hpp"
 #include "video/glutil.hpp"
 #include "control/joystickkeyboardcontroller.hpp"
 #include "options_menu.hpp"
@@ -55,7 +55,8 @@
 #include "worldmap/worldmap.hpp"
 #include "binreloc/binreloc.h"
 
-SDL_Surface* screen = 0;
+DrawingContext context;
+SDL_Surface *screen;
 JoystickKeyboardController* main_controller = 0;
 TinyGetText::DictionaryManager dictionary_manager;
 
@@ -365,9 +366,6 @@ void init_video()
   static int desktop_width = 0;
   static int desktop_height = 0;
 
-  if(texture_manager != NULL)
-    texture_manager->save_textures();
-
 /* unfortunately only newer SDLs have these infos */
 #if SDL_MAJOR_VERSION > 1 || SDL_MINOR_VERSION > 2 || (SDL_MINOR_VERSION == 2 && SDL_PATCHLEVEL >= 10)
   /* find which resolution the user normally uses */
@@ -376,32 +374,10 @@ void init_video()
     desktop_width  = info->current_w;
     desktop_height = info->current_h;
   }
-
-  if(config->try_vsync) {
-    /* we want vsync for smooth scrolling */
-       SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
-  }
 #endif
 
-  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-  SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
-  SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
-  SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
-
-  int flags = SDL_OPENGL;
-  if(config->use_fullscreen)
-    flags |= SDL_FULLSCREEN;
-  int width = config->screenwidth;
-  int height = config->screenheight;
-  int bpp = 0;
-
-  screen = SDL_SetVideoMode(width, height, bpp, flags);
-  if(screen == 0) {
-    std::stringstream msg;
-    msg << "Couldn't set video mode (" << width << "x" << height
-        << "-" << bpp << "bpp): " << SDL_GetError();
-    throw std::runtime_error(msg.str());
-  }
+  context.init_renderer();
+  screen = SDL_GetVideoSurface();
 
   SDL_WM_SetCaption(PACKAGE_NAME " " PACKAGE_VERSION, 0);
 
@@ -441,29 +417,6 @@ void init_video()
   }
 
   log_info << (config->use_fullscreen?"fullscreen ":"window ") << SCREEN_WIDTH << "x" << SCREEN_HEIGHT << " Ratio: " << aspect_ratio << "\n";
-
-  // setup opengl state and transform
-  glDisable(GL_DEPTH_TEST);
-  glDisable(GL_CULL_FACE);
-  glEnable(GL_TEXTURE_2D);
-  glEnable(GL_BLEND);
-  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-  glViewport(0, 0, screen->w, screen->h);
-  glMatrixMode(GL_PROJECTION);
-  glLoadIdentity();
-  // logical resolution here not real monitor resolution
-  glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
-  glMatrixMode(GL_MODELVIEW);
-  glLoadIdentity();
-  glTranslatef(0, 0, 0);
-
-  check_gl_error("Setting up view matrices");
-
-  if(texture_manager != NULL)
-    texture_manager->reload_textures();
-  else
-    texture_manager = new TextureManager();
 }
 
 static void init_audio()
@@ -612,7 +565,7 @@ int main(int argc, char** argv)
     }
 
     //init_rand(); PAK: this call might subsume the above 3, but I'm chicken!
-    main_loop->run();
+    main_loop->run(context);
 #ifndef NO_CATCH
   } catch(std::exception& e) {
     log_fatal << "Unexpected exception: " << e.what() << std::endl;
index 314de15..e5db024 100644 (file)
@@ -228,10 +228,8 @@ MainLoop::handle_screen_switch()
 }
 
 void
-MainLoop::run()
+MainLoop::run(DrawingContext &context)
 {
-  DrawingContext context;
-
   Uint32 last_ticks = 0;
   Uint32 elapsed_ticks = 0;
 
index e9fa1a1..bd03372 100644 (file)
@@ -34,7 +34,7 @@ public:
   MainLoop();
   ~MainLoop();
 
-  void run();
+  void run(DrawingContext &context);
   void exit_screen(ScreenFade* fade = NULL);
   void quit(ScreenFade* fade = NULL);
   void set_speed(float speed);
index 8d223af..52e404a 100644 (file)
@@ -104,8 +104,8 @@ SpriteData::parse_action(const lisp::Lisp* lisp, const std::string& basedir)
           i++) {
         Surface* surface = new Surface(*(act_tmp->surfaces[i]));
         surface->hflip();
-        max_w = std::max(max_w, surface->get_width());
-        max_h = std::max(max_h, surface->get_height());
+        max_w = std::max(max_w, (float) surface->get_width());
+        max_h = std::max(max_h, (float) surface->get_height());
         action->surfaces.push_back(surface);
       }
       if (action->hitbox_w < 1) action->hitbox_w = max_w;
@@ -124,8 +124,8 @@ SpriteData::parse_action(const lisp::Lisp* lisp, const std::string& basedir)
     float max_h = 0;
     for(std::vector<std::string>::size_type i = 0; i < images.size(); i++) {
       Surface* surface = new Surface(basedir + images[i]);
-      max_w = std::max(max_w, surface->get_width());
-      max_h = std::max(max_h, surface->get_height());
+      max_w = std::max(max_w, (float) surface->get_width());
+      max_h = std::max(max_h, (float) surface->get_height());
       action->surfaces.push_back(surface);
     }
     if (action->hitbox_w < 1) action->hitbox_w = max_w;
index e94b362..e3ff678 100644 (file)
@@ -66,6 +66,16 @@ public:
       log_warning << "color value out of range: " << red << ", " << green << ", " << blue << ", " << alpha << std::endl;
   }
 
+  float greyscale() const
+  {
+    return red * 0.30 + green * 0.59 + blue * 0.11;
+  }
+
+  bool operator < (const Color& other) const
+  {
+    return greyscale() < other.greyscale();
+  }
+
   float red, green, blue, alpha;
 };
 
index 8633956..428454d 100644 (file)
 #include <cassert>
 #include <iostream>
 #include <SDL_image.h>
-#include <GL/gl.h>
 #include <sstream>
 #include <iomanip>
 #include <physfs.h>
 
 #include "drawing_context.hpp"
+#include "drawing_request.hpp"
+#include "gl_renderer.hpp"
+#include "gl_lightmap.hpp"
+#include "sdl_renderer.hpp"
+#include "sdl_lightmap.hpp"
 #include "surface.hpp"
-#include "font.hpp"
 #include "main.hpp"
 #include "gameconfig.hpp"
-#include "glutil.hpp"
 #include "texture.hpp"
 #include "texture_manager.hpp"
 #include "obstack/obstackpp.hpp"
 #define LIGHTMAP_DIV 5
 
-enum RequestType
-{
-  SURFACE, SURFACE_PART, TEXT, GRADIENT, FILLRECT, LIGHTMAPREQUEST, GETLIGHT
-};
-
-struct SurfacePartRequest
-{
-  const Surface* surface;
-  Vector source, size;
-};
-
-struct TextRequest
-{
-  const Font* font;
-  std::string text;
-  FontAlignment alignment;
-};
-
-struct GradientRequest
-{
-  Color top, bottom;
-  Vector size;
-};
-
-struct FillRectRequest
-{
-  Color color;
-  Vector size;
-};
-
-struct DrawingRequest
-{
-  RequestType type;
-  Vector pos;
-
-  int layer;
-  DrawingEffect drawing_effect;
-  float alpha;
-  Blend blend;
-  float angle;
-  Color color;
-
-  void* request_data;
-
-  DrawingRequest()
-    : angle(0.0f),
-      color(1.0f, 1.0f, 1.0f, 1.0f)
-  {}
-
-  bool operator<(const DrawingRequest& other) const
-  {
-    return layer < other.layer;
-  }
-};
-
-struct GetLightRequest
-{
-  Color* color_ptr;
-};
-
 static inline int next_po2(int val)
 {
   int result = 1;
@@ -108,33 +50,41 @@ static inline int next_po2(int val)
   return result;
 }
 
-DrawingContext::DrawingContext()
-  : ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL), screenshot_requested(false)
+DrawingContext::DrawingContext() :
+  renderer(0), lightmap(0), ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL), screenshot_requested(false)
 {
-  screen = SDL_GetVideoSurface();
-
-  lightmap_width = screen->w / LIGHTMAP_DIV;
-  lightmap_height = screen->h / LIGHTMAP_DIV;
-  unsigned int width = next_po2(lightmap_width);
-  unsigned int height = next_po2(lightmap_height);
-
-  lightmap = new Texture(width, height, GL_RGB);
-
-  lightmap_uv_right = static_cast<float>(lightmap_width) / static_cast<float>(width);
-  lightmap_uv_bottom = static_cast<float>(lightmap_height) / static_cast<float>(height);
-  texture_manager->register_texture(lightmap);
-
   requests = &drawing_requests;
-
   obstack_init(&obst);
 }
 
 DrawingContext::~DrawingContext()
 {
+  delete renderer;
+  delete lightmap;
+
   obstack_free(&obst, NULL);
+}
 
-  texture_manager->remove_texture(lightmap);
-  delete lightmap;
+void
+DrawingContext::init_renderer()
+{
+  if(renderer)
+    delete renderer;
+  if(lightmap)
+    delete lightmap;
+
+#ifdef HAVE_OPENGL
+  if(config->video == "opengl")
+  {
+    renderer = new GL::Renderer();
+    lightmap = new GL::Lightmap();
+  }
+  else
+#endif
+  {
+    renderer = new SDL::Renderer();
+    lightmap = new SDL::Lightmap();
+  }
 }
 
 void
@@ -146,6 +96,7 @@ DrawingContext::draw_surface(const Surface* surface, const Vector& position,
 
   DrawingRequest* request = new(obst) DrawingRequest();
 
+  request->target = target;
   request->type = SURFACE;
   request->pos = transform.apply(position);
 
@@ -181,6 +132,7 @@ DrawingContext::draw_surface_part(const Surface* surface, const Vector& source,
 
   DrawingRequest* request = new(obst) DrawingRequest();
 
+  request->target = target;
   request->type = SURFACE_PART;
   request->pos = transform.apply(dest);
   request->layer = layer;
@@ -218,6 +170,7 @@ DrawingContext::draw_text(const Font* font, const std::string& text,
 {
   DrawingRequest* request = new(obst) DrawingRequest();
 
+  request->target = target;
   request->type = TEXT;
   request->pos = transform.apply(position);
   request->layer = layer;
@@ -246,6 +199,7 @@ DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
 {
   DrawingRequest* request = new(obst) DrawingRequest();
 
+  request->target = target;
   request->type = GRADIENT;
   request->pos = Vector(0,0);
   request->layer = layer;
@@ -267,6 +221,7 @@ DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
 {
   DrawingRequest* request = new(obst) DrawingRequest();
 
+  request->target = target;
   request->type = FILLRECT;
   request->pos = transform.apply(topleft);
   request->layer = layer;
@@ -289,6 +244,7 @@ DrawingContext::draw_filled_rect(const Rect& rect, const Color& color,
 {
   DrawingRequest* request = new(obst) DrawingRequest();
 
+  request->target = target;
   request->type = FILLRECT;
   request->pos = transform.apply(rect.p1);
   request->layer = layer;
@@ -315,6 +271,7 @@ DrawingContext::get_light(const Vector& position, Color* color)
   }
 
   DrawingRequest* request = new(obst) DrawingRequest();
+  request->target = target;
   request->type = GETLIGHT;
   request->pos = transform.apply(position);
 
@@ -333,120 +290,6 @@ DrawingContext::get_light(const Vector& position, Color* color)
 }
 
 void
-DrawingContext::get_light(const DrawingRequest& request) const
-{
-  const GetLightRequest* getlightrequest 
-    = (GetLightRequest*) request.request_data;
-
-  float pixels[3];
-  for( int i = 0; i<3; i++)
-    pixels[i] = 0.0f; //set to black
-
-  float posX = request.pos.x * lightmap_width / SCREEN_WIDTH;
-  float posY = screen->h - request.pos.y * lightmap_height / SCREEN_HEIGHT;
-  glReadPixels((GLint) posX, (GLint) posY , 1, 1, GL_RGB, GL_FLOAT, pixels);
-    *(getlightrequest->color_ptr) = Color( pixels[0], pixels[1], pixels[2]);
-  //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]);
-}
-
-void
-DrawingContext::draw_surface_part(const DrawingRequest& request) const
-{
-  const SurfacePartRequest* surfacepartrequest
-    = (SurfacePartRequest*) request.request_data;
-
-  surfacepartrequest->surface->draw_part(
-      surfacepartrequest->source.x, surfacepartrequest->source.y,
-      request.pos.x, request.pos.y,
-      surfacepartrequest->size.x, surfacepartrequest->size.y,
-      request.alpha, request.drawing_effect);
-}
-
-void
-DrawingContext::draw_gradient(const DrawingRequest& request) const
-{
-  const GradientRequest* gradientrequest 
-    = (GradientRequest*) request.request_data;
-  const Color& top = gradientrequest->top;
-  const Color& bottom = gradientrequest->bottom;
-
-  glDisable(GL_TEXTURE_2D);
-  glBegin(GL_QUADS);
-  glColor4f(top.red, top.green, top.blue, top.alpha);
-  glVertex2f(0, 0);
-  glVertex2f(SCREEN_WIDTH, 0);
-  glColor4f(bottom.red, bottom.green, bottom.blue, bottom.alpha);
-  glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
-  glVertex2f(0, SCREEN_HEIGHT);
-  glEnd();
-  glEnable(GL_TEXTURE_2D);
-  glColor4f(1, 1, 1, 1);
-}
-
-void
-DrawingContext::draw_text(const DrawingRequest& request) const
-{
-  const TextRequest* textrequest = (TextRequest*) request.request_data;
-
-  textrequest->font->draw(textrequest->text, request.pos,
-      textrequest->alignment, request.drawing_effect, request.alpha);
-}
-
-void
-DrawingContext::draw_filled_rect(const DrawingRequest& request) const
-{
-  const FillRectRequest* fillrectrequest
-    = (FillRectRequest*) request.request_data;
-
-  float x = request.pos.x;
-  float y = request.pos.y;
-  float w = fillrectrequest->size.x;
-  float h = fillrectrequest->size.y;
-
-  glDisable(GL_TEXTURE_2D);
-  glColor4f(fillrectrequest->color.red, fillrectrequest->color.green,
-            fillrectrequest->color.blue, fillrectrequest->color.alpha);
-
-  glBegin(GL_QUADS);
-  glVertex2f(x, y);
-  glVertex2f(x+w, y);
-  glVertex2f(x+w, y+h);
-  glVertex2f(x, y+h);
-  glEnd();
-  glEnable(GL_TEXTURE_2D);
-  
-  glColor4f(1, 1, 1, 1);
-}
-
-void
-DrawingContext::draw_lightmap(const DrawingRequest& request) const
-{
-  const Texture* texture = reinterpret_cast<Texture*> (request.request_data);
-
-  // multiple the lightmap with the framebuffer
-  glBlendFunc(GL_DST_COLOR, GL_ZERO);
-
-  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
-  glBegin(GL_QUADS);
-
-  glTexCoord2f(0, lightmap_uv_bottom);
-  glVertex2f(0, 0);
-
-  glTexCoord2f(lightmap_uv_right, lightmap_uv_bottom);
-  glVertex2f(SCREEN_WIDTH, 0);
-
-  glTexCoord2f(lightmap_uv_right, 0);
-  glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
-
-  glTexCoord2f(0, 0);
-  glVertex2f(0, SCREEN_HEIGHT);
-
-  glEnd();
-
-  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-}
-
-void
 DrawingContext::do_drawing()
 {
 #ifdef DEBUG
@@ -462,52 +305,25 @@ DrawingContext::do_drawing()
 
   // PART1: create lightmap
   if(use_lightmap) {
-    glViewport(0, screen->h - lightmap_height, lightmap_width, lightmap_height);
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-
-    glClearColor( ambient_color.red, ambient_color.green, ambient_color.blue, 1 );
-    glClear(GL_COLOR_BUFFER_BIT);
+    lightmap->start_draw(ambient_color);
     handle_drawing_requests(lightmap_requests);
-    lightmap_requests.clear();
-
-    glDisable(GL_BLEND);
-    glBindTexture(GL_TEXTURE_2D, lightmap->get_handle());
-    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, screen->h - lightmap_height, lightmap_width, lightmap_height);
-
-    glViewport(0, 0, screen->w, screen->h);
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-    glEnable(GL_BLEND);
-
-    // add a lightmap drawing request into the queue
-    DrawingRequest* request = new(obst) DrawingRequest();
-    request->type = LIGHTMAPREQUEST;
-    request->layer = LAYER_HUD - 1;
-    request->request_data = lightmap;
-    requests->push_back(request);
+    lightmap->end_draw();
   }
 
-  //glClear(GL_COLOR_BUFFER_BIT);
   handle_drawing_requests(drawing_requests);
-  drawing_requests.clear();
+  if(use_lightmap) {
+    lightmap->do_draw();
+  }
   obstack_free(&obst, NULL);
   obstack_init(&obst);
-  assert_gl("drawing");
 
   // if a screenshot was requested, take one
   if (screenshot_requested) {
-    do_take_screenshot();
+    renderer->do_take_screenshot();
     screenshot_requested = false;
   }
 
-  SDL_GL_SwapBuffers();
+  renderer->flip();
 }
 
 class RequestPtrCompare
@@ -523,7 +339,7 @@ public:
 };
 
 void
-DrawingContext::handle_drawing_requests(DrawingRequests& requests) const
+DrawingContext::handle_drawing_requests(DrawingRequests& requests)
 {
   std::stable_sort(requests.begin(), requests.end(), RequestPtrCompare());
 
@@ -531,42 +347,54 @@ DrawingContext::handle_drawing_requests(DrawingRequests& requests) const
   for(i = requests.begin(); i != requests.end(); ++i) {
     const DrawingRequest& request = **i;
 
-    switch(request.type) {
-      case SURFACE:
-      {
-        const Surface* surface = (const Surface*) request.request_data;
-        if (request.angle == 0.0f &&
-            request.color.red == 1.0f && request.color.green == 1.0f  &&
-            request.color.blue == 1.0f &&  request.color.alpha == 1.0f) {
-          surface->draw(request.pos.x, request.pos.y, request.alpha,
-              request.drawing_effect);
-        } else {
-          surface->draw(request.pos.x, request.pos.y,
-              request.alpha, request.angle, request.color,
-              request.blend, request.drawing_effect);
+    switch(request.target) {
+      case NORMAL:
+        switch(request.type) {
+          case SURFACE:
+            renderer->draw_surface(request);
+            break;
+          case SURFACE_PART:
+            renderer->draw_surface_part(request);
+            break;
+          case GRADIENT:
+            renderer->draw_gradient(request);
+            break;
+          case TEXT:
+            renderer->draw_text(request);
+            break;
+          case FILLRECT:
+            renderer->draw_filled_rect(request);
+            break;
+          case GETLIGHT:
+            lightmap->get_light(request);
+            break;
         }
         break;
-      }
-      case SURFACE_PART:
-        draw_surface_part(request);
-        break;
-      case GRADIENT:
-        draw_gradient(request);
-        break;
-      case TEXT:
-        draw_text(request);
-        break;
-      case FILLRECT:
-        draw_filled_rect(request);
-        break;
-      case LIGHTMAPREQUEST:
-        draw_lightmap(request);
-        break;
-      case GETLIGHT:
-        get_light(request);
+      case LIGHTMAP:
+        switch(request.type) {
+          case SURFACE:
+            lightmap->draw_surface(request);
+            break;
+          case SURFACE_PART:
+            lightmap->draw_surface_part(request);
+            break;
+          case GRADIENT:
+            lightmap->draw_gradient(request);
+            break;
+          case TEXT:
+            lightmap->draw_text(request);
+            break;
+          case FILLRECT:
+            lightmap->draw_filled_rect(request);
+            break;
+          case GETLIGHT:
+            lightmap->get_light(request);
+            break;
+        }
         break;
     }
   }
+  requests.clear();
 }
 
 void
@@ -640,65 +468,6 @@ DrawingContext::set_ambient_color( Color new_color )
 }
 
 void 
-DrawingContext::do_take_screenshot()
-{
-  // [Christoph] TODO: Yes, this method also takes care of the actual disk I/O. Split it?
-
-  // create surface to hold screenshot
-  #if SDL_BYTEORDER == SDL_BIG_ENDIAN
-  SDL_Surface* shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x00FF0000, 0x0000FF00, 0x000000FF, 0);
-  #else
-  SDL_Surface* shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0);
-  #endif
-  if (!shot_surf) {
-    log_warning << "Could not create RGB Surface to contain screenshot" << std::endl;
-    return;
-  }
-
-  // read pixels into array
-  char* pixels = new char[3 * SCREEN_WIDTH * SCREEN_HEIGHT];
-  if (!pixels) {
-    log_warning << "Could not allocate memory to store screenshot" << std::endl;
-    SDL_FreeSurface(shot_surf);
-    return;
-  }
-  glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels);
-
-  // copy array line-by-line
-  for (int i = 0; i < SCREEN_HEIGHT; i++) {
-    char* src = pixels + (3 * SCREEN_WIDTH * (SCREEN_HEIGHT - i - 1));
-    char* dst = ((char*)shot_surf->pixels) + i * shot_surf->pitch;
-    memcpy(dst, src, 3 * SCREEN_WIDTH);
-  }
-
-  // free array
-  delete[](pixels);
-
-  // save screenshot
-  static const std::string writeDir = PHYSFS_getWriteDir();
-  static const std::string dirSep = PHYSFS_getDirSeparator();
-  static const std::string baseName = "screenshot";
-  static const std::string fileExt = ".bmp";
-  std::string fullFilename;
-  for (int num = 0; num < 1000; num++) {
-    std::ostringstream oss;
-    oss << baseName;
-    oss << std::setw(3) << std::setfill('0') << num;
-    oss << fileExt;
-    std::string fileName = oss.str();
-    fullFilename = writeDir + dirSep + fileName;
-    if (!PHYSFS_exists(fileName.c_str())) {
-      SDL_SaveBMP(shot_surf, fullFilename.c_str());
-      log_debug << "Wrote screenshot to \"" << fullFilename << "\"" << std::endl;
-      SDL_FreeSurface(shot_surf);
-      return;
-    }
-  }
-  log_warning << "Did not save screenshot, because all files up to \"" << fullFilename << "\" already existed" << std::endl;
-  SDL_FreeSurface(shot_surf);
-}
-
-void 
 DrawingContext::take_screenshot()
 {
   screenshot_requested = true;
index 296ea8e..c8f9012 100644 (file)
 
 #include <stdint.h>
 
-#include <GL/gl.h>
 #include <SDL_video.h>
 
+#include "glutil.hpp"
 #include "obstack/obstack.h"
 #include "math/vector.hpp"
 #include "math/rect.hpp"
-#include "surface.hpp"
+#include "drawing_request.hpp"
 #include "font.hpp"
 #include "color.hpp"
 
 class Surface;
 class Texture;
 struct DrawingRequest;
-
-// some constants for predefined layer values
-enum {
-  LAYER_BACKGROUND0 = -300,
-  LAYER_BACKGROUND1 = -200,
-  LAYER_BACKGROUNDTILES = -100,
-  LAYER_TILES = 0,
-  LAYER_OBJECTS = 50,
-  LAYER_FLOATINGOBJECTS = 150,
-  LAYER_FOREGROUNDTILES = 200,
-  LAYER_FOREGROUND0 = 300,
-  LAYER_FOREGROUND1 = 400,
-  LAYER_HUD = 500,
-  LAYER_GUI         = 600
-};
-
-class Blend
-{
-public:
-  GLenum sfactor;
-  GLenum dfactor;
-
-  Blend()
-    : sfactor(GL_SRC_ALPHA), dfactor(GL_ONE_MINUS_SRC_ALPHA)
-  {}
-
-  Blend(GLenum s, GLenum d)
-    : sfactor(s), dfactor(d)
-  {}
-};
+class Renderer;
+class Lightmap;
 
 /**
  * This class provides functions for drawing things on screen. It also
@@ -79,6 +51,8 @@ public:
   DrawingContext();
   ~DrawingContext();
 
+  void init_renderer();
+
   /// Adds a drawing request for a surface into the request list.
   void draw_surface(const Surface* surface, const Vector& position,
                     int layer);
@@ -129,9 +103,9 @@ public:
   /// on next update, set color to lightmap's color at position
   void get_light(const Vector& position, Color* color );
 
-  enum Target {
-    NORMAL, LIGHTMAP
-  };
+  typedef ::Target Target;
+  static const Target NORMAL = ::NORMAL;
+  static const Target LIGHTMAP = ::LIGHTMAP;
   void push_target();
   void pop_target();
   void set_target(Target target);
@@ -161,6 +135,9 @@ private:
     }
   };
 
+  Renderer *renderer;
+  Lightmap *lightmap;
+
   /// the transform stack
   std::vector<Transform> transformstack;
   /// the currently active transform
@@ -171,15 +148,7 @@ private:
 
   typedef std::vector<DrawingRequest*> DrawingRequests;
 
-  void handle_drawing_requests(DrawingRequests& requests) const;
-  void draw_surface_part(const DrawingRequest& request) const;
-  void draw_text(const DrawingRequest& request) const;
-  void draw_text_center(const DrawingRequest& request) const;
-  void draw_gradient(const DrawingRequest& request) const;
-  void draw_filled_rect(const DrawingRequest& request) const;
-  void draw_lightmap(const DrawingRequest& request) const;
-  void get_light(const DrawingRequest& request) const;
-  void do_take_screenshot();
+  void handle_drawing_requests(DrawingRequests& requests);
 
   DrawingRequests drawing_requests;
   DrawingRequests lightmap_requests;
@@ -187,12 +156,8 @@ private:
   DrawingRequests* requests;
   Color ambient_color;
 
-  SDL_Surface* screen;
   Target target;
   std::vector<Target> target_stack;
-  Texture* lightmap;
-  int lightmap_width, lightmap_height;
-  float lightmap_uv_right, lightmap_uv_bottom;
 
   /* obstack holding the memory of the drawing requests */
   struct obstack obst;
diff --git a/src/video/drawing_request.hpp b/src/video/drawing_request.hpp
new file mode 100644 (file)
index 0000000..24e0c02
--- /dev/null
@@ -0,0 +1,133 @@
+//  $Id: drawing_request.hpp 4986 2007-04-16 17:48:28Z matzeb $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef SUPERTUX_DRAWINGREQUEST_H
+#define SUPERTUX_DRAWINGREQUEST_H
+
+#include <vector>
+#include <string>
+#include <memory>
+
+#include <stdint.h>
+
+#include <SDL_video.h>
+
+#include "glutil.hpp"
+#include "math/vector.hpp"
+#include "color.hpp"
+#include "font.hpp"
+
+class Surface;
+
+// some constants for predefined layer values
+enum {
+  LAYER_BACKGROUND0 = -300,
+  LAYER_BACKGROUND1 = -200,
+  LAYER_BACKGROUNDTILES = -100,
+  LAYER_TILES = 0,
+  LAYER_OBJECTS = 50,
+  LAYER_FLOATINGOBJECTS = 150,
+  LAYER_FOREGROUNDTILES = 200,
+  LAYER_FOREGROUND0 = 300,
+  LAYER_FOREGROUND1 = 400,
+  LAYER_HUD = 500,
+  LAYER_GUI         = 600
+};
+
+class Blend
+{
+public:
+  GLenum sfactor;
+  GLenum dfactor;
+
+  Blend()
+    : sfactor(GL_SRC_ALPHA), dfactor(GL_ONE_MINUS_SRC_ALPHA)
+  {}
+
+  Blend(GLenum s, GLenum d)
+    : sfactor(s), dfactor(d)
+  {}
+};
+
+enum Target {
+  NORMAL, LIGHTMAP
+};
+
+enum RequestType
+{
+  SURFACE, SURFACE_PART, TEXT, GRADIENT, FILLRECT, GETLIGHT
+};
+
+struct SurfacePartRequest
+{
+  const Surface* surface;
+  Vector source, size;
+};
+
+struct TextRequest
+{
+  const Font* font;
+  std::string text;
+  FontAlignment alignment;
+};
+
+struct GradientRequest
+{
+  Color top, bottom;
+  Vector size;
+};
+
+struct FillRectRequest
+{
+  Color color;
+  Vector size;
+};
+
+struct DrawingRequest
+{
+  Target target;
+  RequestType type;
+  Vector pos;
+
+  int layer;
+  DrawingEffect drawing_effect;
+  float alpha;
+  Blend blend;
+  float angle;
+  Color color;
+
+  void* request_data;
+
+  DrawingRequest()
+    : angle(0.0f),
+      color(1.0f, 1.0f, 1.0f, 1.0f)
+  {}
+
+  bool operator<(const DrawingRequest& other) const
+  {
+    return layer < other.layer;
+  }
+};
+
+struct GetLightRequest
+{
+  Color* color_ptr;
+};
+
+#endif
+
index f967892..e5b6bb1 100644 (file)
@@ -31,6 +31,7 @@
 #include "lisp/lisp.hpp"
 #include "screen.hpp"
 #include "font.hpp"
+#include "renderer.hpp"
 #include "drawing_context.hpp"
 #include "log.hpp"
 
@@ -266,8 +267,9 @@ Font::wrap_to_width(const std::string& s, float width, std::string* overflow)
 }
 
 void
-Font::draw(const std::string& text, const Vector& pos_, FontAlignment alignment,
-           DrawingEffect drawing_effect, float alpha) const
+Font::draw(Renderer *renderer, const std::string& text, const Vector& pos_,
+           FontAlignment alignment, DrawingEffect drawing_effect,
+           float alpha) const
 {
   float x = pos_.x;
   float y = pos_.y;
@@ -291,7 +293,7 @@ Font::draw(const std::string& text, const Vector& pos_, FontAlignment alignment,
           // no bluring as we would get with subpixel positions
           pos.x = static_cast<int>(pos.x);
 
-          draw_text(temp, pos, drawing_effect, alpha);
+          draw_text(renderer, temp, pos, drawing_effect, alpha);
 
           if (i == text.size())
             break;
@@ -303,7 +305,7 @@ Font::draw(const std::string& text, const Vector& pos_, FontAlignment alignment,
 }
 
 void
-Font::draw_text(const std::string& text, const Vector& pos,
+Font::draw_text(Renderer *renderer, const std::string& text, const Vector& pos,
                 DrawingEffect drawing_effect, float alpha) const
 {
   if(shadowsize > 0)
@@ -311,11 +313,11 @@ Font::draw_text(const std::string& text, const Vector& pos,
       // FIXME: shadow_glyph_surface and glyph_surface do currently
       // share the same glyph array, this is incorrect and should be
       // fixed, it is however hardly noticable
-      draw_chars(shadow_glyph_surface, text, pos + Vector(shadowsize, shadowsize),
-                 drawing_effect, alpha);
+      draw_chars(renderer, shadow_glyph_surface, text,
+                 pos + Vector(shadowsize, shadowsize), drawing_effect, alpha);
     }
 
-  draw_chars(glyph_surface, text, pos, drawing_effect, alpha);
+  draw_chars(renderer, glyph_surface, text, pos, drawing_effect, alpha);
 }
 
 int
@@ -341,8 +343,9 @@ Font::chr2glyph(uint32_t chr) const
 }
 
 void
-Font::draw_chars(Surface* pchars, const std::string& text, const Vector& pos,
-                 DrawingEffect drawing_effect, float alpha) const
+Font::draw_chars(Renderer *renderer, Surface* pchars, const std::string& text,
+                 const Vector& pos, DrawingEffect drawing_effect,
+                 float alpha) const
 {
   Vector p = pos;
 
@@ -362,12 +365,20 @@ Font::draw_chars(Surface* pchars, const std::string& text, const Vector& pos,
       else
         {
           const Glyph& glyph = glyphs[font_index];
-          pchars->draw_part(glyph.rect.get_left(),
-                            glyph.rect.get_top(),
-                            p.x + glyph.offset.y,
-                            p.y + glyph.offset.y,
-                            glyph.rect.get_width(), glyph.rect.get_height(),
-                            alpha, drawing_effect);
+          DrawingRequest request;
+
+          request.pos = p + glyph.offset;
+          request.drawing_effect = drawing_effect;
+          request.alpha = alpha;
+
+          SurfacePartRequest surfacepartrequest;
+          surfacepartrequest.size = glyph.rect.p2 - glyph.rect.p1;
+          surfacepartrequest.source = glyph.rect.p1;
+          surfacepartrequest.surface = pchars;
+
+          request.request_data = &surfacepartrequest;
+          renderer->draw_surface_part(request);
+
           p.x += glyphs[font_index].advance;
         }
     }
index 1cf38eb..5625be1 100644 (file)
@@ -28,6 +28,8 @@
 #include "math/vector.hpp"
 #include "math/rect.hpp"
 
+class Renderer;
+
 enum FontAlignment {
   ALIGN_LEFT,
   ALIGN_CENTER,
@@ -85,7 +87,7 @@ public:
 
   /** Draws the given text to the screen. Also needs the position.
    * Type of alignment, drawing effect and alpha are optional. */
-  void draw(const std::string& text, const Vector& pos,
+  void draw(Renderer *renderer, const std::string& text, const Vector& pos,
             FontAlignment allignment = ALIGN_LEFT,
             DrawingEffect drawing_effect = NO_EFFECT,
             float alpha = 1.0f) const;
@@ -93,11 +95,11 @@ public:
 private:
   friend class DrawingContext;
 
-  void draw_text(const std::string& text, const Vector& pos,
+  void draw_text(Renderer *renderer, const std::string& text, const Vector& pos,
                  DrawingEffect drawing_effect = NO_EFFECT,
                  float alpha = 1.0f) const;
 
-  void draw_chars(Surface* pchars, const std::string& text,
+  void draw_chars(Renderer *renderer, Surface* pchars, const std::string& text,
                   const Vector& position, DrawingEffect drawing_effect,
                   float alpha) const;
 
diff --git a/src/video/gl_lightmap.cpp b/src/video/gl_lightmap.cpp
new file mode 100644 (file)
index 0000000..6649a0e
--- /dev/null
@@ -0,0 +1,317 @@
+//  $Id: gl_lightmap.cpp 5063 2007-05-27 11:32:00Z matzeb $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#ifdef HAVE_OPENGL
+
+#include <functional>
+#include <algorithm>
+#include <cassert>
+#include <math.h>
+#include <iostream>
+#include <SDL_image.h>
+#include <sstream>
+#include <iomanip>
+#include <physfs.h>
+
+#include "glutil.hpp"
+#include "gl_lightmap.hpp"
+#include "drawing_context.hpp"
+#include "drawing_request.hpp"
+#include "renderer.hpp"
+#include "surface.hpp"
+#include "font.hpp"
+#include "main.hpp"
+#include "gameconfig.hpp"
+#include "gl_texture.hpp"
+#include "texture_manager.hpp"
+#include "obstack/obstackpp.hpp"
+#define LIGHTMAP_DIV 5
+
+namespace
+{
+  inline void intern_draw(float left, float top, float right, float bottom,
+                                  float uv_left, float uv_top,
+                                  float uv_right, float uv_bottom,
+                                  float angle, float alpha,
+                                  const Color& color,
+                                  const Blend& blend,
+                                  DrawingEffect effect)
+  {
+    if(effect & HORIZONTAL_FLIP)
+      std::swap(uv_left, uv_right);
+    if(effect & VERTICAL_FLIP) {
+      std::swap(uv_top, uv_bottom);
+    }
+
+    float center_x = (left + right) / 2;
+    float center_y = (top + bottom) / 2;
+
+    float sa = sinf(angle/180.0f*M_PI);
+    float ca = cosf(angle/180.0f*M_PI);
+
+    left  -= center_x;
+    right -= center_x;
+
+    top    -= center_y;
+    bottom -= center_y;
+
+    glBlendFunc(blend.sfactor, blend.dfactor);
+    glColor4f(color.red, color.green, color.blue, color.alpha * alpha);
+    glBegin(GL_QUADS);
+    glTexCoord2f(uv_left, uv_top);
+    glVertex2f(left*ca - top*sa + center_x,
+               left*sa + top*ca + center_y);
+
+    glTexCoord2f(uv_right, uv_top);
+    glVertex2f(right*ca - top*sa + center_x,
+               right*sa + top*ca + center_y);
+
+    glTexCoord2f(uv_right, uv_bottom);
+    glVertex2f(right*ca - bottom*sa + center_x,
+               right*sa + bottom*ca + center_y);
+
+    glTexCoord2f(uv_left, uv_bottom);
+    glVertex2f(left*ca - bottom*sa + center_x,
+               left*sa + bottom*ca + center_y);
+    glEnd();
+
+    // FIXME: find a better way to restore the blend mode
+    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+  }
+}
+
+namespace GL
+{
+  static inline int next_po2(int val)
+  {
+    int result = 1;
+    while(result < val)
+      result *= 2;
+
+    return result;
+  }
+
+  Lightmap::Lightmap()
+  {
+    screen = SDL_GetVideoSurface();
+
+    lightmap_width = screen->w / LIGHTMAP_DIV;
+    lightmap_height = screen->h / LIGHTMAP_DIV;
+    unsigned int width = next_po2(lightmap_width);
+    unsigned int height = next_po2(lightmap_height);
+
+    lightmap = new Texture(width, height);
+
+    lightmap_uv_right = static_cast<float>(lightmap_width) / static_cast<float>(width);
+    lightmap_uv_bottom = static_cast<float>(lightmap_height) / static_cast<float>(height);
+    texture_manager->register_texture(lightmap);
+  }
+
+  Lightmap::~Lightmap()
+  {
+    texture_manager->remove_texture(lightmap);
+    delete lightmap;
+  }
+
+  void
+  Lightmap::start_draw(const Color &ambient_color)
+  {
+    glViewport(0, screen->h - lightmap_height, lightmap_width, lightmap_height);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    glClearColor( ambient_color.red, ambient_color.green, ambient_color.blue, 1 );
+    glClear(GL_COLOR_BUFFER_BIT);
+  }
+
+  void
+  Lightmap::end_draw()
+  {
+    glDisable(GL_BLEND);
+    glBindTexture(GL_TEXTURE_2D, lightmap->get_handle());
+    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, screen->h - lightmap_height, lightmap_width, lightmap_height);
+
+    glViewport(0, 0, screen->w, screen->h);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glEnable(GL_BLEND);
+    //glClear(GL_COLOR_BUFFER_BIT);
+  }
+
+  void
+  Lightmap::do_draw()
+  {
+    const Texture* texture = lightmap;
+
+    // multiple the lightmap with the framebuffer
+    glBlendFunc(GL_DST_COLOR, GL_ZERO);
+
+    glBindTexture(GL_TEXTURE_2D, texture->get_handle());
+    glBegin(GL_QUADS);
+
+    glTexCoord2f(0, lightmap_uv_bottom);
+    glVertex2f(0, 0);
+
+    glTexCoord2f(lightmap_uv_right, lightmap_uv_bottom);
+    glVertex2f(SCREEN_WIDTH, 0);
+
+    glTexCoord2f(lightmap_uv_right, 0);
+    glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
+
+    glTexCoord2f(0, 0);
+    glVertex2f(0, SCREEN_HEIGHT);
+
+    glEnd();
+
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+  }
+
+  void
+  Lightmap::draw_surface(const DrawingRequest& request)
+  {
+    const Surface* surface = (const Surface*) request.request_data;
+    GL::Texture *gltexture = dynamic_cast<GL::Texture *>(surface->get_texture());
+    glBindTexture(GL_TEXTURE_2D, gltexture->get_handle());
+    intern_draw(request.pos.x, request.pos.y,
+                request.pos.x + surface->get_width(),
+                request.pos.y + surface->get_height(),
+                surface->get_uv_left(),
+                surface->get_uv_top(),
+                surface->get_uv_right(),
+                surface->get_uv_bottom(),
+                request.angle,
+                request.alpha,
+                request.color,
+                request.blend,
+                request.drawing_effect);
+  }
+
+  void
+  Lightmap::draw_surface_part(const DrawingRequest& request)
+  {
+    const SurfacePartRequest* surfacepartrequest
+      = (SurfacePartRequest*) request.request_data;
+    const Surface *surface = surfacepartrequest->surface;
+    GL::Texture *gltexture = dynamic_cast<GL::Texture *>(surface->get_texture());
+
+    float uv_width = surface->get_uv_right() - surface->get_uv_left();
+    float uv_height = surface->get_uv_bottom() - surface->get_uv_top();
+
+    float uv_left = surface->get_uv_left() + (uv_width * surfacepartrequest->source.x) / surface->get_width();
+    float uv_top = surface->get_uv_top() + (uv_height * surfacepartrequest->source.y) / surface->get_height();
+    float uv_right = surface->get_uv_left() + (uv_width * (surfacepartrequest->source.x + surfacepartrequest->size.x)) / surface->get_width();
+    float uv_bottom = surface->get_uv_top() + (uv_height * (surfacepartrequest->source.y + surfacepartrequest->size.y)) / surface->get_height();
+
+    glBindTexture(GL_TEXTURE_2D, gltexture->get_handle());
+    intern_draw(request.pos.x, request.pos.y,
+                request.pos.x + surfacepartrequest->size.x,
+                request.pos.y + surfacepartrequest->size.y,
+                uv_left,
+                uv_top,
+                uv_right,
+                uv_bottom,
+                0.0,
+                request.alpha,
+                Color(1.0, 1.0, 1.0),
+                Blend(),
+                request.drawing_effect);
+  }
+
+  void
+  Lightmap::draw_gradient(const DrawingRequest& request)
+  {
+    const GradientRequest* gradientrequest 
+      = (GradientRequest*) request.request_data;
+    const Color& top = gradientrequest->top;
+    const Color& bottom = gradientrequest->bottom;
+
+    glDisable(GL_TEXTURE_2D);
+    glBegin(GL_QUADS);
+    glColor4f(top.red, top.green, top.blue, top.alpha);
+    glVertex2f(0, 0);
+    glVertex2f(SCREEN_WIDTH, 0);
+    glColor4f(bottom.red, bottom.green, bottom.blue, bottom.alpha);
+    glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
+    glVertex2f(0, SCREEN_HEIGHT);
+    glEnd();
+    glEnable(GL_TEXTURE_2D);
+    glColor4f(1, 1, 1, 1);
+  }
+
+  void
+  Lightmap::draw_text(const DrawingRequest& /*request*/)
+  {
+    //const TextRequest* textrequest = (TextRequest*) request.request_data;
+
+    //textrequest->font->draw(textrequest->text, request.pos,
+    //    textrequest->alignment, request.drawing_effect, request.alpha);
+  }
+
+  void
+  Lightmap::draw_filled_rect(const DrawingRequest& request)
+  {
+    const FillRectRequest* fillrectrequest
+      = (FillRectRequest*) request.request_data;
+
+    float x = request.pos.x;
+    float y = request.pos.y;
+    float w = fillrectrequest->size.x;
+    float h = fillrectrequest->size.y;
+
+    glDisable(GL_TEXTURE_2D);
+    glColor4f(fillrectrequest->color.red, fillrectrequest->color.green,
+              fillrectrequest->color.blue, fillrectrequest->color.alpha);
+
+    glBegin(GL_QUADS);
+    glVertex2f(x, y);
+    glVertex2f(x+w, y);
+    glVertex2f(x+w, y+h);
+    glVertex2f(x, y+h);
+    glEnd();
+    glEnable(GL_TEXTURE_2D);
+    glColor4f(1, 1, 1, 1);
+  }
+
+  void
+  Lightmap::get_light(const DrawingRequest& request) const
+  {
+    const GetLightRequest* getlightrequest 
+      = (GetLightRequest*) request.request_data;
+
+    float pixels[3];
+    for( int i = 0; i<3; i++)
+      pixels[i] = 0.0f; //set to black
+
+    float posX = request.pos.x * lightmap_width / SCREEN_WIDTH;
+    float posY = screen->h - request.pos.y * lightmap_height / SCREEN_HEIGHT;
+    glReadPixels((GLint) posX, (GLint) posY , 1, 1, GL_RGB, GL_FLOAT, pixels);
+    *(getlightrequest->color_ptr) = Color( pixels[0], pixels[1], pixels[2]);
+    //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]);
+  }
+}
+
+#endif
diff --git a/src/video/gl_lightmap.hpp b/src/video/gl_lightmap.hpp
new file mode 100644 (file)
index 0000000..dd5b131
--- /dev/null
@@ -0,0 +1,61 @@
+//  $Id: gl_lightmap.hpp 4986 2007-04-16 17:48:28Z matzeb $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#ifdef HAVE_OPENGL
+
+#ifndef SUPERTUX_GL_LIGHTMAP_H
+#define SUPERTUX_GL_LIGHTMAP_H
+
+#include <SDL_video.h>
+
+#include "lightmap.hpp"
+
+struct DrawingRequest;
+
+namespace GL
+{
+  class Texture;
+  class Lightmap : public ::Lightmap
+  {
+  public:
+    Lightmap();
+    ~Lightmap();
+
+    void start_draw(const Color &ambient_color);
+    void end_draw();
+    void do_draw();
+    void draw_surface(const DrawingRequest& request);
+    void draw_surface_part(const DrawingRequest& request);
+    void draw_text(const DrawingRequest& request);
+    void draw_gradient(const DrawingRequest& request);
+    void draw_filled_rect(const DrawingRequest& request);
+    void get_light(const DrawingRequest& request) const;
+
+  private:
+    SDL_Surface* screen;
+    Texture* lightmap;
+    int lightmap_width, lightmap_height;
+    float lightmap_uv_right, lightmap_uv_bottom;
+  };
+}
+
+#endif
+
+#endif
diff --git a/src/video/gl_renderer.cpp b/src/video/gl_renderer.cpp
new file mode 100644 (file)
index 0000000..8158874
--- /dev/null
@@ -0,0 +1,336 @@
+//  $Id: gl_renderer.cpp 5063 2007-05-27 11:32:00Z matzeb $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#ifdef HAVE_OPENGL
+
+#include <functional>
+#include <algorithm>
+#include <cassert>
+#include <math.h>
+#include <iostream>
+#include <SDL_image.h>
+#include <sstream>
+#include <iomanip>
+#include <physfs.h>
+
+#include "glutil.hpp"
+#include "gl_renderer.hpp"
+#include "gl_texture.hpp"
+#include "drawing_context.hpp"
+#include "drawing_request.hpp"
+#include "surface.hpp"
+#include "font.hpp"
+#include "main.hpp"
+#include "gameconfig.hpp"
+#include "texture.hpp"
+#include "texture_manager.hpp"
+#include "obstack/obstackpp.hpp"
+#define LIGHTMAP_DIV 5
+
+namespace
+{
+  inline void intern_draw(float left, float top, float right, float bottom,
+                                  float uv_left, float uv_top,
+                                  float uv_right, float uv_bottom,
+                                  float angle, float alpha,
+                                  const Color& color,
+                                  const Blend& blend,
+                                  DrawingEffect effect)
+  {
+    if(effect & HORIZONTAL_FLIP)
+      std::swap(uv_left, uv_right);
+    if(effect & VERTICAL_FLIP) {
+      std::swap(uv_top, uv_bottom);
+    }
+
+    float center_x = (left + right) / 2;
+    float center_y = (top + bottom) / 2;
+
+    float sa = sinf(angle/180.0f*M_PI);
+    float ca = cosf(angle/180.0f*M_PI);
+
+    left  -= center_x;
+    right -= center_x;
+
+    top    -= center_y;
+    bottom -= center_y;
+
+    glBlendFunc(blend.sfactor, blend.dfactor);
+    glColor4f(color.red, color.green, color.blue, color.alpha * alpha);
+    glBegin(GL_QUADS);
+    glTexCoord2f(uv_left, uv_top);
+    glVertex2f(left*ca - top*sa + center_x,
+               left*sa + top*ca + center_y);
+
+    glTexCoord2f(uv_right, uv_top);
+    glVertex2f(right*ca - top*sa + center_x,
+               right*sa + top*ca + center_y);
+
+    glTexCoord2f(uv_right, uv_bottom);
+    glVertex2f(right*ca - bottom*sa + center_x,
+               right*sa + bottom*ca + center_y);
+
+    glTexCoord2f(uv_left, uv_bottom);
+    glVertex2f(left*ca - bottom*sa + center_x,
+               left*sa + bottom*ca + center_y);
+    glEnd();
+
+    // FIXME: find a better way to restore the blend mode
+    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+  }
+}
+
+namespace GL
+{
+  Renderer::Renderer()
+  {
+    if(texture_manager != 0)
+      texture_manager->save_textures();
+
+    if(config->try_vsync) {
+      /* we want vsync for smooth scrolling */
+    SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
+    }
+
+    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
+    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
+    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
+
+    int flags = SDL_OPENGL;
+    if(config->use_fullscreen)
+      flags |= SDL_FULLSCREEN;
+    int width = config->screenwidth;
+    int height = config->screenheight;
+    int bpp = 0;
+
+    SDL_Surface *screen = SDL_SetVideoMode(width, height, bpp, flags);
+    if(screen == 0) {
+      std::stringstream msg;
+      msg << "Couldn't set video mode (" << width << "x" << height
+          << "-" << bpp << "bpp): " << SDL_GetError();
+      throw std::runtime_error(msg.str());
+    }
+
+    // setup opengl state and transform
+    glDisable(GL_DEPTH_TEST);
+    glDisable(GL_CULL_FACE);
+    glEnable(GL_TEXTURE_2D);
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    glViewport(0, 0, screen->w, screen->h);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    // logical resolution here not real monitor resolution
+    glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glTranslatef(0, 0, 0);
+
+    check_gl_error("Setting up view matrices");
+
+
+    if(texture_manager == 0)
+      texture_manager = new TextureManager();
+    else
+      texture_manager->reload_textures();
+  }
+
+  Renderer::~Renderer()
+  {
+  }
+
+  void
+  Renderer::draw_surface(const DrawingRequest& request)
+  {
+    const Surface* surface = (const Surface*) request.request_data;
+    GL::Texture *gltexture = dynamic_cast<GL::Texture *>(surface->get_texture());
+    glBindTexture(GL_TEXTURE_2D, gltexture->get_handle());
+    intern_draw(request.pos.x, request.pos.y,
+                request.pos.x + surface->get_width(),
+                request.pos.y + surface->get_height(),
+                surface->get_uv_left(),
+                surface->get_uv_top(),
+                surface->get_uv_right(),
+                surface->get_uv_bottom(),
+                request.angle,
+                request.alpha,
+                request.color,
+                request.blend,
+                request.drawing_effect);
+  }
+
+  void
+  Renderer::draw_surface_part(const DrawingRequest& request)
+  {
+    const SurfacePartRequest* surfacepartrequest
+      = (SurfacePartRequest*) request.request_data;
+    const Surface *surface = surfacepartrequest->surface;
+    GL::Texture *gltexture = dynamic_cast<GL::Texture *>(surface->get_texture());
+
+    float uv_width = surface->get_uv_right() - surface->get_uv_left();
+    float uv_height = surface->get_uv_bottom() - surface->get_uv_top();
+
+    float uv_left = surface->get_uv_left() + (uv_width * surfacepartrequest->source.x) / surface->get_width();
+    float uv_top = surface->get_uv_top() + (uv_height * surfacepartrequest->source.y) / surface->get_height();
+    float uv_right = surface->get_uv_left() + (uv_width * (surfacepartrequest->source.x + surfacepartrequest->size.x)) / surface->get_width();
+    float uv_bottom = surface->get_uv_top() + (uv_height * (surfacepartrequest->source.y + surfacepartrequest->size.y)) / surface->get_height();
+
+    glBindTexture(GL_TEXTURE_2D, gltexture->get_handle());
+    intern_draw(request.pos.x, request.pos.y,
+                request.pos.x + surfacepartrequest->size.x,
+                request.pos.y + surfacepartrequest->size.y,
+                uv_left,
+                uv_top,
+                uv_right,
+                uv_bottom,
+                0.0,
+                request.alpha,
+                Color(1.0, 1.0, 1.0),
+                Blend(),
+                request.drawing_effect);
+  }
+
+  void
+  Renderer::draw_gradient(const DrawingRequest& request)
+  {
+    const GradientRequest* gradientrequest 
+      = (GradientRequest*) request.request_data;
+    const Color& top = gradientrequest->top;
+    const Color& bottom = gradientrequest->bottom;
+
+    glDisable(GL_TEXTURE_2D);
+    glBegin(GL_QUADS);
+    glColor4f(top.red, top.green, top.blue, top.alpha);
+    glVertex2f(0, 0);
+    glVertex2f(SCREEN_WIDTH, 0);
+    glColor4f(bottom.red, bottom.green, bottom.blue, bottom.alpha);
+    glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
+    glVertex2f(0, SCREEN_HEIGHT);
+    glEnd();
+    glEnable(GL_TEXTURE_2D);
+    glColor4f(1, 1, 1, 1);
+  }
+
+  void
+  Renderer::draw_text(const DrawingRequest& request)
+  {
+    const TextRequest* textrequest = (TextRequest*) request.request_data;
+
+    textrequest->font->draw(this, textrequest->text, request.pos,
+        textrequest->alignment, request.drawing_effect, request.alpha);
+  }
+
+  void
+  Renderer::draw_filled_rect(const DrawingRequest& request)
+  {
+    const FillRectRequest* fillrectrequest
+      = (FillRectRequest*) request.request_data;
+
+    float x = request.pos.x;
+    float y = request.pos.y;
+    float w = fillrectrequest->size.x;
+    float h = fillrectrequest->size.y;
+
+    glDisable(GL_TEXTURE_2D);
+    glColor4f(fillrectrequest->color.red, fillrectrequest->color.green,
+              fillrectrequest->color.blue, fillrectrequest->color.alpha);
+
+    glBegin(GL_QUADS);
+    glVertex2f(x, y);
+    glVertex2f(x+w, y);
+    glVertex2f(x+w, y+h);
+    glVertex2f(x, y+h);
+    glEnd();
+    glEnable(GL_TEXTURE_2D);
+    glColor4f(1, 1, 1, 1);
+  }
+
+  void 
+  Renderer::do_take_screenshot()
+  {
+    // [Christoph] TODO: Yes, this method also takes care of the actual disk I/O. Split it?
+
+    SDL_Surface *shot_surf;
+    // create surface to hold screenshot
+    #if SDL_BYTEORDER == SDL_BIG_ENDIAN
+    shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x00FF0000, 0x0000FF00, 0x000000FF, 0);
+    #else
+    shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0);
+    #endif
+    if (!shot_surf) {
+      log_warning << "Could not create RGB Surface to contain screenshot" << std::endl;
+      return;
+    }
+
+    // read pixels into array
+    char* pixels = new char[3 * SCREEN_WIDTH * SCREEN_HEIGHT];
+    if (!pixels) {
+      log_warning << "Could not allocate memory to store screenshot" << std::endl;
+      SDL_FreeSurface(shot_surf);
+      return;
+    }
+    glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels);
+
+    // copy array line-by-line
+    for (int i = 0; i < SCREEN_HEIGHT; i++) {
+      char* src = pixels + (3 * SCREEN_WIDTH * (SCREEN_HEIGHT - i - 1));
+      char* dst = ((char*)shot_surf->pixels) + i * shot_surf->pitch;
+      memcpy(dst, src, 3 * SCREEN_WIDTH);
+    }
+
+    // free array
+    delete[](pixels);
+
+    // save screenshot
+    static const std::string writeDir = PHYSFS_getWriteDir();
+    static const std::string dirSep = PHYSFS_getDirSeparator();
+    static const std::string baseName = "screenshot";
+    static const std::string fileExt = ".bmp";
+    std::string fullFilename;
+    for (int num = 0; num < 1000; num++) {
+      std::ostringstream oss;
+      oss << baseName;
+      oss << std::setw(3) << std::setfill('0') << num;
+      oss << fileExt;
+      std::string fileName = oss.str();
+      fullFilename = writeDir + dirSep + fileName;
+      if (!PHYSFS_exists(fileName.c_str())) {
+        SDL_SaveBMP(shot_surf, fullFilename.c_str());
+        log_debug << "Wrote screenshot to \"" << fullFilename << "\"" << std::endl;
+        SDL_FreeSurface(shot_surf);
+        return;
+      }
+    }
+    log_warning << "Did not save screenshot, because all files up to \"" << fullFilename << "\" already existed" << std::endl;
+    SDL_FreeSurface(shot_surf);
+  }
+
+  void
+  Renderer::flip()
+  {
+    assert_gl("drawing");
+    SDL_GL_SwapBuffers();
+  }
+}
+
+#endif
diff --git a/src/video/gl_renderer.hpp b/src/video/gl_renderer.hpp
new file mode 100644 (file)
index 0000000..1eef6b4
--- /dev/null
@@ -0,0 +1,48 @@
+//  $Id: gl_renderer.hpp 4986 2007-04-16 17:48:28Z matzeb $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#ifdef HAVE_OPENGL
+
+#ifndef SUPERTUX_GL_RENDERER_H
+#define SUPERTUX_GL_RENDERER_H
+
+#include "renderer.hpp"
+
+namespace GL
+{
+  class Renderer : public ::Renderer
+  {
+  public:
+    Renderer();
+    ~Renderer();
+
+    void draw_surface(const DrawingRequest& request);
+    void draw_surface_part(const DrawingRequest& request);
+    void draw_text(const DrawingRequest& request);
+    void draw_gradient(const DrawingRequest& request);
+    void draw_filled_rect(const DrawingRequest& request);
+    void do_take_screenshot();
+    void flip();
+  };
+}
+
+#endif
+
+#endif
diff --git a/src/video/gl_texture.cpp b/src/video/gl_texture.cpp
new file mode 100644 (file)
index 0000000..e9d72d0
--- /dev/null
@@ -0,0 +1,146 @@
+//  $Id: gl_texture.cpp 4063 2006-07-21 21:05:23Z anmaster $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+#include <config.h>
+
+#ifdef HAVE_OPENGL
+
+#include "gl_texture.hpp"
+#include "gameconfig.hpp"
+#include "glutil.hpp"
+#include "log.hpp"
+
+#include <assert.h>
+#include <stdexcept>
+
+namespace
+{
+  inline bool is_power_of_2(int v)
+  {
+    return (v & (v-1)) == 0;
+  }
+
+  inline int next_power_of_two(int val)
+  {
+    int result = 1;
+    while(result < val)
+      result *= 2;
+    return result;
+  }
+}
+
+namespace GL
+{
+  Texture::Texture(unsigned int width, unsigned int height)
+  {
+    assert(is_power_of_2(width));
+    assert(is_power_of_2(height));
+    texture_width = width;
+    texture_height = height;
+    image_width = width;
+    image_height = height;
+
+    assert_gl("before creating texture");
+    glGenTextures(1, &handle);
+
+    try {
+      glBindTexture(GL_TEXTURE_2D, handle);
+
+      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_width,
+                   texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+
+      set_texture_params();
+    } catch(...) {
+      glDeleteTextures(1, &handle);
+      throw;
+    }
+  }
+
+  Texture::Texture(SDL_Surface* image)
+  {
+    texture_width = next_power_of_two(image->w);
+    texture_height = next_power_of_two(image->h);
+    image_width = image->w;
+    image_height = image->h;
+
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+    SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
+        texture_width, texture_height, 32,
+        0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
+#else
+    SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
+        texture_width, texture_height, 32,
+        0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
+#endif
+
+    if(convert == 0) {
+      throw std::runtime_error("Couldn't create texture: out of memory");
+    }
+
+    SDL_SetAlpha(image, 0, 0);
+    SDL_BlitSurface(image, 0, convert, 0);
+
+    assert_gl("before creating texture");
+    glGenTextures(1, &handle);
+
+    try {
+      GLenum sdl_format;
+      if(convert->format->BytesPerPixel == 3)
+        sdl_format = GL_RGB;
+      else if(convert->format->BytesPerPixel == 4)
+        sdl_format = GL_RGBA;
+      else
+        assert(false);
+
+      glBindTexture(GL_TEXTURE_2D, handle);
+      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+      glPixelStorei(GL_UNPACK_ROW_LENGTH, convert->pitch/convert->format->BytesPerPixel);
+      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_width,
+              texture_height, 0, sdl_format,
+              GL_UNSIGNED_BYTE, convert->pixels);
+
+      assert_gl("creating texture");
+
+      set_texture_params();
+    } catch(...) {
+      glDeleteTextures(1, &handle);
+      SDL_FreeSurface(convert);
+      throw;
+    }
+    SDL_FreeSurface(convert);
+  }
+
+  Texture::~Texture()
+  {
+    glDeleteTextures(1, &handle);
+  }
+
+  void
+  Texture::set_texture_params()
+  {
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+    assert_gl("set texture params");
+  }
+}
+
+#endif
diff --git a/src/video/gl_texture.hpp b/src/video/gl_texture.hpp
new file mode 100644 (file)
index 0000000..14532cc
--- /dev/null
@@ -0,0 +1,97 @@
+//  $Id: gl_texture.hpp 4063 2006-07-21 21:05:23Z anmaster $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#ifdef HAVE_OPENGL
+
+#ifndef __GL_TEXTURE_HPP__
+#define __GL_TEXTURE_HPP__
+
+#include <SDL.h>
+
+#include "texture.hpp"
+#include "glutil.hpp"
+
+/**
+ * This class is a wrapper around a texture handle. It stores the texture width
+ * and height and provides convenience functions for uploading SDL_Surfaces
+ * into the texture
+ */
+namespace GL
+{
+  class Texture : public ::Texture
+  {
+  protected:
+    GLuint handle;
+    unsigned int texture_width;
+    unsigned int texture_height;
+    unsigned int image_width;
+    unsigned int image_height;
+
+  public:
+    Texture(unsigned int width, unsigned int height);
+    Texture(SDL_Surface* image);
+    ~Texture();
+
+    const GLuint &get_handle() const {
+      return handle;
+    }
+
+    void set_handle(GLuint handle) {
+      this->handle = handle;
+    }
+
+    unsigned int get_texture_width() const
+    {
+      return texture_width;
+    }
+
+    unsigned int get_texture_height() const
+    {
+      return texture_height;
+    }
+
+    unsigned int get_image_width() const
+    {
+      return image_width;
+    }
+
+    unsigned int get_image_height() const
+    {
+      return image_height;
+    }
+
+    void set_image_width(unsigned int width)
+    {
+      image_width = width;
+    }
+
+    void set_image_height(unsigned int height)
+    {
+      image_height = height;
+    }
+
+  private:
+    void set_texture_params();
+  };
+}
+
+#endif
+
+#endif
index 90dd525..b19ce8b 100644 (file)
 #ifndef __GLUTIL_HPP__
 #define __GLUTIL_HPP__
 
+#include <config.h>
+
+#ifdef HAVE_OPENGL
+
 #include <sstream>
 #include <stdexcept>
 #include <GL/gl.h>
+#include <GL/glext.h>
 
 static inline void check_gl_error(const char* message)
 {
@@ -77,4 +82,15 @@ static inline void assert_gl(const char* message)
 #endif
 }
 
+#else
+
+#define GLenum int
+#define GLint int
+#define GL_SRC_ALPHA 0
+#define GL_ONE_MINUS_SRC_ALPHA 1
+#define GL_RGBA 2
+#define GL_ONE 3
+
+#endif
+
 #endif
index 445fdc8..c9a0de1 100644 (file)
@@ -17,6 +17,7 @@
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
+#if 0
 #include <config.h>
 
 #include "image_texture.hpp"
@@ -36,3 +37,4 @@ ImageTexture::release()
 {
   texture_manager->release(this);
 }
+#endif
index dccc9bf..9d32f76 100644 (file)
@@ -17,6 +17,7 @@
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
+#if 0
 #ifndef __SURFACE_TEXTURE_HPP__
 #define __SURFACE_TEXTURE_HPP__
 
@@ -76,3 +77,4 @@ private:
 };
 
 #endif
+#endif
diff --git a/src/video/lightmap.hpp b/src/video/lightmap.hpp
new file mode 100644 (file)
index 0000000..bca28d4
--- /dev/null
@@ -0,0 +1,59 @@
+//  $Id: lightmap.hpp 4986 2007-04-16 17:48:28Z matzeb $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef SUPERTUX_LIGHTMAP_H
+#define SUPERTUX_LIGHTMAP_H
+
+#include <vector>
+#include <string>
+#include <memory>
+
+#include <stdint.h>
+
+#include <SDL_video.h>
+
+#include "glutil.hpp"
+#include "obstack/obstack.h"
+#include "math/vector.hpp"
+#include "math/rect.hpp"
+#include "drawing_request.hpp"
+#include "surface.hpp"
+#include "font.hpp"
+#include "color.hpp"
+
+class Texture;
+struct DrawingRequest;
+
+class Lightmap
+{
+public:
+  virtual ~Lightmap() {}
+
+  virtual void start_draw(const Color &ambient_color) = 0;
+  virtual void end_draw() = 0;
+  virtual void do_draw() = 0;
+  virtual void draw_surface(const DrawingRequest& request) = 0;
+  virtual void draw_surface_part(const DrawingRequest& request) = 0;
+  virtual void draw_text(const DrawingRequest& request) = 0;
+  virtual void draw_gradient(const DrawingRequest& request) = 0;
+  virtual void draw_filled_rect(const DrawingRequest& request) = 0;
+  virtual void get_light(const DrawingRequest& request) const = 0;
+};
+
+#endif
+
diff --git a/src/video/renderer.hpp b/src/video/renderer.hpp
new file mode 100644 (file)
index 0000000..c1f10bf
--- /dev/null
@@ -0,0 +1,57 @@
+//  $Id: drawing_context.hpp 4986 2007-04-16 17:48:28Z matzeb $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef SUPERTUX_RENDERER_H
+#define SUPERTUX_RENDERER_H
+
+#include <vector>
+#include <string>
+#include <memory>
+
+#include <stdint.h>
+
+#include <SDL_video.h>
+
+#include "glutil.hpp"
+#include "obstack/obstack.h"
+#include "math/vector.hpp"
+#include "math/rect.hpp"
+#include "surface.hpp"
+#include "font.hpp"
+#include "color.hpp"
+
+class Surface;
+class Texture;
+struct DrawingRequest;
+
+class Renderer
+{
+public:
+  virtual ~Renderer() {}
+
+  virtual void draw_surface(const DrawingRequest& request) = 0;
+  virtual void draw_surface_part(const DrawingRequest& request) = 0;
+  virtual void draw_text(const DrawingRequest& request) = 0;
+  virtual void draw_gradient(const DrawingRequest& request) = 0;
+  virtual void draw_filled_rect(const DrawingRequest& request)= 0;
+  virtual void do_take_screenshot() = 0;
+  virtual void flip() = 0;
+};
+
+#endif
+
diff --git a/src/video/sdl_lightmap.cpp b/src/video/sdl_lightmap.cpp
new file mode 100644 (file)
index 0000000..0d19c48
--- /dev/null
@@ -0,0 +1,389 @@
+//  $Id: sdl_lightmap.cpp 5063 2007-05-27 11:32:00Z matzeb $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#include <functional>
+#include <algorithm>
+#include <cassert>
+#include <iostream>
+#include <SDL_image.h>
+#include <sstream>
+#include <iomanip>
+#include <physfs.h>
+
+#include "glutil.hpp"
+#include "sdl_lightmap.hpp"
+#include "sdl_texture.hpp"
+#include "drawing_context.hpp"
+#include "drawing_request.hpp"
+#include "renderer.hpp"
+#include "surface.hpp"
+#include "font.hpp"
+#include "main.hpp"
+#include "gameconfig.hpp"
+#include "texture.hpp"
+#include "texture_manager.hpp"
+#include "obstack/obstackpp.hpp"
+
+namespace SDL
+{
+  Lightmap::Lightmap()
+  {
+    screen = SDL_GetVideoSurface();
+
+    width = screen->w;
+    height = screen->h;
+
+    red_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
+    green_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
+    blue_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
+  }
+
+  Lightmap::~Lightmap()
+  {
+    free(red_channel);
+    free(green_channel);
+    free(blue_channel);
+  }
+
+  void
+  Lightmap::start_draw(const Color &ambient_color)
+  {
+    memset(red_channel, (Uint8) (ambient_color.red * 255), width * height * sizeof(Uint8));
+    memset(green_channel, (Uint8) (ambient_color.green * 255), width * height * sizeof(Uint8));
+    memset(blue_channel, (Uint8) (ambient_color.blue * 255), width * height * sizeof(Uint8));
+  }
+
+  void
+  Lightmap::end_draw()
+  {
+  }
+
+  void
+  Lightmap::do_draw()
+  {
+    // FIXME: This is really slow
+    int bpp = screen->format->BytesPerPixel;
+    for(int y = 0;y < height;y++) {
+      for(int x = 0;x < width;x++) {
+        int loc = y * width + x;
+        if(red_channel[loc] == 255 && green_channel[loc] == 255 && blue_channel[loc] == 255)
+        {
+          continue;
+        }
+        Uint8 *pixel = (Uint8 *) screen->pixels + y * screen->pitch + x * bpp;
+        Uint32 mapped = 0;
+        switch(bpp) {
+          case 1:
+            mapped = *pixel;
+            break;
+          case 2:
+            mapped = *(Uint16 *)pixel;
+            break;
+          case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+            mapped |= pixel[0] << 16;
+            mapped |= pixel[1] << 8;
+            mapped |= pixel[2] << 0;
+#else
+            mapped |= pixel[0] << 0;
+            mapped |= pixel[1] << 8;
+            mapped |= pixel[2] << 16;
+#endif
+            break;
+          case 4:
+            mapped = *(Uint32 *)pixel;
+            break;
+        }
+        Uint8 red, green, blue, alpha;
+        SDL_GetRGBA(mapped, screen->format, &red, &green, &blue, &alpha);
+        red = (red * red_channel[loc]) / 255;
+        green = (green * green_channel[loc]) / 255;
+        blue = (blue * blue_channel[loc]) / 255;
+        mapped = SDL_MapRGBA(screen->format, red, green, blue, alpha);
+        switch(bpp) {
+          case 1:
+            *pixel = mapped;
+            break;
+          case 2:
+            *(Uint16 *)pixel = mapped;
+            break;
+          case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+            pixel[0] = (mapped >> 16) & 0xff;
+            pixel[1] = (mapped >> 8) & 0xff;
+            pixel[2] = (mapped >> 0) & 0xff;
+#else
+            pixel[0] = (mapped >> 0) & 0xff;
+            pixel[1] = (mapped >> 8) & 0xff;
+            pixel[2] = (mapped >> 16) & 0xff;
+#endif
+            break;
+          case 4:
+            *(Uint32 *)pixel = mapped;
+            break;
+        }
+      }
+    }
+  }
+
+  void Lightmap::light_blit(SDL_Surface *src, int dstx, int dsty,
+                            int srcx, int srcy, int blit_width, int blit_height)
+  {
+    for(int y = 0;y < blit_height;y++) {
+      for(int x = 0;x < blit_width;x++) {
+        if(x + dstx < 0 || y + dsty < 0 || x + dstx >= width || y + dsty >= height)
+        {
+          continue;
+        }
+        int loc = (y + dsty) * width + (x + dstx);
+        if(red_channel[loc] == 255 && green_channel[loc] == 255 && blue_channel[loc])
+        {
+          continue;
+        }
+
+        Uint8 *pixel = (Uint8 *) src->pixels + (y + srcy) * src->pitch + (x + srcx) * src->format->BytesPerPixel;
+        Uint32 mapped = 0;
+        switch(src->format->BytesPerPixel) {
+          case 1:
+            mapped = *pixel;
+            break;
+          case 2:
+            mapped = *(Uint16 *)pixel;
+            break;
+          case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+            mapped |= pixel[0] << 16;
+            mapped |= pixel[1] << 8;
+            mapped |= pixel[2] << 0;
+#else
+            mapped |= pixel[0] << 0;
+            mapped |= pixel[1] << 8;
+            mapped |= pixel[2] << 16;
+#endif
+            break;
+          case 4:
+            mapped = *(Uint32 *)pixel;
+            break;
+        }
+        Uint8 red, green, blue, alpha;
+        SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
+
+        red_channel[loc] = std::min(red_channel[loc] + (red * alpha / 255), 255);
+        green_channel[loc] = std::min(green_channel[loc] + (green * alpha / 255), 255);
+        blue_channel[loc] = std::min(blue_channel[loc] + (blue * alpha / 255), 255);
+      }
+    }
+  }
+
+  void
+  Lightmap::draw_surface(const DrawingRequest& request)
+  {
+    if((request.color.red == 0.0 && request.color.green == 0.0 && request.color.blue == 0.0) || request.color.alpha == 0.0 || request.alpha == 0.0)
+    {
+      return;
+    }
+    //FIXME: support parameters request.alpha, request.angle, request.blend
+    const Surface* surface = (const Surface*) request.request_data;
+    SDL::Texture *sdltexture = dynamic_cast<SDL::Texture *>(surface->get_texture());
+    DrawingEffect effect = request.drawing_effect;
+    if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
+
+    SDL_Surface *transform = sdltexture->get_transform(request.color, effect);
+
+    // get and check SDL_Surface
+    if (transform == 0) {
+      std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
+      return;
+    }  
+
+    int ox, oy;
+    if (effect == HORIZONTAL_FLIP)
+    {
+      ox = sdltexture->get_texture_width() - surface->get_x() - surface->get_width();
+    }
+    else
+    {
+      ox = surface->get_x();
+    }
+    if (effect == VERTICAL_FLIP)
+    {
+      oy = sdltexture->get_texture_height() - surface->get_y() - surface->get_height();
+    }
+    else
+    {
+      oy = surface->get_y();
+    }
+
+    int numerator, denominator;
+    float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
+    float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
+    if(xfactor < yfactor)
+    {
+      numerator = config->screenwidth;
+      denominator = SCREEN_WIDTH;
+    }
+    else
+    {
+      numerator = config->screenheight;
+      denominator = SCREEN_HEIGHT;
+    }
+
+    int dstx = (int) request.pos.x * numerator / denominator;
+    int dsty = (int) request.pos.y * numerator / denominator;
+    int srcx = ox * numerator / denominator;
+    int srcy = oy * numerator / denominator;
+    int blit_width = surface->get_width() * numerator / denominator;
+    int blit_height = surface->get_height() * numerator / denominator;
+    light_blit(transform, dstx, dsty, srcx, srcy, blit_width, blit_height);
+  }
+
+  void
+  Lightmap::draw_surface_part(const DrawingRequest& request)
+  {
+    const SurfacePartRequest* surfacepartrequest
+      = (SurfacePartRequest*) request.request_data;
+
+    const Surface* surface = surfacepartrequest->surface;
+    SDL::Texture *sdltexture = dynamic_cast<SDL::Texture *>(surface->get_texture());
+    DrawingEffect effect = request.drawing_effect;
+    if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
+
+    SDL_Surface *transform = sdltexture->get_transform(Color(1.0, 1.0, 1.0), effect);
+
+    // get and check SDL_Surface
+    if (transform == 0) {
+      std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
+      return;
+    }  
+
+    int ox, oy;
+    if (effect == HORIZONTAL_FLIP)
+    {
+      ox = sdltexture->get_texture_width() - surface->get_x() - (int) surfacepartrequest->size.x;
+    }
+    else
+    {
+      ox = surface->get_x();
+    }
+    if (effect == VERTICAL_FLIP)
+    {
+      oy = sdltexture->get_texture_height() - surface->get_y() - (int) surfacepartrequest->size.y;
+    }
+    else
+    {
+      oy = surface->get_y();
+    }
+
+    int numerator, denominator;
+    float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
+    float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
+    if(xfactor < yfactor)
+    {
+      numerator = config->screenwidth;
+      denominator = SCREEN_WIDTH;
+    }
+    else
+    {
+      numerator = config->screenheight;
+      denominator = SCREEN_HEIGHT;
+    }
+
+    int dstx = (int) request.pos.x * numerator / denominator;
+    int dsty = (int) request.pos.y * numerator / denominator;
+    int srcx = (ox + (int) surfacepartrequest->source.x) * numerator / denominator;
+    int srcy = (oy + (int) surfacepartrequest->source.y) * numerator / denominator;
+    int blit_width = (int) surfacepartrequest->size.x * numerator / denominator;
+    int blit_height = (int) surfacepartrequest->size.y * numerator / denominator;
+    light_blit(transform, dstx, dsty, srcx, srcy, blit_width, blit_height);
+  }
+
+  void
+  Lightmap::draw_gradient(const DrawingRequest& request)
+  {
+    const GradientRequest* gradientrequest 
+      = (GradientRequest*) request.request_data;
+    const Color& top = gradientrequest->top;
+    const Color& bottom = gradientrequest->bottom;
+
+    for(int y = 0;y < height;++y)
+    {
+      Uint8 r = (Uint8)((((float)(top.red-bottom.red)/(0-height)) * y + top.red) * 255);
+      Uint8 g = (Uint8)((((float)(top.green-bottom.green)/(0-height)) * y + top.green) * 255);
+      Uint8 b = (Uint8)((((float)(top.blue-bottom.blue)/(0-height)) * y + top.blue) * 255);
+      // FIXME
+      //Uint8 a = (Uint8)((((float)(top.alpha-bottom.alpha)/(0-height)) * y + top.alpha) * 255);
+      for(int x = 0;x < width;x++) {
+        int loc = y * width + x;
+        red_channel[loc] = std::min(red_channel[loc] + r, 255);
+        green_channel[loc] = std::min(green_channel[loc] + g, 255);
+        blue_channel[loc] = std::min(blue_channel[loc] + b, 255);
+      }
+    }
+  }
+
+  void
+  Lightmap::draw_text(const DrawingRequest& /*request*/)
+  {
+    //const TextRequest* textrequest = (TextRequest*) request.request_data;
+
+    //textrequest->font->draw(textrequest->text, request.pos,
+    //    textrequest->alignment, request.drawing_effect, request.alpha);
+  }
+
+  void
+  Lightmap::draw_filled_rect(const DrawingRequest& request)
+  {
+    const FillRectRequest* fillrectrequest
+      = (FillRectRequest*) request.request_data;
+
+    int rect_x = (int) (request.pos.x * width / SCREEN_WIDTH);
+    int rect_y = (int) (request.pos.y * height / SCREEN_HEIGHT);
+    int rect_w = (int) (fillrectrequest->size.x * width / SCREEN_WIDTH);
+    int rect_h = (int) (fillrectrequest->size.y * height / SCREEN_HEIGHT);
+    Uint8 red = (Uint8) (fillrectrequest->color.red * fillrectrequest->color.alpha * 255);
+    Uint8 green = (Uint8) (fillrectrequest->color.green * fillrectrequest->color.alpha * 255);
+    Uint8 blue = (Uint8) (fillrectrequest->color.blue * fillrectrequest->color.alpha * 255);
+    if(red == 0 && green == 0 && blue == 0)
+    {
+      return;
+    }
+    for(int y = rect_y;y < rect_y + rect_h;y++) {
+      for(int x = rect_x;x < rect_x + rect_w;x++) {
+        int loc = y * width + x;
+        red_channel[loc] = std::min(red_channel[loc] + red, 255);
+        green_channel[loc] = std::min(green_channel[loc] + green, 255);
+        blue_channel[loc] = std::min(blue_channel[loc] + blue, 255);
+      }
+    }
+  }
+
+  void
+  Lightmap::get_light(const DrawingRequest& request) const
+  {
+    const GetLightRequest* getlightrequest 
+      = (GetLightRequest*) request.request_data;
+
+    int x = (int) (request.pos.x * width / SCREEN_WIDTH);
+    int y = (int) (request.pos.y * height / SCREEN_HEIGHT);
+    int loc = y * width + x;
+    *(getlightrequest->color_ptr) = Color(((float)red_channel[loc])/255, ((float)green_channel[loc])/255, ((float)blue_channel[loc])/255);
+  }
+}
diff --git a/src/video/sdl_lightmap.hpp b/src/video/sdl_lightmap.hpp
new file mode 100644 (file)
index 0000000..985615a
--- /dev/null
@@ -0,0 +1,60 @@
+//  $Id: sdl_lightmap.hpp 4986 2007-04-16 17:48:28Z matzeb $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef SUPERTUX_SDL_LIGHTMAP_H
+#define SUPERTUX_SDL_LIGHTMAP_H
+
+#include <SDL_video.h>
+
+#include "lightmap.hpp"
+
+class Color;
+struct DrawingRequest;
+
+namespace SDL
+{
+  class Lightmap : public ::Lightmap
+  {
+  public:
+    Lightmap();
+    ~Lightmap();
+
+    void start_draw(const Color &ambient_color);
+    void end_draw();
+    void do_draw();
+    void draw_surface(const DrawingRequest& request);
+    void draw_surface_part(const DrawingRequest& request);
+    void draw_text(const DrawingRequest& request);
+    void draw_gradient(const DrawingRequest& request);
+    void draw_filled_rect(const DrawingRequest& request);
+    void get_light(const DrawingRequest& request) const;
+
+  private:
+    SDL_Surface* screen;
+    Uint8 *red_channel;
+    Uint8 *blue_channel;
+    Uint8 *green_channel;
+    int width, height;
+
+    void light_blit(SDL_Surface *src, int dstx, int dsty,
+                    int srcx, int srcy, int blit_width, int blit_height);
+  };
+}
+
+#endif
+
diff --git a/src/video/sdl_renderer.cpp b/src/video/sdl_renderer.cpp
new file mode 100644 (file)
index 0000000..f4bae63
--- /dev/null
@@ -0,0 +1,307 @@
+//  $Id: sdl_renderer.cpp 5063 2007-05-27 11:32:00Z matzeb $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#include <functional>
+#include <algorithm>
+#include <stdexcept>
+#include <cassert>
+#include <iostream>
+#include <SDL_image.h>
+#include <sstream>
+#include <iomanip>
+#include <physfs.h>
+
+#include "glutil.hpp"
+#include "sdl_renderer.hpp"
+#include "sdl_texture.hpp"
+#include "drawing_context.hpp"
+#include "drawing_request.hpp"
+#include "surface.hpp"
+#include "font.hpp"
+#include "main.hpp"
+#include "gameconfig.hpp"
+#include "texture.hpp"
+#include "texture_manager.hpp"
+#include "obstack/obstackpp.hpp"
+
+namespace SDL
+{
+  Renderer::Renderer()
+  {
+    int flags = SDL_SWSURFACE;
+    if(config->use_fullscreen)
+      flags |= SDL_FULLSCREEN;
+    int width = config->screenwidth;
+    int height = config->screenheight;
+    int bpp = 0;
+
+    screen = SDL_SetVideoMode(width, height, bpp, flags);
+    if(screen == 0) {
+      std::stringstream msg;
+      msg << "Couldn't set video mode (" << width << "x" << height
+          << "-" << bpp << "bpp): " << SDL_GetError();
+      throw std::runtime_error(msg.str());
+    }
+
+    if(texture_manager == 0)
+      texture_manager = new TextureManager();
+  }
+
+  Renderer::~Renderer()
+  {
+  }
+
+  void
+  Renderer::draw_surface(const DrawingRequest& request)
+  {
+    //FIXME: support parameters request.alpha, request.angle, request.blend
+    const Surface* surface = (const Surface*) request.request_data;
+    SDL::Texture *sdltexture = dynamic_cast<Texture *>(surface->get_texture());
+    DrawingEffect effect = request.drawing_effect;
+    if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
+
+    SDL_Surface *transform = sdltexture->get_transform(request.color, effect);
+
+    // get and check SDL_Surface
+    if (transform == 0) {
+      std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
+      return;
+    }  
+
+    int ox, oy;
+    if (effect == HORIZONTAL_FLIP)
+    {
+      ox = sdltexture->get_texture_width() - surface->get_x() - surface->get_width();
+    }
+    else
+    {
+      ox = surface->get_x();
+    }
+    if (effect == VERTICAL_FLIP)
+    {
+      oy = sdltexture->get_texture_height() - surface->get_y() - surface->get_height();
+    }
+    else
+    {
+      oy = surface->get_y();
+    }
+
+    int numerator, denominator;
+    float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
+    float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
+    if(xfactor < yfactor)
+    {
+      numerator = config->screenwidth;
+      denominator = SCREEN_WIDTH;
+    }
+    else
+    {
+      numerator = config->screenheight;
+      denominator = SCREEN_HEIGHT;
+    }
+
+    SDL_Rect srcRect;
+    srcRect.x = ox * numerator / denominator;
+    srcRect.y = oy * numerator / denominator;
+    srcRect.w = surface->get_width() * numerator / denominator;
+    srcRect.h = surface->get_height() * numerator / denominator;
+
+    SDL_Rect dstRect;
+    dstRect.x = (int) request.pos.x * numerator / denominator;
+    dstRect.y = (int) request.pos.y * numerator / denominator;
+
+    SDL_BlitSurface(transform, &srcRect, screen, &dstRect);
+  }
+
+  void
+  Renderer::draw_surface_part(const DrawingRequest& request)
+  {
+    const SurfacePartRequest* surfacepartrequest
+      = (SurfacePartRequest*) request.request_data;
+
+    const Surface* surface = surfacepartrequest->surface;
+    SDL::Texture *sdltexture = dynamic_cast<Texture *>(surface->get_texture());
+    DrawingEffect effect = request.drawing_effect;
+    if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
+
+    SDL_Surface *transform = sdltexture->get_transform(Color(1.0, 1.0, 1.0), effect);
+
+    // get and check SDL_Surface
+    if (transform == 0) {
+      std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
+      return;
+    }  
+
+    int ox, oy;
+    if (effect == HORIZONTAL_FLIP)
+    {
+      ox = sdltexture->get_texture_width() - surface->get_x() - (int) surfacepartrequest->size.x;
+    }
+    else
+    {
+      ox = surface->get_x();
+    }
+    if (effect == VERTICAL_FLIP)
+    {
+      oy = sdltexture->get_texture_height() - surface->get_y() - (int) surfacepartrequest->size.y;
+    }
+    else
+    {
+      oy = surface->get_y();
+    }
+
+    int numerator, denominator;
+    float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
+    float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
+    if(xfactor < yfactor)
+    {
+      numerator = config->screenwidth;
+      denominator = SCREEN_WIDTH;
+    }
+    else
+    {
+      numerator = config->screenheight;
+      denominator = SCREEN_HEIGHT;
+    }
+
+    SDL_Rect srcRect;
+    srcRect.x = (ox + (int) surfacepartrequest->source.x) * numerator / denominator;
+    srcRect.y = (oy + (int) surfacepartrequest->source.y) * numerator / denominator;
+    srcRect.w = (int) surfacepartrequest->size.x * numerator / denominator;
+    srcRect.h = (int) surfacepartrequest->size.y * numerator / denominator;
+
+    SDL_Rect dstRect;
+    dstRect.x = (int) request.pos.x * numerator / denominator;
+    dstRect.y = (int) request.pos.y * numerator / denominator;
+
+    SDL_BlitSurface(transform, &srcRect, screen, &dstRect);
+  }
+
+  void
+  Renderer::draw_gradient(const DrawingRequest& request)
+  {
+    const GradientRequest* gradientrequest 
+      = (GradientRequest*) request.request_data;
+    const Color& top = gradientrequest->top;
+    const Color& bottom = gradientrequest->bottom;
+
+    for(int y = 0;y < screen->h;++y)
+    {
+      Uint8 r = (Uint8)((((float)(top.red-bottom.red)/(0-screen->h)) * y + top.red) * 255);
+      Uint8 g = (Uint8)((((float)(top.green-bottom.green)/(0-screen->h)) * y + top.green) * 255);
+      Uint8 b = (Uint8)((((float)(top.blue-bottom.blue)/(0-screen->h)) * y + top.blue) * 255);
+      Uint8 a = (Uint8)((((float)(top.alpha-bottom.alpha)/(0-screen->h)) * y + top.alpha) * 255);
+      Uint32 color = SDL_MapRGB(screen->format, r, g, b);
+
+      SDL_Rect rect;
+      rect.x = 0;
+      rect.y = y;
+      rect.w = screen->w;
+      rect.h = 1;
+
+      if(a == SDL_ALPHA_OPAQUE) {
+        SDL_FillRect(screen, &rect, color);
+      } else if(a != SDL_ALPHA_TRANSPARENT) {
+        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);
+
+        SDL_FillRect(temp, 0, color);
+        SDL_SetAlpha(temp, SDL_SRCALPHA, a);
+        SDL_BlitSurface(temp, 0, screen, &rect);
+        SDL_FreeSurface(temp);
+      }
+    }
+  }
+
+  void
+  Renderer::draw_text(const DrawingRequest& request)
+  {
+    const TextRequest* textrequest = (TextRequest*) request.request_data;
+
+    textrequest->font->draw(this, textrequest->text, request.pos,
+        textrequest->alignment, request.drawing_effect, request.alpha);
+  }
+
+  void
+  Renderer::draw_filled_rect(const DrawingRequest& request)
+  {
+    const FillRectRequest* fillrectrequest
+      = (FillRectRequest*) request.request_data;
+
+    SDL_Rect rect;
+    rect.x = (Sint16)request.pos.x * screen->w / SCREEN_WIDTH;
+    rect.y = (Sint16)request.pos.y * screen->h / SCREEN_HEIGHT;
+    rect.w = (Uint16)fillrectrequest->size.x * screen->w / SCREEN_WIDTH;
+    rect.h = (Uint16)fillrectrequest->size.y * screen->h / SCREEN_HEIGHT;
+    Uint8 r = static_cast<Uint8>(fillrectrequest->color.red * 255);
+    Uint8 g = static_cast<Uint8>(fillrectrequest->color.green * 255);
+    Uint8 b = static_cast<Uint8>(fillrectrequest->color.blue * 255);
+    Uint8 a = static_cast<Uint8>(fillrectrequest->color.alpha * 255);
+    Uint32 color = SDL_MapRGB(screen->format, r, g, b);
+    if(a == SDL_ALPHA_OPAQUE) {
+      SDL_FillRect(screen, &rect, color);
+    } else if(a != SDL_ALPHA_TRANSPARENT) {
+      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);
+
+      SDL_FillRect(temp, 0, color);
+      SDL_SetAlpha(temp, SDL_SRCALPHA, a);
+      SDL_BlitSurface(temp, 0, screen, &rect);
+      SDL_FreeSurface(temp);
+    }
+  }
+
+  void 
+  Renderer::do_take_screenshot()
+  {
+    // [Christoph] TODO: Yes, this method also takes care of the actual disk I/O. Split it?
+
+    SDL_Surface *shot_surf;
+    shot_surf = SDL_GetVideoSurface();
+    shot_surf->refcount++;
+
+    // save screenshot
+    static const std::string writeDir = PHYSFS_getWriteDir();
+    static const std::string dirSep = PHYSFS_getDirSeparator();
+    static const std::string baseName = "screenshot";
+    static const std::string fileExt = ".bmp";
+    std::string fullFilename;
+    for (int num = 0; num < 1000; num++) {
+      std::ostringstream oss;
+      oss << baseName;
+      oss << std::setw(3) << std::setfill('0') << num;
+      oss << fileExt;
+      std::string fileName = oss.str();
+      fullFilename = writeDir + dirSep + fileName;
+      if (!PHYSFS_exists(fileName.c_str())) {
+        SDL_SaveBMP(shot_surf, fullFilename.c_str());
+        log_debug << "Wrote screenshot to \"" << fullFilename << "\"" << std::endl;
+        SDL_FreeSurface(shot_surf);
+        return;
+      }
+    }
+    log_warning << "Did not save screenshot, because all files up to \"" << fullFilename << "\" already existed" << std::endl;
+    SDL_FreeSurface(shot_surf);
+  }
+
+  void
+  Renderer::flip()
+  {
+    SDL_Flip(screen);
+  }
+}
diff --git a/src/video/sdl_renderer.hpp b/src/video/sdl_renderer.hpp
new file mode 100644 (file)
index 0000000..8c943f1
--- /dev/null
@@ -0,0 +1,47 @@
+//  $Id: sdl_renderer.hpp 4986 2007-04-16 17:48:28Z matzeb $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef SUPERTUX_SDL_RENDERER_H
+#define SUPERTUX_SDL_RENDERER_H
+
+#include <SDL_video.h>
+
+#include "renderer.hpp"
+
+namespace SDL
+{
+  class Renderer : public ::Renderer
+  {
+  public:
+    Renderer();
+    ~Renderer();
+
+    void draw_surface(const DrawingRequest& request);
+    void draw_surface_part(const DrawingRequest& request);
+    void draw_text(const DrawingRequest& request);
+    void draw_gradient(const DrawingRequest& request);
+    void draw_filled_rect(const DrawingRequest& request);
+    void do_take_screenshot();
+    void flip();
+  private:
+    SDL_Surface *screen;
+  };
+}
+
+#endif
+
diff --git a/src/video/sdl_texture.cpp b/src/video/sdl_texture.cpp
new file mode 100644 (file)
index 0000000..d5a9d9c
--- /dev/null
@@ -0,0 +1,451 @@
+//  $Id: sdl_texture.cpp 4063 2006-07-21 21:05:23Z anmaster $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+#include <config.h>
+
+#include "sdl_texture.hpp"
+#include "color.hpp"
+#include "gameconfig.hpp"
+#include "main.hpp"
+
+#include <assert.h>
+
+#include <SDL.h>
+
+namespace
+{
+#define BILINEAR
+
+#ifdef NAIVE
+  SDL_Surface *scale(SDL_Surface *src, int numerator, int denominator)
+  {
+    if(numerator == denominator)
+    {
+      src->refcount++;
+      return src;
+    }
+    else
+    {
+      SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w * numerator / denominator, src->h * numerator / denominator, src->format->BitsPerPixel, src->format->Rmask,  src->format->Gmask, src->format->Bmask, src->format->Amask);
+      int bpp = dst->format->BytesPerPixel;
+      for(int y = 0;y < dst->h;y++) {
+        for(int x = 0;x < dst->w;x++) {
+          Uint8 *srcpixel = (Uint8 *) src->pixels + (y * denominator / numerator) * src->pitch + (x * denominator / numerator) * bpp;
+          Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
+          switch(bpp) {
+            case 4:
+              dstpixel[3] = srcpixel[3];
+            case 3:
+              dstpixel[2] = srcpixel[2];
+            case 2:
+              dstpixel[1] = srcpixel[1];
+            case 1:
+              dstpixel[0] = srcpixel[0];
+          }
+        }
+      }
+      return dst;
+    }
+  }
+#endif
+
+#ifdef BILINEAR
+  void getpixel(SDL_Surface *src, int srcx, int srcy, Uint8 color[4])
+  {
+    int bpp = src->format->BytesPerPixel;
+    Uint8 *srcpixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp;
+    Uint32 mapped = 0;
+    switch(bpp) {
+      case 1:
+        mapped = *srcpixel;
+        break;
+      case 2:
+        mapped = *(Uint16 *)srcpixel;
+        break;
+      case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+        mapped |= srcpixel[0] << 16;
+        mapped |= srcpixel[1] << 8;
+        mapped |= srcpixel[2] << 0;
+#else
+        mapped |= srcpixel[0] << 0;
+        mapped |= srcpixel[1] << 8;
+        mapped |= srcpixel[2] << 16;
+#endif
+        break;
+      case 4:
+        mapped = *(Uint32 *)srcpixel;
+        break;
+    }
+    SDL_GetRGBA(mapped, src->format, &color[0], &color[1], &color[2], &color[3]);
+  }
+
+  void merge(Uint8 color[4], Uint8 color0[4], Uint8 color1[4], int rem, int total)
+  {
+    color[0] = (color0[0] * (total - rem) + color1[0] * rem) / total;
+    color[1] = (color0[1] * (total - rem) + color1[1] * rem) / total;
+    color[2] = (color0[2] * (total - rem) + color1[2] * rem) / total;
+    color[3] = (color0[3] * (total - rem) + color1[3] * rem) / total;
+  }
+
+  SDL_Surface *scale(SDL_Surface *src, int numerator, int denominator)
+  {
+    if(numerator == denominator)
+    {
+      src->refcount++;
+      return src;
+    }
+    else
+    {
+      SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w * numerator / denominator, src->h * numerator / denominator, src->format->BitsPerPixel, src->format->Rmask,  src->format->Gmask, src->format->Bmask, src->format->Amask);
+      int bpp = dst->format->BytesPerPixel;
+      for(int y = 0;y < dst->h;y++) {
+        for(int x = 0;x < dst->w;x++) {
+          int srcx = x * denominator / numerator;
+          int srcy = y * denominator / numerator;
+          Uint8 color00[4], color01[4], color10[4], color11[4];
+          getpixel(src, srcx, srcy, color00);
+          getpixel(src, srcx + 1, srcy, color01);
+          getpixel(src, srcx, srcy + 1, color10);
+          getpixel(src, srcx + 1, srcy + 1, color11);
+          Uint8 color0[4], color1[4], color[4];
+          int remx = x * denominator % numerator;
+          merge(color0, color00, color01, remx, numerator);
+          merge(color1, color10, color11, remx, numerator);
+          int remy = y * denominator % numerator;
+          merge(color, color0, color1, remy, numerator);
+          Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
+          Uint32 mapped = SDL_MapRGBA(dst->format, color[0], color[1], color[2], color[3]);
+          switch(bpp) {
+            case 1:
+              *dstpixel = mapped;
+              break;
+            case 2:
+              *(Uint16 *)dstpixel = mapped;
+              break;
+            case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+              dstpixel[0] = (mapped >> 16) & 0xff;
+              dstpixel[1] = (mapped >> 8) & 0xff;
+              dstpixel[2] = (mapped >> 0) & 0xff;
+#else
+              dstpixel[0] = (mapped >> 0) & 0xff;
+              dstpixel[1] = (mapped >> 8) & 0xff;
+              dstpixel[2] = (mapped >> 16) & 0xff;
+#endif
+              break;
+            case 4:
+              *(Uint32 *)dstpixel = mapped;
+              break;
+          }
+        }
+      }
+      return dst;
+    }
+  }
+#endif
+
+  // FIXME: Horizontal and vertical line problem
+#ifdef BRESENHAM
+  void accumulate(SDL_Surface *src, int srcx, int srcy, int color[4], int weight)
+  {
+    if(srcx < 0 || srcy < 0 || weight == 0) {
+      return;
+    }
+    int bpp = src->format->BytesPerPixel;
+    Uint8 *srcpixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp;
+    Uint32 mapped = 0;
+    switch(bpp) {
+      case 1:
+        mapped = *srcpixel;
+        break;
+      case 2:
+        mapped = *(Uint16 *)srcpixel;
+        break;
+      case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+        mapped |= srcpixel[0] << 16;
+        mapped |= srcpixel[1] << 8;
+        mapped |= srcpixel[2] << 0;
+#else
+        mapped |= srcpixel[0] << 0;
+        mapped |= srcpixel[1] << 8;
+        mapped |= srcpixel[2] << 16;
+#endif
+        break;
+      case 4:
+        mapped = *(Uint32 *)srcpixel;
+        break;
+    }
+    Uint8 red, green, blue, alpha;
+    SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
+    color[0] += red * weight;
+    color[1] += green * weight;
+    color[2] += blue * weight;
+    color[3] += alpha * weight;
+  }
+
+  void accumulate_line(SDL_Surface *src, int srcy, int line[][4], int linesize, int weight, int numerator, int denominator)
+  {
+    int intpart = denominator / numerator;
+    int fractpart = denominator % numerator;
+    for(int x = 0, xe = 0, srcx = 0;x < linesize;x++) {
+      accumulate(src, srcx, srcy, line[x], (numerator - xe) * weight);
+      srcx++;
+      for(int i = 0;i < intpart - 1;i++) {
+        accumulate(src, srcx, srcy, line[x], numerator * weight);
+        srcx++;
+      }
+      xe += fractpart;
+      if(xe >= numerator) {
+        xe -= numerator;
+        srcx++;
+      }
+      accumulate(src, srcx, srcy, line[x], xe * weight);
+    }
+  }
+
+  SDL_Surface *scale(SDL_Surface *src, int numerator, int denominator)
+  {
+    if(numerator == denominator)
+    {
+      src->refcount++;
+      return src;
+    }
+    else
+    {
+      SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w * numerator / denominator, src->h * numerator / denominator, src->format->BitsPerPixel, src->format->Rmask,  src->format->Gmask, src->format->Bmask, src->format->Amask);
+      int bpp = dst->format->BytesPerPixel;
+      int intpart = denominator / numerator;
+      int fractpart = denominator % numerator;
+      for(int y = 0, ye = 0, srcy = 0;y < dst->h;y++) {
+        int line[dst->w][4];
+        memset(line, 0, sizeof(int) * dst->w * 4);
+        accumulate_line(src, srcy, line, dst->w, numerator - ye, numerator, denominator);
+        srcy++;
+        for(int i = 0;i < intpart - 1;i++) {
+          accumulate_line(src, srcy, line, dst->w, numerator, numerator, denominator);
+          srcy++;
+        }
+        ye += fractpart;
+        if(ye >= numerator) {
+          ye -= numerator;
+          srcy++;
+        }
+        accumulate_line(src, srcy, line, dst->w, ye, numerator, denominator);
+        for(int x = 0;x < dst->w;x++) {
+          Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
+          Uint32 mapped = SDL_MapRGBA(dst->format, line[x][0] / (denominator * denominator), line[x][1] / (denominator * denominator), line[x][2] / (denominator * denominator), line[x][3] / (denominator * denominator));
+          switch(bpp) {
+            case 1:
+              *dstpixel = mapped;
+              break;
+            case 2:
+              *(Uint16 *)dstpixel = mapped;
+              break;
+            case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+              dstpixel[0] = (mapped >> 16) & 0xff;
+              dstpixel[1] = (mapped >> 8) & 0xff;
+              dstpixel[2] = (mapped >> 0) & 0xff;
+#else
+              dstpixel[0] = (mapped >> 0) & 0xff;
+              dstpixel[1] = (mapped >> 8) & 0xff;
+              dstpixel[2] = (mapped >> 16) & 0xff;
+#endif
+              break;
+            case 4:
+              *(Uint32 *)dstpixel = mapped;
+              break;
+          }
+        }
+      }
+      return dst;
+    }
+  }
+#endif
+
+  SDL_Surface *horz_flip(SDL_Surface *src)
+  {
+    SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w, src->h, src->format->BitsPerPixel, src->format->Rmask,  src->format->Gmask, src->format->Bmask, src->format->Amask);
+    int bpp = dst->format->BytesPerPixel;
+    for(int y = 0;y < dst->h;y++) {
+      for(int x = 0;x < dst->w;x++) {
+        Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
+        Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + (dst->w - x - 1) * bpp;
+        switch(bpp) {
+          case 4:
+            dstpixel[3] = srcpixel[3];
+          case 3:
+            dstpixel[2] = srcpixel[2];
+          case 2:
+            dstpixel[1] = srcpixel[1];
+          case 1:
+            dstpixel[0] = srcpixel[0];
+        }
+      }
+    }
+    return dst;
+  }
+
+  SDL_Surface *vert_flip(SDL_Surface *src)
+  {
+    SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w, src->h, src->format->BitsPerPixel, src->format->Rmask,  src->format->Gmask, src->format->Bmask, src->format->Amask);
+    int bpp = dst->format->BytesPerPixel;
+    for(int y = 0;y < dst->h;y++) {
+      for(int x = 0;x < dst->w;x++) {
+        Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
+        Uint8 *dstpixel = (Uint8 *) dst->pixels + (dst->h - y - 1) * dst->pitch + x * bpp;
+        switch(bpp) {
+          case 4:
+            dstpixel[3] = srcpixel[3];
+          case 3:
+            dstpixel[2] = srcpixel[2];
+          case 2:
+            dstpixel[1] = srcpixel[1];
+          case 1:
+            dstpixel[0] = srcpixel[0];
+        }
+      }
+    }
+    return dst;
+  }
+
+  const Color white(1.0, 1.0, 1.0);
+
+  SDL_Surface *colorize(SDL_Surface *src, const Color &color)
+  {
+    // FIXME: This is really slow
+    assert(color.red != 1.0 || color.green != 1.0 || color.blue != 1.0);
+    SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w, src->h, src->format->BitsPerPixel, src->format->Rmask,  src->format->Gmask, src->format->Bmask, src->format->Amask);
+    int bpp = dst->format->BytesPerPixel;
+    for(int y = 0;y < dst->h;y++) {
+      for(int x = 0;x < dst->w;x++) {
+        Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
+        Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
+        Uint32 mapped = 0;
+        switch(bpp) {
+          case 1:
+            mapped = *srcpixel;
+            break;
+          case 2:
+            mapped = *(Uint16 *)srcpixel;
+            break;
+          case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+            mapped |= srcpixel[0] << 16;
+            mapped |= srcpixel[1] << 8;
+            mapped |= srcpixel[2] << 0;
+#else
+            mapped |= srcpixel[0] << 0;
+            mapped |= srcpixel[1] << 8;
+            mapped |= srcpixel[2] << 16;
+#endif
+            break;
+          case 4:
+            mapped = *(Uint32 *)srcpixel;
+            break;
+        }
+        Uint8 red, green, blue, alpha;
+        SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
+        red = (Uint8) (red * color.red);
+        green = (Uint8) (green * color.green);
+        blue = (Uint8) (blue * color.blue);
+        mapped = SDL_MapRGBA(dst->format, red, green, blue, alpha);
+        switch(bpp) {
+          case 1:
+            *dstpixel = mapped;
+            break;
+          case 2:
+            *(Uint16 *)dstpixel = mapped;
+            break;
+          case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+            dstpixel[0] = (mapped >> 16) & 0xff;
+            dstpixel[1] = (mapped >> 8) & 0xff;
+            dstpixel[2] = (mapped >> 0) & 0xff;
+#else
+            dstpixel[0] = (mapped >> 0) & 0xff;
+            dstpixel[1] = (mapped >> 8) & 0xff;
+            dstpixel[2] = (mapped >> 16) & 0xff;
+#endif
+            break;
+          case 4:
+            *(Uint32 *)dstpixel = mapped;
+            break;
+        }
+      }
+    }
+    return dst;
+  }
+}
+
+namespace SDL
+{
+  Texture::Texture(SDL_Surface* image)
+  {
+    texture = SDL_DisplayFormatAlpha(image);
+    //image->refcount++;
+    //texture = image;
+
+    float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
+    float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
+    if(xfactor < yfactor)
+    {
+      numerator = config->screenwidth;
+      denominator = SCREEN_WIDTH;
+    }
+    else
+    {
+      numerator = config->screenheight;
+      denominator = SCREEN_HEIGHT;
+    }
+    cache[white][NO_EFFECT] = scale(texture, numerator, denominator);
+  }
+
+  Texture::~Texture()
+  {
+    SDL_FreeSurface(texture);
+  }
+
+  SDL_Surface *Texture::get_transform(const Color &color, DrawingEffect effect)
+  {
+    if(cache.find(color) == cache.end())
+    {
+      cache[color][NO_EFFECT] = colorize(cache[white][NO_EFFECT], color);
+    }
+    if(cache[color][effect] == 0) {
+      assert(cache[color][NO_EFFECT]);
+      switch(effect) {
+        case NO_EFFECT:
+          break;
+        case HORIZONTAL_FLIP:
+          cache[color][HORIZONTAL_FLIP] = horz_flip(cache[color][NO_EFFECT]);
+          break;
+        case VERTICAL_FLIP:
+          cache[color][VERTICAL_FLIP] = vert_flip(cache[color][NO_EFFECT]);
+          break;
+        default:
+          std::cerr << "Warning: transformation unknown" << std::endl;
+          return 0;
+      }
+    }
+    return cache[color][effect];
+  }
+}
diff --git a/src/video/sdl_texture.hpp b/src/video/sdl_texture.hpp
new file mode 100644 (file)
index 0000000..0a8045f
--- /dev/null
@@ -0,0 +1,109 @@
+//  $Id: sdl_texture.hpp 4063 2006-07-21 21:05:23Z anmaster $
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+#ifndef __SDL_TEXTURE_HPP__
+#define __SDL_TEXTURE_HPP__
+
+#include <config.h>
+
+#include <SDL.h>
+
+#include "texture.hpp"
+
+class Color;
+
+namespace SDL
+{
+  class Texture : public ::Texture
+  {
+  protected:
+    SDL_Surface *texture;
+    int numerator;
+    int denominator;
+
+    struct Cache
+    {
+      static void ref(SDL_Surface *surface)
+      {
+        if(surface)
+        {
+          surface->refcount++;
+        }
+      }
+
+      SDL_Surface *data[NUM_EFFECTS];
+
+      Cache()
+      {
+        memset(data, 0, NUM_EFFECTS * sizeof(SDL_Surface *));
+      }
+
+      ~Cache()
+      {
+        std::for_each(data, data + NUM_EFFECTS, SDL_FreeSurface);
+      }
+
+      void operator = (const Cache &other)
+      {
+        std::for_each(other.data, other.data + NUM_EFFECTS, ref);
+        std::for_each(data, data + NUM_EFFECTS, SDL_FreeSurface);
+        memcpy(data, other.data, sizeof(Cache));
+      }
+
+      SDL_Surface *&operator [] (DrawingEffect effect)
+      {
+        return data[effect];
+      }
+    };
+    mutable std::map<Color, Cache> cache; /**< Cache for processed surfaces */
+
+  public:
+    Texture(SDL_Surface* sdlsurface);
+    virtual ~Texture();
+
+    SDL_Surface *get_transform(const Color &color, DrawingEffect effect);
+
+    SDL_Surface *get_texture() const
+    {
+      return texture;
+    }
+
+    unsigned int get_texture_width() const
+    {
+      return texture->w;
+    }
+
+    unsigned int get_texture_height() const
+    {
+      return texture->h;
+    }
+
+    unsigned int get_image_width() const
+    {
+      return texture->w;
+    }
+
+    unsigned int get_image_height() const
+    {
+      return texture->h;
+    }
+  };
+}
+
+#endif
diff --git a/src/video/surface.cpp b/src/video/surface.cpp
deleted file mode 100644 (file)
index fc0f870..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-//  $Id$
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#include <config.h>
-
-#include <cassert>
-#include <iostream>
-#include <algorithm>
-#include <stdexcept>
-#include <sstream>
-#include <math.h>
-
-#include <SDL.h>
-#include <SDL_image.h>
-
-#include "gameconfig.hpp"
-#include "physfs/physfs_sdl.hpp"
-#include "video/surface.hpp"
-#include "video/drawing_context.hpp"
-#include "video/color.hpp"
-#include "image_texture.hpp"
-#include "texture_manager.hpp"
-
-Surface::Surface(const std::string& file)
-{
-  texture = texture_manager->get(file);
-  texture->ref();
-  uv_left = 0;
-  uv_top = 0;
-  uv_right = texture->get_uv_right();
-  uv_bottom = texture->get_uv_bottom();
-
-  width = texture->get_image_width();
-  height = texture->get_image_height();
-}
-
-Surface::Surface(const std::string& file, int x, int y, int w, int h)
-{
-  texture = texture_manager->get(file);
-  texture->ref();
-
-  float tex_w = static_cast<float> (texture->get_width());
-  float tex_h = static_cast<float> (texture->get_height());
-  uv_left = static_cast<float>(x) / tex_w;
-  uv_top = static_cast<float>(y) / tex_h;
-  uv_right = static_cast<float>(x+w) / tex_w;
-  uv_bottom = static_cast<float>(y+h) / tex_h;
-
-  width = w;
-  height = h;
-}
-
-Surface::Surface(const Surface& other)
-{
-  texture = other.texture;
-  texture->ref();
-
-  uv_left = other.uv_left;
-  uv_top = other.uv_top;
-  uv_right = other.uv_right;
-  uv_bottom = other.uv_bottom;
-  width = other.width;
-  height = other.height;
-}
-
-const Surface&
-Surface::operator= (const Surface& other)
-{
-  other.texture->ref();
-  texture->unref();
-  texture = other.texture;
-
-  uv_left = other.uv_left;
-  uv_top = other.uv_top;
-  uv_right = other.uv_right;
-  uv_bottom = other.uv_bottom;
-  width = other.width;
-  height = other.height;
-
-  return *this;
-}
-
-Surface::~Surface()
-{
-  texture->unref();
-}
-
-void
-Surface::hflip()
-{
-  std::swap(uv_left, uv_right);
-}
-
-static inline void intern_draw(float left, float top, float right, float bottom,                               float uv_left, float uv_top,
-                               float uv_right, float uv_bottom,
-                               DrawingEffect effect)
-{
-  if(effect & HORIZONTAL_FLIP)
-    std::swap(uv_left, uv_right);
-  if(effect & VERTICAL_FLIP) {
-    std::swap(uv_top, uv_bottom);
-  }
-
-  glBegin(GL_QUADS);
-  glTexCoord2f(uv_left, uv_top);
-  glVertex2f(left, top);
-
-  glTexCoord2f(uv_right, uv_top);
-  glVertex2f(right, top);
-
-  glTexCoord2f(uv_right, uv_bottom);
-  glVertex2f(right, bottom);
-
-  glTexCoord2f(uv_left, uv_bottom);
-  glVertex2f(left, bottom);
-  glEnd();
-}
-
-static inline void intern_draw2(float left, float top, float right, float bottom,
-                                float uv_left, float uv_top,
-                                float uv_right, float uv_bottom,
-                                float angle, float alpha,
-                                const Color& color,
-                                const Blend& blend,
-                                DrawingEffect effect)
-{
-  if(effect & HORIZONTAL_FLIP)
-    std::swap(uv_left, uv_right);
-  if(effect & VERTICAL_FLIP) {
-    std::swap(uv_top, uv_bottom);
-  }
-
-  float center_x = (left + right) / 2;
-  float center_y = (top + bottom) / 2;
-
-  float sa = sinf(angle/180.0f*M_PI);
-  float ca = cosf(angle/180.0f*M_PI);
-
-  left  -= center_x;
-  right -= center_x;
-
-  top    -= center_y;
-  bottom -= center_y;
-
-  glBlendFunc(blend.sfactor, blend.dfactor);
-  glColor4f(color.red, color.green, color.blue, color.alpha * alpha);
-  glBegin(GL_QUADS);
-  glTexCoord2f(uv_left, uv_top);
-  glVertex2f(left*ca - top*sa + center_x,
-             left*sa + top*ca + center_y);
-
-  glTexCoord2f(uv_right, uv_top);
-  glVertex2f(right*ca - top*sa + center_x,
-             right*sa + top*ca + center_y);
-
-  glTexCoord2f(uv_right, uv_bottom);
-  glVertex2f(right*ca - bottom*sa + center_x,
-             right*sa + bottom*ca + center_y);
-
-  glTexCoord2f(uv_left, uv_bottom);
-  glVertex2f(left*ca - bottom*sa + center_x,
-             left*sa + bottom*ca + center_y);
-  glEnd();
-
-  // FIXME: find a better way to restore the blend mode
-  glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
-  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-}
-
-void
-Surface::draw(float x, float y, float alpha, float angle, const Color& color, const Blend& blend, DrawingEffect effect) const
-{
-  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
-
-  intern_draw2(x, y,
-               x + width, y + height,
-               uv_left, uv_top, uv_right, uv_bottom,
-               angle,
-               alpha,
-               color,
-               blend,
-               effect);
-}
-
-void
-Surface::draw(float x, float y, float alpha, DrawingEffect effect) const
-{
-  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
-
-  glColor4f(1, 1, 1, alpha);
-  intern_draw(x, y,
-              x + width, y + height,
-              uv_left, uv_top, uv_right, uv_bottom, effect);
-  glColor4f(1, 1, 1, 1);
-}
-
-void
-Surface::draw_part(float src_x, float src_y, float dst_x, float dst_y,
-                   float width, float height, float alpha,
-                   DrawingEffect effect) const
-{
-  float uv_width = uv_right - uv_left;
-  float uv_height = uv_bottom - uv_top;
-
-  float uv_left = this->uv_left + (uv_width * src_x) / this->width;
-  float uv_top = this->uv_top + (uv_height * src_y) / this->height;
-  float uv_right = this->uv_left + (uv_width * (src_x + width)) / this->width;
-  float uv_bottom = this->uv_top + (uv_height * (src_y + height)) / this->height;
-
-  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
-
-  glColor4f(1, 1, 1, alpha);
-  intern_draw(dst_x, dst_y,
-              dst_x + width, dst_y + height,
-              uv_left, uv_top, uv_right, uv_bottom, effect);
-  glColor4f(1, 1, 1, 1);
-}
index d702181..e1b7cd4 100644 (file)
 #ifndef __SURFACE_HPP__
 #define __SURFACE_HPP__
 
+#include <config.h>
+
 #include <string>
+#include <SDL.h>
 #include "math/vector.hpp"
-
-class Color;
-class Blend;
-class ImageTexture;
-
-/// bitset for drawing effects
-enum DrawingEffect {
-  /** Don't apply anything */
-  NO_EFFECT       = 0x0000,
-  /** Draw the Surface upside down */
-  VERTICAL_FLIP     = 0x0001,
-  /** Draw the Surface from left to down */
-  HORIZONTAL_FLIP   = 0x0002,
-};
+#include "texture.hpp"
 
 /**
  * A rectangular image.
@@ -45,50 +35,126 @@ enum DrawingEffect {
 class Surface
 {
 private:
-  friend class DrawingContext;
-  friend class Font;
-  ImageTexture* texture;
-
-  float uv_left;
-  float uv_top;
-  float uv_right;
-  float uv_bottom;
-
-  void draw(float x, float y, float alpha, float angle, const Color& color, const Blend& blend, DrawingEffect effect) const;
-  void draw(float x, float y, float alpha, DrawingEffect effect) const;
-  void draw_part(float src_x, float src_y, float dst_x, float dst_y,
-                 float width, float height,
-                 float alpha, DrawingEffect effect) const;
-
-  float width;
-  float height;
+  Texture* texture;
+  int x;
+  int y;
+  int w;
+  int h;
+  bool flipx;
+
 public:
-  Surface(const std::string& file);
-  Surface(const std::string& file, int x, int y, int w, int h);
-  Surface(const Surface& other);
-  ~Surface();
+  Surface(const std::string& file) :
+    texture(texture_manager->get(file)),
+    x(0), y(0), w(0), h(0),
+    flipx(false)
+  {
+    texture->ref();
+    w = texture->get_image_width();
+    h = texture->get_image_height();
+  }
+
+  Surface(const std::string& file, int x, int y, int w, int h) :
+    texture(texture_manager->get(file)),
+    x(x), y(y), w(w), h(h),
+    flipx(false)
+  {
+    texture->ref();
+  }
+
+  Surface(const Surface& other) :
+    texture(other.texture),
+    x(other.x), y(other.y),
+    w(other.w), h(other.h),
+    flipx(false)
+  {
+    texture->ref();
+  }
+
+  ~Surface()
+  {
+    texture->unref();
+  }
 
   /** flip the surface horizontally */
-  void hflip();
+  void hflip()
+  {
+    flipx = !flipx;
+  }
+
+  bool get_flipx() const
+  {
+    return flipx;
+  }
+
+  const Surface& operator= (const Surface& other)
+  {
+    other.texture->ref();
+    texture->unref();
+    texture = other.texture;
+    x = other.x;
+    y = other.y;
+    w = other.w;
+    h = other.h;
+    return *this;
+  }
+
+  Texture *get_texture() const
+  {
+    return texture;
+  }
 
-  const Surface& operator= (const Surface& other);
+  int get_x() const
+  {
+    return x;
+  }
 
-  float get_width() const
+  int get_y() const
   {
-    return width;
+    return y;
   }
 
-  float get_height() const
+  int get_width() const
   {
-    return height;
+    return w;
   }
 
+  int get_height() const
+  {
+    return h;
+  }
+
+  Vector get_position() const
+  { return Vector(get_x(), get_y()); }
+
   /**
    * returns a vector containing width and height
    */
   Vector get_size() const
   { return Vector(get_width(), get_height()); }
 
+  float get_uv_left() const
+  {
+    return (float) (x + (flipx ? w : 0)) / texture->get_texture_width();
+  }
+
+  float get_uv_top() const
+  {
+    return (float) y / texture->get_texture_height();
+  }
+
+  float get_uv_right() const
+  {
+    return (float) (x + (flipx ? 0 : w)) / texture->get_texture_width();
+  }
+
+  float get_uv_bottom() const
+  {
+    return (float) (y + h) / texture->get_texture_height();
+  }
+
+  //void draw_part(float src_x, float src_y, float dst_x, float dst_y,
+  //               float width, float height, float alpha,
+  //               DrawingEffect effect) const;
 };
 
 #endif
diff --git a/src/video/texture.cpp b/src/video/texture.cpp
deleted file mode 100644 (file)
index 9c41ddd..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-//  $Id$
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#include <config.h>
-
-#include "texture.hpp"
-
-#include <GL/gl.h>
-#include <assert.h>
-#include "glutil.hpp"
-
-static inline bool is_power_of_2(int v)
-{
-  return (v & (v-1)) == 0;
-}
-
-Texture::Texture(unsigned int w, unsigned int h, GLenum glformat)
-{
-  assert(is_power_of_2(w));
-  assert(is_power_of_2(h));
-
-  this->width = w;
-  this->height = h;
-
-  assert_gl("before creating texture");
-  glGenTextures(1, &handle);
-
-  try {
-    glBindTexture(GL_TEXTURE_2D, handle);
-
-    glTexImage2D(GL_TEXTURE_2D, 0, glformat, width, height, 0, GL_RGBA,
-                 GL_UNSIGNED_BYTE, 0);
-
-    set_texture_params();
-  } catch(...) {
-    glDeleteTextures(1, &handle);
-    throw;
-  }
-}
-
-Texture::Texture(SDL_Surface* image, GLenum glformat)
-{
-  const SDL_PixelFormat* format = image->format;
-  if(!is_power_of_2(image->w) || !is_power_of_2(image->h))
-    throw std::runtime_error("image has no power of 2 size");
-  if(format->BitsPerPixel != 24 && format->BitsPerPixel != 32)
-    throw std::runtime_error("image has no 24 or 32 bit color depth");
-
-  this->width = image->w;
-  this->height = image->h;
-
-  assert_gl("before creating texture");
-  glGenTextures(1, &handle);
-
-  try {
-    GLenum sdl_format;
-    if(format->BytesPerPixel == 3)
-      sdl_format = GL_RGB;
-    else if(format->BytesPerPixel == 4)
-      sdl_format = GL_RGBA;
-    else
-      assert(false);
-
-    glBindTexture(GL_TEXTURE_2D, handle);
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-    glPixelStorei(GL_UNPACK_ROW_LENGTH, image->pitch/format->BytesPerPixel);
-    glTexImage2D(GL_TEXTURE_2D, 0, glformat, width, height, 0, sdl_format,
-            GL_UNSIGNED_BYTE, image->pixels);
-
-    assert_gl("creating texture");
-
-    set_texture_params();
-  } catch(...) {
-    glDeleteTextures(1, &handle);
-    throw;
-  }
-}
-
-Texture::~Texture()
-{
-  glDeleteTextures(1, &handle);
-}
-
-void
-Texture::set_texture_params()
-{
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-
-  assert_gl("set texture params");
-}
index bf87c65..6e4c462 100644 (file)
 #ifndef __TEXTURE_HPP__
 #define __TEXTURE_HPP__
 
-#include <SDL.h>
-#include <GL/gl.h>
+#include <config.h>
+
+#include <assert.h>
+#include <string>
+
+#include "texture_manager.hpp"
+
+/// bitset for drawing effects
+enum DrawingEffect {
+  /** Don't apply anything */
+  NO_EFFECT,
+  /** Draw the Surface upside down */
+  VERTICAL_FLIP,
+  /** Draw the Surface from left to down */
+  HORIZONTAL_FLIP,
+  NUM_EFFECTS
+};
 
 /**
  * This class is a wrapper around a texture handle. It stores the texture width
 class Texture
 {
 protected:
-  friend class TextureManager;
-  GLuint handle;
-  unsigned int width;
-  unsigned int height;
+  int refcount;
+  std::string filename;
 
 public:
-  Texture(unsigned int width, unsigned int height, GLenum glformat);
-  Texture(SDL_Surface* surface, GLenum glformat);
-  virtual ~Texture();
+  Texture() : refcount(0), filename() {}
+  virtual ~Texture() {}
+
+  virtual unsigned int get_texture_width() const = 0;
+  virtual unsigned int get_texture_height() const = 0;
+  virtual unsigned int get_image_width() const = 0;
+  virtual unsigned int get_image_height() const = 0;
 
-  GLuint get_handle() const
+  std::string get_filename() const
   {
-    return handle;
+    return filename;
   }
 
-  unsigned int get_width() const
+  void set_filename(std::string filename)
   {
-    return width;
+    this->filename = filename;
   }
 
-  unsigned int get_height() const
+  void ref()
   {
-    return height;
+    refcount++;
+  }
+
+  void unref()
+  {
+    assert(refcount > 0);
+    refcount--;
+    if(refcount == 0)
+      release();
   }
 
 private:
-  void set_texture_params();
+  void release()
+  {
+    texture_manager->release(this);
+  }
 };
 
 #endif
index 6326d04..7b556a6 100644 (file)
 #include <assert.h>
 #include <SDL.h>
 #include <SDL_image.h>
-#include <GL/gl.h>
-#include <GL/glext.h>
 #include <iostream>
 #include <sstream>
 #include <stdexcept>
 #include "physfs/physfs_sdl.hpp"
-#include "image_texture.hpp"
+#include "gl_texture.hpp"
+#include "sdl_texture.hpp"
 #include "glutil.hpp"
+#include "gameconfig.hpp"
 #include "file_system.hpp"
 #include "log.hpp"
 
@@ -52,13 +52,13 @@ TextureManager::~TextureManager()
   }
 }
 
-ImageTexture*
+Texture*
 TextureManager::get(const std::string& _filename)
 {
   std::string filename = FileSystem::normalize(_filename);
   ImageTextures::iterator i = image_textures.find(filename);
 
-  ImageTexture* texture = NULL;
+  Texture* texture = NULL;
   if(i != image_textures.end())
     texture = i->second;
 
@@ -71,81 +71,60 @@ TextureManager::get(const std::string& _filename)
 }
 
 void
-TextureManager::release(ImageTexture* texture)
+TextureManager::release(Texture* texture)
 {
-  image_textures.erase(texture->filename);
+  image_textures.erase(texture->get_filename());
   delete texture;
 }
 
+#ifdef HAVE_OPENGL
 void
-TextureManager::register_texture(Texture* texture)
+TextureManager::register_texture(GL::Texture* texture)
 {
   textures.insert(texture);
 }
 
 void
-TextureManager::remove_texture(Texture* texture)
+TextureManager::remove_texture(GL::Texture* texture)
 {
   textures.erase(texture);
 }
+#endif
 
-static inline int next_power_of_two(int val)
-{
-  int result = 1;
-  while(result < val)
-    result *= 2;
-  return result;
-}
-
-ImageTexture*
+Texture*
 TextureManager::create_image_texture(const std::string& filename)
 {
   SDL_Surface* image = IMG_Load_RW(get_physfs_SDLRWops(filename), 1);
-  if(image == NULL) {
+  if(image == 0) {
     std::ostringstream msg;
     msg << "Couldn't load image '" << filename << "' :" << SDL_GetError();
     throw std::runtime_error(msg.str());
   }
 
-  int texture_w = next_power_of_two(image->w);
-  int texture_h = next_power_of_two(image->h);
-
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-  SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
-      texture_w, texture_h, 32,
-      0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
-#else
-  SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
-      texture_w, texture_h, 32,
-      0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
-#endif
-
-  if(convert == 0) {
-    SDL_FreeSurface(image);
-    throw std::runtime_error("Couldn't create texture: out of memory");
-  }
-
-  SDL_SetAlpha(image, 0, 0);
-  SDL_BlitSurface(image, 0, convert, 0);
-
-  ImageTexture* result = NULL;
+  Texture* result = 0;
   try {
-    result = new ImageTexture(convert);
-    result->filename = filename;
-    result->image_width = image->w;
-    result->image_height = image->h;
+#ifdef HAVE_OPENGL
+    if(config->video == "opengl")
+    {
+      result = new GL::Texture(image);
+    }
+    else
+#endif
+    {
+      result = new SDL::Texture(image);
+    }
+    result->set_filename(filename);
   } catch(...) {
     delete result;
     SDL_FreeSurface(image);
-    SDL_FreeSurface(convert);
     throw;
   }
 
   SDL_FreeSurface(image);
-  SDL_FreeSurface(convert);
   return result;
 }
 
+#ifdef HAVE_OPENGL
 void
 TextureManager::save_textures()
 {
@@ -160,12 +139,12 @@ TextureManager::save_textures()
   }
   for(ImageTextures::iterator i = image_textures.begin();
       i != image_textures.end(); ++i) {
-    save_texture(i->second);
+    save_texture(dynamic_cast<GL::Texture *>(i->second));
   }
 }
 
 void
-TextureManager::save_texture(Texture* texture)
+TextureManager::save_texture(GL::Texture* texture)
 {
   SavedTexture saved_texture;
   saved_texture.texture = texture;
@@ -193,8 +172,8 @@ TextureManager::save_texture(Texture* texture)
 
   saved_textures.push_back(saved_texture);
 
-  glDeleteTextures(1, &(texture->handle));
-  texture->handle = 0;
+  glDeleteTextures(1, &(texture->get_handle()));
+  texture->set_handle(0);
 
   assert_gl("retrieving texture for save");
 }
@@ -235,8 +214,9 @@ TextureManager::reload_textures()
                     saved_texture.wrap_t);
 
     assert_gl("setting texture_params");
-    saved_texture.texture->handle = handle;
+    saved_texture.texture->set_handle(handle);
   }
 
   saved_textures.clear();
 }
+#endif
index ee75655..1431c68 100644 (file)
 #ifndef __IMAGE_TEXTURE_MANAGER_HPP__
 #define __IMAGE_TEXTURE_MANAGER_HPP__
 
-#include <GL/gl.h>
+#include <config.h>
+
+#include "glutil.hpp"
 #include <string>
 #include <vector>
 #include <map>
 #include <set>
 
 class Texture;
-class ImageTexture;
+namespace GL { class Texture; }
 
 class TextureManager
 {
@@ -35,29 +37,32 @@ public:
   TextureManager();
   ~TextureManager();
 
-  ImageTexture* get(const std::string& filename);
+  Texture* get(const std::string& filename);
 
-  void register_texture(Texture* texture);
-  void remove_texture(Texture* texture);
+#ifdef HAVE_OPENGL
+  void register_texture(GL::Texture* texture);
+  void remove_texture(GL::Texture* texture);
 
   void save_textures();
   void reload_textures();
+#endif
 
 private:
-  friend class ImageTexture;
-  void release(ImageTexture* texture);
+  friend class Texture;
+  void release(Texture* texture);
 
-  typedef std::map<std::string, ImageTexture*> ImageTextures;
+  typedef std::map<std::string, Texture*> ImageTextures;
   ImageTextures image_textures;
 
-  ImageTexture* create_image_texture(const std::string& filename);
+  Texture* create_image_texture(const std::string& filename);
 
-  typedef std::set<Texture*> Textures;
+#ifdef HAVE_OPENGL
+  typedef std::set<GL::Texture*> Textures;
   Textures textures;
 
   struct SavedTexture
   {
-    Texture* texture;
+    GL::Texture* texture;
     GLint width;
     GLint height;
     char* pixels;
@@ -70,7 +75,8 @@ private:
   };
   std::vector<SavedTexture> saved_textures;
 
-  void save_texture(Texture* texture);
+  void save_texture(GL::Texture* texture);
+#endif
 };
 
 extern TextureManager* texture_manager;