[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.
Config::Config()
{
use_fullscreen = true;
+#ifdef HAVE_OPENGL
+ video = "opengl";
+#else
+ video = "sdl";
+#endif
try_vsync = true;
show_fps = false;
sound_enabled = true;
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);
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);
#ifndef SUPERTUX_CONFIG_H
#define SUPERTUX_CONFIG_H
+#include <config.h>
+
#include <string>
class Config
float aspect_ratio;
bool use_fullscreen;
+ std::string video;
bool try_vsync;
bool show_fps;
bool sound_enabled;
#include <physfs.h>
#include <SDL.h>
#include <SDL_image.h>
-#include <GL/gl.h>
#include "gameconfig.hpp"
#include "resources.hpp"
#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"
#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;
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 */
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);
}
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()
}
//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;
}
void
-MainLoop::run()
+MainLoop::run(DrawingContext &context)
{
- DrawingContext context;
-
Uint32 last_ticks = 0;
Uint32 elapsed_ticks = 0;
MainLoop();
~MainLoop();
- void run();
+ void run(DrawingContext &context);
void exit_screen(ScreenFade* fade = NULL);
void quit(ScreenFade* fade = NULL);
void set_speed(float speed);
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;
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;
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;
};
#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;
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
DrawingRequest* request = new(obst) DrawingRequest();
+ request->target = target;
request->type = SURFACE;
request->pos = transform.apply(position);
DrawingRequest* request = new(obst) DrawingRequest();
+ request->target = target;
request->type = SURFACE_PART;
request->pos = transform.apply(dest);
request->layer = layer;
{
DrawingRequest* request = new(obst) DrawingRequest();
+ request->target = target;
request->type = TEXT;
request->pos = transform.apply(position);
request->layer = layer;
{
DrawingRequest* request = new(obst) DrawingRequest();
+ request->target = target;
request->type = GRADIENT;
request->pos = Vector(0,0);
request->layer = layer;
{
DrawingRequest* request = new(obst) DrawingRequest();
+ request->target = target;
request->type = FILLRECT;
request->pos = transform.apply(topleft);
request->layer = layer;
{
DrawingRequest* request = new(obst) DrawingRequest();
+ request->target = target;
request->type = FILLRECT;
request->pos = transform.apply(rect.p1);
request->layer = layer;
}
DrawingRequest* request = new(obst) DrawingRequest();
+ request->target = target;
request->type = GETLIGHT;
request->pos = transform.apply(position);
}
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
// 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
};
void
-DrawingContext::handle_drawing_requests(DrawingRequests& requests) const
+DrawingContext::handle_drawing_requests(DrawingRequests& requests)
{
std::stable_sort(requests.begin(), requests.end(), RequestPtrCompare());
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
}
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;
#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
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);
/// 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);
}
};
+ Renderer *renderer;
+ Lightmap *lightmap;
+
/// the transform stack
std::vector<Transform> transformstack;
/// the currently active transform
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;
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;
--- /dev/null
+// $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
+
#include "lisp/lisp.hpp"
#include "screen.hpp"
#include "font.hpp"
+#include "renderer.hpp"
#include "drawing_context.hpp"
#include "log.hpp"
}
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;
// 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;
}
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)
// 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
}
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;
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;
}
}
#include "math/vector.hpp"
#include "math/rect.hpp"
+class Renderer;
+
enum FontAlignment {
ALIGN_LEFT,
ALIGN_CENTER,
/** 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;
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;
--- /dev/null
+// $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
--- /dev/null
+// $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
--- /dev/null
+// $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
--- /dev/null
+// $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
--- /dev/null
+// $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
--- /dev/null
+// $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
#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)
{
#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
// 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"
{
texture_manager->release(this);
}
+#endif
// 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__
};
#endif
+#endif
--- /dev/null
+// $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
+
--- /dev/null
+// $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
+
--- /dev/null
+// $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);
+ }
+}
--- /dev/null
+// $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
+
--- /dev/null
+// $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);
+ }
+}
--- /dev/null
+// $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
+
--- /dev/null
+// $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];
+ }
+}
--- /dev/null
+// $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
+++ /dev/null
-// $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);
-}
#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.
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
+++ /dev/null
-// $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");
-}
#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
#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"
}
}
-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;
}
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()
{
}
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;
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");
}
saved_texture.wrap_t);
assert_gl("setting texture_params");
- saved_texture.texture->handle = handle;
+ saved_texture.texture->set_handle(handle);
}
saved_textures.clear();
}
+#endif
#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
{
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;
};
std::vector<SavedTexture> saved_textures;
- void save_texture(Texture* texture);
+ void save_texture(GL::Texture* texture);
+#endif
};
extern TextureManager* texture_manager;