From: Matthias Braun Date: Mon, 3 Oct 2005 15:29:22 +0000 (+0000) Subject: - Reworked Surface class and drawing stuff: X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=86181b0a14d89cf45daf97199c3556c4dd1ee7b7;p=supertux.git - Reworked Surface class and drawing stuff: - colors and alpha values are floats now - No complicated SurfaceData/SurfaceImpl stuff anymore - Loaded images are cached and reused SVN-Revision: 2806 --- diff --git a/data/images/engine/fonts/numbers.png b/data/images/engine/fonts/numbers.png deleted file mode 100644 index 8ac308387..000000000 Binary files a/data/images/engine/fonts/numbers.png and /dev/null differ diff --git a/data/images/engine/fonts/shadow-big.png b/data/images/engine/fonts/shadow-big.png new file mode 100644 index 000000000..72354f7f7 Binary files /dev/null and b/data/images/engine/fonts/shadow-big.png differ diff --git a/data/images/engine/fonts/shadow-small.png b/data/images/engine/fonts/shadow-small.png new file mode 100644 index 000000000..4b25a25e6 Binary files /dev/null and b/data/images/engine/fonts/shadow-small.png differ diff --git a/data/images/engine/fonts/shadow.png b/data/images/engine/fonts/shadow.png new file mode 100644 index 000000000..b7e054480 Binary files /dev/null and b/data/images/engine/fonts/shadow.png differ diff --git a/data/levels/world2/dfk-level3.stl b/data/levels/world2/dfk-level3.stl index d3c728666..03fe7e7bb 100644 --- a/data/levels/world2/dfk-level3.stl +++ b/data/levels/world2/dfk-level3.stl @@ -1087,8 +1087,8 @@ (spawnpoint (name "main") (x 64) (y 11040)) (background - (top_color 0 0 50) - (bottom_color 0 0 150) + (top_color 0 0 0.2) + (bottom_color 0 0 0.6) (speed 1.000000) ) (particles-clouds @@ -1221,8 +1221,8 @@ ) (background - (top_color 0 0 50) - (bottom_color 0 0 150) + (top_color 0 0 0.2) + (bottom_color 0 0 0.6) (speed 1.000000) ) (particles-clouds diff --git a/data/levels/world2/level2.stl b/data/levels/world2/level2.stl index 3797a4b55..aeb103d36 100644 --- a/data/levels/world2/level2.stl +++ b/data/levels/world2/level2.stl @@ -202,16 +202,16 @@ (bonusblock (x 672) (y 1056) (contents "custom") (powerup - (sprite "red-potion") + (sprite "images/powerups/potions/red-potion.sprite") (script "levelflip();") ) ) (powerup (x 8608) (y 1024) - (sprite "red-potion") + (sprite "images/powerups/potions/red-potion.sprite") (script "levelflip();") ) (powerup (x 9952) (y 416) - (sprite "red-potion") + (sprite "images/powerups/potions/red-potion.sprite") (script "levelflip();") ) (powerup (x 8000) (y 352) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 308e3e9b3..700904e4e 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -47,8 +47,8 @@ BadGuy::draw(DrawingContext& context) if(state == STATE_INIT || state == STATE_INACTIVE) return; if(state == STATE_FALLING) { - uint32_t old_effect = context.get_drawing_effect(); - context.set_drawing_effect(old_effect | VERTICAL_FLIP); + DrawingEffect old_effect = context.get_drawing_effect(); + context.set_drawing_effect((DrawingEffect) (old_effect | VERTICAL_FLIP)); sprite->draw(context, get_pos(), LAYER_OBJECTS); context.set_drawing_effect(old_effect); } else { diff --git a/src/flip_level_transformer.cpp b/src/flip_level_transformer.cpp index 73fe33bef..1b8839996 100644 --- a/src/flip_level_transformer.cpp +++ b/src/flip_level_transformer.cpp @@ -80,7 +80,7 @@ FlipLevelTransformer::transform_tilemap(TileMap* tilemap) } } if(tilemap->get_drawing_effect() != 0) { - tilemap->set_drawing_effect(0); + tilemap->set_drawing_effect(NO_EFFECT); } else { tilemap->set_drawing_effect(VERTICAL_FLIP); } diff --git a/src/game_session.cpp b/src/game_session.cpp index 2aa30368a..a18a77448 100644 --- a/src/game_session.cpp +++ b/src/game_session.cpp @@ -457,12 +457,17 @@ GameSession::draw_pause() -((pause_menu_frame * i)%SCREEN_WIDTH) ,(i*20+pause_menu_frame)%SCREEN_HEIGHT), Vector(SCREEN_WIDTH,10), - Color(20,20,20, rand() % 20 + 1), LAYER_FOREGROUND1+1); + Color(0.1, 0.1, 0.1, static_cast(rand() % 20 + 1) / 255.0), + LAYER_FOREGROUND1+1); } context->draw_filled_rect( Vector(0,0), Vector(SCREEN_WIDTH, SCREEN_HEIGHT), - Color(rand() % 50, rand() % 50, rand() % 50, 128), LAYER_FOREGROUND1); + Color( + static_cast(rand() % 50) / 255.0, + static_cast(rand() % 50) / 255.0, + static_cast(rand() % 50) / 255.0, + 0.5), LAYER_FOREGROUND1); #if 0 context->draw_text(blue_text, _("PAUSE - Press 'P' To Play"), Vector(SCREEN_WIDTH/2, 230), CENTER_ALLIGN, LAYER_FOREGROUND1+2); diff --git a/src/gui/button.cpp b/src/gui/button.cpp index 16d901db5..2e4a3360e 100644 --- a/src/gui/button.cpp +++ b/src/gui/button.cpp @@ -37,7 +37,7 @@ Button::Button(Surface* image_, std::string info_, SDLKey binding_) : binding(binding_) { image = image_; - size = Vector(image->w, image->h); + size = Vector(image->get_width(), image->get_height()); id = 0; info = info_; } diff --git a/src/gui/menu.cpp b/src/gui/menu.cpp index 37d74c668..5993bf4dd 100644 --- a/src/gui/menu.cpp +++ b/src/gui/menu.cpp @@ -84,7 +84,8 @@ bool confirm_dialog(Surface *background, std::string text) } if(background == NULL) - context.draw_gradient(Color(200,240,220), Color(200,200,220), LAYER_BACKGROUND0); + context.draw_gradient(Color(0.8, 0.95, 0.85), Color(0.8, 0.8, 0.8), + LAYER_BACKGROUND0); else context.draw_surface(background, Vector(0,0), LAYER_BACKGROUND0); @@ -537,9 +538,11 @@ Menu::draw_item(DrawingContext& context, int index) int y = y_pos - 12 - effect_offset; /* Draw a horizontal line with a little 3d effect */ context.draw_filled_rect(Vector(x, y + 6), - Vector(menu_width, 4), Color(150,200,255,225), LAYER_GUI); + Vector(menu_width, 4), + Color(0.6f, 0.7f, 1.0f, 1.0f), LAYER_GUI); context.draw_filled_rect(Vector(x, y + 6), - Vector(menu_width, 2), Color(255,255,255,255), LAYER_GUI); + Vector(menu_width, 2), + Color(1.0f, 1.0f, 1.0f, 1.0f), LAYER_GUI); break; } case MN_LABEL: @@ -560,11 +563,11 @@ Menu::draw_item(DrawingContext& context, int index) context.draw_filled_rect( Vector(input_pos - 5, y_pos - 10), Vector(input_width + 10, 20), - Color(255,255,255,255), LAYER_GUI-5); + Color(1.0f, 1.0f, 1.0f, 1.0f), LAYER_GUI-5); context.draw_filled_rect( Vector(input_pos - 4, y_pos - 9), Vector(input_width + 8, 18), - Color(0,0,0,128), LAYER_GUI-4); + Color(0, 0, 0, 0.5f), LAYER_GUI-4); if(pitem.kind == MN_TEXTFIELD || pitem.kind == MN_NUMFIELD) { @@ -607,11 +610,11 @@ Menu::draw_item(DrawingContext& context, int index) context.draw_filled_rect( Vector(x_pos - list_pos + text_pos - 1, y_pos - 10), Vector(list_pos_2 + 2, 20), - Color(255,255,255,255), LAYER_GUI - 4); + Color(1.0f, 1.0f, 1.0f, 1.0f), LAYER_GUI - 4); context.draw_filled_rect( Vector(x_pos - list_pos + text_pos, y_pos - 9), Vector(list_pos_2, 18), - Color(0,0,0,128), LAYER_GUI - 5); + Color(0, 0, 0, 0.5f), LAYER_GUI - 5); context.draw_text(text_font, pitem.list[pitem.selected], Vector(SCREEN_WIDTH/2 + text_pos, y_pos - int(text_font->get_height()/2)), @@ -701,7 +704,7 @@ Menu::draw(DrawingContext& context) context.draw_filled_rect( Vector(pos_x - menu_width/2, pos_y - 24*items.size()/2 - 10), Vector(menu_width,menu_height + 20), - Color(150,180,200,125), LAYER_GUI-10); + Color(0.6f, 0.7f, 0.8f, 0.5f), LAYER_GUI-10); for(unsigned int i = 0; i < items.size(); ++i) { diff --git a/src/gui/mousecursor.cpp b/src/gui/mousecursor.cpp index d2a082e20..51bf98482 100644 --- a/src/gui/mousecursor.cpp +++ b/src/gui/mousecursor.cpp @@ -27,7 +27,7 @@ extern SDL_Surface* screen; MouseCursor::MouseCursor(std::string cursor_file) : mid_x(0), mid_y(0) { - cursor = new Surface(cursor_file, true); + cursor = new Surface(cursor_file); cur_state = MC_NORMAL; @@ -68,8 +68,8 @@ void MouseCursor::draw(DrawingContext& context) x = int(x * float(SCREEN_WIDTH)/screen->w); y = int(y * float(SCREEN_HEIGHT)/screen->h); - w = cursor->w; - h = cursor->h / MC_STATES_NB; + w = (int) cursor->get_width(); + h = (int) (cursor->get_height() / MC_STATES_NB); if(ispressed &SDL_BUTTON(1) || ispressed &SDL_BUTTON(2)) { if(cur_state != MC_CLICK) { state_before_click = cur_state; diff --git a/src/gui/mousecursor.hpp b/src/gui/mousecursor.hpp index 98f03c2a7..8ccfda8b5 100644 --- a/src/gui/mousecursor.hpp +++ b/src/gui/mousecursor.hpp @@ -32,6 +32,8 @@ enum { MC_HIDE }; +class DrawingContext; + /// Mouse cursor. /** Used to create mouse cursors. The mouse cursors can be animated diff --git a/src/lisp/writer.cpp b/src/lisp/writer.cpp index 9312ea280..396978966 100644 --- a/src/lisp/writer.cpp +++ b/src/lisp/writer.cpp @@ -143,6 +143,17 @@ Writer::write_int_vector(const std::string& name, } void +Writer::write_float_vector(const std::string& name, + const std::vector& value) +{ + indent(); + *out << '(' << name; + for(std::vector::const_iterator i = value.begin(); i != value.end(); ++i) + *out << " " << *i; + *out << ")\n"; +} + +void Writer::indent() { for(int i = 0; i& value); void write_int_vector(const std::string& name, const std::vector& value); + void write_float_vector(const std::string& name, const std::vector& value); // add more write-functions when needed... void end_list(const std::string& listname); diff --git a/src/main.cpp b/src/main.cpp index 84b0e9688..caf7812f7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,6 +43,7 @@ #include "gettext.hpp" #include "audio/sound_manager.hpp" #include "video/surface.hpp" +#include "video/texture_manager.hpp" #include "control/joystickkeyboardcontroller.hpp" #include "misc.hpp" #include "title.hpp" @@ -301,6 +302,9 @@ static void check_gl_error() void init_video() { + if(texture_manager != NULL) + texture_manager->save_textures(); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); @@ -339,6 +343,9 @@ void init_video() // 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); @@ -351,7 +358,10 @@ void init_video() check_gl_error(); - Surface::reload_all(); + if(texture_manager != NULL) + texture_manager->reload_textures(); + else + texture_manager = new TextureManager(); } static void init_audio() @@ -450,15 +460,13 @@ int main(int argc, char** argv) free_menu(); unload_shared(); -#ifdef DEBUG - Surface::debug_check(); -#endif quit_audio(); if(config) config->save(); delete config; delete main_controller; + delete texture_manager; SDL_Quit(); PHYSFS_deinit(); diff --git a/src/object/ambient_sound.cpp b/src/object/ambient_sound.cpp index 68253b093..21ad67f3b 100644 --- a/src/object/ambient_sound.cpp +++ b/src/object/ambient_sound.cpp @@ -20,6 +20,7 @@ #include #include +#include #include "ambient_sound.hpp" #include "object_factory.hpp" diff --git a/src/object/background.cpp b/src/object/background.cpp index 4b8adc4f4..7c43cfad9 100644 --- a/src/object/background.cpp +++ b/src/object/background.cpp @@ -40,10 +40,11 @@ Background::Background(const lisp::Lisp& reader) && reader.get("speed", speed)) { set_image(imagefile, speed); } else { - std::vector bkgd_top_color, bkgd_bottom_color; + std::vector bkgd_top_color, bkgd_bottom_color; if(reader.get_vector("top_color", bkgd_top_color) && reader.get_vector("bottom_color", bkgd_bottom_color)) - set_gradient(Color(bkgd_top_color), Color(bkgd_bottom_color)); + set_gradient(Color(bkgd_top_color), + Color(bkgd_bottom_color)); } } @@ -64,15 +65,15 @@ Background::write(lisp::Writer& writer) writer.write_string("image", imagefile); writer.write_float("speed", speed); } else if(type == GRADIENT) { - std::vector bkgd_top_color, bkgd_bottom_color; + std::vector bkgd_top_color, bkgd_bottom_color; bkgd_top_color.push_back(gradient_top.red); bkgd_top_color.push_back(gradient_top.green); bkgd_top_color.push_back(gradient_top.blue); bkgd_bottom_color.push_back(gradient_top.red); bkgd_bottom_color.push_back(gradient_top.green); bkgd_bottom_color.push_back(gradient_top.blue); - writer.write_int_vector("top_color", bkgd_top_color); - writer.write_int_vector("bottom_color", bkgd_bottom_color); + writer.write_float_vector("top_color", bkgd_top_color); + writer.write_float_vector("bottom_color", bkgd_bottom_color); } writer.write_int("layer", layer); @@ -92,7 +93,7 @@ Background::set_image(const std::string& name, float speed) this->speed = speed; delete image; - image = new Surface("images/background/" + name, false); + image = new Surface("images/background/" + name); } void @@ -103,7 +104,7 @@ Background::set_gradient(Color top, Color bottom) gradient_bottom = bottom; delete image; - image = new Surface(top, bottom, SCREEN_WIDTH, SCREEN_HEIGHT); + image = NULL; } void @@ -112,18 +113,20 @@ Background::draw(DrawingContext& context) if(type == GRADIENT) { context.push_transform(); context.set_translation(Vector(0, 0)); - context.draw_surface(image, Vector(0, 0), layer); + context.draw_gradient(gradient_top, gradient_bottom, layer); context.pop_transform(); } else if(type == IMAGE) { if(!image) return; - int sx = int(-context.get_translation().x * speed) % image->w - image->w; - int sy = int(-context.get_translation().y * speed) % image->h - image->h; + int w = (int) image->get_width(); + int h = (int) image->get_height(); + int sx = int(-context.get_translation().x * speed) % w - w; + int sy = int(-context.get_translation().y * speed) % h - h; context.push_transform(); context.set_translation(Vector(0, 0)); - for(int x = sx; x < SCREEN_WIDTH; x += image->w) - for(int y = sy; y < SCREEN_HEIGHT; y += image->h) + for(int x = sx; x < SCREEN_WIDTH; x += w) + for(int y = sy; y < SCREEN_HEIGHT; y += h) context.draw_surface(image, Vector(x, y), layer); context.pop_transform(); } diff --git a/src/object/display_effect.cpp b/src/object/display_effect.cpp index 7bf875b4f..1f67b43e8 100644 --- a/src/object/display_effect.cpp +++ b/src/object/display_effect.cpp @@ -56,18 +56,16 @@ DisplayEffect::draw(DrawingContext& context) context.set_translation(Vector(0, 0)); if(black || type != NO_FADE) { - uint8_t alpha; + float alpha; if(black) { - alpha = 255; + alpha = 1.0f; } else { switch(type) { case FADE_IN: - alpha = static_cast - (fading * 255.0 / fadetime); + alpha = fading / fadetime; break; case FADE_OUT: - alpha = static_cast - ((fadetime-fading) * 255.0 / fadetime); + alpha = (fadetime-fading) / fadetime; break; default: alpha = 0; @@ -80,9 +78,9 @@ DisplayEffect::draw(DrawingContext& context) if (borders_fading || borders_active) { context.draw_filled_rect(Vector(0, 0), Vector(SCREEN_WIDTH, border_size), - Color(0, 0, 0, 255), LAYER_GUI-10); + Color(0, 0, 0, 1.0f), LAYER_GUI-10); context.draw_filled_rect(Vector(0, SCREEN_HEIGHT - border_size), Vector(SCREEN_WIDTH, border_size), - Color(0, 0, 0, 255), LAYER_GUI-10); + Color(0, 0, 0, 1.0f), LAYER_GUI-10); } context.pop_transform(); @@ -129,3 +127,4 @@ DisplayEffect::four_to_three() { borders_fading = false; } + diff --git a/src/object/fireworks.cpp b/src/object/fireworks.cpp index 62904c5b4..7047bf94b 100644 --- a/src/object/fireworks.cpp +++ b/src/object/fireworks.cpp @@ -46,8 +46,8 @@ Fireworks::update(float ) pos += Vector(SCREEN_WIDTH * ((float) rand() / RAND_MAX), SCREEN_HEIGHT/2 * ((float) rand() / RAND_MAX)); - int red = rand() % 255; - int green = rand() % red; + float red = static_cast(rand() % 255) / 255.0; + float green = static_cast(rand() % ((int) red*255)) / 255.0; sector->add_object(new Particles(pos, 0, 360, Vector(140, 140), Vector(0, 0), 45, Color(red, green, 0), 3, 1.3, LAYER_FOREGROUND1+1)); diff --git a/src/object/gameobjs.hpp b/src/object/gameobjs.hpp index 4aa1fa91e..53e8b4827 100644 --- a/src/object/gameobjs.hpp +++ b/src/object/gameobjs.hpp @@ -27,6 +27,7 @@ #include "game_object.hpp" #include "moving_object.hpp" #include "serializable.hpp" +#include "video/color.hpp" /* Bounciness of distros: */ #define NO_BOUNCE 0 diff --git a/src/object/level_time.cpp b/src/object/level_time.cpp index 591df8023..532afc58d 100644 --- a/src/object/level_time.cpp +++ b/src/object/level_time.cpp @@ -3,6 +3,7 @@ #include "level_time.hpp" #include +#include #include "main.hpp" #include "resources.hpp" #include "sector.hpp" diff --git a/src/object/particlesystem.cpp b/src/object/particlesystem.cpp index 5edb5a4f8..c9b484b28 100644 --- a/src/object/particlesystem.cpp +++ b/src/object/particlesystem.cpp @@ -73,9 +73,9 @@ void ParticleSystem::draw(DrawingContext& context) SnowParticleSystem::SnowParticleSystem() { - snowimages[0] = new Surface("images/objects/particles/snow0.png", true); - snowimages[1] = new Surface("images/objects/particles/snow1.png", true); - snowimages[2] = new Surface("images/objects/particles/snow2.png", true); + snowimages[0] = new Surface("images/objects/particles/snow0.png"); + snowimages[1] = new Surface("images/objects/particles/snow1.png"); + snowimages[2] = new Surface("images/objects/particles/snow2.png"); virtual_width = SCREEN_WIDTH * 2; @@ -133,8 +133,8 @@ void SnowParticleSystem::update(float elapsed_time) // Ghosts don't change their movement pattern - not random GhostParticleSystem::GhostParticleSystem() { - ghosts[0] = new Surface("images/objects/particles/ghost0.png", true); - ghosts[1] = new Surface("images/objects/particles/ghost1.png", true); + ghosts[0] = new Surface("images/objects/particles/ghost0.png"); + ghosts[1] = new Surface("images/objects/particles/ghost1.png"); virtual_width = SCREEN_WIDTH * 2; @@ -190,7 +190,7 @@ void GhostParticleSystem::update(float elapsed_time) CloudParticleSystem::CloudParticleSystem() { - cloudimage = new Surface("images/objects/particles/cloud.png", true); + cloudimage = new Surface("images/objects/particles/cloud.png"); virtual_width = 2000.0; diff --git a/src/object/particlesystem_interactive.cpp b/src/object/particlesystem_interactive.cpp index 5bdf862b9..edb2cbc05 100644 --- a/src/object/particlesystem_interactive.cpp +++ b/src/object/particlesystem_interactive.cpp @@ -142,8 +142,8 @@ ParticleSystem_Interactive::collision(Particle* object, Vector movement) RainParticleSystem::RainParticleSystem() { - rainimages[0] = new Surface("images/objects/particles/rain0.png", true); - rainimages[1] = new Surface("images/objects/particles/rain1.png", true); + rainimages[0] = new Surface("images/objects/particles/rain0.png"); + rainimages[1] = new Surface("images/objects/particles/rain1.png"); virtual_width = SCREEN_WIDTH * 2; @@ -224,8 +224,8 @@ void RainParticleSystem::update(float elapsed_time) CometParticleSystem::CometParticleSystem() { - cometimages[0] = new Surface("images/creatures/mr_bomb/exploding-left-0.png", true); - cometimages[1] = new Surface("images/creatures/mr_bomb/exploding-left-0.png", true); + cometimages[0] = new Surface("images/creatures/mr_bomb/exploding-left-0.png"); + cometimages[1] = new Surface("images/creatures/mr_bomb/exploding-left-0.png"); virtual_width = SCREEN_WIDTH * 2; diff --git a/src/object/platform.cpp b/src/object/platform.cpp index 9bbc5fe17..c0a59a74a 100644 --- a/src/object/platform.cpp +++ b/src/object/platform.cpp @@ -17,10 +17,11 @@ // 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 "platform.hpp" + +#include #include "video/drawing_context.hpp" #include "resources.hpp" #include "player.hpp" diff --git a/src/object/text_object.cpp b/src/object/text_object.cpp index 9d2dd3313..348d9341b 100644 --- a/src/object/text_object.cpp +++ b/src/object/text_object.cpp @@ -1,6 +1,8 @@ #include #include "text_object.hpp" + +#include #include "resources.hpp" #include "video/drawing_context.hpp" @@ -74,17 +76,16 @@ TextObject::draw(DrawingContext& context) context.push_transform(); context.set_translation(Vector(0, 0)); if(fading > 0) { - context.set_alpha(static_cast - ((fadetime-fading) * 255.0 / fadetime)); + context.set_alpha((fadetime-fading) / fadetime); } else if(fading < 0) { - context.set_alpha(static_cast (-fading * 255.0 / fadetime)); + context.set_alpha(-fading / fadetime); } else if(!visible) { context.pop_transform(); return; } context.draw_filled_rect(Vector(125, 50), Vector(550, 120), - Color(150, 180, 200, 125), LAYER_GUI-50); + Color(0.6, 0.7, 0.8, 0.5), LAYER_GUI-50); if (centered) { context.draw_center_text(font, text, Vector(0, 50+35), LAYER_GUI-40); } diff --git a/src/object/tilemap.cpp b/src/object/tilemap.cpp index 8775418a6..a6765ee67 100644 --- a/src/object/tilemap.cpp +++ b/src/object/tilemap.cpp @@ -37,7 +37,7 @@ TileMap::TileMap() : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES), - drawing_effect(0) + drawing_effect(NO_EFFECT) { tilemanager = tile_manager; @@ -47,7 +47,7 @@ TileMap::TileMap() TileMap::TileMap(const lisp::Lisp& reader, TileManager* new_tile_manager) : solid(false), speed(1), width(-1), height(-1), layer(LAYER_TILES), - drawing_effect(0) + drawing_effect(NO_EFFECT) { tilemanager = new_tile_manager; if(tilemanager == 0) @@ -94,7 +94,7 @@ TileMap::TileMap(const lisp::Lisp& reader, TileManager* new_tile_manager) TileMap::TileMap(int layer_, bool solid_, size_t width_, size_t height_) : solid(solid_), speed(1), width(0), height(0), layer(layer_), - drawing_effect(0) + drawing_effect(NO_EFFECT) { tilemanager = tile_manager; @@ -180,13 +180,13 @@ TileMap::draw(DrawingContext& context) for (pos.x = start_x; pos.x < end_x; pos.x += 32) { context.draw_filled_rect(Vector (pos.x, start_y), Vector(1, fabsf(start_y - end_y)), - Color(225, 225, 225), LAYER_GUI-50); + Color(0.8f, 0.8f, 0.8f), LAYER_GUI-50); } for (pos.y = start_y; pos.y < end_y; pos.y += 32) { context.draw_filled_rect(Vector (start_x, pos.y), Vector(fabsf(start_x - end_x), 1), - Color(225, 225, 225), LAYER_GUI-50); + Color(1.0f, 1.0f, 1.0f), LAYER_GUI-50); } } #endif diff --git a/src/object/tilemap.hpp b/src/object/tilemap.hpp index e344fa097..82196234a 100644 --- a/src/object/tilemap.hpp +++ b/src/object/tilemap.hpp @@ -25,6 +25,7 @@ #include "game_object.hpp" #include "serializable.hpp" #include "math/vector.hpp" +#include "video/drawing_context.hpp" namespace lisp { class Lisp; @@ -87,12 +88,12 @@ public: return tilemanager; } - void set_drawing_effect(int effect) + void set_drawing_effect(DrawingEffect effect) { drawing_effect = effect; } - int get_drawing_effect() + DrawingEffect get_drawing_effect() { return drawing_effect; } @@ -108,7 +109,7 @@ private: int width, height; int layer; - int drawing_effect; + DrawingEffect drawing_effect; }; #endif /*SUPERTUX_TILEMAP_H*/ diff --git a/src/player_status.cpp b/src/player_status.cpp index 29ed5bb10..1367c9894 100644 --- a/src/player_status.cpp +++ b/src/player_status.cpp @@ -209,7 +209,7 @@ PlayerStatus::draw(DrawingContext& context) if (player_status->lives >= 5) { sprintf(str, "%dx", player_status->lives); - float x = SCREEN_WIDTH - gold_text->get_text_width(str) - tux_life->w; + float x = SCREEN_WIDTH - gold_text->get_text_width(str) - tux_life->get_width(); context.draw_text(gold_text, str, Vector(x - BORDER_X, BORDER_Y + 20), LEFT_ALLIGN, LAYER_FOREGROUND1); context.draw_surface(tux_life, Vector(SCREEN_WIDTH - 16 - BORDER_X, BORDER_Y + 20), @@ -217,7 +217,8 @@ PlayerStatus::draw(DrawingContext& context) } else { for(int i= 0; i < player_status->lives; ++i) context.draw_surface(tux_life, - Vector(SCREEN_WIDTH - tux_life->w*4 +(tux_life->w*i) - BORDER_X, BORDER_Y + 20), + Vector(SCREEN_WIDTH - tux_life->get_width()*4 +(tux_life->get_width()*i) - BORDER_X, + BORDER_Y + 20), LAYER_FOREGROUND1); } diff --git a/src/resources.cpp b/src/resources.cpp index 92f2f41ef..e1ac72fba 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -35,7 +35,6 @@ MouseCursor* mouse_cursor = 0; Font* gold_text; Font* blue_text; Font* gray_text; -Font* yellow_nums; Font* white_text; Font* white_small_text; Font* white_big_text; @@ -44,26 +43,29 @@ Font* white_big_text; void load_shared() { /* Load GUI/menu images: */ - checkbox = new Surface("images/engine/menu/checkbox-unchecked.png", true); - checkbox_checked = new Surface("images/engine/menu/checkbox-checked.png", true); - back = new Surface("images/engine/menu/arrow-back.png", true); - arrow_left = new Surface("images/engine/menu/arrow-left.png", true); - arrow_right = new Surface("images/engine/menu/arrow-right.png", true); + checkbox = new Surface("images/engine/menu/checkbox-unchecked.png"); + checkbox_checked = new Surface("images/engine/menu/checkbox-checked.png"); + back = new Surface("images/engine/menu/arrow-back.png"); + arrow_left = new Surface("images/engine/menu/arrow-left.png"); + arrow_right = new Surface("images/engine/menu/arrow-right.png"); /* Load the mouse-cursor */ mouse_cursor = new MouseCursor("images/engine/menu/mousecursor.png"); MouseCursor::set_current(mouse_cursor); /* Load global images: */ - gold_text = new Font("images/engine/fonts/gold.png", Font::TEXT, 16,18); - blue_text = new Font("images/engine/fonts/blue.png", Font::TEXT, 16,18,3); - white_text = new Font("images/engine/fonts/white.png", Font::TEXT, 16,18); - gray_text = new Font("images/engine/fonts/gray.png", Font::TEXT, 16,18); + gold_text = new Font("images/engine/fonts/gold.png", + "images/engine/fonts/shadow.png", 16, 18); + blue_text = new Font("images/engine/fonts/blue.png", + "images/engine/fonts/shadow.png", 16, 18, 3); + white_text = new Font("images/engine/fonts/white.png", + "images/engine/fonts/shadow.png", 16, 18); + gray_text = new Font("images/engine/fonts/gray.png", + "images/engine/fonts/shadow.png", 16, 18); white_small_text = new Font("images/engine/fonts/white-small.png", - Font::TEXT, 8,9, 1); - white_big_text = new Font("images/engine/fonts/white-big.png", - Font::TEXT, 20,22, 3); - yellow_nums = new Font("images/engine/fonts/numbers.png", Font::NUM, 32,32); + "images/engine/fonts/shadow-small.png", 8, 9, 1); + white_big_text = new Font("images/engine/fonts/white-big.png", + "images/engine/fonts/shadow-big.png", 20, 22, 3); Menu::default_font = white_text; Menu::active_font = blue_text; @@ -81,10 +83,10 @@ void load_shared() for (int i = 0; i < GROWING_FRAMES; i++) { sprintf(img_name, "images/creatures/tux_grow/left-%i.png", i+1); - growingtux_left[i] = new Surface(img_name, true); + growingtux_left[i] = new Surface(img_name); sprintf(img_name, "images/creatures/tux_grow/right-%i.png", i+1); - growingtux_right[i] = new Surface(img_name, true); + growingtux_right[i] = new Surface(img_name); } small_tux = new TuxBodyParts(); @@ -115,7 +117,7 @@ void load_shared() load_object_gfx(); /* Tux life: */ - tux_life = new Surface("images/creatures/tux_small/tux-life.png", true); + tux_life = new Surface("images/creatures/tux_small/tux-life.png"); player_status = new PlayerStatus(); } @@ -130,7 +132,6 @@ void unload_shared() delete gray_text; delete white_small_text; delete white_big_text; - delete yellow_nums; free_object_gfx(); diff --git a/src/resources.hpp b/src/resources.hpp index 30a6eb518..02639590a 100644 --- a/src/resources.hpp +++ b/src/resources.hpp @@ -50,7 +50,6 @@ extern Font* blue_text; extern Font* gray_text; extern Font* white_small_text; extern Font* white_big_text; -extern Font* yellow_nums; void load_shared(); void unload_shared(); diff --git a/src/sector.cpp b/src/sector.cpp index 79d80c6f5..9e3ae22d5 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -201,16 +201,16 @@ Sector::parse_old_format(const lisp::Lisp& reader) reader.get("bkgd_red_top", r); reader.get("bkgd_green_top", g); reader.get("bkgd_blue_top", b); - bkgd_top.red = r; - bkgd_top.green = g; - bkgd_top.blue = b; + bkgd_top.red = static_cast (r) / 255.0f; + bkgd_top.green = static_cast (g) / 255.0f; + bkgd_top.blue = static_cast (b) / 255.0f; reader.get("bkgd_red_bottom", r); reader.get("bkgd_green_bottom", g); reader.get("bkgd_blue_bottom", b); - bkgd_bottom.red = r; - bkgd_bottom.green = g; - bkgd_bottom.blue = b; + bkgd_bottom.red = static_cast (r) / 255.0f; + bkgd_bottom.green = static_cast (g) / 255.0f; + bkgd_bottom.blue = static_cast (b) / 255.0f; if(backgroundimage != "") { Background* background = new Background; diff --git a/src/sprite/sprite.cpp b/src/sprite/sprite.cpp index 3dc91f2d2..50475461e 100644 --- a/src/sprite/sprite.cpp +++ b/src/sprite/sprite.cpp @@ -48,7 +48,7 @@ Sprite::~Sprite() } void -Sprite::set_action(std::string name, int loops) +Sprite::set_action(const std::string& name, int loops) { if(action && action->name == name) return; @@ -129,13 +129,13 @@ Sprite::draw_part(DrawingContext& context, const Vector& source, int Sprite::get_width() const { - return action->surfaces[get_frame()]->w; + return (int) action->surfaces[get_frame()]->get_width(); } int Sprite::get_height() const { - return action->surfaces[get_frame()]->h; + return (int) action->surfaces[get_frame()]->get_height(); } diff --git a/src/sprite/sprite.hpp b/src/sprite/sprite.hpp index 9b1dee850..1c166326f 100644 --- a/src/sprite/sprite.hpp +++ b/src/sprite/sprite.hpp @@ -21,73 +21,74 @@ #define SUPERTUX_SPRITE_H #include -#include -#include -#include +#include +#include #include "video/surface.hpp" #include "math/vector.hpp" #include "sprite_data.hpp" +class DrawingContext; + class Sprite { public: - Sprite(SpriteData& data); - Sprite(const Sprite& other); - ~Sprite(); - - /** Draw sprite, automatically calculates next frame */ - void draw(DrawingContext& context, const Vector& pos, int layer); - - void draw_part(DrawingContext& context, const Vector& source, - const Vector& size, const Vector& pos, int layer); - - /** Set action (or state) */ - void set_action(std::string act, int loops = -1); - - /* Stop animation */ - void stop_animation() - { animation_loops = 0; } - /** Check if animation is stopped or not */ - bool check_animation(); - - float get_fps() const - { return action->fps; } - /** Get current action total frames */ - int get_frames() const - { return action->surfaces.size(); } - /** Get sprite's name */ - const std::string& get_name() const - { return data.name; } - /** Get current action name */ - const std::string& get_action_name() const - { return action->name; } - - int get_width() const; - int get_height() const; - - /** Get current frame */ - int get_frame() const - { return (int)frame; } - /** Set current frame */ - void set_frame(int frame_) - { if(frame_ > get_frames()) frame = 0; else frame = frame_; } - Surface* get_frame(unsigned int frame) - { - assert(frame < action->surfaces.size()); - return action->surfaces[frame]; - } + Sprite(SpriteData& data); + Sprite(const Sprite& other); + ~Sprite(); + + /** Draw sprite, automatically calculates next frame */ + void draw(DrawingContext& context, const Vector& pos, int layer); + + void draw_part(DrawingContext& context, const Vector& source, + const Vector& size, const Vector& pos, int layer); + + /** Set action (or state) */ + void set_action(const std::string& act, int loops = -1); + + /* Stop animation */ + void stop_animation() + { animation_loops = 0; } + /** Check if animation is stopped or not */ + bool check_animation(); + + float get_fps() const + { return action->fps; } + /** Get current action total frames */ + int get_frames() const + { return action->surfaces.size(); } + /** Get sprite's name */ + const std::string& get_name() const + { return data.name; } + /** Get current action name */ + const std::string& get_action_name() const + { return action->name; } + + int get_width() const; + int get_height() const; + + /** Get current frame */ + int get_frame() const + { return (int)frame; } + /** Set current frame */ + void set_frame(int frame_) + { if(frame_ > get_frames()) frame = 0; else frame = frame_; } + Surface* get_frame(unsigned int frame) + { + assert(frame < action->surfaces.size()); + return action->surfaces[frame]; + } private: - void update(); + void update(); - SpriteData& data; + SpriteData& data; - float frame; - int animation_loops; - Uint32 last_ticks; + float frame; + int animation_loops; + Uint32 last_ticks; - SpriteData::Action* action; + SpriteData::Action* action; }; #endif diff --git a/src/sprite/sprite_data.cpp b/src/sprite/sprite_data.cpp index 58d22cf1b..ca971246f 100644 --- a/src/sprite/sprite_data.cpp +++ b/src/sprite/sprite_data.cpp @@ -90,9 +90,8 @@ SpriteData::parse_action(const lisp::Lisp* lisp, const std::string& basedir) } else { for(int i = 0; static_cast(i) < act_tmp->surfaces.size(); i++) { - Surface* surface = new Surface(sdl_surface_from_sdl_surface( - act_tmp->surfaces[i]->impl->get_sdl_surface()), true); - surface->apply_filter(HORIZONTAL_FLIP_FILTER); + Surface* surface = new Surface(*(act_tmp->surfaces[i])); + surface->hflip(); action->surfaces.push_back(surface); } } @@ -106,7 +105,7 @@ SpriteData::parse_action(const lisp::Lisp* lisp, const std::string& basedir) } for(std::vector::size_type i = 0; i < images.size(); i++) { - action->surfaces.push_back(new Surface(basedir + images[i], true)); + action->surfaces.push_back(new Surface(basedir + images[i])); } } actions[action->name] = action; diff --git a/src/textscroller.cpp b/src/textscroller.cpp index d76342a06..0c4406218 100644 --- a/src/textscroller.cpp +++ b/src/textscroller.cpp @@ -98,13 +98,12 @@ void display_text_file(const std::string& filename) if(line[0] == '!') { std::string imagename = line.substr(1, line.size()-1); std::cout << "Imagename: " << imagename << "\n"; - images.insert(std::make_pair(imagename, new Surface(imagename, true))); + images.insert(std::make_pair(imagename, new Surface(imagename))); } } // load background image - Surface* background - = new Surface("images/background/" + background_file, false); + Surface* background = new Surface("images/background/" + background_file); bool done = false; float scroll = 0; @@ -187,9 +186,9 @@ void display_text_file(const std::string& filename) } if(image != 0) { context.draw_surface(image, - Vector( (SCREEN_WIDTH - image->w) / 2, + Vector( (SCREEN_WIDTH - image->get_width()) / 2, SCREEN_HEIGHT + y - scroll), 255); - y += image->h + ITEMS_SPACE; + y += image->get_height() + ITEMS_SPACE; } } @@ -240,7 +239,7 @@ InfoBox::draw(DrawingContext& context) float height = 200; context.draw_filled_rect(Vector(x1, y1), Vector(width, height), - Color(150, 180, 200, 125), LAYER_GUI-1); + Color(0.6f, 0.7f, 0.8f, 0.5f), LAYER_GUI-1); float y = y1; for(size_t i = firstline; i < lines.size(); ++i) { diff --git a/src/tile.cpp b/src/tile.cpp index 6c75fb1e3..f2ec18a23 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -137,18 +137,18 @@ Tile::load_images(const std::string& tilesetpath) Surface* surface; std::string file = tilesetpath + spec.file; if(spec.rect.get_width() <= 0) { - surface = new Surface(file, true); + surface = new Surface(file); } else { surface = new Surface(file, (int) spec.rect.p1.x, (int) spec.rect.p1.y, (int) spec.rect.get_width(), - (int) spec.rect.get_height(), true); + (int) spec.rect.get_height()); } images.push_back(surface); } if(editor_imagefile != "") { - editor_image = new Surface(tilesetpath + editor_imagefile, true); + editor_image = new Surface(tilesetpath + editor_imagefile); } } diff --git a/src/tile.hpp b/src/tile.hpp index ed1196e30..a551d309b 100644 --- a/src/tile.hpp +++ b/src/tile.hpp @@ -21,10 +21,13 @@ #define TILE_H #include +#include #include "video/surface.hpp" #include "math/rect.hpp" #include "lisp/lisp.hpp" +class DrawingContext; + /** Tile Class */ @@ -115,7 +118,7 @@ public: { if(!images.size()) return 0; - return images[0]->w; + return (int) images[0]->get_width(); } /// returns the height of the tiles in pixels @@ -123,7 +126,7 @@ public: { if(!images.size()) return 0; - return images[0]->h; + return (int) images[0]->get_height(); } protected: diff --git a/src/tile_manager.cpp b/src/tile_manager.cpp index 5e941d0b3..6ade3d9bd 100644 --- a/src/tile_manager.cpp +++ b/src/tile_manager.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include "video/drawing_context.hpp" #include "lisp/lisp.hpp" diff --git a/src/tile_manager.hpp b/src/tile_manager.hpp index e5ab10982..b8ef087f5 100644 --- a/src/tile_manager.hpp +++ b/src/tile_manager.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "tile.hpp" diff --git a/src/title.cpp b/src/title.cpp index 266b28b92..97efc08bd 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -285,9 +285,9 @@ void title() titlesession = new GameSession("levels/misc/menu.stl", ST_GL_DEMO_GAME); /* Load images: */ - bkg_title = new Surface("images/background/arctis.jpg", false); - logo = new Surface("images/engine/menu/logo.png", true); - //img_choose_subset = new Surface("images/status/choose-level-subset.png", true); + bkg_title = new Surface("images/background/arctis.jpg"); + logo = new Surface("images/engine/menu/logo.png"); + //img_choose_subset = new Surface("images/status/choose-level-subset.png"); titlesession->get_current_sector()->activate("main"); titlesession->set_current(); @@ -335,7 +335,7 @@ void title() draw_demo(elapsed_time); if (Menu::current() == main_menu) - context.draw_surface(logo, Vector(SCREEN_WIDTH/2 - logo->w/2, 30), + context.draw_surface(logo, Vector(SCREEN_WIDTH/2 - logo->get_width()/2, 30), LAYER_FOREGROUND1+1); context.draw_text(white_small_text, " SuperTux " PACKAGE_VERSION "\n", diff --git a/src/video/color.hpp b/src/video/color.hpp new file mode 100644 index 000000000..18f8849db --- /dev/null +++ b/src/video/color.hpp @@ -0,0 +1,28 @@ +#ifndef __COLOR_HPP__ +#define __COLOR_HPP__ + +#include + +class Color +{ +public: + Color() + : red(0), green(0), blue(0), alpha(1.0) + { } + Color(float red, float green, float blue, float alpha = 1.0) + : red(red), green(green), blue(blue), alpha(alpha) + { } + Color(const std::vector& vals) + { + red = vals[0]; + green = vals[1]; + blue = vals[2]; + if(vals.size() > 3) + alpha = vals[3]; + } + + float red, green, blue, alpha; +}; + +#endif + diff --git a/src/video/drawing_context.cpp b/src/video/drawing_context.cpp index 48b9c9776..6f1aee1fd 100644 --- a/src/video/drawing_context.cpp +++ b/src/video/drawing_context.cpp @@ -32,6 +32,7 @@ #include "gameconfig.hpp" #include "glutil.hpp" #include "texture.hpp" +#include "texture_manager.hpp" #define LIGHTMAP_DIV 4 @@ -50,19 +51,22 @@ DrawingContext::DrawingContext() lightmap_width = screen->w / LIGHTMAP_DIV; lightmap_height = screen->h / LIGHTMAP_DIV; - int width = next_po2(lightmap_width); - int height = next_po2(lightmap_height); + unsigned int width = next_po2(lightmap_width); + unsigned int height = next_po2(lightmap_height); - lightmap.reset(new Texture(width, height, GL_RGB)); + lightmap = new Texture(width, height, GL_RGB); lightmap_uv_right = static_cast(lightmap_width) / static_cast(width); lightmap_uv_bottom = static_cast(lightmap_height) / static_cast(height); + texture_manager->register_texture(lightmap); requests = &drawing_requests; } DrawingContext::~DrawingContext() { + texture_manager->remove_texture(lightmap); + delete lightmap; } void @@ -77,12 +81,12 @@ DrawingContext::draw_surface(const Surface* surface, const Vector& position, request.pos = transform.apply(position); if(request.pos.x >= SCREEN_WIDTH || request.pos.y >= SCREEN_HEIGHT - || request.pos.x + surface->w < 0 || request.pos.y + surface->h < 0) + || request.pos.x + surface->get_width() < 0 + || request.pos.y + surface->get_height() < 0) return; request.layer = layer; request.drawing_effect = transform.drawing_effect; - request.zoom = transform.zoom; request.alpha = transform.alpha; request.request_data = const_cast (surface); @@ -138,7 +142,6 @@ DrawingContext::draw_text(const Font* font, const std::string& text, request.pos = transform.apply(position); request.layer = layer; request.drawing_effect = transform.drawing_effect; - request.zoom = transform.zoom; request.alpha = transform.alpha; TextRequest* textrequest = new TextRequest; @@ -159,7 +162,7 @@ DrawingContext::draw_center_text(const Font* font, const std::string& text, } void -DrawingContext::draw_gradient(Color top, Color bottom, int layer) +DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer) { DrawingRequest request; @@ -168,7 +171,6 @@ DrawingContext::draw_gradient(Color top, Color bottom, int layer) request.layer = layer; request.drawing_effect = transform.drawing_effect; - request.zoom = transform.zoom; request.alpha = transform.alpha; GradientRequest* gradientrequest = new GradientRequest; @@ -181,7 +183,7 @@ DrawingContext::draw_gradient(Color top, Color bottom, int layer) void DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size, - Color color, int layer) + const Color& color, int layer) { DrawingRequest request; @@ -190,15 +192,12 @@ DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size, request.layer = layer; request.drawing_effect = transform.drawing_effect; - request.zoom = transform.zoom; request.alpha = transform.alpha; FillRectRequest* fillrectrequest = new FillRectRequest; fillrectrequest->size = size; fillrectrequest->color = color; - fillrectrequest->color.alpha - = (int) ((float) fillrectrequest->color.alpha - * ((float) transform.alpha / 255.0)); + fillrectrequest->color.alpha = color.alpha * transform.alpha; request.request_data = fillrectrequest; requests->push_back(request); @@ -210,11 +209,11 @@ DrawingContext::draw_surface_part(DrawingRequest& request) SurfacePartRequest* surfacepartrequest = (SurfacePartRequest*) request.request_data; - surfacepartrequest->surface->impl->draw_part( + 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); + surfacepartrequest->size.x, surfacepartrequest->size.y, + request.alpha, request.drawing_effect); delete surfacepartrequest; } @@ -227,10 +226,10 @@ DrawingContext::draw_gradient(DrawingRequest& request) const Color& bottom = gradientrequest->bottom; glBegin(GL_QUADS); - glColor3ub(top.red, top.green, top.blue); + glColor4f(top.red, top.green, top.blue, top.alpha); glVertex2f(0, 0); glVertex2f(SCREEN_WIDTH, 0); - glColor3ub(bottom.red, bottom.green, bottom.blue); + glColor4f(bottom.red, bottom.green, bottom.blue, bottom.alpha); glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT); glVertex2f(0, SCREEN_HEIGHT); glEnd(); @@ -259,18 +258,17 @@ DrawingContext::draw_filled_rect(DrawingRequest& request) float w = fillrectrequest->size.x; float h = fillrectrequest->size.y; - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4ub(fillrectrequest->color.red, fillrectrequest->color.green, - fillrectrequest->color.blue, fillrectrequest->color.alpha); - - glBegin(GL_POLYGON); + 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(); - glDisable(GL_BLEND); + glEnable(GL_TEXTURE_2D); delete fillrectrequest; } @@ -296,14 +294,13 @@ DrawingContext::do_drawing() glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - glClearColor(1, 1, 1, 1); + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); handle_drawing_requests(lightmap_requests); lightmap_requests.clear(); glDisable(GL_BLEND); - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, lightmap->handle); + 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); @@ -312,6 +309,7 @@ DrawingContext::do_drawing() glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); + glEnable(GL_BLEND); } //glClear(GL_COLOR_BUFFER_BIT); @@ -319,17 +317,9 @@ DrawingContext::do_drawing() drawing_requests.clear(); if(use_lightmap) { - glEnable(GL_BLEND); glBlendFunc(GL_DST_COLOR, GL_ZERO); - //glDisable(GL_BLEND); - //glColor4f((float) rand() / (float) RAND_MAX, .22, .88, 1.0f); - - glEnable(GL_TEXTURE_2D); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_ALPHA_TEST); - glBindTexture(GL_TEXTURE_2D, lightmap->handle); + glBindTexture(GL_TEXTURE_2D, lightmap->get_handle()); glBegin(GL_QUADS); glTexCoord2f(0, lightmap_uv_bottom); @@ -345,6 +335,8 @@ DrawingContext::do_drawing() glVertex2f(0, SCREEN_HEIGHT); glEnd(); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } assert_gl("drawing"); @@ -363,13 +355,7 @@ DrawingContext::handle_drawing_requests(DrawingRequests& requests) case SURFACE: { const Surface* surface = (const Surface*) i->request_data; - - if(i->zoom != 1.0) - surface->impl->draw_stretched(i->pos.x * i->zoom, i->pos.y * i->zoom, - (int)(surface->w * i->zoom), (int)(surface->h * i->zoom), - i->alpha, i->drawing_effect); - else - surface->impl->draw(i->pos.x, i->pos.y, i->alpha, i->drawing_effect); + surface->draw(i->pos.x, i->pos.y, i->alpha, i->drawing_effect); break; } case SURFACE_PART: @@ -404,30 +390,24 @@ DrawingContext::pop_transform() } void -DrawingContext::set_drawing_effect(uint32_t effect) +DrawingContext::set_drawing_effect(DrawingEffect effect) { transform.drawing_effect = effect; } -uint32_t +DrawingEffect DrawingContext::get_drawing_effect() const { return transform.drawing_effect; } void -DrawingContext::set_zooming(float zoom) -{ - transform.zoom = zoom; -} - -void -DrawingContext::set_alpha(uint8_t alpha) +DrawingContext::set_alpha(float alpha) { transform.alpha = alpha; } -uint8_t +float DrawingContext::get_alpha() const { return transform.alpha; diff --git a/src/video/drawing_context.hpp b/src/video/drawing_context.hpp index b3b6d284f..dccd31bfc 100644 --- a/src/video/drawing_context.hpp +++ b/src/video/drawing_context.hpp @@ -23,14 +23,15 @@ #include #include +#include #include #include #include #include "math/vector.hpp" -#include "video/screen.hpp" -#include "video/surface.hpp" -#include "video/font.hpp" +#include "surface.hpp" +#include "font.hpp" +#include "color.hpp" class Surface; class Texture; @@ -74,10 +75,10 @@ public: void draw_center_text(const Font* font, const std::string& text, const Vector& position, int layer); /// Draws a color gradient onto the whole screen */ - void draw_gradient(Color from, Color to, int layer); + void draw_gradient(const Color& from, const Color& to, int layer); /// Fills a rectangle. void draw_filled_rect(const Vector& topleft, const Vector& size, - Color color, int layer); + const Color& color, int layer); /// Processes all pending drawing requests and flushes the list. void do_drawing(); @@ -92,15 +93,13 @@ public: void pop_transform(); /// Apply that effect in the next draws (effects are listed on surface.h). - void set_drawing_effect(uint32_t effect); + void set_drawing_effect(DrawingEffect effect); /// return currently applied drawing effect - uint32_t get_drawing_effect() const; - /// apply that zoom in the next draws */ - void set_zooming(float zoom); - /// apply that alpha in the next draws */ - void set_alpha(uint8_t alpha); + DrawingEffect get_drawing_effect() const; + /// apply that alpha in the next draws (1.0 means fully opaque) */ + void set_alpha(float alpha); /// return currently set alpha - uint8_t get_alpha() const; + float get_alpha() const; enum Target { NORMAL, LIGHTMAP @@ -114,12 +113,11 @@ private: { public: Vector translation; - uint32_t drawing_effect; - float zoom; - uint8_t alpha; + DrawingEffect drawing_effect; + float alpha; Transform() - : drawing_effect(NONE_EFFECT), zoom(1), alpha(255) + : drawing_effect(NO_EFFECT), alpha(1.0f) { } Vector apply(const Vector& v) const @@ -182,9 +180,8 @@ private: Vector pos; int layer; - uint32_t drawing_effect; - float zoom; - int alpha; + DrawingEffect drawing_effect; + float alpha; Blend blend; void* request_data; @@ -212,7 +209,7 @@ private: SDL_Surface* screen; Target target; std::vector target_stack; - std::auto_ptr lightmap; + Texture* lightmap; int lightmap_width, lightmap_height; float lightmap_uv_right, lightmap_uv_bottom; }; diff --git a/src/video/font.cpp b/src/video/font.cpp index 72c2ff431..c38557689 100644 --- a/src/video/font.cpp +++ b/src/video/font.cpp @@ -29,37 +29,15 @@ #include "font.hpp" #include "drawing_context.hpp" -Font::Font(const std::string& file, FontType ntype, int nw, int nh, - int nshadowsize) - : chars(0), shadow_chars(0), type(ntype), w(nw), h(nh), - shadowsize(nshadowsize) +Font::Font(const std::string& file, const std::string& shadowfile, + int w, int h, int shadowsize) + : chars(0), shadow_chars(0), w(w), h(h), shadowsize(shadowsize) { - chars = new Surface(file, true); + chars = new Surface(file); + shadow_chars = new Surface(shadowfile); - switch(type) { - case TEXT: - first_char = 32; - break; - case NUM: - first_char = 48; - break; - } - char_count = (chars->h / h) * 16; - - // Load shadow font. - if(shadowsize > 0) { - SDL_Surface* conv = SDL_DisplayFormatAlpha(chars->impl->get_sdl_surface()); - int pixels = conv->w * conv->h; - SDL_LockSurface(conv); - for(int i = 0; i < pixels; ++i) { - Uint32 *p = (Uint32 *)conv->pixels + i; - *p = *p & conv->format->Amask; - } - SDL_UnlockSurface(conv); - SDL_SetAlpha(conv, SDL_SRCALPHA, 128); - shadow_chars = new Surface(conv, true); - SDL_FreeSurface(conv); - } + first_char = 32; + char_count = ((int) chars->get_height() / h) * 16; } Font::~Font() @@ -118,7 +96,7 @@ Font::get_height() const void Font::draw(const std::string& text, const Vector& pos_, FontAlignment alignment, - uint32_t drawing_effect, uint8_t alpha) const + DrawingEffect drawing_effect, float alpha) const { /* Cut lines changes into seperate strings, needed to support center/right text alignments with break lines. @@ -154,7 +132,7 @@ Font::draw(const std::string& text, const Vector& pos_, FontAlignment alignment, void Font::draw_text(const std::string& text, const Vector& pos, - uint32_t drawing_effect, uint8_t alpha) const + DrawingEffect drawing_effect, float alpha) const { if(shadowsize > 0) draw_chars(shadow_chars, text, pos + Vector(shadowsize, shadowsize), @@ -208,10 +186,8 @@ uint32_t decode_utf8(const std::string& text, size_t& p) void Font::draw_chars(Surface* pchars, const std::string& text, const Vector& pos, - uint32_t drawing_effect, uint8_t alpha) const + DrawingEffect drawing_effect, float alpha) const { - SurfaceImpl* impl = pchars->impl; - Vector p = pos; size_t i = 0; while(i < text.size()) { @@ -250,7 +226,8 @@ Font::draw_chars(Surface* pchars, const std::string& text, const Vector& pos, int source_x = (font_index % 16) * w; int source_y = (font_index / 16) * h; - impl->draw_part(source_x, source_y, p.x, p.y, w, h, alpha, drawing_effect); + pchars->draw_part(source_x, source_y, p.x, p.y, w, h, alpha, + drawing_effect); p.x += w; } } diff --git a/src/video/font.hpp b/src/video/font.hpp index af6cd0b3c..6cace57c0 100644 --- a/src/video/font.hpp +++ b/src/video/font.hpp @@ -35,13 +35,8 @@ enum FontAlignment { class Font { public: - enum FontType { - TEXT, // images for all characters - NUM // only images for numbers - }; - - Font(const std::string& file, FontType type, int w, int h, - int shadowsize=2); + Font(const std::string& file, const std::string& shadowfile, + int w, int h, int shadowsize = 2); ~Font(); /** returns the width of a given text. (Note that I won't add a normal @@ -63,20 +58,22 @@ public: * Type of alignment, drawing effect and alpha are optional. */ void draw(const std::string& text, const Vector& pos, FontAlignment allignment = LEFT_ALLIGN, - uint32_t drawing_effect = NONE_EFFECT, uint8_t alpha = 255) const; + DrawingEffect drawing_effect = NO_EFFECT, + float alpha = 1.0f) const; private: friend class DrawingContext; void draw_text(const std::string& text, const Vector& pos, - uint32_t drawing_effect = NONE_EFFECT, uint8_t alpha = 255) const; + DrawingEffect drawing_effect = NO_EFFECT, + float alpha = 1.0f) const; void draw_chars(Surface* pchars, const std::string& text, - const Vector& position, uint32_t drawing_effect, uint8_t alpha) const; + const Vector& position, DrawingEffect drawing_effect, + float alpha) const; Surface* chars; Surface* shadow_chars; - FontType type; int w; int h; int shadowsize; diff --git a/src/video/image_texture.cpp b/src/video/image_texture.cpp new file mode 100644 index 000000000..2bd9af4bb --- /dev/null +++ b/src/video/image_texture.cpp @@ -0,0 +1,19 @@ +#include + +#include "image_texture.hpp" +#include "texture_manager.hpp" + +ImageTexture::ImageTexture(SDL_Surface* surface) + : Texture(surface, GL_RGBA), refcount(0) +{ +} + +ImageTexture::~ImageTexture() +{ +} + +void +ImageTexture::release() +{ + texture_manager->release(this); +} diff --git a/src/video/image_texture.hpp b/src/video/image_texture.hpp new file mode 100644 index 000000000..9fe08af9e --- /dev/null +++ b/src/video/image_texture.hpp @@ -0,0 +1,59 @@ +#ifndef __SURFACE_TEXTURE_HPP__ +#define __SURFACE_TEXTURE_HPP__ + +#include +#include "texture.hpp" + +class ImageTexture : public Texture +{ +private: + std::string filename; + float image_width; + float image_height; + int refcount; + +public: + float get_image_width() const + { + return image_width; + } + + float get_image_height() const + { + return image_height; + } + + float get_uv_right() const + { + return image_width / static_cast (get_width()); + } + + float get_uv_bottom() const + { + return image_height / static_cast (get_height()); + } + + void ref() + { + refcount++; + } + + void unref() + { + assert(refcount > 0); + refcount--; + if(refcount == 0) + release(); + } + +private: + friend class TextureManager; + + ImageTexture(SDL_Surface* surface); + virtual ~ImageTexture(); + + void release(); +}; + +#endif + diff --git a/src/video/screen.cpp b/src/video/screen.cpp index f7463f0cc..2227ccfe0 100644 --- a/src/video/screen.cpp +++ b/src/video/screen.cpp @@ -28,12 +28,6 @@ #include #include -#include - -#ifndef WIN32 -#include -#include -#endif #include "gameconfig.hpp" #include "screen.hpp" @@ -43,107 +37,6 @@ #include "math/vector.hpp" static const float LOOP_DELAY = 20.0; -extern SDL_Surface* screen; - -/* 'Stolen' from the SDL documentation. - * Return the pixel value at (x, y) - * NOTE: The surface must be locked before calling this! - */ -Uint32 getpixel(SDL_Surface *surface, int x, int y) -{ - int bpp = surface->format->BytesPerPixel; - /* Here p is the address to the pixel we want to retrieve */ - Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; - - switch(bpp) { - case 1: - return *p; - - case 2: - return *(Uint16 *)p; - - case 3: - if(SDL_BYTEORDER == SDL_BIG_ENDIAN) - return p[0] << 16 | p[1] << 8 | p[2]; - else - return p[0] | p[1] << 8 | p[2] << 16; - - case 4: - return *(Uint32 *)p; - - default: - return 0; /* shouldn't happen, but avoids warnings */ - } -} - -/* 'Stolen' from the SDL documentation. - * Set the pixel at (x, y) to the given value - * NOTE: The surface must be locked before calling this! - */ -void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel) -{ - int bpp = surface->format->BytesPerPixel; - /* Here p is the address to the pixel we want to set */ - Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; - - switch(bpp) { - case 1: - *p = pixel; - break; - - case 2: - *(Uint16 *)p = pixel; - break; - - case 3: - if(SDL_BYTEORDER == SDL_BIG_ENDIAN) - { - p[0] = (pixel >> 16) & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = pixel & 0xff; - } - else - { - p[0] = pixel & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = (pixel >> 16) & 0xff; - } - break; - - case 4: - *(Uint32 *)p = pixel; - break; - - default: - assert(false); - } -} - -/* Draw a single pixel on the screen. */ -void drawpixel(int x, int y, Uint32 pixel) -{ - /* Lock the screen for direct access to the pixels */ - if ( SDL_MUSTLOCK(screen) ) - { - if ( SDL_LockSurface(screen) < 0 ) - { - fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError()); - return; - } - } - - if(!(x < 0 || y < 0 || x > SCREEN_WIDTH || y > SCREEN_HEIGHT)) - putpixel(screen, x, y, pixel); - - if ( SDL_MUSTLOCK(screen) ) - { - SDL_UnlockSurface(screen); - } - /* Update just the part of the display that we've changed */ - SDL_UpdateRect(screen, x, y, 1, 1); -} - -/* --- FILL A RECT --- */ void fillrect(float x, float y, float w, float h, int r, int g, int b, int a) { @@ -156,38 +49,18 @@ void fillrect(float x, float y, float w, float h, int r, int g, int b, int a) h = -h; } - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4ub(r, g, b,a); - + + glDisable(GL_TEXTURE_2D); glBegin(GL_POLYGON); glVertex2f(x, y); glVertex2f(x+w, y); glVertex2f(x+w, y+h); glVertex2f(x, y+h); glEnd(); - glDisable(GL_BLEND); -} - -/* Needed for line calculations */ -#define SGN(x) ((x)>0 ? 1 : ((x)==0 ? 0:(-1))) -#define ABS(x) ((x)>0 ? (x) : (-x)) - -void draw_line(float x1, float y1, float x2, float y2, - int r, int g, int b, int a) -{ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4ub(r, g, b,a); - - glBegin(GL_LINES); - glVertex2f(x1, y1); - glVertex2f(x2, y2); - glEnd(); - glDisable(GL_BLEND); + glEnable(GL_TEXTURE_2D); } - void fadeout(int fade_time) { float alpha_inc = 256 / (fade_time / LOOP_DELAY); @@ -196,9 +69,8 @@ void fadeout(int fade_time) while(alpha > 0) { alpha -= alpha_inc; fillrect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0,0,0, (int)alpha_inc); // left side - - DrawingContext context; // ugly... - context.do_drawing(); + + SDL_GL_SwapBuffers(); sound_manager->update(); SDL_Delay(int(LOOP_DELAY)); @@ -227,8 +99,8 @@ void shrink_fade(const Vector& point, int fade_time) fillrect(SCREEN_WIDTH - right_cor, 0, right_cor, SCREEN_HEIGHT, 0,0,0); // right side fillrect(0, 0, SCREEN_WIDTH, up_cor, 0,0,0); // up side fillrect(0, SCREEN_HEIGHT - down_cor, SCREEN_WIDTH, down_cor+1, 0,0,0); // down side - DrawingContext context; // ugly... - context.do_drawing(); + + SDL_GL_SwapBuffers(); sound_manager->update(); SDL_Delay(int(LOOP_DELAY)); diff --git a/src/video/screen.hpp b/src/video/screen.hpp index 8f634982b..a26d5e9cb 100644 --- a/src/video/screen.hpp +++ b/src/video/screen.hpp @@ -26,53 +26,7 @@ #include #include "math/vector.hpp" -/** Stores 8bit RGBA values. */ -class Color -{ -public: - Color() - : red(0), green(0), blue(0), alpha(255) - {} - - Color(Uint8 red_, Uint8 green_, Uint8 blue_, Uint8 alpha_ = 255) - : red(red_), green(green_), blue(blue_), alpha(alpha_) - {} - - Color(std::vector color) - : red(0), green(0), blue(0), alpha(255) - { if(color.size() >= 3) { red = color[0]; green = color[1]; blue = color[2]; } - if(color.size() == 4) alpha = color[3]; } - - Color(std::vector color) - : red(0), green(0), blue(0), alpha(255) - { if(color.size() >= 3) { red = color[0]; green = color[1]; blue = color[2]; } - if(color.size() == 4) alpha = color[3]; } - - Color(const Color& o) - : red(o.red), green(o.green), blue(o.blue), alpha(o.alpha) - { } - - bool operator==(const Color& o) - { - if(red == o.red && green == o.green && - blue == o.blue && alpha == o.alpha) - return true; - return false; - } - - Uint32 map_rgb(SDL_Surface* surface) - { return SDL_MapRGB(surface->format, red, green, blue); } - Uint32 map_rgba(SDL_Surface* surface) - { return SDL_MapRGBA(surface->format, red, green, blue, alpha); } - - Uint8 red, green, blue, alpha; -}; - -Uint32 getpixel(SDL_Surface* surface, int x, int y); -void putpixel(SDL_Surface* surface, int x, int y, Uint32 pixel); -void drawpixel(int x, int y, Uint32 pixel); void fillrect(float x, float y, float w, float h, int r, int g, int b, int a = 255); -void draw_line(float x1, float y1, float x2, float y2, int r, int g, int b, int a = 255); void fadeout(int fade_time); void shrink_fade(const Vector& point, int fade_time); diff --git a/src/video/surface.cpp b/src/video/surface.cpp index 312129119..daca15c34 100644 --- a/src/video/surface.cpp +++ b/src/video/surface.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -32,752 +33,133 @@ #include "physfs/physfs_sdl.hpp" #include "video/surface.hpp" #include "video/screen.hpp" +#include "image_texture.hpp" +#include "texture_manager.hpp" -Surface::Surfaces Surface::surfaces; - -extern SDL_Surface* screen; - -SurfaceData::SurfaceData(SDL_Surface* temp, bool use_alpha_) - : type(SURFACE), surface(0), use_alpha(use_alpha_), - x(0), y(0), w(0), h(0) +Surface::Surface(const std::string& file) { - // 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) - throw std::runtime_error("No memory left for surface"); - - SDL_SetAlpha(temp,0,0); - SDL_BlitSurface(temp, NULL, surface, NULL); -} + 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(); -SurfaceData::SurfaceData(const std::string& file_, bool 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_, bool 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_; + width = texture->get_image_width(); + height = texture->get_image_height(); } - -SurfaceData::~SurfaceData() +Surface::Surface(const std::string& file, int x, int y, int w, int h) { - SDL_FreeSurface(surface); -} + texture = texture_manager->get(file); + texture->ref(); -SurfaceImpl* -SurfaceData::create() -{ - return create_SurfaceOpenGL(); -} + float tex_w = static_cast (texture->get_width()); + float tex_h = static_cast (texture->get_height()); + uv_left = static_cast(x) / tex_w; + uv_top = static_cast(y) / tex_h; + uv_right = static_cast(x+w) / tex_w; + uv_bottom = static_cast(y+h) / tex_h; -SurfaceOpenGL* -SurfaceData::create_SurfaceOpenGL() -{ - switch(type) - { - case LOAD: - return new SurfaceOpenGL(file); - case LOAD_PART: - return new SurfaceOpenGL(file, x, y, w, h); - case SURFACE: - return new SurfaceOpenGL(surface); - case GRADIENT: - return new SurfaceOpenGL(top_gradient, bottom_gradient, w, h); - default: - assert(false); - } -} - -/* Quick utility function for texture creation */ -static int power_of_two(int input) -{ - int value = 1; - - while ( value < input ) - { - value <<= 1; - } - return value; -} - -Surface::Surface(SDL_Surface* surf, bool use_alpha) - : impl(0), 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, bool use_alpha) - : impl(0), data(file, use_alpha), w(0), h(0) -{ - impl = data.create(); - if (impl) - { - w = impl->w; - h = impl->h; - } - surfaces.push_back(this); + width = w; + height = h; } -Surface::Surface(const std::string& file, int x, int y, int w_, int h_, bool use_alpha) - : impl(0), data(file, x, y, w_, h_, use_alpha), w(0), h(0) +Surface::Surface(const Surface& other) { - impl = data.create(); - if (impl) - { - w = impl->w; - h = impl->h; - } - surfaces.push_back(this); -} + texture = other.texture; + texture->ref(); -Surface::Surface(Color top_background, Color bottom_background, int w_, int h_) - : impl(0), 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); + 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; } -void -Surface::reload() +const Surface& +Surface::operator= (const Surface& other) { - delete impl; - impl = data.create(); - if (impl) - { - w = impl->w; - h = impl->h; - for(std::vector::iterator i = - data.applied_filters.begin(); i != data.applied_filters.end(); - i++) - impl->apply_filter(i->type, i->color); - } -} + other.texture->ref(); + texture->unref(); + texture = other.texture; -void Surface::apply_filter(int filter, Color color) -{ - impl->apply_filter(filter, color); + 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; - SurfaceData::Filter apply_filter; - apply_filter.type = filter; - apply_filter.color = color; - data.applied_filters.push_back(apply_filter); + return *this; } 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; + texture->unref(); } 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 -apply_filter_to_surface(SDL_Surface* surface, int filter, Color color) -{ - if(filter == HORIZONTAL_FLIP_FILTER) { - SDL_Surface* sur_copy = sdl_surface_from_sdl_surface(surface); - SDL_BlitSurface(surface, NULL, sur_copy, NULL); - SDL_SetAlpha(sur_copy,0,0); - - SDL_Rect src, dst; - src.y = dst.y = 0; - src.w = dst.w = 1; - src.h = dst.h = sur_copy->h; - for(int x = 0; x < sur_copy->w; x++) - { - src.x = x; dst.x = sur_copy->w-1 - x; - SDL_BlitSurface(sur_copy, &src, surface, &dst); - } - - SDL_FreeSurface(sur_copy); - } else if(filter == MASK_FILTER) { - SDL_Surface* sur_copy = sdl_surface_from_sdl_surface(surface); - - Uint8 r,g,b,a; - - SDL_LockSurface(sur_copy); - for(int x = 0; x < sur_copy->w; x++) - for(int y = 0; y < sur_copy->h; y++) { - SDL_GetRGBA(getpixel(sur_copy,x,y), sur_copy->format, &r,&g,&b,&a); - if(a != 0) { - putpixel(sur_copy, x,y, color.map_rgba(sur_copy)); - } - } - SDL_UnlockSurface(sur_copy); - - SDL_BlitSurface(sur_copy, NULL, surface, NULL); - SDL_FreeSurface(sur_copy); - } -} - -SDL_Surface* -sdl_surface_part_from_file(const std::string& file, int x, int y, int w, int h) -{ - SDL_Rect src; - SDL_Surface * sdl_surface; - SDL_Surface * temp; - SDL_Surface * conv; - - temp = IMG_Load_RW(get_physfs_SDLRWops(file), true); - if (temp == 0) { - std::stringstream msg; - msg << "Couldn't load '" << file << "': " << SDL_GetError(); - throw std::runtime_error(msg.str()); - } - - /* Set source rectangle for conv: */ - - src.x = x; - src.y = y; - src.w = w; - src.h = h; - - conv = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, temp->format->BitsPerPixel, - temp->format->Rmask, - temp->format->Gmask, - temp->format->Bmask, - temp->format->Amask); - - SDL_SetAlpha(temp,0,0); - - SDL_BlitSurface(temp, &src, conv, NULL); - sdl_surface = SDL_DisplayFormatAlpha(conv); - - if (sdl_surface == NULL) { - std::stringstream msg; - msg << "Can't convert file '" << file << "' to display format."; - throw std::runtime_error(msg.str()); - } - - SDL_FreeSurface(temp); - SDL_FreeSurface(conv); - - return sdl_surface; -} - -SDL_Surface* -sdl_surface_from_file(const std::string& file) -{ - SDL_Surface* sdl_surface; - SDL_Surface* temp; - - temp = IMG_Load_RW(get_physfs_SDLRWops(file), true); - if (temp == 0) { - std::stringstream msg; - msg << "Couldn't load file '" << file << "': " << SDL_GetError(); - throw std::runtime_error(msg.str()); - } - - sdl_surface = SDL_DisplayFormatAlpha(temp); - - if (sdl_surface == NULL) { - std::stringstream msg; - msg << "Couldn't convert file '" << file << "' to display format"; - throw std::runtime_error(msg.str()); - } - - SDL_FreeSurface(temp); - - return sdl_surface; -} - -SDL_Surface* -sdl_surface_from_sdl_surface(SDL_Surface* sdl_surf) +Surface::hflip() { - SDL_Surface* sdl_surface = SDL_DisplayFormatAlpha(sdl_surf); - if (sdl_surface == 0) { - std::stringstream msg; - msg << "Can't convert surface to display format."; - throw std::runtime_error(msg.str()); - } - - return sdl_surface; + std::swap(uv_left, uv_right); } -SDL_Surface* -sdl_surface_from_gradient(Color top, Color bottom, int w, int h) +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) { - SDL_Surface* sdl_surface - = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, - screen->format->BitsPerPixel, screen->format->Rmask, - screen->format->Gmask, screen->format->Bmask, 0); - - if(sdl_surface == 0) - throw std::runtime_error("Can't create 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))); - } + if(effect & HORIZONTAL_FLIP) + std::swap(uv_left, uv_right); + if(effect & VERTICAL_FLIP) { + std::swap(uv_top, uv_bottom); } - - return sdl_surface; -} - -//--------------------------------------------------------------------------- - -SurfaceImpl::SurfaceImpl() - : sdl_surface(0) -{} - -SurfaceImpl::~SurfaceImpl() -{ - if(sdl_surface != 0) - SDL_FreeSurface(sdl_surface); -} - -SDL_Surface* SurfaceImpl::get_sdl_surface() const -{ - return sdl_surface; -} - -SurfaceOpenGL::SurfaceOpenGL(SDL_Surface* surf) -{ - sdl_surface = sdl_surface_from_sdl_surface(surf); - create_gl(sdl_surface,&gl_texture); - - w = sdl_surface->w; - h = sdl_surface->h; -} - -SurfaceOpenGL::SurfaceOpenGL(const std::string& file) -{ - sdl_surface = sdl_surface_from_file(file); - 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_) -{ - sdl_surface = sdl_surface_part_from_file(file_, x_, y_, w_, h_); - 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_RGBA; - 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 & HORIZONTAL_FLIP) - { - glTexCoord2f(0, 0); - glVertex2f((float)w+x, (float)h+y); - - glTexCoord2f((float)w / pw, 0); - glVertex2f(x, (float)h+y); - - glTexCoord2f((float)w / pw, (float)h / ph); - glVertex2f(x, y); - - glTexCoord2f(0, (float)h / ph); - glVertex2f((float)w+x, y); - } - else 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 if(effect & HORIZONTAL_FLIP) - { - glTexCoord2f(0, 0); - glVertex2f((float)w+x, y); - - glTexCoord2f((float)w / pw, 0); - glVertex2f(x, y); - - glTexCoord2f((float)w / pw, (float)h / ph); - glVertex2f(x, (float)h+y); - - glTexCoord2f(0, (float)h / ph); - glVertex2f((float)w+x, (float)h+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); + glTexCoord2f(uv_left, uv_top); + glVertex2f(left, top); + + glTexCoord2f(uv_right, uv_top); + glVertex2f(right, top); - if(effect & VERTICAL_FLIP & HORIZONTAL_FLIP) - { - glTexCoord2f(sx / pw, (float)(sy+h) / ph); - glVertex2f((float)w+x, (float)h+y); - - glTexCoord2f((sx+w) / pw, (sy+h) / ph); - glVertex2f(x, (float)h+y); - - glTexCoord2f((float)(sx + w) / pw, sy / ph); - glVertex2f(x, y); - - glTexCoord2f(sx / pw, sy / ph); - glVertex2f((float)w+x, y); - } - else 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 if(effect & HORIZONTAL_FLIP) - { - glTexCoord2f(sx / pw, sy / ph); - glVertex2f((float)w+x, y); - - glTexCoord2f((float)(sx + w) / pw, sy / ph); - glVertex2f(x, y); - - glTexCoord2f((sx+w) / pw, (sy+h) / ph); - glVertex2f(x, (float)h+y); - - glTexCoord2f(sx / pw, (float)(sy+h) / ph); - glVertex2f((float)w+x, (float)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); - } + glTexCoord2f(uv_right, uv_bottom); + glVertex2f(right, bottom); + glTexCoord2f(uv_left, uv_bottom); + glVertex2f(left, bottom); glEnd(); - - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - - return 0; } -int -SurfaceOpenGL::draw_stretched(float x, float y, int sw, int sh, Uint8 alpha, Uint32 effect) +void +Surface::draw(float x, float y, float alpha, DrawingEffect effect) const { - float pw = power_of_two(sw); - float ph = power_of_two(sh); + glColor4f(1.0f, 1.0f, 1.0f, alpha); + glBindTexture(GL_TEXTURE_2D, texture->get_handle()); - 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 & HORIZONTAL_FLIP) - { - glTexCoord2f(0, 0); - glVertex2f((float)sw+x, (float)sh+y); - - glTexCoord2f((float)w / pw, 0); - glVertex2f(x, (float)sh+y); - - glTexCoord2f((float)w / pw, (float)h / ph); - glVertex2f(x, y); - - glTexCoord2f(0, (float)h / ph); - glVertex2f((float)sw+x, y); - } - else if(effect & VERTICAL_FLIP) - { - glTexCoord2f(0, 0); - glVertex2f(x, (float)sh+y); - - glTexCoord2f((float)w / pw, 0); - glVertex2f((float)sw+x, (float)sh+y); - - glTexCoord2f((float)w / pw, (float)h / ph); - glVertex2f((float)sw+x, y); - - glTexCoord2f(0, (float)h / ph); - glVertex2f(x, y); - } - else if(effect & HORIZONTAL_FLIP) - { - glTexCoord2f(0, 0); - glVertex2f((float)sw+x, y); - - glTexCoord2f((float)w / pw, 0); - glVertex2f(x, y); - - glTexCoord2f((float)w / pw, (float)h / ph); - glVertex2f(x, (float)sh+y); - - glTexCoord2f(0, (float)h / ph); - glVertex2f((float)sw+x, (float)sh+y); - } - else - { - glTexCoord2f(0, 0); - glVertex2f(x, y); - - glTexCoord2f((float)w / pw, 0); - glVertex2f((float)sw+x, y); - - glTexCoord2f((float)w / pw, (float)h / ph); - glVertex2f((float)sw+x, (float)sh+y); - - glTexCoord2f(0, (float)h / ph); - glVertex2f(x, (float)sh+y); - } - glEnd(); - - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - - return 0; + intern_draw(x, y, + x + width, y + height, + uv_left, uv_top, uv_right, uv_bottom, effect); } void -SurfaceOpenGL::apply_filter(int filter, Color color) +Surface::draw_part(float src_x, float src_y, float dst_x, float dst_y, + float width, float height, float alpha, + DrawingEffect effect) const { - ::apply_filter_to_surface(sdl_surface, filter, color); - create_gl(sdl_surface,&gl_texture); - - w = sdl_surface->w; - h = sdl_surface->h; + 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; + + glColor4f(1.0f, 1.0f, 1.0f, alpha); + glBindTexture(GL_TEXTURE_2D, texture->get_handle()); + + intern_draw(dst_x, dst_y, + dst_x + width, dst_y + height, + uv_left, uv_top, uv_right, uv_bottom, effect); } + diff --git a/src/video/surface.hpp b/src/video/surface.hpp index bd0da7c0e..a5ba95558 100644 --- a/src/video/surface.hpp +++ b/src/video/surface.hpp @@ -1,7 +1,7 @@ -// $Id: surface.h 2175 2004-11-24 19:02:49Z sik0fewl $ +// $Id$ // // SuperTux -// Copyright (C) 2004 Tobias Glaesser +// Copyright (C) 2005 Matthias Braun // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -17,152 +17,69 @@ // 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 +#ifndef __SURFACE_HPP__ +#define __SURFACE_HPP__ #include -#include -#include -#include +class ImageTexture; -#include "math/vector.hpp" -#include "video/screen.hpp" - -void apply_filter_to_surface(SDL_Surface *surface, int filter, int value); -SDL_Surface* sdl_surface_from_sdl_surface(SDL_Surface* sdl_surf); -SDL_Surface* sdl_surface_from_nothing(); - -class SurfaceImpl; -class SurfaceOpenGL; -class DrawingContext; - /// bitset for drawing effects -enum { +enum DrawingEffect { /** Don't apply anything */ - NONE_EFFECT = 0x0000, + NO_EFFECT = 0x0000, /** Draw the Surface upside down */ VERTICAL_FLIP = 0x0001, /** Draw the Surface from left to down */ HORIZONTAL_FLIP = 0x0002, - /** Draw the Surface with alpha equal to 128 */ - SEMI_TRANSPARENT = 0x0004 -}; - -/// types of filters -enum { - HORIZONTAL_FLIP_FILTER, - MASK_FILTER, - NONE_FILTER -}; - -/** 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; - - struct Filter { int type; Color color; }; - std::vector applied_filters; - - bool use_alpha; - int x; - int y; - int w; - int h; - Color top_gradient; - Color bottom_gradient; - - SurfaceData(SDL_Surface* surf, bool use_alpha_); - SurfaceData(const std::string& file_, bool use_alpha_); - SurfaceData(const std::string& file_, int x_, int y_, int w_, int h_, bool use_alpha_); - SurfaceData(Color top_gradient_, Color bottom_gradient_, int w_, int h_); - ~SurfaceData(); - - SurfaceOpenGL* create_SurfaceOpenGL(); - SurfaceImpl* create(); }; - -/** Container class that holds a surface, necessary so that we can - * switch Surface implementations (OpenGL, SDL) on the fly +/** + * Container class that holds a surface, necessary so that we can + * reload Surface implementations on the fly */ 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, 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; public: - SurfaceImpl* impl; - SurfaceData data; - int w; - int h; - - typedef std::list Surfaces; - static Surfaces surfaces; -public: - static void reload_all(); - static void debug_check(); - - Surface(SDL_Surface* surf, bool use_alpha); - Surface(const std::string& file, bool use_alpha); - Surface(const std::string& file, int x, int y, int w, int h, bool use_alpha); - Surface(Color top_gradient, Color bottom_gradient, int w_, int h_); + Surface(const std::string& file); + Surface(const std::string& file, int x, int y, int w, int h); + Surface(const Surface& other); ~Surface(); + + /** flip the surface horizontally */ + void hflip(); /** Reload the surface, which is necesarry in case of a mode swich */ void reload(); - - void apply_filter(int filter, Color color = Color(0,0,0)); -}; -/** 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; - virtual int draw_stretched(float x, float y, int w, int h, Uint8 alpha, Uint32 effect = NONE_EFFECT) = 0; - - - SDL_Surface* get_sdl_surface() const; // @evil@ try to avoid this function - - virtual void apply_filter(int filter, Color color = Color(0,0,0)) = 0; -}; + const Surface& operator= (const Surface& other); -class SurfaceOpenGL : public SurfaceImpl -{ -public: - GLuint gl_texture; - -public: - SurfaceOpenGL(SDL_Surface* surf); - SurfaceOpenGL(const std::string& file); - SurfaceOpenGL(const std::string& file, int x, int y, int w, int h); - 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); - int draw_stretched(float x, float y, int w, int h, Uint8 alpha, Uint32 effect = NONE_EFFECT); - - void apply_filter(int filter, Color color); - -private: - void create_gl(SDL_Surface * surf, GLuint * tex); + float get_width() const + { + return width; + } + + float get_height() const + { + return height; + } }; #endif diff --git a/src/video/texture.cpp b/src/video/texture.cpp index 98bfc91d3..a49a5cc68 100644 --- a/src/video/texture.cpp +++ b/src/video/texture.cpp @@ -96,12 +96,6 @@ Texture::~Texture() glDeleteTextures(1, &handle); } -void upload_texture(SDL_Surface* , int , int , int , int , int , int ) -{ - // TODO - assert(false); -} - void Texture::set_texture_params() { @@ -109,7 +103,6 @@ Texture::set_texture_params() 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); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP); assert_gl("set texture params"); } diff --git a/src/video/texture.hpp b/src/video/texture.hpp index 8322e3c7a..3c8b4f708 100644 --- a/src/video/texture.hpp +++ b/src/video/texture.hpp @@ -23,25 +23,41 @@ #include /** - * This class is a very simple wrapper around a texture handle + * 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 */ class Texture { -public: +protected: + friend class TextureManager; GLuint handle; unsigned int width; unsigned int height; - + +public: Texture(unsigned int width, unsigned int height, GLenum glformat); Texture(SDL_Surface* surface, GLenum glformat); - ~Texture(); + virtual ~Texture(); + + GLuint get_handle() const + { + return handle; + } + + unsigned int get_width() const + { + return width; + } + + unsigned int get_height() const + { + return height; + } - void upload_texture(SDL_Surface* image, int src_x, int src_y, int dst_x, int dst_y, - int width, int height); private: void set_texture_params(); }; - #endif diff --git a/src/video/texture_manager.cpp b/src/video/texture_manager.cpp new file mode 100644 index 000000000..ab5788eaa --- /dev/null +++ b/src/video/texture_manager.cpp @@ -0,0 +1,218 @@ +#include + +#include "texture_manager.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include "physfs/physfs_sdl.hpp" +#include "image_texture.hpp" +#include "glutil.hpp" + +TextureManager* texture_manager = NULL; + +TextureManager::TextureManager() +{ +} + +TextureManager::~TextureManager() +{ + for(ImageTextures::iterator i = image_textures.begin(); + i != image_textures.end(); ++i) { + if(i->second == NULL) + continue; +#ifdef DEBUG + std::cerr << "Warning: Texture '" << i->first << "' not freed\n"; +#endif + delete i->second; + } +} + +ImageTexture* +TextureManager::get(const std::string& filename) +{ + ImageTextures::iterator i = image_textures.find(filename); + + ImageTexture* texture = NULL; + if(i != image_textures.end()) + texture = i->second; + + if(texture == NULL) { + texture = create_image_texture(filename); + image_textures[filename] = texture; + } + + return texture; +} + +void +TextureManager::release(ImageTexture* texture) +{ + image_textures[texture->filename] = NULL; + delete texture; +} + +void +TextureManager::register_texture(Texture* texture) +{ + textures.insert(texture); +} + +void +TextureManager::remove_texture(Texture* texture) +{ + textures.erase(texture); +} + +static inline int next_power_of_two(int val) +{ + int result = 1; + while(result < val) + result *= 2; + return result; +} + +ImageTexture* +TextureManager::create_image_texture(const std::string& filename) +{ + SDL_Surface* image = IMG_Load_RW(get_physfs_SDLRWops(filename), 1); + if(image == NULL) { + 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) + 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; + try { + result = new ImageTexture(convert); + result->filename = filename; + result->image_width = image->w; + result->image_height = image->h; + } catch(...) { + delete result; + SDL_FreeSurface(convert); + throw; + } + + SDL_FreeSurface(convert); + return result; +} + +void +TextureManager::save_textures() +{ + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0); + glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + glPixelStorei(GL_PACK_SKIP_ROWS, 0); + glPixelStorei(GL_PACK_SKIP_IMAGES, 0); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + for(Textures::iterator i = textures.begin(); i != textures.end(); ++i) { + save_texture(*i); + } + for(ImageTextures::iterator i = image_textures.begin(); + i != image_textures.end(); ++i) { + save_texture(i->second); + } +} + +void +TextureManager::save_texture(Texture* texture) +{ + SavedTexture saved_texture; + saved_texture.texture = texture; + glBindTexture(GL_TEXTURE_2D, texture->get_handle()); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, + &saved_texture.width); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, + &saved_texture.height); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, + &saved_texture.border); + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + &saved_texture.min_filter); + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + &saved_texture.mag_filter); + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + &saved_texture.wrap_s); + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, + &saved_texture.wrap_t); + + size_t pixelssize = saved_texture.width * saved_texture.height * 4; + saved_texture.pixels = new char[pixelssize]; + + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, + saved_texture.pixels); + + saved_textures.push_back(saved_texture); + + glDeleteTextures(1, &(texture->handle)); + texture->handle = 0; + + assert_gl("retrieving texture"); +} + +void +TextureManager::reload_textures() +{ + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + for(std::vector::iterator i = saved_textures.begin(); + i != saved_textures.end(); ++i) { + SavedTexture& saved_texture = *i; + + GLuint handle; + glGenTextures(1, &handle); + assert_gl("creating texture handle"); + + glBindTexture(GL_TEXTURE_2D, handle); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + saved_texture.width, saved_texture.height, + saved_texture.border, GL_RGBA, + GL_UNSIGNED_BYTE, saved_texture.pixels); + delete[] saved_texture.pixels; + assert_gl("uploading texture pixel data"); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + saved_texture.min_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + saved_texture.mag_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + saved_texture.wrap_s); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, + saved_texture.wrap_t); + + assert_gl("setting texture_params"); + saved_texture.texture->handle = handle; + } + + saved_textures.clear(); +} + diff --git a/src/video/texture_manager.hpp b/src/video/texture_manager.hpp new file mode 100644 index 000000000..0b0854faa --- /dev/null +++ b/src/video/texture_manager.hpp @@ -0,0 +1,60 @@ +#ifndef __IMAGE_TEXTURE_MANAGER_HPP__ +#define __IMAGE_TEXTURE_MANAGER_HPP__ + +#include +#include +#include +#include +#include + +class Texture; +class ImageTexture; + +class TextureManager +{ +public: + TextureManager(); + ~TextureManager(); + + ImageTexture* get(const std::string& filename); + + void register_texture(Texture* texture); + void remove_texture(Texture* texture); + + void save_textures(); + void reload_textures(); + +private: + friend class ImageTexture; + void release(ImageTexture* texture); + + typedef std::map ImageTextures; + ImageTextures image_textures; + + ImageTexture* create_image_texture(const std::string& filename); + + typedef std::set Textures; + Textures textures; + + struct SavedTexture + { + Texture* texture; + int width; + int height; + char* pixels; + int border; + + int min_filter; + int mag_filter; + int wrap_s; + int wrap_t; + }; + std::vector saved_textures; + + void save_texture(Texture* texture); +}; + +extern TextureManager* texture_manager; + +#endif + diff --git a/src/worldmap.cpp b/src/worldmap.cpp index 45cc1bdb0..d731b4ea9 100644 --- a/src/worldmap.cpp +++ b/src/worldmap.cpp @@ -352,8 +352,8 @@ WorldMap::WorldMap() tux = new Tux(this); add_object(tux); - messagedot = new Surface("images/worldmap/common/messagedot.png", true); - teleporterdot = new Surface("images/worldmap/common/teleporterdot.png", true); + messagedot = new Surface("images/worldmap/common/messagedot.png"); + teleporterdot = new Surface("images/worldmap/common/teleporterdot.png"); name = ""; music = "salcon.ogg";