From c79b901309bf5e0544fef1e92d264f51402f4370 Mon Sep 17 00:00:00 2001 From: Ingo Ruhnke Date: Mon, 14 Jun 2004 22:45:24 +0000 Subject: [PATCH] - moved tilemanager into its own class - renamed texture.h to surface.h SVN-Revision: 1490 --- src/Makefile.am | 6 +- src/background.h | 2 +- src/badguy.h | 2 +- src/button.h | 2 +- src/gameobjs.cpp | 2 + src/gameobjs.h | 2 +- src/high_scores.cpp | 2 +- src/level.h | 2 +- src/leveleditor.cpp | 1 + src/leveleditor.h | 2 +- src/menu.h | 2 +- src/mousecursor.h | 2 +- src/particlesystem.h | 2 +- src/player.h | 2 +- src/scene.h | 2 +- src/screen/drawing_context.cpp | 2 +- src/screen/font.h | 2 +- src/screen/screen.h | 2 +- src/screen/surface.cpp | 874 +++++++++++++++++++++++++++++++++++++++++ src/screen/surface.h | 180 +++++++++ src/sector.cpp | 1 + src/setup.cpp | 2 +- src/special.h | 2 +- src/sprite.h | 2 +- src/supertux.cpp | 4 +- src/tile.cpp | 132 +------ src/tile.h | 63 +-- src/tile_manager.cpp | 156 ++++++++ src/tile_manager.h | 82 ++++ src/tilemap.cpp | 1 + src/title.cpp | 2 +- src/worldmap.cpp | 2 +- 32 files changed, 1332 insertions(+), 210 deletions(-) create mode 100644 src/screen/surface.cpp create mode 100644 src/screen/surface.h create mode 100644 src/tile_manager.cpp create mode 100644 src/tile_manager.h diff --git a/src/Makefile.am b/src/Makefile.am index 3cff78bea..6fc28fdb9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,8 +11,8 @@ screen/font.h \ screen/font.cpp \ screen/screen.h \ screen/screen.cpp \ -screen/texture.cpp \ -screen/texture.h \ +screen/surface.cpp \ +screen/surface.h \ lispwriter.h \ lispwriter.cpp \ badguy.cpp \ @@ -85,6 +85,8 @@ worldmap.cpp \ worldmap.h \ tile.h \ tile.cpp \ +tile_manager.h \ +tile_manager.cpp \ resources.h \ resources.cpp \ gameobjs.h \ diff --git a/src/background.h b/src/background.h index 91df5ae2a..bafb77c5d 100644 --- a/src/background.h +++ b/src/background.h @@ -20,7 +20,7 @@ #ifndef SUPERTUX_BACKGROUND_H #define SUPERTUX_BACKGROUND_H -#include "screen/texture.h" +#include "screen/surface.h" #include "screen/drawing_context.h" #include "game_object.h" #include "lispreader.h" diff --git a/src/badguy.h b/src/badguy.h index b9c2d129f..6e53ec98b 100644 --- a/src/badguy.h +++ b/src/badguy.h @@ -26,7 +26,7 @@ #include "SDL.h" #include "timer.h" -#include "screen/texture.h" +#include "screen/surface.h" #include "physic.h" #include "sprite.h" #include "defines.h" diff --git a/src/button.h b/src/button.h index 1290ff1e4..a42254eff 100644 --- a/src/button.h +++ b/src/button.h @@ -23,7 +23,7 @@ #include -#include "screen/texture.h" +#include "screen/surface.h" #include "timer.h" enum ButtonState { diff --git a/src/gameobjs.cpp b/src/gameobjs.cpp index cd9d1c0b1..674c89aa8 100644 --- a/src/gameobjs.cpp +++ b/src/gameobjs.cpp @@ -23,7 +23,9 @@ #include #include +#include "globals.h" #include "tile.h" +#include "tile_manager.h" #include "gameloop.h" #include "gameobjs.h" #include "sprite_manager.h" diff --git a/src/gameobjs.h b/src/gameobjs.h index 16106b4ff..c19a72468 100644 --- a/src/gameobjs.h +++ b/src/gameobjs.h @@ -23,7 +23,7 @@ #define SUPERTUX_GAMEOBJS_H #include "type.h" -#include "screen/texture.h" +#include "screen/surface.h" #include "timer.h" #include "scene.h" #include "physic.h" diff --git a/src/high_scores.cpp b/src/high_scores.cpp index db3cbfe11..ae49086b3 100644 --- a/src/high_scores.cpp +++ b/src/high_scores.cpp @@ -28,7 +28,7 @@ #include "menu.h" #include "screen/drawing_context.h" #include "screen/screen.h" -#include "screen/texture.h" +#include "screen/surface.h" #include "setup.h" #include "lispreader.h" diff --git a/src/level.h b/src/level.h index 091d9b25d..e9bb6f0d3 100644 --- a/src/level.h +++ b/src/level.h @@ -24,7 +24,7 @@ #include #include -#include "screen/texture.h" +#include "screen/surface.h" #include "lispreader.h" #include "musicref.h" diff --git a/src/leveleditor.cpp b/src/leveleditor.cpp index 71135d0ec..6b1b9aa41 100644 --- a/src/leveleditor.cpp +++ b/src/leveleditor.cpp @@ -44,6 +44,7 @@ #include "player.h" #include "scene.h" #include "tile.h" +#include "tile_manager.h" #include "resources.h" #include "background.h" #include "camera.h" diff --git a/src/leveleditor.h b/src/leveleditor.h index 6598994e9..4ded83fbc 100644 --- a/src/leveleditor.h +++ b/src/leveleditor.h @@ -25,7 +25,7 @@ #include "screen/drawing_context.h" #include "game_object.h" -#include "screen/texture.h" +#include "screen/surface.h" #include "level.h" #include "button.h" #include "menu.h" diff --git a/src/menu.h b/src/menu.h index eb596dd2d..a3b99e021 100644 --- a/src/menu.h +++ b/src/menu.h @@ -24,7 +24,7 @@ #include "SDL.h" -#include "screen/texture.h" +#include "screen/surface.h" #include "timer.h" #include "type.h" #include "mousecursor.h" diff --git a/src/mousecursor.h b/src/mousecursor.h index cd8697714..a35b96cb2 100644 --- a/src/mousecursor.h +++ b/src/mousecursor.h @@ -23,7 +23,7 @@ #include #include "timer.h" -#include "screen/texture.h" +#include "screen/surface.h" #define MC_FRAME_PERIOD 800 // in ms diff --git a/src/particlesystem.h b/src/particlesystem.h index e27930e31..80b3e73e5 100644 --- a/src/particlesystem.h +++ b/src/particlesystem.h @@ -22,7 +22,7 @@ #include -#include "screen/texture.h" +#include "screen/surface.h" #include "game_object.h" #include "serializable.h" diff --git a/src/player.h b/src/player.h index 0d17af3a7..2d0646516 100644 --- a/src/player.h +++ b/src/player.h @@ -25,7 +25,7 @@ #include "bitmask.h" #include "type.h" #include "timer.h" -#include "screen/texture.h" +#include "screen/surface.h" #include "collision.h" #include "sound.h" #include "moving_object.h" diff --git a/src/scene.h b/src/scene.h index 75271985b..57745d2d5 100644 --- a/src/scene.h +++ b/src/scene.h @@ -20,7 +20,7 @@ #ifndef SUPERTUX_SCENE_H #define SUPERTUX_SCENE_H -#include "screen/texture.h" +#include "screen/surface.h" #include "timer.h" #define FRAME_RATE 10 // 100 Frames per second (10ms) diff --git a/src/screen/drawing_context.cpp b/src/screen/drawing_context.cpp index 13d260dc7..9a2227441 100644 --- a/src/screen/drawing_context.cpp +++ b/src/screen/drawing_context.cpp @@ -21,7 +21,7 @@ #include #include "drawing_context.h" -#include "texture.h" +#include "surface.h" #include "globals.h" #include "font.h" diff --git a/src/screen/font.h b/src/screen/font.h index 5b44f6ed6..f3f31cde0 100644 --- a/src/screen/font.h +++ b/src/screen/font.h @@ -23,7 +23,7 @@ #include -#include "texture.h" +#include "surface.h" #include "vector.h" void display_text_file(const std::string& file, const std::string& surface, float scroll_speed); diff --git a/src/screen/screen.h b/src/screen/screen.h index 2383573e2..7932391d1 100644 --- a/src/screen/screen.h +++ b/src/screen/screen.h @@ -49,7 +49,7 @@ public: Uint8 red, green, blue, alpha; }; -#include "texture.h" +#include "surface.h" class Vector; diff --git a/src/screen/surface.cpp b/src/screen/surface.cpp new file mode 100644 index 000000000..0353b3dde --- /dev/null +++ b/src/screen/surface.cpp @@ -0,0 +1,874 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2004 Tobias Glaesser +// +// 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 +#include +#include + +#include "SDL.h" +#include "SDL_image.h" + +#include "surface.h" +#include "globals.h" +#include "setup.h" + +Surface::Surfaces Surface::surfaces; + +SurfaceData::SurfaceData(SDL_Surface* temp, int use_alpha_) + : type(SURFACE), surface(0), use_alpha(use_alpha_) +{ + // Copy the given surface and make sure that it is not stored in + // video memory + surface = SDL_CreateRGBSurface(temp->flags & (~SDL_HWSURFACE), + temp->w, temp->h, + temp->format->BitsPerPixel, + temp->format->Rmask, + temp->format->Gmask, + temp->format->Bmask, + temp->format->Amask); + if(!surface) + st_abort("No memory left.", ""); + SDL_SetAlpha(temp,0,0); + SDL_BlitSurface(temp, NULL, surface, NULL); +} + +SurfaceData::SurfaceData(const std::string& file_, int use_alpha_) + : type(LOAD), surface(0), file(file_), use_alpha(use_alpha_) +{} + +SurfaceData::SurfaceData(const std::string& file_, int x_, int y_, int w_, int h_, int use_alpha_) + : type(LOAD_PART), surface(0), file(file_), use_alpha(use_alpha_), + x(x_), y(y_), w(w_), h(h_) +{} + +SurfaceData::SurfaceData(Color top_gradient_, Color bottom_gradient_, int w_, int h_) + : type(GRADIENT), surface(0), use_alpha(false), w(w_), h(h_) +{ +top_gradient = top_gradient_; +bottom_gradient = bottom_gradient_; +} + + +SurfaceData::~SurfaceData() +{ + SDL_FreeSurface(surface); +} + +SurfaceImpl* +SurfaceData::create() +{ +#ifndef NOOPENGL + if (use_gl) + return create_SurfaceOpenGL(); + else + return create_SurfaceSDL(); +#else + return create_SurfaceSDL(); +#endif +} + +SurfaceSDL* +SurfaceData::create_SurfaceSDL() +{ + switch(type) + { + case LOAD: + return new SurfaceSDL(file, use_alpha); + case LOAD_PART: + return new SurfaceSDL(file, x, y, w, h, use_alpha); + case SURFACE: + return new SurfaceSDL(surface, use_alpha); + case GRADIENT: + return new SurfaceSDL(top_gradient, bottom_gradient, w, h); + } + assert(0); +} + +SurfaceOpenGL* +SurfaceData::create_SurfaceOpenGL() +{ +#ifndef NOOPENGL + switch(type) + { + case LOAD: + return new SurfaceOpenGL(file, use_alpha); + case LOAD_PART: + return new SurfaceOpenGL(file, x, y, w, h, use_alpha); + case SURFACE: + return new SurfaceOpenGL(surface, use_alpha); + case GRADIENT: + return new SurfaceOpenGL(top_gradient, bottom_gradient, w, h); + } +#endif + assert(0); +} + +#ifndef NOOPENGL +/* Quick utility function for texture creation */ +static int power_of_two(int input) +{ + int value = 1; + + while ( value < input ) + { + value <<= 1; + } + return value; +} +#endif + +Surface::Surface(SDL_Surface* surf, int use_alpha) + : data(surf, use_alpha), w(0), h(0) +{ + impl = data.create(); + if (impl) + { + w = impl->w; + h = impl->h; + } + surfaces.push_back(this); +} + +Surface::Surface(const std::string& file, int use_alpha) + : data(file, use_alpha), w(0), h(0) +{ + impl = data.create(); + if (impl) + { + w = impl->w; + h = impl->h; + } + surfaces.push_back(this); +} + +Surface::Surface(const std::string& file, int x, int y, int w, int h, int use_alpha) + : data(file, x, y, w, h, use_alpha), w(0), h(0) +{ + impl = data.create(); + if (impl) + { + w = impl->w; + h = impl->h; + } + surfaces.push_back(this); +} + +Surface::Surface(Color top_background, Color bottom_background, int w, int h) + : data(top_background, bottom_background, w, h), w(0), h(0) +{ + impl = data.create(); + if (impl) + { + w = impl->w; + h = impl->h; + } + surfaces.push_back(this); +} + +void +Surface::reload() +{ + delete impl; + impl = data.create(); + if (impl) + { + w = impl->w; + h = impl->h; + } +} + +Surface::~Surface() +{ +#ifdef DEBUG + bool found = false; + for(std::list::iterator i = surfaces.begin(); i != surfaces.end(); + ++i) + { + if(*i == this) + { + found = true; break; + } + } + if(!found) + printf("Error: Surface freed twice!!!\n"); +#endif + surfaces.remove(this); + delete impl; +} + +void +Surface::reload_all() +{ + for(Surfaces::iterator i = surfaces.begin(); i != surfaces.end(); ++i) + { + (*i)->reload(); + } +} + +void +Surface::debug_check() +{ + for(Surfaces::iterator i = surfaces.begin(); i != surfaces.end(); ++i) + { + printf("Surface not freed: T:%d F:%s.\n", (*i)->data.type, + (*i)->data.file.c_str()); + } +} + +void +Surface::resize(int w_, int h_) +{ + if (impl) + { + w = w_; + h = h_; + if (impl->resize(w_,h_) == -2) + reload(); + } +} + +SDL_Surface* +sdl_surface_part_from_file(const std::string& file, int x, int y, int w, int h, int use_alpha) +{ + SDL_Rect src; + SDL_Surface * sdl_surface; + SDL_Surface * temp; + SDL_Surface * conv; + + temp = IMG_Load(file.c_str()); + + if (temp == NULL) + st_abort("Can't load", file); + + /* Set source rectangle for conv: */ + + src.x = x; + src.y = y; + src.w = w; + src.h = h; + + conv = SDL_CreateRGBSurface(temp->flags, w, h, temp->format->BitsPerPixel, + temp->format->Rmask, + temp->format->Gmask, + temp->format->Bmask, + temp->format->Amask); + + /* #if SDL_BYTEORDER == SDL_BIG_ENDIAN + 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); + #else + + 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + #endif*/ + + SDL_SetAlpha(temp,0,0); + + SDL_BlitSurface(temp, &src, conv, NULL); + if(use_alpha == IGNORE_ALPHA && !use_gl) + sdl_surface = SDL_DisplayFormat(conv); + else + sdl_surface = SDL_DisplayFormatAlpha(conv); + + if (sdl_surface == NULL) + st_abort("Can't covert to display format", file); + + if (use_alpha == IGNORE_ALPHA && !use_gl) + SDL_SetAlpha(sdl_surface, 0, 0); + + SDL_FreeSurface(temp); + SDL_FreeSurface(conv); + + return sdl_surface; +} + +SDL_Surface* +sdl_surface_from_file(const std::string& file, int use_alpha) +{ + SDL_Surface* sdl_surface; + SDL_Surface* temp; + + temp = IMG_Load(file.c_str()); + + if (temp == NULL) + st_abort("Can't load", file); + + if(use_alpha == IGNORE_ALPHA && !use_gl) + sdl_surface = SDL_DisplayFormat(temp); + else + sdl_surface = SDL_DisplayFormatAlpha(temp); + + if (sdl_surface == NULL) + st_abort("Can't covert to display format", file); + + if (use_alpha == IGNORE_ALPHA && !use_gl) + SDL_SetAlpha(sdl_surface, 0, 0); + + SDL_FreeSurface(temp); + + return sdl_surface; +} + +SDL_Surface* +sdl_surface_from_sdl_surface(SDL_Surface* sdl_surf, int use_alpha) +{ + SDL_Surface* sdl_surface; + Uint32 saved_flags; + Uint8 saved_alpha; + + /* Save the alpha blending attributes */ + saved_flags = sdl_surf->flags&(SDL_SRCALPHA|SDL_RLEACCELOK); + saved_alpha = sdl_surf->format->alpha; + if ( (saved_flags & SDL_SRCALPHA) + == SDL_SRCALPHA ) + { + SDL_SetAlpha(sdl_surf, 0, 0); + } + + if(use_alpha == IGNORE_ALPHA && !use_gl) + sdl_surface = SDL_DisplayFormat(sdl_surf); + else + sdl_surface = SDL_DisplayFormatAlpha(sdl_surf); + + /* Restore the alpha blending attributes */ + if ( (saved_flags & SDL_SRCALPHA) + == SDL_SRCALPHA ) + { + SDL_SetAlpha(sdl_surface, saved_flags, saved_alpha); + } + + if (sdl_surface == NULL) + st_abort("Can't covert to display format", "SURFACE"); + + if (use_alpha == IGNORE_ALPHA && !use_gl) + SDL_SetAlpha(sdl_surface, 0, 0); + + return sdl_surface; +} + +SDL_Surface* +sdl_surface_from_gradient(Color top, Color bottom, int w, int h) +{ + SDL_Surface* sdl_surface; + + sdl_surface = SDL_CreateRGBSurface(screen->flags, w, h, + screen->format->BitsPerPixel, screen->format->Rmask, + screen->format->Gmask, screen->format->Bmask, screen->format->Amask); + + if(sdl_surface == NULL) + st_abort("Cannot create surface for the gradient", "SURFACE"); + + if(top == bottom) + { + SDL_FillRect(sdl_surface, NULL, SDL_MapRGB(sdl_surface->format, + top.red, top.green, top.blue)); + } + else + { + float redstep = (float(bottom.red)-float(top.red)) / float(h); + float greenstep = (float(bottom.green)-float(top.green)) / float(h); + float bluestep = (float(bottom.blue) - float(top.blue)) / float(h); + + SDL_Rect rect; + rect.x = 0; + rect.w = w; + rect.h = 1; + for(float y = 0; y < h; y++) + { + rect.y = (int)y; + SDL_FillRect(sdl_surface, &rect, SDL_MapRGB(sdl_surface->format, + int(float(top.red) + redstep * y), + int(float(top.green) + greenstep * y), + int(float(top.blue) + bluestep * y))); + } + } + + return sdl_surface; +} + +//--------------------------------------------------------------------------- + +SurfaceImpl::SurfaceImpl() +{} + +SurfaceImpl::~SurfaceImpl() +{ + SDL_FreeSurface(sdl_surface); +} + +SDL_Surface* SurfaceImpl::get_sdl_surface() const +{ + return sdl_surface; +} + +int SurfaceImpl::resize(int w_, int h_) +{ + w = w_; + h = h_; + SDL_Rect dest; + dest.x = 0; + dest.y = 0; + dest.w = w; + dest.h = h; + int ret = SDL_SoftStretch(sdl_surface, NULL, + sdl_surface, &dest); + return ret; +} + +#ifndef NOOPENGL +SurfaceOpenGL::SurfaceOpenGL(SDL_Surface* surf, int use_alpha) +{ + sdl_surface = sdl_surface_from_sdl_surface(surf, use_alpha); + create_gl(sdl_surface,&gl_texture); + + w = sdl_surface->w; + h = sdl_surface->h; +} + +SurfaceOpenGL::SurfaceOpenGL(const std::string& file, int use_alpha) +{ + sdl_surface = sdl_surface_from_file(file, use_alpha); + create_gl(sdl_surface,&gl_texture); + + w = sdl_surface->w; + h = sdl_surface->h; +} + +SurfaceOpenGL::SurfaceOpenGL(const std::string& file_, int x_, int y_, int w_, int h_, int use_alpha_) +{ + sdl_surface = sdl_surface_part_from_file(file_,x_,y_,w_,h_,use_alpha_); + + create_gl(sdl_surface, &gl_texture); + + w = sdl_surface->w; + h = sdl_surface->h; +} + +SurfaceOpenGL::SurfaceOpenGL(Color top_gradient, Color bottom_gradient, int w, int h) +{ + sdl_surface = sdl_surface_from_gradient(top_gradient, bottom_gradient, w, h); + create_gl(sdl_surface, &gl_texture); + + w = sdl_surface->w; + h = sdl_surface->h; +} + +SurfaceOpenGL::~SurfaceOpenGL() +{ + glDeleteTextures(1, &gl_texture); +} + +void +SurfaceOpenGL::create_gl(SDL_Surface * surf, GLuint * tex) +{ + Uint32 saved_flags; + Uint8 saved_alpha; + int w, h; + SDL_Surface *conv; + + w = power_of_two(surf->w); + h = power_of_two(surf->h), + +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + conv = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, surf->format->BitsPerPixel, + 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); +#else + conv = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, surf->format->BitsPerPixel, + 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); +#endif + + /* Save the alpha blending attributes */ + saved_flags = surf->flags&(SDL_SRCALPHA|SDL_RLEACCELOK); + saved_alpha = surf->format->alpha; + if ( (saved_flags & SDL_SRCALPHA) + == SDL_SRCALPHA ) + { + SDL_SetAlpha(surf, 0, 0); + } + + SDL_BlitSurface(surf, 0, conv, 0); + + /* Restore the alpha blending attributes */ + if ( (saved_flags & SDL_SRCALPHA) + == SDL_SRCALPHA ) + { + SDL_SetAlpha(surf, saved_flags, saved_alpha); + } + + // We check all the pixels of the surface to figure out which + // internal format OpenGL should use for storing it, ie. if no alpha + // is present store in RGB instead of RGBA, this saves a few bytes + // of memory, but much more importantly it makes the game look + // *much* better in 16bit color mode + int internal_format = GL_RGB10_A2; + bool has_alpha = false; + + unsigned char* buf = static_cast(conv->pixels); + for (int y = 0; y < surf->h; ++y) + for (int x = 0; x < surf->w; ++x) + { + if (buf[(conv->pitch*y + x*4) + 3] != 255) + { + has_alpha = true; + break; + } + } + + if (!has_alpha) + { + internal_format = GL_RGB; + } + + glGenTextures(1, &*tex); + glBindTexture(GL_TEXTURE_2D , *tex); + 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_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glPixelStorei(GL_UNPACK_ROW_LENGTH, conv->pitch / conv->format->BytesPerPixel); + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, conv->pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + SDL_FreeSurface(conv); +} + +int +SurfaceOpenGL::draw(float x, float y, Uint8 alpha, Uint32 effect) +{ + float pw = power_of_two(w); + float ph = power_of_two(h); + + if(effect & SEMI_TRANSPARENT) + alpha = 128; + + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glColor4ub(alpha, alpha, alpha, alpha); + + glBindTexture(GL_TEXTURE_2D, gl_texture); + + glBegin(GL_QUADS); + + if(effect & VERTICAL_FLIP) + { + glTexCoord2f(0, 0); + glVertex2f(x, (float)h+y); + + glTexCoord2f((float)w / pw, 0); + glVertex2f((float)w+x, (float)h+y); + + glTexCoord2f((float)w / pw, (float)h / ph); + glVertex2f((float)w+x, y); + + glTexCoord2f(0, (float)h / ph); + glVertex2f(x, y); + } + else + { + glTexCoord2f(0, 0); + glVertex2f(x, y); + + glTexCoord2f((float)w / pw, 0); + glVertex2f((float)w+x, y); + + glTexCoord2f((float)w / pw, (float)h / ph); + glVertex2f((float)w+x, (float)h+y); + + glTexCoord2f(0, (float)h / ph); + glVertex2f(x, (float)h+y); + } + glEnd(); + + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + + return 0; +} + +int +SurfaceOpenGL::draw_part(float sx, float sy, float x, float y, float w, float h, Uint8 alpha, Uint32 effect) +{ + float pw = power_of_two(int(this->w)); + float ph = power_of_two(int(this->h)); + + if(effect & SEMI_TRANSPARENT) + alpha = 128; + + glBindTexture(GL_TEXTURE_2D, gl_texture); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glColor4ub(alpha, alpha, alpha, alpha); + + glEnable(GL_TEXTURE_2D); + + + glBegin(GL_QUADS); + + if(effect & VERTICAL_FLIP) + { + glTexCoord2f(sx / pw, sy / ph); + glVertex2f(x, y); + + glTexCoord2f((float)(sx + w) / pw, sy / ph); + glVertex2f(w+x, y); + + glTexCoord2f((sx+w) / pw, (sy+h) / ph); + glVertex2f(w +x, h+y); + + glTexCoord2f(sx / pw, (float)(sy+h) / ph); + glVertex2f(x, h+y); + } + else + { + glTexCoord2f(sx / pw, (float)(sy+h) / ph); + glVertex2f(x, h+y); + + glTexCoord2f((sx+w) / pw, (sy+h) / ph); + glVertex2f(w +x, h+y); + + glTexCoord2f((float)(sx + w) / pw, sy / ph); + glVertex2f(w+x, y); + + glTexCoord2f(sx / pw, sy / ph); + glVertex2f(x, y); + } + + glEnd(); + + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + + return 0; +} + +#if 0 +int +SurfaceOpenGL::draw_stretched(float x, float y, int sw, int sh, Uint8 alpha) +{ + float pw = power_of_two(int(this->w)); + float ph = power_of_two(int(this->h)); + + glBindTexture(GL_TEXTURE_2D, gl_texture); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glColor4ub(alpha, alpha, alpha, alpha); + + glEnable(GL_TEXTURE_2D); + + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(x, y); + glTexCoord2f((float)w / pw, 0); + glVertex2f(sw+x, y); + glTexCoord2f((float)w / pw, (float)h / ph); glVertex2f((float)sw+x, (float)sh+y); + glVertex2f(sw +x, sh+y); + glTexCoord2f(0, (float)h / ph); + glVertex2f(x, sh+y); + glEnd(); + + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + + return 0; +} +#endif + +#endif + +SurfaceSDL::SurfaceSDL(SDL_Surface* surf, int use_alpha) +{ + sdl_surface = sdl_surface_from_sdl_surface(surf, use_alpha); + w = sdl_surface->w; + h = sdl_surface->h; +} + +SurfaceSDL::SurfaceSDL(const std::string& file, int use_alpha) +{ + sdl_surface = sdl_surface_from_file(file, use_alpha); + w = sdl_surface->w; + h = sdl_surface->h; +} + +SurfaceSDL::SurfaceSDL(const std::string& file, int x, int y, int w, int h, int use_alpha) +{ + sdl_surface = sdl_surface_part_from_file(file, x, y, w, h, use_alpha); + w = sdl_surface->w; + h = sdl_surface->h; +} + +SurfaceSDL::SurfaceSDL(Color top_gradient, Color bottom_gradient, int w, int h) +{ + sdl_surface = sdl_surface_from_gradient(top_gradient, bottom_gradient, w, h); + w = sdl_surface->w; + h = sdl_surface->h; +} + +int +SurfaceSDL::draw(float x, float y, Uint8 alpha, Uint32 effect) +{ + SDL_Rect dest; + + dest.x = (int)x; + dest.y = (int)y; + dest.w = w; + dest.h = h; + + if(effect & SEMI_TRANSPARENT) + alpha = 128; + + if(effect & VERTICAL_FLIP) // FIXME: feel free to replace this hack + { + for(float sy = 0; sy < h; sy++) + if(draw_part(0, sy, x, y+(h-sy), w, 1, alpha, NONE_EFFECT) == -2) + return -2; + return 0; + } + + if(alpha != 255) + { + /* Create a Surface, make it using colorkey, blit surface into temp, apply alpha + to temp sur, blit the temp into the screen */ + /* Note: this has to be done, since SDL doesn't allow to set alpha to surfaces that + already have an alpha mask yet... */ + + SDL_Surface* sdl_surface_copy = SDL_CreateRGBSurface (sdl_surface->flags, + sdl_surface->w, sdl_surface->h, sdl_surface->format->BitsPerPixel, + sdl_surface->format->Rmask, sdl_surface->format->Gmask, + sdl_surface->format->Bmask, + 0); + int colorkey = SDL_MapRGB(sdl_surface_copy->format, 255, 0, 255); + SDL_FillRect(sdl_surface_copy, NULL, colorkey); + SDL_SetColorKey(sdl_surface_copy, SDL_SRCCOLORKEY, colorkey); + + + SDL_BlitSurface(sdl_surface, NULL, sdl_surface_copy, NULL); + SDL_SetAlpha(sdl_surface_copy ,SDL_SRCALPHA,alpha); + + int ret = SDL_BlitSurface(sdl_surface_copy, NULL, screen, &dest); + + SDL_FreeSurface (sdl_surface_copy); + return ret; + } + + int ret = SDL_BlitSurface(sdl_surface, NULL, screen, &dest); + + return ret; +} + +int +SurfaceSDL::draw_part(float sx, float sy, float x, float y, float w, float h, Uint8 alpha, Uint32 effect) +{ + SDL_Rect src, dest; + + src.x = (int)sx; + src.y = (int)sy; + src.w = (int)w; + src.h = (int)h; + + dest.x = (int)x; + dest.y = (int)y; + dest.w = (int)w; + dest.h = (int)h; + + if(effect & SEMI_TRANSPARENT) + alpha = 128; + + if(effect & VERTICAL_FLIP) // FIXME: feel free to replace this hack + { + for(float sy_ = sy; sy_ < h; sy_++) + if(draw_part(sx, sy_, x, y+(h-sy_), w, 1, alpha, NONE_EFFECT) == -2) + return -2; + return 0; + } + + if(alpha != 255) + { + /* Create a Surface, make it using colorkey, blit surface into temp, apply alpha + to temp sur, blit the temp into the screen */ + /* Note: this has to be done, since SDL doesn't allow to set alpha to surfaces that + already have an alpha mask yet... */ + + SDL_Surface* sdl_surface_copy = SDL_CreateRGBSurface (sdl_surface->flags, + sdl_surface->w, sdl_surface->h, sdl_surface->format->BitsPerPixel, + sdl_surface->format->Rmask, sdl_surface->format->Gmask, + sdl_surface->format->Bmask, + 0); + int colorkey = SDL_MapRGB(sdl_surface_copy->format, 255, 0, 255); + SDL_FillRect(sdl_surface_copy, NULL, colorkey); + SDL_SetColorKey(sdl_surface_copy, SDL_SRCCOLORKEY, colorkey); + + + SDL_BlitSurface(sdl_surface, NULL, sdl_surface_copy, NULL); + SDL_SetAlpha(sdl_surface_copy ,SDL_SRCALPHA,alpha); + + int ret = SDL_BlitSurface(sdl_surface_copy, NULL, screen, &dest); + + SDL_FreeSurface (sdl_surface_copy); + return ret; + } + + int ret = SDL_BlitSurface(sdl_surface, &src, screen, &dest); + + return ret; +} + +#if 0 +int +SurfaceSDL::draw_stretched(float x, float y, int sw, int sh, Uint8 alpha, bool update) +{ + SDL_Rect dest; + + dest.x = (int)x; + dest.y = (int)y; + dest.w = (int)sw; + dest.h = (int)sh; + + if(alpha != 255) + SDL_SetAlpha(sdl_surface ,SDL_SRCALPHA,alpha); + + + SDL_Surface* sdl_surface_copy = SDL_CreateRGBSurface (sdl_surface->flags, + sw, sh, sdl_surface->format->BitsPerPixel, + sdl_surface->format->Rmask, sdl_surface->format->Gmask, + sdl_surface->format->Bmask, + 0); + + SDL_BlitSurface(sdl_surface, NULL, sdl_surface_copy, NULL); + SDL_SoftStretch(sdl_surface_copy, NULL, sdl_surface_copy, &dest); + + int ret = SDL_BlitSurface(sdl_surface_copy,NULL,screen,&dest); + SDL_FreeSurface(sdl_surface_copy); + + if (update == UPDATE) + update_rect(screen, dest.x, dest.y, dest.w, dest.h); + + return ret; +} +#endif + +SurfaceSDL::~SurfaceSDL() +{} + +/* EOF */ diff --git a/src/screen/surface.h b/src/screen/surface.h new file mode 100644 index 000000000..6fe26e332 --- /dev/null +++ b/src/screen/surface.h @@ -0,0 +1,180 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2004 Tobias Glaesser +// +// 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_TEXTURE_H +#define SUPERTUX_TEXTURE_H + +#include +#include + +#ifndef NOOPENGL +#include "SDL_opengl.h" +#endif + +#include "SDL.h" + +#include "screen.h" +#include "vector.h" + +SDL_Surface* sdl_surface_from_sdl_surface(SDL_Surface* sdl_surf, int use_alpha); +SDL_Surface* sdl_surface_from_nothing(); + +class SurfaceImpl; +class SurfaceSDL; +class SurfaceOpenGL; +class DrawingContext; + +/// bitset for drawing effects +enum { + /** Don't apply anything */ + NONE_EFFECT = 0x0000, + /** Draw the Surface upside down */ + VERTICAL_FLIP = 0x0001, + /** Draw the Surface with alpha equal to 128 */ + SEMI_TRANSPARENT = 0x0002 + }; + +/** This class holds all the data necessary to construct a surface */ +class SurfaceData +{ +public: + enum ConstructorType { LOAD, LOAD_PART, SURFACE, GRADIENT }; + ConstructorType type; + SDL_Surface* surface; + std::string file; + int use_alpha; + int x; + int y; + int w; + int h; + Color top_gradient; + Color bottom_gradient; + + SurfaceData(SDL_Surface* surf, int use_alpha_); + SurfaceData(const std::string& file_, int use_alpha_); + SurfaceData(const std::string& file_, int x_, int y_, int w_, int h_, int use_alpha_); + SurfaceData(Color top_gradient_, Color bottom_gradient_, int w_, int h_); + ~SurfaceData(); + + SurfaceSDL* create_SurfaceSDL(); + SurfaceOpenGL* create_SurfaceOpenGL(); + SurfaceImpl* create(); +}; + +/** Container class that holds a surface, necessary so that we can + switch Surface implementations (OpenGL, SDL) on the fly */ +class Surface +{ +public: + SurfaceData data; + SurfaceImpl* impl; + int w; + int h; + + typedef std::list Surfaces; + static Surfaces surfaces; +public: + static void reload_all(); + static void debug_check(); + + Surface(SDL_Surface* surf, int use_alpha); + Surface(const std::string& file, int use_alpha); + Surface(const std::string& file, int x, int y, int w, int h, int use_alpha); + Surface(Color top_gradient, Color bottom_gradient, int w, int h); + ~Surface(); + + /** Reload the surface, which is necesarry in case of a mode swich */ + void reload(); + + void resize(int widht, int height); +}; + +/** Surface implementation, all implementation have to inherit from + this class */ +class SurfaceImpl +{ +protected: + SDL_Surface* sdl_surface; + +public: + int w; + int h; + +public: + SurfaceImpl(); + virtual ~SurfaceImpl(); + + /** Return 0 on success, -2 if surface needs to be reloaded */ + virtual int draw(float x, float y, Uint8 alpha, Uint32 effect = NONE_EFFECT) = 0; + virtual int draw_part(float sx, float sy, float x, float y, float w, float h, Uint8 alpha, Uint32 effect = NONE_EFFECT) = 0; +#if 0 + virtual int draw_stretched(float x, float y, int w, int h, Uint8 alpha, bool update) = 0; +#endif + int resize(int w_, int h_); + + SDL_Surface* get_sdl_surface() const; // @evil@ try to avoid this function +}; + +class SurfaceSDL : public SurfaceImpl +{ +public: + SurfaceSDL(SDL_Surface* surf, int use_alpha); + SurfaceSDL(const std::string& file, int use_alpha); + SurfaceSDL(const std::string& file, int x, int y, int w, int h, int use_alpha); + SurfaceSDL(Color top_gradient, Color bottom_gradient, int w, int h); + virtual ~SurfaceSDL(); + + int draw(float x, float y, Uint8 alpha, Uint32 effect = NONE_EFFECT); + int draw_part(float sx, float sy, float x, float y, float w, float h, Uint8 alpha, Uint32 effect = NONE_EFFECT); +#if 0 + int draw_stretched(float x, float y, int w, int h, Uint8 alpha); +#endif +}; + +#ifndef NOOPENGL +class SurfaceOpenGL : public SurfaceImpl +{ +public: + GLuint gl_texture; + +public: + SurfaceOpenGL(SDL_Surface* surf, int use_alpha); + SurfaceOpenGL(const std::string& file, int use_alpha); + SurfaceOpenGL(const std::string& file, int x, int y, int w, int h, int use_alpha); + SurfaceOpenGL(Color top_gradient, Color bottom_gradient, int w, int h); + + virtual ~SurfaceOpenGL(); + + int draw(float x, float y, Uint8 alpha, Uint32 effect = NONE_EFFECT); + int draw_part(float sx, float sy, float x, float y, float w, float h, Uint8 alpha, Uint32 effect = NONE_EFFECT); +#if 0 + int draw_stretched(float x, float y, int w, int h, Uint8 alpha); +#endif + +private: + void create_gl(SDL_Surface * surf, GLuint * tex); +}; +#endif + +#endif /*SUPERTUX_TEXTURE_H*/ + +/* Local Variables: */ +/* mode: c++ */ +/* End: */ diff --git a/src/sector.cpp b/src/sector.cpp index dc24cbed1..163611803 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -24,6 +24,7 @@ #include #include +#include "globals.h" #include "sector.h" #include "lispreader.h" #include "badguy.h" diff --git a/src/setup.cpp b/src/setup.cpp index 7654c3fc0..19ac305bb 100644 --- a/src/setup.cpp +++ b/src/setup.cpp @@ -45,7 +45,7 @@ #include "globals.h" #include "setup.h" #include "screen/screen.h" -#include "screen/texture.h" +#include "screen/surface.h" #include "menu.h" #include "gameloop.h" #include "configfile.h" diff --git a/src/special.h b/src/special.h index e4b09c531..cbf33e5fe 100644 --- a/src/special.h +++ b/src/special.h @@ -24,7 +24,7 @@ #include "bitmask.h" #include "type.h" -#include "screen/texture.h" +#include "screen/surface.h" #include "collision.h" #include "player.h" #include "physic.h" diff --git a/src/sprite.h b/src/sprite.h index 61a6d9523..47ab31afa 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -24,7 +24,7 @@ #include #include "lispreader.h" -#include "screen/texture.h" +#include "screen/surface.h" #include "vector.h" class Sprite diff --git a/src/supertux.cpp b/src/supertux.cpp index cf5b0424a..588639a20 100644 --- a/src/supertux.cpp +++ b/src/supertux.cpp @@ -34,8 +34,8 @@ #include "screen/screen.h" #include "worldmap.h" #include "resources.h" -#include "screen/texture.h" -#include "tile.h" +#include "screen/surface.h" +#include "tile_manager.h" #include "gettext.h" int main(int argc, char * argv[]) diff --git a/src/tile.cpp b/src/tile.cpp index 674cf7892..bdb82b14f 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -21,13 +21,13 @@ #include #include +#include "globals.h" #include "tile.h" #include "scene.h" +#include "lispreader.h" +#include "vector.h" #include "screen/drawing_context.h" -TileManager* TileManager::instance_ = 0; -std::set* TileManager::tilegroups_ = 0; - Tile::Tile() : id(-1), attributes(0), data(0), next_tile(0), anim_speed(25) { @@ -115,129 +115,5 @@ Tile::read(LispReader& reader) return id; } -//--------------------------------------------------------------------------- - -TileManager::TileManager() -{ - std::string filename = datadir + "/images/tilesets/supertux.stgt"; - load_tileset(filename); -} - -TileManager::~TileManager() -{ - for(std::vector::iterator i = tiles.begin(); i != tiles.end(); ++i) { - delete *i; - } - - delete tilegroups_; -} - -void TileManager::load_tileset(std::string filename) -{ - if(filename == current_tileset) - return; - - // free old tiles - for(std::vector::iterator i = tiles.begin(); i != tiles.end(); ++i) { - delete *i; - } - tiles.clear(); - - lisp_object_t* root_obj = lisp_read_from_file(filename); - - if (!root_obj) - st_abort("Couldn't load file", filename); - - if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-tiles") == 0) - { - lisp_object_t* cur = lisp_cdr(root_obj); - int tileset_id = 0; - - while(!lisp_nil_p(cur)) - { - lisp_object_t* element = lisp_car(cur); - - if (strcmp(lisp_symbol(lisp_car(element)), "tile") == 0) - { - LispReader reader(lisp_cdr(element)); - - Tile* tile = new Tile; - int tile_id = tile->read(reader); - if(tile_id < 0) { - std::cerr - << "Warning: parse error when reading a tile, skipping.\n"; - continue; - } - - tile_id += tileset_id; - - if(tile_id >= int(tiles.size())) - tiles.resize(tile_id+1); - tiles[tile_id] = tile; - } - else if (strcmp(lisp_symbol(lisp_car(element)), "tileset") == 0) - { - LispReader reader(lisp_cdr(element)); - std::string filename; - reader.read_string("file", filename); - filename = datadir + "/images/tilesets/" + filename; - load_tileset(filename); - } - else if (strcmp(lisp_symbol(lisp_car(element)), "tilegroup") == 0) - { - TileGroup new_; - LispReader reader(lisp_cdr(element)); - reader.read_string("name", new_.name); - reader.read_int_vector("tiles", new_.tiles); - if(!tilegroups_) - tilegroups_ = new std::set; - tilegroups_->insert(new_).first; - } - else if (strcmp(lisp_symbol(lisp_car(element)), "properties") == 0) - { - LispReader reader(lisp_cdr(element)); - reader.read_int("id", tileset_id); - tileset_id *= 1000; - } - else - { - std::cerr << "Unknown symbol: " << - lisp_symbol(lisp_car(element)) << "\n"; - } - - cur = lisp_cdr(cur); - } - } - else - { - assert(0); - } - - lisp_free(root_obj); - current_tileset = filename; -} - -void -TileManager::draw_tile(DrawingContext& context, unsigned int c, - const Vector& pos, int layer) -{ - if(c == 0) - return; - - Tile& tile = get(c); - - if(!tile.images.size()) - return; - - if(tile.images.size() > 1) - { - size_t frame - = ((global_frame_counter*25) / tile.anim_speed) % tile.images.size(); - context.draw_surface(tile.images[frame], pos, layer); - } - else if (tile.images.size() == 1) - { - context.draw_surface(tile.images[0], pos, layer); - } -} +/* EOF */ diff --git a/src/tile.h b/src/tile.h index 80de06274..cf809aa30 100644 --- a/src/tile.h +++ b/src/tile.h @@ -21,16 +21,11 @@ #ifndef TILE_H #define TILE_H -#include -#include #include +#include "SDL.h" +#include "screen/surface.h" -#include "screen/texture.h" -#include "globals.h" -#include "lispreader.h" -#include "setup.h" -#include "vector.h" - +class Vector; class LispReader; /** @@ -107,54 +102,6 @@ public: } }; -struct TileGroup -{ - friend bool operator<(const TileGroup& lhs, const TileGroup& rhs) - { return lhs.name < rhs.name; }; - friend bool operator>(const TileGroup& lhs, const TileGroup& rhs) - { return lhs.name > rhs.name; }; - - std::string name; - std::vector tiles; -}; - -class TileManager -{ - private: - TileManager(); - ~TileManager(); - - std::vector tiles; - static TileManager* instance_ ; - static std::set* tilegroups_; - void load_tileset(std::string filename); - - std::string current_tileset; - - public: - static TileManager* instance() - { return instance_ ? instance_ : instance_ = new TileManager(); } - static void destroy_instance() - { delete instance_; instance_ = 0; } - - void draw_tile(DrawingContext& context, unsigned int id, - const Vector& pos, int layer); - - static std::set* tilegroups() { if(!instance_) { instance_ = new TileManager(); } return tilegroups_ ? tilegroups_ : tilegroups_ = new std::set; } - Tile& get(unsigned int id) { - - if(id < tiles.size()) - { - return *tiles[id]; - } - else - { - // Never return 0, but return the 0th tile instead so that - // user code doesn't have to check for NULL pointers all over - // the place - return *tiles[0]; - } - } -}; - #endif + +/* EOF */ diff --git a/src/tile_manager.cpp b/src/tile_manager.cpp new file mode 100644 index 000000000..f9ad0c235 --- /dev/null +++ b/src/tile_manager.cpp @@ -0,0 +1,156 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2004 Tobias Glaesser +// +// 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 +#include "screen/drawing_context.h" +#include "setup.h" +#include "globals.h" +#include "lispreader.h" +#include "tile.h" +#include "tile_manager.h" + +TileManager* TileManager::instance_ = 0; +std::set* TileManager::tilegroups_ = 0; + +TileManager::TileManager() +{ + std::string filename = datadir + "/images/tilesets/supertux.stgt"; + load_tileset(filename); +} + +TileManager::~TileManager() +{ + for(std::vector::iterator i = tiles.begin(); i != tiles.end(); ++i) { + delete *i; + } + + delete tilegroups_; +} + +void TileManager::load_tileset(std::string filename) +{ + if(filename == current_tileset) + return; + + // free old tiles + for(std::vector::iterator i = tiles.begin(); i != tiles.end(); ++i) { + delete *i; + } + tiles.clear(); + + lisp_object_t* root_obj = lisp_read_from_file(filename); + + if (!root_obj) + st_abort("Couldn't load file", filename); + + if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-tiles") == 0) + { + lisp_object_t* cur = lisp_cdr(root_obj); + int tileset_id = 0; + + while(!lisp_nil_p(cur)) + { + lisp_object_t* element = lisp_car(cur); + + if (strcmp(lisp_symbol(lisp_car(element)), "tile") == 0) + { + LispReader reader(lisp_cdr(element)); + + Tile* tile = new Tile; + int tile_id = tile->read(reader); + if(tile_id < 0) { + std::cerr + << "Warning: parse error when reading a tile, skipping.\n"; + continue; + } + + tile_id += tileset_id; + + if(tile_id >= int(tiles.size())) + tiles.resize(tile_id+1); + tiles[tile_id] = tile; + } + else if (strcmp(lisp_symbol(lisp_car(element)), "tileset") == 0) + { + LispReader reader(lisp_cdr(element)); + std::string filename; + reader.read_string("file", filename); + filename = datadir + "/images/tilesets/" + filename; + load_tileset(filename); + } + else if (strcmp(lisp_symbol(lisp_car(element)), "tilegroup") == 0) + { + TileGroup new_; + LispReader reader(lisp_cdr(element)); + reader.read_string("name", new_.name); + reader.read_int_vector("tiles", new_.tiles); + if(!tilegroups_) + tilegroups_ = new std::set; + tilegroups_->insert(new_).first; + } + else if (strcmp(lisp_symbol(lisp_car(element)), "properties") == 0) + { + LispReader reader(lisp_cdr(element)); + reader.read_int("id", tileset_id); + tileset_id *= 1000; + } + else + { + std::cerr << "Unknown symbol: " << + lisp_symbol(lisp_car(element)) << "\n"; + } + + cur = lisp_cdr(cur); + } + } + else + { + assert(0); + } + + lisp_free(root_obj); + current_tileset = filename; +} + +void +TileManager::draw_tile(DrawingContext& context, unsigned int c, + const Vector& pos, int layer) +{ + if(c == 0) + return; + + Tile& tile = get(c); + + if(!tile.images.size()) + return; + + if(tile.images.size() > 1) + { + size_t frame + = ((global_frame_counter*25) / tile.anim_speed) % tile.images.size(); + context.draw_surface(tile.images[frame], pos, layer); + } + else if (tile.images.size() == 1) + { + context.draw_surface(tile.images[0], pos, layer); + } +} + +/* EOF */ diff --git a/src/tile_manager.h b/src/tile_manager.h new file mode 100644 index 000000000..a55fcb84d --- /dev/null +++ b/src/tile_manager.h @@ -0,0 +1,82 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2004 Tobias Glaesser +// +// 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 HEADER_TILE_MANAGER_HXX +#define HEADER_TILE_MANAGER_HXX + +#include +#include +#include + +class Tile; + +struct TileGroup +{ + friend bool operator<(const TileGroup& lhs, const TileGroup& rhs) + { return lhs.name < rhs.name; }; + friend bool operator>(const TileGroup& lhs, const TileGroup& rhs) + { return lhs.name > rhs.name; }; + + std::string name; + std::vector tiles; +}; + +class TileManager +{ + private: + TileManager(); + ~TileManager(); + + std::vector tiles; + static TileManager* instance_ ; + static std::set* tilegroups_; + void load_tileset(std::string filename); + + std::string current_tileset; + + public: + static TileManager* instance() + { return instance_ ? instance_ : instance_ = new TileManager(); } + static void destroy_instance() + { delete instance_; instance_ = 0; } + + void draw_tile(DrawingContext& context, unsigned int id, + const Vector& pos, int layer); + + static std::set* tilegroups() { if(!instance_) { instance_ = new TileManager(); } return tilegroups_ ? tilegroups_ : tilegroups_ = new std::set; } + Tile& get(unsigned int id) { + + if(id < tiles.size()) + { + return *tiles[id]; + } + else + { + // Never return 0, but return the 0th tile instead so that + // user code doesn't have to check for NULL pointers all over + // the place + return *tiles[0]; + } + } +}; + +#endif + +/* EOF */ diff --git a/src/tilemap.cpp b/src/tilemap.cpp index 571a6f3af..11ebde4d7 100644 --- a/src/tilemap.cpp +++ b/src/tilemap.cpp @@ -27,6 +27,7 @@ #include "screen/drawing_context.h" #include "level.h" #include "tile.h" +#include "tile_manager.h" #include "globals.h" #include "lispreader.h" #include "lispwriter.h" diff --git a/src/title.cpp b/src/title.cpp index 21ec64eeb..7d75ef1a7 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -37,7 +37,7 @@ #include "globals.h" #include "title.h" #include "screen/screen.h" -#include "screen/texture.h" +#include "screen/surface.h" #include "high_scores.h" #include "menu.h" #include "timer.h" diff --git a/src/worldmap.cpp b/src/worldmap.cpp index 373dec213..811274af1 100644 --- a/src/worldmap.cpp +++ b/src/worldmap.cpp @@ -24,7 +24,7 @@ #include #include "globals.h" -#include "screen/texture.h" +#include "screen/surface.h" #include "screen/screen.h" #include "screen/drawing_context.h" #include "lispreader.h" -- 2.11.0