From: Ingo Ruhnke Date: Thu, 21 Aug 2008 22:07:11 +0000 (+0000) Subject: qMax 's font patch, adds unicode support and support for drawing... X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=88044088f138f9f6bdaaaf873f114f34f053c864;p=supertux.git qMax 's font patch, adds unicode support and support for drawing fonts in different colors SVN-Revision: 5736 --- diff --git a/data/images/engine/fonts/README b/data/images/engine/fonts/README index 4faa8d38d..9392ef373 100644 --- a/data/images/engine/fonts/README +++ b/data/images/engine/fonts/README @@ -1,3 +1,4 @@ -The list of letters in UTF-8 format that is currently used in the fonts can be optained with: +These are images containing glyphs of font. +They expectde to be in RGBA pixel format and any SDL-loabale file format. +Glyphs themselves and charsets described in data/fonts/*.stf files. -ruby -e '((32..127).to_a + (128+32..383).to_a).each_with_index{|c,idx| print [c].pack("I"); if ((idx+1) % 16 == 0) then print [10].pack("I") end }' | recode "UCS-4LE..UTF-8" diff --git a/src/badguy/dispenser.cpp b/src/badguy/dispenser.cpp index 3bbe81bb3..6010b14d0 100644 --- a/src/badguy/dispenser.cpp +++ b/src/badguy/dispenser.cpp @@ -18,6 +18,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include +#include #include "dispenser.hpp" #include "object/bullet.hpp" diff --git a/src/colorscheme.cpp b/src/colorscheme.cpp new file mode 100644 index 000000000..5673e0018 --- /dev/null +++ b/src/colorscheme.cpp @@ -0,0 +1,54 @@ +#include "video/color.hpp" + +namespace LevelIntro { + Color header_color(1.0,1.0,1.0); + Color author_color(1.0,1.0,1.0); + Color stat_hdr_color(1.0,1.0,1.0); + Color stat_color(1.0,1.0,1.0); +} + +namespace Statistics { + Color header_color(0.5,1.0,0.2); + Color text_color(1.0,1.0,1.0); +} + +namespace Menu { + Color default_color(1.0,1.0,1.0); + Color active_color(0.6,1.0,1.0); + Color inactive_color(0.5,0.5,1.0); + Color label_color(0.8,0.4,0.2); + Color field_color(1.0,0.8,0.6); +} + +namespace PlayerStatus { + Color text_color(1.0,1.0,0.6); +} + +namespace TextObject { + Color default_color(1.0,1.0,0.6); +} + +namespace FloatingText { + Color text_color(1.0,1.0,0.6); +} + +namespace LevelTime { + Color text_color(1.0,1.0,0.6); +} + +namespace SecretAreaTrigger { + Color text_color(1.0,1.0,0.6); +} + +namespace Climbable { + Color text_color(1.0,1.0,0.6); +} + +namespace WorldMapNS { + namespace WorldMap { + Color level_title_color(1.0,1.0,0.2); + Color message_color(1.0,1.0,1.0); + Color teleporter_message_color(0.5,1.0,0.5); +}} + + diff --git a/src/console.cpp b/src/console.cpp index fb1f5f382..9c82a0e3d 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -53,9 +53,7 @@ Console::~Console() void Console::init_graphics() { - font.reset(new Font(Font::FIXED, - "images/engine/fonts/andale12.png", - "images/engine/fonts/andale12-shadow.png", 7, 14, 1)); + font.reset(new Font(Font::FIXED,"fonts/andale12.stf",1)); fontheight = font->get_height(); background.reset(new Surface("images/engine/console.png")); background2.reset(new Surface("images/engine/console2.png")); diff --git a/src/gui/menu.cpp b/src/gui/menu.cpp index b7873b6c0..6571e3f30 100644 --- a/src/gui/menu.cpp +++ b/src/gui/menu.cpp @@ -51,11 +51,6 @@ std::vector Menu::last_menus; std::list Menu::all_menus; Menu* Menu::current_ = 0; Menu* Menu::previous = 0; -Font* Menu::default_font; -Font* Menu::active_font; -Font* Menu::inactive_font; -Font* Menu::label_font; -Font* Menu::field_font; /* just displays a Yes/No text that can be used to confirm stuff */ bool confirm_dialog(Surface *background, std::string text) @@ -207,11 +202,11 @@ void MenuItem::set_help(const std::string& help_text) { std::string overflow; - help = Menu::default_font->wrap_to_width(help_text, 600, &overflow); + help = normal_font->wrap_to_width(help_text, 600, &overflow); while (!overflow.empty()) { help += "\n"; - help += Menu::default_font->wrap_to_width(overflow, 600, &overflow); + help += normal_font->wrap_to_width(overflow, 600, &overflow); } } @@ -626,19 +621,19 @@ Menu::draw_item(DrawingContext& context, int index) MenuItem& pitem = *(items[index]); - Font* text_font = default_font; + Color text_color = default_color; float x_pos = pos_x; float y_pos = pos_y + 24*index - menu_height/2 + 12; int shadow_size = 2; - int text_width = int(text_font->get_text_width(pitem.text)); - int input_width = int(text_font->get_text_width(pitem.input) + 10); + int text_width = int(normal_font->get_text_width(pitem.text)); + int input_width = int(normal_font->get_text_width(pitem.input) + 10); int list_width = 0; float left = pos_x - menu_width/2 + 16; float right = pos_x + menu_width/2 - 16; if(pitem.list.size() > 0) { - list_width = (int) text_font->get_text_width(pitem.list[pitem.selected]); + list_width = (int) normal_font->get_text_width(pitem.list[pitem.selected]); } if (arrange_left) @@ -647,7 +642,7 @@ Menu::draw_item(DrawingContext& context, int index) if(index == active_item) { shadow_size = 3; - text_font = active_font; + text_color = active_color; } if(active_item == index) @@ -669,9 +664,9 @@ Menu::draw_item(DrawingContext& context, int index) { case MN_INACTIVE: { - context.draw_text(inactive_font, pitem.text, - Vector(pos_x, y_pos - int(inactive_font->get_height()/2)), - ALIGN_CENTER, LAYER_GUI); + context.draw_text(normal_font, pitem.text, + Vector(pos_x, y_pos - int(normal_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI, inactive_color); break; } @@ -691,9 +686,9 @@ Menu::draw_item(DrawingContext& context, int index) } case MN_LABEL: { - context.draw_text(label_font, pitem.text, - Vector(pos_x, y_pos - int(label_font->get_height()/2)), - ALIGN_CENTER, LAYER_GUI); + context.draw_text(big_font, pitem.text, + Vector(pos_x, y_pos - int(big_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI, label_color); break; } case MN_TEXTFIELD: @@ -703,33 +698,33 @@ Menu::draw_item(DrawingContext& context, int index) if(pitem.kind == MN_TEXTFIELD || pitem.kind == MN_NUMFIELD) { if(active_item == index) - context.draw_text(field_font, + context.draw_text(normal_font, pitem.get_input_with_symbol(true), - Vector(right, y_pos - int(field_font->get_height()/2)), - ALIGN_RIGHT, LAYER_GUI); + Vector(right, y_pos - int(normal_font->get_height()/2)), + ALIGN_RIGHT, LAYER_GUI, field_color); else - context.draw_text(field_font, + context.draw_text(normal_font, pitem.get_input_with_symbol(false), - Vector(right, y_pos - int(field_font->get_height()/2)), - ALIGN_RIGHT, LAYER_GUI); + Vector(right, y_pos - int(normal_font->get_height()/2)), + ALIGN_RIGHT, LAYER_GUI, field_color); } else - context.draw_text(field_font, pitem.input, - Vector(right, y_pos - int(field_font->get_height()/2)), - ALIGN_RIGHT, LAYER_GUI); + context.draw_text(normal_font, pitem.input, + Vector(right, y_pos - int(normal_font->get_height()/2)), + ALIGN_RIGHT, LAYER_GUI, field_color); - context.draw_text(text_font, pitem.text, - Vector(left, y_pos - int(text_font->get_height()/2)), - ALIGN_LEFT, LAYER_GUI); + context.draw_text(normal_font, pitem.text, + Vector(left, y_pos - int(normal_font->get_height()/2)), + ALIGN_LEFT, LAYER_GUI, text_color); break; } case MN_STRINGSELECT: { float roff = arrow_left->get_width(); // Draw left side - context.draw_text(text_font, pitem.text, - Vector(left, y_pos - int(text_font->get_height()/2)), - ALIGN_LEFT, LAYER_GUI); + context.draw_text(normal_font, pitem.text, + Vector(left, y_pos - int(normal_font->get_height()/2)), + ALIGN_LEFT, LAYER_GUI, text_color); // Draw right side context.draw_surface(arrow_left.get(), @@ -738,16 +733,16 @@ Menu::draw_item(DrawingContext& context, int index) context.draw_surface(arrow_right.get(), Vector(right - roff, y_pos - 8), LAYER_GUI); - context.draw_text(field_font, pitem.list[pitem.selected], - Vector(right - roff, y_pos - int(text_font->get_height()/2)), - ALIGN_RIGHT, LAYER_GUI); + context.draw_text(normal_font, pitem.list[pitem.selected], + Vector(right - roff, y_pos - int(normal_font->get_height()/2)), + ALIGN_RIGHT, LAYER_GUI, text_color); break; } case MN_BACK: { - context.draw_text(text_font, pitem.text, - Vector(pos_x, y_pos - int(text_font->get_height()/2)), - ALIGN_CENTER, LAYER_GUI); + context.draw_text(normal_font, pitem.text, + Vector(pos_x, y_pos - int(normal_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI, text_color); context.draw_surface(back.get(), Vector(x_pos + text_width/2 + 16, y_pos - 8), LAYER_GUI); @@ -756,9 +751,9 @@ Menu::draw_item(DrawingContext& context, int index) case MN_TOGGLE: { - context.draw_text(text_font, pitem.text, - Vector(pos_x - menu_width/2 + 16, y_pos - (text_font->get_height()/2)), - ALIGN_LEFT, LAYER_GUI); + context.draw_text(normal_font, pitem.text, + Vector(pos_x - menu_width/2 + 16, y_pos - (normal_font->get_height()/2)), + ALIGN_LEFT, LAYER_GUI, text_color); if(pitem.toggled) context.draw_surface(checkbox_checked.get(), @@ -771,15 +766,15 @@ Menu::draw_item(DrawingContext& context, int index) break; } case MN_ACTION: - context.draw_text(text_font, pitem.text, - Vector(pos_x, y_pos - int(text_font->get_height()/2)), - ALIGN_CENTER, LAYER_GUI); + context.draw_text(normal_font, pitem.text, + Vector(pos_x, y_pos - int(normal_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI, text_color); break; case MN_GOTO: - context.draw_text(text_font, pitem.text, - Vector(pos_x, y_pos - int(text_font->get_height()/2)), - ALIGN_CENTER, LAYER_GUI); + context.draw_text(normal_font, pitem.text, + Vector(pos_x, y_pos - int(normal_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI, text_color); break; } } @@ -792,12 +787,12 @@ Menu::get_width() const float menu_width = 0; for(unsigned int i = 0; i < items.size(); ++i) { - Font* font = default_font; + Font* font = normal_font; if(items[i]->kind == MN_LABEL) - font = label_font; + font = big_font; float w = font->get_text_width(items[i]->text) + - label_font->get_text_width(items[i]->input) + 16; + big_font->get_text_width(items[i]->input) + 16; if(items[i]->kind == MN_TOGGLE) w += 32; @@ -860,8 +855,8 @@ Menu::draw(DrawingContext& context) if (!items[active_item]->help.empty()) { - int text_width = (int) default_font->get_text_width(items[active_item]->help); - int text_height = (int) default_font->get_text_height(items[active_item]->help); + int text_width = (int) normal_font->get_text_width(items[active_item]->help); + int text_height = (int) normal_font->get_text_height(items[active_item]->help); Rect text_rect(pos_x - text_width/2 - 8, SCREEN_HEIGHT - 48 - text_height/2 - 4, @@ -879,7 +874,7 @@ Menu::draw(DrawingContext& context) 16.0f, LAYER_GUI-10); - context.draw_text(default_font, items[active_item]->help, + context.draw_text(normal_font, items[active_item]->help, Vector(pos_x, SCREEN_HEIGHT - 48 - text_height/2), ALIGN_CENTER, LAYER_GUI); } diff --git a/src/gui/menu.hpp b/src/gui/menu.hpp index 6aaeb3ff8..2875b1374 100644 --- a/src/gui/menu.hpp +++ b/src/gui/menu.hpp @@ -91,6 +91,11 @@ private: class Menu { + static Color default_color; + static Color active_color; + static Color inactive_color; + static Color label_color; + static Color field_color; private: static std::vector last_menus; @@ -149,12 +154,6 @@ private: bool close; public: - static Font* default_font; - static Font* active_font; - static Font* inactive_font; - static Font* label_font; - static Font* field_font; - std::vector items; Menu(); diff --git a/src/levelintro.cpp b/src/levelintro.cpp index b6ee5f122..5ad48a1b0 100644 --- a/src/levelintro.cpp +++ b/src/levelintro.cpp @@ -26,7 +26,6 @@ #include "mainloop.hpp" #include "gettext.hpp" #include "resources.hpp" -#include "video/font.hpp" #include "video/drawing_context.hpp" #include "gui/menu.hpp" #include "main.hpp" @@ -35,7 +34,6 @@ #include "sprite/sprite_manager.hpp" #include "random_generator.hpp" - LevelIntro::LevelIntro(const Level* level, const Statistics* best_level_statistics) : level(level), best_level_statistics(best_level_statistics), player_sprite_py(0), player_sprite_vy(0) { @@ -83,20 +81,20 @@ void LevelIntro::draw(DrawingContext& context) { const Statistics& stats = level->stats; - int py = static_cast(SCREEN_HEIGHT / 2 - gold_text->get_height() / 2); + int py = static_cast(SCREEN_HEIGHT / 2 - normal_font->get_height() / 2); context.draw_filled_rect(Vector(0, 0), Vector(SCREEN_WIDTH, SCREEN_HEIGHT), Color(0.0f, 0.0f, 0.0f, 1.0f), 0); { - context.draw_center_text(gold_text, level->get_name(), Vector(0, py), LAYER_FOREGROUND1); - py += static_cast(gold_text->get_height()); + context.draw_center_text(normal_font, level->get_name(), Vector(0, py), LAYER_FOREGROUND1, LevelIntro::header_color); + py += static_cast(normal_font->get_height()); } std::string author = level->get_author(); if ((author != "") && (author != "SuperTux Team")) { std::string author_text = std::string(_("contributed by ")) + author; - context.draw_center_text(white_small_text, author_text, Vector(0, py), LAYER_FOREGROUND1); - py += static_cast(white_small_text->get_height()); + context.draw_center_text(small_font, author_text, Vector(0, py), LAYER_FOREGROUND1, LevelIntro::author_color); + py += static_cast(small_font->get_height()); } py += 32; @@ -109,29 +107,29 @@ LevelIntro::draw(DrawingContext& context) py += 32; { - context.draw_center_text(blue_text, std::string("- ") + _("Best Level Statistics") + std::string(" -"), Vector(0, py), LAYER_FOREGROUND1); - py += static_cast(blue_text->get_height()); + context.draw_center_text(normal_font, std::string("- ") + _("Best Level Statistics") + std::string(" -"), Vector(0, py), LAYER_FOREGROUND1, LevelIntro::header_color); + py += static_cast(normal_font->get_height()); } { std::stringstream ss; ss << _("Coins") << ": " << Statistics::coins_to_string((best_level_statistics && (best_level_statistics->coins >= 0)) ? best_level_statistics->coins : 0, stats.total_coins); - context.draw_center_text(white_text, ss.str(), Vector(0, py), LAYER_FOREGROUND1); - py += static_cast(white_text->get_height()); + context.draw_center_text(normal_font, ss.str(), Vector(0, py), LAYER_FOREGROUND1, LevelIntro::stat_color); + py += static_cast(normal_font->get_height()); } { std::stringstream ss; ss << _("Secrets") << ": " << Statistics::secrets_to_string((best_level_statistics && (best_level_statistics->coins >= 0)) ? best_level_statistics->secrets : 0, stats.total_secrets); - context.draw_center_text(white_text, ss.str(), Vector(0, py), LAYER_FOREGROUND1); - py += static_cast(white_text->get_height()); + context.draw_center_text(normal_font, ss.str(), Vector(0, py), LAYER_FOREGROUND1,LevelIntro::stat_color); + py += static_cast(normal_font->get_height()); } { std::stringstream ss; ss << _("Time") << ": " << Statistics::time_to_string((best_level_statistics && (best_level_statistics->coins >= 0)) ? best_level_statistics->time : 0); - context.draw_center_text(white_text, ss.str(), Vector(0, py), LAYER_FOREGROUND1); - py += static_cast(white_text->get_height()); + context.draw_center_text(normal_font, ss.str(), Vector(0, py), LAYER_FOREGROUND1,LevelIntro::stat_color); + py += static_cast(normal_font->get_height()); } } diff --git a/src/levelintro.hpp b/src/levelintro.hpp index fc6028783..6765eed0d 100644 --- a/src/levelintro.hpp +++ b/src/levelintro.hpp @@ -35,13 +35,15 @@ class DrawingContext; class Surface; -class Font; /** * Screen that welcomes the player to a level */ class LevelIntro : public Screen { + static Color header_color; + static Color author_color; + static Color stat_color; public: LevelIntro(const Level* level, const Statistics* best_level_statistics); virtual ~LevelIntro(); diff --git a/src/mainloop.cpp b/src/mainloop.cpp index 1a7a1324a..08525fa4f 100644 --- a/src/mainloop.cpp +++ b/src/mainloop.cpp @@ -124,8 +124,8 @@ MainLoop::draw_fps(DrawingContext& context, float fps_fps) char str[60]; snprintf(str, sizeof(str), "%3.1f", fps_fps); const char* fpstext = "FPS"; - context.draw_text(white_text, fpstext, Vector(SCREEN_WIDTH - white_text->get_text_width(fpstext) - gold_text->get_text_width(" 99999") - BORDER_X, BORDER_Y + 20), ALIGN_LEFT, LAYER_HUD); - context.draw_text(gold_text, str, Vector(SCREEN_WIDTH - BORDER_X, BORDER_Y + 20), ALIGN_RIGHT, LAYER_HUD); + context.draw_text(small_font, fpstext, Vector(SCREEN_WIDTH - small_font->get_text_width(fpstext) - small_font->get_text_width(" 99999") - BORDER_X, BORDER_Y + 20), ALIGN_LEFT, LAYER_HUD); + context.draw_text(small_font, str, Vector(SCREEN_WIDTH - BORDER_X, BORDER_Y + 20), ALIGN_RIGHT, LAYER_HUD); } void diff --git a/src/object/gameobjs.cpp b/src/object/gameobjs.cpp index a0276edbc..59b09ce01 100644 --- a/src/object/gameobjs.cpp +++ b/src/object/gameobjs.cpp @@ -170,7 +170,7 @@ FloatingText::draw(DrawingContext& context) context.push_transform(); context.set_alpha(alpha); - context.draw_text(gold_text, text, position, ALIGN_LEFT, LAYER_OBJECTS+1); + context.draw_text(normal_font, text, position, ALIGN_LEFT, LAYER_OBJECTS+1, FloatingText::text_color); context.pop_transform(); } diff --git a/src/object/gameobjs.hpp b/src/object/gameobjs.hpp index b3d50d7b4..c7334662b 100644 --- a/src/object/gameobjs.hpp +++ b/src/object/gameobjs.hpp @@ -66,6 +66,7 @@ private: class FloatingText : public GameObject { + static Color text_color; public: FloatingText(const Vector& pos, const std::string& text_); FloatingText(const Vector& pos, int s); // use this for score, for instance diff --git a/src/object/level_time.cpp b/src/object/level_time.cpp index 92a5a9082..3244a46fd 100644 --- a/src/object/level_time.cpp +++ b/src/object/level_time.cpp @@ -96,9 +96,9 @@ LevelTime::draw(DrawingContext& context) Surface* time_surf = time_surface.get(); if (time_surf) { - float all_width = time_surf->get_width() + white_text->get_text_width(time_text); + float all_width = time_surf->get_width() + normal_font->get_text_width(time_text); context.draw_surface(time_surf, Vector((SCREEN_WIDTH - all_width)/2, BORDER_Y + 1), LAYER_FOREGROUND1); - context.draw_text(gold_text, time_text, Vector((SCREEN_WIDTH - all_width)/2 + time_surf->get_width(), BORDER_Y), ALIGN_LEFT, LAYER_FOREGROUND1); + context.draw_text(normal_font, time_text, Vector((SCREEN_WIDTH - all_width)/2 + time_surf->get_width(), BORDER_Y), ALIGN_LEFT, LAYER_FOREGROUND1, LevelTime::text_color); } } diff --git a/src/object/level_time.hpp b/src/object/level_time.hpp index 2ef9c8c69..348bd9ce4 100644 --- a/src/object/level_time.hpp +++ b/src/object/level_time.hpp @@ -26,9 +26,11 @@ #include "lisp/lisp.hpp" #include "video/surface.hpp" #include "script_interface.hpp" +#include "video/color.hpp" class LevelTime : public GameObject, public ScriptInterface { + static Color text_color; public: LevelTime(const lisp::Lisp& reader); diff --git a/src/object/text_object.cpp b/src/object/text_object.cpp index 42716282b..ebe3e32d7 100644 --- a/src/object/text_object.cpp +++ b/src/object/text_object.cpp @@ -33,7 +33,7 @@ TextObject::TextObject(std::string name) pos(0, 0) { this->name = name; - font = blue_text; + font = normal_font; centered = false; } @@ -62,18 +62,12 @@ TextObject::unexpose(HSQUIRRELVM vm, SQInteger table_idx) void TextObject::set_font(const std::string& name) { - if(name == "gold") { - font = gold_text; - } else if(name == "white") { - font = white_text; - } else if(name == "blue") { - font = blue_text; - } else if(name == "gray") { - font = gray_text; + if(name == "normal") { + font = normal_font; } else if(name == "big") { - font = white_big_text; + font = big_font; } else if(name == "small") { - font = white_small_text; + font = small_font; } else { log_warning << "Unknown font '" << name << "'." << std::endl; } @@ -134,9 +128,9 @@ TextObject::draw(DrawingContext& context) context.draw_filled_rect(spos, Vector(width, height), Color(0.6f, 0.7f, 0.8f, 0.5f), LAYER_GUI-50); if (centered) { - context.draw_center_text(font, text, spos, LAYER_GUI-40); + context.draw_center_text(font, text, spos, LAYER_GUI-40, TextObject::default_color); } else { - context.draw_text(font, text, spos + Vector(10, 10), ALIGN_LEFT, LAYER_GUI-40); + context.draw_text(font, text, spos + Vector(10, 10), ALIGN_LEFT, LAYER_GUI-40, TextObject::default_color); } context.pop_transform(); diff --git a/src/object/text_object.hpp b/src/object/text_object.hpp index b5e0862ec..c0e35b3f0 100644 --- a/src/object/text_object.hpp +++ b/src/object/text_object.hpp @@ -24,6 +24,7 @@ #include "scripting/text.hpp" #include "script_interface.hpp" #include "anchor_point.hpp" +#include "video/color.hpp" class Font; @@ -31,6 +32,7 @@ class Font; class TextObject : public GameObject, public Scripting::Text, public ScriptInterface { + static Color default_color; public: TextObject(std::string name = ""); virtual ~TextObject(); diff --git a/src/player_status.cpp b/src/player_status.cpp index 4bed7dfcb..84925da0c 100644 --- a/src/player_status.cpp +++ b/src/player_status.cpp @@ -159,9 +159,9 @@ PlayerStatus::draw(DrawingContext& context) Surface* coin_surf = coin_surface.get(); if (coin_surf) { - context.draw_surface(coin_surf, Vector(SCREEN_WIDTH - BORDER_X - coin_surf->get_width() - gold_fixed_text->get_text_width(coins_text), BORDER_Y + 1), LAYER_HUD); + context.draw_surface(coin_surf, Vector(SCREEN_WIDTH - BORDER_X - coin_surf->get_width() - fixed_font->get_text_width(coins_text), BORDER_Y + 1), LAYER_HUD); } - context.draw_text(gold_fixed_text, coins_text, Vector(SCREEN_WIDTH - BORDER_X, BORDER_Y), ALIGN_RIGHT, LAYER_HUD); + context.draw_text(fixed_font, coins_text, Vector(SCREEN_WIDTH - BORDER_X, BORDER_Y), ALIGN_RIGHT, LAYER_HUD, PlayerStatus::text_color); context.pop_transform(); } diff --git a/src/player_status.hpp b/src/player_status.hpp index 85ac0590b..520bd7423 100644 --- a/src/player_status.hpp +++ b/src/player_status.hpp @@ -22,6 +22,7 @@ #include #include "serializable.hpp" +#include "video/color.hpp" namespace lisp{ class Writer; } namespace lisp{ class Lisp; } @@ -41,6 +42,7 @@ class DrawingContext; */ class PlayerStatus : public Serializable { + static Color text_color; public: PlayerStatus(); ~PlayerStatus(); diff --git a/src/resources.cpp b/src/resources.cpp index ba34085fb..4e6f6e1f1 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -20,23 +20,20 @@ #include #include "sprite/sprite_manager.hpp" -#include "gui/menu.hpp" -#include "gui/button.hpp" #include "resources.hpp" #include "file_system.hpp" #include "tile_manager.hpp" #include "object/gameobjs.hpp" #include "object/player.hpp" +#include "gui/mousecursor.hpp" +#include "player_status.hpp" MouseCursor* mouse_cursor = NULL; -Font* gold_text = NULL; -Font* gold_fixed_text = NULL; -Font* blue_text = NULL; -Font* gray_text = NULL; -Font* white_text = NULL; -Font* white_small_text = NULL; -Font* white_big_text = NULL; +Font* fixed_font = NULL; +Font* normal_font = NULL; +Font* small_font = NULL; +Font* big_font = NULL; /* Load graphics/sounds shared between all levels: */ void load_shared() @@ -46,35 +43,10 @@ void load_shared() MouseCursor::set_current(mouse_cursor); /* Load global images: */ - gold_text = new Font(Font::VARIABLE, - "images/engine/fonts/gold.png", - "images/engine/fonts/shadow.png", 16, 18); - gold_fixed_text = new Font(Font::FIXED, - "images/engine/fonts/gold.png", - "images/engine/fonts/shadow.png", 16, 18); - blue_text = new Font(Font::VARIABLE, - "images/engine/fonts/blue.png", - "images/engine/fonts/shadow.png", 16, 18, 3); - white_text = new Font(Font::VARIABLE, - "images/engine/fonts/white.png", - "images/engine/fonts/shadow.png", 16, 18); - gray_text = new Font(Font::VARIABLE, - "images/engine/fonts/gray.png", - "images/engine/fonts/shadow.png", 16, 18); - white_small_text = new Font(Font::VARIABLE, - "images/engine/fonts/white-small.png", - "images/engine/fonts/shadow-small.png", 8, 9, 1); - white_big_text = new Font(Font::VARIABLE, - "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; - Menu::inactive_font = gray_text; - Menu::label_font = white_big_text; - Menu::field_font = gold_text; - - Button::info_font = white_small_text; + fixed_font = new Font(Font::FIXED, "fonts/white.stf"); + normal_font = new Font(Font::VARIABLE, "fonts/white.stf"); + small_font = new Font(Font::VARIABLE, "fonts/white-small.stf", 1); + big_font = new Font(Font::VARIABLE, "fonts/white-big.stf", 3); tile_manager = new TileManager(); sprite_manager = new SpriteManager(); @@ -86,13 +58,9 @@ void load_shared() void unload_shared() { /* Free global images: */ - delete gold_text; - delete gold_fixed_text; - delete white_text; - delete blue_text; - delete gray_text; - delete white_small_text; - delete white_big_text; + delete normal_font; + delete small_font; + delete big_font; delete sprite_manager; sprite_manager = NULL; diff --git a/src/resources.hpp b/src/resources.hpp index 27d1e9894..c9e5bad80 100644 --- a/src/resources.hpp +++ b/src/resources.hpp @@ -25,13 +25,10 @@ class MouseCursor; extern MouseCursor* mouse_cursor; -extern Font* gold_text; -extern Font* gold_fixed_text; -extern Font* white_text; -extern Font* blue_text; -extern Font* gray_text; -extern Font* white_small_text; -extern Font* white_big_text; +extern Font* fixed_font; +extern Font* normal_font; +extern Font* small_font; +extern Font* big_font; void load_shared(); void unload_shared(); diff --git a/src/statistics.cpp b/src/statistics.cpp index 9f9191ec5..eddd71db0 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -129,7 +129,7 @@ Statistics::draw_worldmap_info(DrawingContext& context) // skip draw if stats were declared invalid if (!valid) return; - context.draw_text(white_small_text, std::string("- ") + _("Best Level Statistics") + " -", Vector((WMAP_INFO_LEFT_X + WMAP_INFO_RIGHT_X) / 2, WMAP_INFO_TOP_Y1), ALIGN_CENTER, LAYER_GUI); + context.draw_text(small_font, std::string("- ") + _("Best Level Statistics") + " -", Vector((WMAP_INFO_LEFT_X + WMAP_INFO_RIGHT_X) / 2, WMAP_INFO_TOP_Y1), ALIGN_CENTER, LAYER_GUI,Statistics::header_color); std::string caption_buf; std::string stat_buf; @@ -158,9 +158,9 @@ Statistics::draw_worldmap_info(DrawingContext& context) break; } - context.draw_text(white_small_text, caption_buf, Vector(WMAP_INFO_LEFT_X, posy), ALIGN_LEFT, LAYER_GUI); - context.draw_text(white_small_text, stat_buf, Vector(WMAP_INFO_RIGHT_X, posy), ALIGN_RIGHT, LAYER_GUI); - posy += white_small_text->get_height() + 2; + context.draw_text(small_font, caption_buf, Vector(WMAP_INFO_LEFT_X, posy), ALIGN_LEFT, LAYER_GUI, Statistics::header_color); + context.draw_text(small_font, stat_buf, Vector(WMAP_INFO_RIGHT_X, posy), ALIGN_RIGHT, LAYER_GUI, Statistics::text_color); + posy += small_font->get_height() + 2; } } @@ -202,25 +202,25 @@ Statistics::draw_endseq_panel(DrawingContext& context, Statistics* best_stats, S context.draw_surface(backdrop, Vector(bd_x, bd_y), LAYER_GUI); context.pop_transform(); - context.draw_text(white_text, _("You"), Vector(col2_x, row1_y), ALIGN_LEFT, LAYER_GUI); - context.draw_text(white_text, _("Best"), Vector(col3_x, row1_y), ALIGN_LEFT, LAYER_GUI); + context.draw_text(normal_font, _("You"), Vector(col2_x, row1_y), ALIGN_LEFT, LAYER_GUI, Statistics::header_color); + context.draw_text(normal_font, _("Best"), Vector(col3_x, row1_y), ALIGN_LEFT, LAYER_GUI, Statistics::header_color); - context.draw_text(white_text, _("Coins"), Vector(col2_x-16, row3_y), ALIGN_RIGHT, LAYER_GUI); + context.draw_text(normal_font, _("Coins"), Vector(col2_x-16, row3_y), ALIGN_RIGHT, LAYER_GUI, Statistics::header_color); int coins_best = (best_stats && (best_stats->coins > coins)) ? best_stats->coins : coins; int total_coins_best = (best_stats && (best_stats->total_coins > total_coins)) ? best_stats->total_coins : total_coins; - context.draw_text(gold_text, coins_to_string(coins, total_coins), Vector(col2_x, row3_y), ALIGN_LEFT, LAYER_GUI); - context.draw_text(gold_text, coins_to_string(coins_best, total_coins_best), Vector(col3_x, row3_y), ALIGN_LEFT, LAYER_GUI); + context.draw_text(normal_font, coins_to_string(coins, total_coins), Vector(col2_x, row3_y), ALIGN_LEFT, LAYER_GUI, Statistics::text_color); + context.draw_text(normal_font, coins_to_string(coins_best, total_coins_best), Vector(col3_x, row3_y), ALIGN_LEFT, LAYER_GUI, Statistics::text_color); - context.draw_text(white_text, _("Secrets"), Vector(col2_x-16, row4_y), ALIGN_RIGHT, LAYER_GUI); + context.draw_text(normal_font, _("Secrets"), Vector(col2_x-16, row4_y), ALIGN_RIGHT, LAYER_GUI, Statistics::header_color); int secrets_best = (best_stats && (best_stats->secrets > secrets)) ? best_stats->secrets : secrets; int total_secrets_best = (best_stats && (best_stats->total_secrets > total_secrets)) ? best_stats->total_secrets : total_secrets; - context.draw_text(gold_text, secrets_to_string(secrets, total_secrets), Vector(col2_x, row4_y), ALIGN_LEFT, LAYER_GUI); - context.draw_text(gold_text, secrets_to_string(secrets_best, total_secrets_best), Vector(col3_x, row4_y), ALIGN_LEFT, LAYER_GUI); + context.draw_text(normal_font, secrets_to_string(secrets, total_secrets), Vector(col2_x, row4_y), ALIGN_LEFT, LAYER_GUI, Statistics::text_color); + context.draw_text(normal_font, secrets_to_string(secrets_best, total_secrets_best), Vector(col3_x, row4_y), ALIGN_LEFT, LAYER_GUI, Statistics::text_color); - context.draw_text(white_text, _("Time"), Vector(col2_x-16, row2_y), ALIGN_RIGHT, LAYER_GUI); + context.draw_text(normal_font, _("Time"), Vector(col2_x-16, row2_y), ALIGN_RIGHT, LAYER_GUI, Statistics::header_color); float time_best = (best_stats && (best_stats->time < time)) ? best_stats->time : time; - context.draw_text(gold_text, time_to_string(time), Vector(col2_x, row2_y), ALIGN_LEFT, LAYER_GUI); - context.draw_text(gold_text, time_to_string(time_best), Vector(col3_x, row2_y), ALIGN_LEFT, LAYER_GUI); + context.draw_text(normal_font, time_to_string(time), Vector(col2_x, row2_y), ALIGN_LEFT, LAYER_GUI, Statistics::text_color); + context.draw_text(normal_font, time_to_string(time_best), Vector(col3_x, row2_y), ALIGN_LEFT, LAYER_GUI, Statistics::text_color); } void diff --git a/src/statistics.hpp b/src/statistics.hpp index 1fe64604e..a6c6c3766 100644 --- a/src/statistics.hpp +++ b/src/statistics.hpp @@ -23,6 +23,7 @@ #define SUPERTUX_STATISTICS_H #include +#include "video/color.hpp" namespace lisp { class Writer; } namespace lisp { class Lisp; } @@ -34,6 +35,8 @@ class DrawingContext; * number of jumps and stuff */ class Statistics { + static Color header_color; + static Color text_color; public: int coins; /**< coins collected */ int total_coins; /**< coins in level */ diff --git a/src/textscroller.cpp b/src/textscroller.cpp index 74dc0678e..d4c4ad728 100644 --- a/src/textscroller.cpp +++ b/src/textscroller.cpp @@ -230,19 +230,19 @@ Font* get_font_by_format_char(char format_char) { switch(format_char) { case ' ': - return white_small_text; + return small_font; break; case '\t': - return white_text; + return normal_font; break; case '-': - return white_big_text; + return big_font; break; case '*': - return blue_text; + return normal_font; // blue_text break; case '#': - return white_text; + return normal_font; break; case '!': return 0; @@ -283,7 +283,7 @@ InfoBoxLine::LineType get_linetype_by_format_char(char format_char) { } } -InfoBoxLine::InfoBoxLine(char format_char, const std::string& text) : lineType(NORMAL), font(white_text), text(text), image(0) +InfoBoxLine::InfoBoxLine(char format_char, const std::string& text) : lineType(NORMAL), font(normal_font), text(text), image(0) { font = get_font_by_format_char(format_char); lineType = get_linetype_by_format_char(format_char); @@ -337,7 +337,6 @@ InfoBoxLine::split(const std::string& text, float width) lines.push_back(new InfoBoxLine(format_char, s2)); s = overflow; } while (s.length() > 0); - } return lines; @@ -352,10 +351,10 @@ InfoBoxLine::draw(DrawingContext& context, const Rect& bbox, int layer) context.draw_surface(image, Vector( (bbox.p1.x + bbox.p2.x - image->get_width()) / 2, position.y), layer); break; case NORMAL_LEFT: - context.draw_text(font, text, Vector(position.x, position.y), ALIGN_LEFT, layer); + context.draw_text(font, text, Vector(position.x, position.y), ALIGN_LEFT, layer, Color(1,1,1)); break; default: - context.draw_text(font, text, Vector((bbox.p1.x + bbox.p2.x) / 2, position.y), ALIGN_CENTER, layer); + context.draw_text(font, text, Vector((bbox.p1.x + bbox.p2.x) / 2, position.y), ALIGN_CENTER, layer,Color(1,1,1)); break; } } diff --git a/src/tile_set.cpp b/src/tile_set.cpp index 679851c8c..19f76fbff 100644 --- a/src/tile_set.cpp +++ b/src/tile_set.cpp @@ -18,6 +18,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. #include +#include #include "tile_set.hpp" #include "log.hpp" diff --git a/src/title.cpp b/src/title.cpp index dfd577c96..a187aeaad 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -395,15 +395,15 @@ TitleScreen::draw(DrawingContext& context) // FIXME: Add something to scale the frame to the resolution of the screen context.draw_surface(frame.get(), Vector(0,0),LAYER_FOREGROUND1); - context.draw_text(white_small_text, "SuperTux " PACKAGE_VERSION "\n", + context.draw_text(small_font, "SuperTux " PACKAGE_VERSION "\n", Vector(5, SCREEN_HEIGHT - 50), ALIGN_LEFT, LAYER_FOREGROUND1); - context.draw_text(white_small_text, + context.draw_text(small_font, _( "Copyright (c) 2007 SuperTux Devel Team\n" "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to\n" "redistribute it under certain conditions; see the file COPYING for details.\n" ), - Vector(5, SCREEN_HEIGHT - 50 + white_small_text->get_height() + 5), + Vector(5, SCREEN_HEIGHT - 50 + small_font->get_height() + 5), ALIGN_LEFT, LAYER_FOREGROUND1); } diff --git a/src/trigger/climbable.cpp b/src/trigger/climbable.cpp index 38dbccf8a..3a498d7d3 100644 --- a/src/trigger/climbable.cpp +++ b/src/trigger/climbable.cpp @@ -93,8 +93,8 @@ Climbable::draw(DrawingContext& context) if (climbed_by) { context.push_transform(); context.set_translation(Vector(0, 0)); - Vector pos = Vector(0, SCREEN_HEIGHT/2 - gold_text->get_height()/2); - context.draw_center_text(gold_text, _("Up we go..."), pos, LAYER_GUI); + Vector pos = Vector(0, SCREEN_HEIGHT/2 - normal_font->get_height()/2); + context.draw_center_text(normal_font, _("Up we go..."), pos, LAYER_GUI, Climbable::text_color); context.pop_transform(); } } diff --git a/src/trigger/climbable.hpp b/src/trigger/climbable.hpp index 170483d8c..359985fd3 100644 --- a/src/trigger/climbable.hpp +++ b/src/trigger/climbable.hpp @@ -29,6 +29,7 @@ class Climbable : public TriggerBase, public Serializable { + static Color text_color; public: Climbable(const lisp::Lisp& reader); Climbable(const Rect& area); diff --git a/src/trigger/secretarea_trigger.cpp b/src/trigger/secretarea_trigger.cpp index 3debac045..51fb36401 100644 --- a/src/trigger/secretarea_trigger.cpp +++ b/src/trigger/secretarea_trigger.cpp @@ -77,8 +77,8 @@ SecretAreaTrigger::draw(DrawingContext& context) if (message_timer.started()) { context.push_transform(); context.set_translation(Vector(0, 0)); - Vector pos = Vector(0, SCREEN_HEIGHT/2 - gold_text->get_height()/2); - context.draw_center_text(gold_text, _("You found a secret area!"), pos, LAYER_GUI); + Vector pos = Vector(0, SCREEN_HEIGHT/2 - normal_font->get_height()/2); + context.draw_center_text(normal_font, _("You found a secret area!"), pos, LAYER_GUI, SecretAreaTrigger::text_color); context.pop_transform(); } if (message_timer.check()) { diff --git a/src/trigger/secretarea_trigger.hpp b/src/trigger/secretarea_trigger.hpp index 2f1130fe2..85000166d 100644 --- a/src/trigger/secretarea_trigger.hpp +++ b/src/trigger/secretarea_trigger.hpp @@ -28,6 +28,7 @@ class SecretAreaTrigger : public TriggerBase, public Serializable { + static Color text_color; public: SecretAreaTrigger(const lisp::Lisp& reader); SecretAreaTrigger(const Rect& area, std::string fade_tilemap = ""); diff --git a/src/video/drawing_context.cpp b/src/video/drawing_context.cpp index f1fecb77e..88e288b00 100644 --- a/src/video/drawing_context.cpp +++ b/src/video/drawing_context.cpp @@ -152,7 +152,7 @@ DrawingContext::draw_surface_part(const Surface* surface, const Vector& source, void DrawingContext::draw_text(const Font* font, const std::string& text, - const Vector& position, FontAlignment alignment, int layer) + const Vector& position, FontAlignment alignment, int layer, Color color) { DrawingRequest* request = new(obst) DrawingRequest(); @@ -162,6 +162,7 @@ DrawingContext::draw_text(const Font* font, const std::string& text, request->layer = layer; request->drawing_effect = transform.drawing_effect; request->alpha = transform.alpha; + request->color = color; TextRequest* textrequest = new(obst) TextRequest(); textrequest->font = font; @@ -174,10 +175,10 @@ DrawingContext::draw_text(const Font* font, const std::string& text, void DrawingContext::draw_center_text(const Font* font, const std::string& text, - const Vector& position, int layer) + const Vector& position, int layer, Color color) { draw_text(font, text, Vector(position.x + SCREEN_WIDTH/2, position.y), - ALIGN_CENTER, layer); + ALIGN_CENTER, layer, color); } void @@ -385,7 +386,7 @@ DrawingContext::handle_drawing_requests(DrawingRequests& requests) { const TextRequest* textrequest = (TextRequest*) request.request_data; textrequest->font->draw(renderer, textrequest->text, request.pos, - textrequest->alignment, request.drawing_effect, request.alpha); + textrequest->alignment, request.drawing_effect, request.color, request.alpha); } break; case FILLRECT: @@ -417,7 +418,7 @@ DrawingContext::handle_drawing_requests(DrawingRequests& requests) { const TextRequest* textrequest = (TextRequest*) request.request_data; textrequest->font->draw(renderer, textrequest->text, request.pos, - textrequest->alignment, request.drawing_effect, request.alpha); + textrequest->alignment, request.drawing_effect, request.color, request.alpha); } break; case FILLRECT: diff --git a/src/video/drawing_context.hpp b/src/video/drawing_context.hpp index 46f6d27bb..0e24d3a3a 100644 --- a/src/video/drawing_context.hpp +++ b/src/video/drawing_context.hpp @@ -65,13 +65,13 @@ public: const Vector& size, const Vector& dest, int layer); /// Draws a text. void draw_text(const Font* font, const std::string& text, - const Vector& position, FontAlignment alignment, int layer); + const Vector& position, FontAlignment alignment, int layer, Color color = Color(1.0,1.0,1.0)); /// Draws text on screen center (feed Vector.x with a 0). /// This is the same as draw_text() with a SCREEN_WIDTH/2 position and /// alignment set to LEFT_ALIGN void draw_center_text(const Font* font, const std::string& text, - const Vector& position, int layer); + const Vector& position, int layer, Color color = Color(1.0,1.0,1.0)); /// Draws a color gradient onto the whole screen */ void draw_gradient(const Color& from, const Color& to, int layer); /// Fills a rectangle. diff --git a/src/video/font.cpp b/src/video/font.cpp index e0f56648b..7ddebbd06 100644 --- a/src/video/font.cpp +++ b/src/video/font.cpp @@ -26,9 +26,12 @@ #include #include "physfs/physfs_sdl.hpp" +#include +#include "file_system.hpp" -#include "lisp/parser.hpp" #include "lisp/lisp.hpp" +#include "lisp/parser.hpp" +#include "lisp/list_iterator.hpp" #include "screen.hpp" #include "font.hpp" #include "renderer.hpp" @@ -38,6 +41,7 @@ namespace { bool has_multibyte_mark(unsigned char c); uint32_t decode_utf8(const std::string& text, size_t& p); +std::string encode_utf8(uint32_t code); struct UTF8Iterator { @@ -97,87 +101,183 @@ bool vline_empty(SDL_Surface* surface, int x, int start_y, int end_y, Uint8 thre Font::Font(GlyphWidth glyph_width_, const std::string& filename, - const std::string& shadowfile, - int char_width, int char_height_, int shadowsize_) - : glyph_width(glyph_width_), - glyph_surface(0), shadow_glyph_surface(0), - char_height(char_height_), - shadowsize(shadowsize_) +: glyph_width(glyph_width_), + shadowsize(shadowsize_), + glyphs(65536) { - glyph_surface = new Surface(filename); - shadow_glyph_surface = new Surface(shadowfile); + for(unsigned int i=0; i<65536;i++) glyphs[i].surface_idx = -1; - first_char = 32; - char_count = ((int) glyph_surface->get_height() / char_height) * 16; + const std::string fontdir = FileSystem::dirname(filename); + const std::string fontname = FileSystem::basename(filename); - if (glyph_width == FIXED) - { - for(uint32_t i = 0; i < char_count; ++i) - { - float x = (i % 16) * char_width; - float y = (i / 16) * char_height; + // scan for prefix-filename in addons search path + char **rc = PHYSFS_enumerateFiles(fontdir.c_str()); + for (char **i = rc; *i != NULL; i++) { + std::string filename(*i); + if( filename.rfind(fontname) != std::string::npos ) { + loadFontFile(fontdir + filename); + } + } + PHYSFS_freeList(rc); +} - Glyph glyph; - glyph.advance = char_width; - glyph.offset = Vector(0, 0); - glyph.rect = Rect(x, y, x + char_width, y + char_height); +void +Font::loadFontFile(const std::string &filename) +{ + lisp::Parser parser; + log_debug << "Loading font: " << filename << std::endl; + const lisp::Lisp* root = parser.parse(filename); + const lisp::Lisp* config_l = root->get_lisp("supertux-font"); + + if(!config_l) { + std::ostringstream msg; + msg << "Font file:" << filename << ": is not a supertux-font file"; + throw std::runtime_error(msg.str()); + } - glyphs.push_back(glyph); - shadow_glyphs.push_back(glyph); - } + int def_char_width=0; + + if( !config_l->get("glyph-width",def_char_width) ) { + log_warning << "Font:"<< filename << ": misses default glyph-width" << std::endl; } - else // glyph_width == VARIABLE - { - // Load the surface into RAM and scan the pixel data for characters - SDL_Surface* surface = IMG_Load_RW(get_physfs_SDLRWops(filename), 1); - if(surface == NULL) { + + if( !config_l->get("glyph-height",char_height) ) { + std::ostringstream msg; + msg << "Font:" << filename << ": misses glyph-height"; + throw std::runtime_error(msg.str()); + } + + lisp::ListIterator iter(config_l); + while(iter.next()) { + const std::string& token = iter.item(); + if( token == "surface" ) { + const lisp::Lisp * glyphs_val = iter.lisp(); + int local_char_width; + bool monospaced; + GlyphWidth local_glyph_width; + std::string glyph_image; + std::string shadow_image; + std::vector chars; + if( ! glyphs_val->get("glyph-width", local_char_width) ) { + local_char_width = def_char_width; + } + if( ! glyphs_val->get("monospace", monospaced ) ) { + local_glyph_width = glyph_width; + } + else { + if( monospaced ) local_glyph_width = FIXED; + else local_glyph_width = VARIABLE; + } + if( ! glyphs_val->get("glyphs", glyph_image) ) { std::ostringstream msg; - msg << "Couldn't load image '" << filename << "' :" << SDL_GetError(); + msg << "Font:" << filename << ": missing glyphs image"; throw std::runtime_error(msg.str()); - } - - SDL_LockSurface(surface); - - for(uint32_t i = 0; i < char_count; ++i) - { - int x = (i % 16) * char_width; - int y = (i / 16) * char_height; + } + if( ! glyphs_val->get("shadows", shadow_image) ) { + std::ostringstream msg; + msg << "Font:" << filename << ": missing shadows image"; + throw std::runtime_error(msg.str()); + } + if( ! glyphs_val->get_vector("chars", chars) || chars.size() == 0) { + std::ostringstream msg; + msg << "Font:" << filename << ": missing chars definition"; + throw std::runtime_error(msg.str()); + } - int left = x; - while (left < x + char_width && - vline_empty(surface, left, y, y + char_height, 64)) - left += 1; + if( local_char_width==0 ) { + std::ostringstream msg; + msg << "Font:" << filename << ": misses glyph-width for some surface"; + throw std::runtime_error(msg.str()); + } - int right = x + char_width - 1; - while (right > left && - vline_empty(surface, right, y, y + char_height, 64)) - right -= 1; + loadFontSurface(glyph_image, shadow_image, chars, + local_glyph_width, local_char_width); + } + } +} - Glyph glyph; - glyph.offset = Vector(0, 0); +void +Font::loadFontSurface( + const std::string &glyphimage, + const std::string &shadowimage, + const std::vector &chars, + GlyphWidth glyph_width, + int char_width + ) +{ + Surface glyph_surface = Surface("images/engine/fonts/" + glyphimage); + Surface shadow_surface = Surface("images/engine/fonts/" + shadowimage); - if (left <= right) - glyph.rect = Rect(left, y, right+1, y + char_height); - else // glyph is completely transparent - glyph.rect = Rect(x, y, x + char_width, y + char_height); + int surface_idx = glyph_surfaces.size(); + glyph_surfaces.push_back(glyph_surface); + shadow_surfaces.push_back(shadow_surface); - glyph.advance = glyph.rect.get_width() + 1; // FIXME: might be useful to make spacing configurable + int row=0, col=0; + int wrap = glyph_surface.get_width() / char_width; + + SDL_Surface *surface = NULL; + + if( glyph_width == VARIABLE ) { + //this does not work: + // surface = ((SDL::Texture *)glyph_surface.get_texture())->get_texture(); + surface = IMG_Load_RW(get_physfs_SDLRWops("images/engine/fonts/"+glyphimage), 1); + if(surface == NULL) { + std::ostringstream msg; + msg << "Couldn't load image '" << glyphimage << "' :" << SDL_GetError(); + throw std::runtime_error(msg.str()); + } + SDL_LockSurface(surface); + } - glyphs.push_back(glyph); - shadow_glyphs.push_back(glyph); + for( unsigned int i = 0; i < chars.size(); i++) { + for(UTF8Iterator chr(chars[i]); !chr.done(); ++chr) { + float y = row * char_height; + float x = col * char_width; + if( ++col == wrap ) { col=0; row++; } + if( *chr == 0x0020 && glyphs[0x20].surface_idx != -1) continue; + + Glyph glyph; + glyph.surface_idx = surface_idx; + + if( glyph_width == FIXED ) { + glyph.rect = Rect(x, y, x + char_width, y + char_height); + glyph.offset = Vector(0, 0); + glyph.advance = char_width; + } + else { + int left = x; + while (left < x + char_width && vline_empty(surface, left, y, y + char_height, 64)) + left += 1; + int right = x + char_width - 1; + while (right > left && vline_empty(surface, right, y, y + char_height, 64)) + right -= 1; + + if (left <= right) + glyph.rect = Rect(left, y, right+1, y + char_height); + else // glyph is completely transparent + glyph.rect = Rect(x, y, x + char_width, y + char_height); + + glyph.offset = Vector(0, 0); + glyph.advance = glyph.rect.get_width() + 1; // FIXME: might be useful to make spacing configurable } - SDL_UnlockSurface(surface); - - SDL_FreeSurface(surface); + glyphs[*chr] = glyph; + } + if( col>0 && col <= wrap ) { + col = 0; + row++; + } + } + + if( surface != NULL ) { + SDL_UnlockSurface(surface); + SDL_FreeSurface(surface); } } Font::~Font() { - delete glyph_surface; - delete shadow_glyph_surface; } float @@ -195,8 +295,10 @@ Font::get_text_width(const std::string& text) const } else { - int idx = chr2glyph(*it); - curr_width += glyphs[idx].advance; + if( glyphs.at(*it).surface_idx != -1 ) + curr_width += glyphs[*it].advance; + else + curr_width += glyphs[0x20].advance; } } @@ -275,7 +377,7 @@ Font::wrap_to_width(const std::string& s_, float width, std::string* overflow) void Font::draw(Renderer *renderer, const std::string& text, const Vector& pos_, - FontAlignment alignment, DrawingEffect drawing_effect, + FontAlignment alignment, DrawingEffect drawing_effect, Color color, float alpha) const { float x = pos_.x; @@ -300,7 +402,7 @@ Font::draw(Renderer *renderer, const std::string& text, const Vector& pos_, // no blurring as we would get with subpixel positions pos.x = static_cast(pos.x); - draw_text(renderer, temp, pos, drawing_effect, alpha); + draw_text(renderer, temp, pos, drawing_effect, color, alpha); if (i == text.size()) break; @@ -313,53 +415,24 @@ Font::draw(Renderer *renderer, const std::string& text, const Vector& pos_, void Font::draw_text(Renderer *renderer, const std::string& text, const Vector& pos, - DrawingEffect drawing_effect, float alpha) const + DrawingEffect drawing_effect, Color color, float alpha) const { if(shadowsize > 0) - { - // FIXME: shadow_glyph_surface and glyph_surface do currently - // share the same glyph array, this is incorrect and should be - // fixed, it is however hardly noticeable - draw_chars(renderer, shadow_glyph_surface, text, - pos + Vector(shadowsize, shadowsize), drawing_effect, alpha); - } + draw_chars(renderer, false, text, + pos + Vector(shadowsize, shadowsize), drawing_effect, Color(1,1,1), alpha); - draw_chars(renderer, glyph_surface, text, pos, drawing_effect, alpha); -} - -int -Font::chr2glyph(uint32_t chr) const -{ - int glyph_index = chr - first_char; - - // we don't have the control chars 0x80-0xa0 in the font - if (chr >= 0x80) { // non-ascii character - glyph_index -= 32; - if(chr <= 0xa0) { - log_debug << "Unsupported utf-8 character '" << chr << "' found" << std::endl; - glyph_index = 0; - } - } - - if(glyph_index < 0 || glyph_index >= (int) char_count) { - log_debug << "Unsupported utf-8 character found" << std::endl; - glyph_index = 0; - } - - return glyph_index; + draw_chars(renderer, true, text, pos, drawing_effect, color, alpha); } void -Font::draw_chars(Renderer *renderer, Surface* pchars, const std::string& text, - const Vector& pos, DrawingEffect drawing_effect, +Font::draw_chars(Renderer *renderer, bool notshadow, const std::string& text, + const Vector& pos, DrawingEffect drawing_effect, Color color, float alpha) const { Vector p = pos; for(UTF8Iterator it(text); !it.done(); ++it) { - int font_index = chr2glyph(*it); - if(*it == '\n') { p.x = pos.x; @@ -367,26 +440,32 @@ Font::draw_chars(Renderer *renderer, Surface* pchars, const std::string& text, } else if(*it == ' ') { - p.x += glyphs[font_index].advance; + p.x += glyphs[0x20].advance; } else { - const Glyph& glyph = glyphs[font_index]; + Glyph glyph; + if( glyphs.at(*it).surface_idx != -1 ) + glyph = glyphs[*it]; + else + glyph = glyphs[0x20]; + DrawingRequest request; request.pos = p + glyph.offset; request.drawing_effect = drawing_effect; + request.color = color; request.alpha = alpha; SurfacePartRequest surfacepartrequest; surfacepartrequest.size = glyph.rect.p2 - glyph.rect.p1; surfacepartrequest.source = glyph.rect.p1; - surfacepartrequest.surface = pchars; + surfacepartrequest.surface = notshadow ? &(glyph_surfaces[glyph.surface_idx]) : &(shadow_surfaces[glyph.surface_idx]); request.request_data = &surfacepartrequest; renderer->draw_surface_part(request); - p.x += glyphs[font_index].advance; + p.x += glyph.advance; } } } diff --git a/src/video/font.hpp b/src/video/font.hpp index 82f8151c4..6810d47d9 100644 --- a/src/video/font.hpp +++ b/src/video/font.hpp @@ -25,6 +25,7 @@ #include #include "video/surface.hpp" +#include "video/color.hpp" #include "math/vector.hpp" #include "math/rect.hpp" @@ -47,14 +48,10 @@ public: /** Construct a fixed-width font * * @param glyph_width VARIABLE for proportional fonts, VARIABLE for monospace ones - * @param filename image file containing the characters - * @param shadowfile image file containing the characters shadows - * @param char_width width of a character - * @param char_height height of a character + * @param fontfile file in format supertux-font + * @param sgadowsize offset of shadow */ - Font(GlyphWidth glyph_width, - const std::string& filename, const std::string& shadowfile, - int char_width, int char_height, int shadowsize = 2); + Font(GlyphWidth glyph_width, const std::string& fontfile, int shadowsize = 2); ~Font(); /** returns the width of a given text. (Note that I won't add a normal @@ -90,6 +87,7 @@ public: void draw(Renderer *renderer, const std::string& text, const Vector& pos, FontAlignment alignment = ALIGN_LEFT, DrawingEffect drawing_effect = NO_EFFECT, + Color color = Color(1.0,1.0,1.0), float alpha = 1.0f) const; private: @@ -97,26 +95,20 @@ private: void draw_text(Renderer *renderer, const std::string& text, const Vector& pos, DrawingEffect drawing_effect = NO_EFFECT, + Color color = Color(1.0,1.0,1.0), float alpha = 1.0f) const; - void draw_chars(Renderer *renderer, Surface* pchars, const std::string& text, - const Vector& position, DrawingEffect drawing_effect, + void draw_chars(Renderer *renderer, bool nonshadow, const std::string& text, + const Vector& position, DrawingEffect drawing_effect, Color color, float alpha) const; - /** Convert a Unicode character code to the index of its glyph */ - int chr2glyph(uint32_t chr) const; - GlyphWidth glyph_width; - Surface* glyph_surface; - Surface* shadow_glyph_surface; + + std::vector glyph_surfaces; + std::vector shadow_surfaces; int char_height; int shadowsize; - /// the number of the first character that is represented in the font - uint32_t first_char; - /// the number of the last character that is represented in the font - uint32_t char_count; - struct Glyph { /** How many pixels should the cursor advance after printing the glyph */ @@ -125,13 +117,22 @@ private: /** Offset that is used when drawing the glyph */ Vector offset; + /** index of containing surface */ + int surface_idx; + /** Position of the glyph inside the surface */ Rect rect; }; - /** Location of the characters inside the surface */ + /** 65536 of glyphs */ std::vector glyphs; - std::vector shadow_glyphs; + + void loadFontFile(const std::string &filename); + void loadFontSurface(const std::string &glyphimage, + const std::string &shadowimage, + const std::vector &chars, + GlyphWidth glyph_width, + int char_width); }; #endif diff --git a/src/video/gl_renderer.cpp b/src/video/gl_renderer.cpp index 83c1847a5..1d062c44b 100644 --- a/src/video/gl_renderer.cpp +++ b/src/video/gl_renderer.cpp @@ -263,7 +263,7 @@ Renderer::draw_surface_part(const DrawingRequest& request) uv_bottom, 0.0, request.alpha, - Color(1.0, 1.0, 1.0), + request.color, Blend(), request.drawing_effect); } diff --git a/src/video/sdl_renderer.cpp b/src/video/sdl_renderer.cpp index 33fee59cd..b02d0a189 100644 --- a/src/video/sdl_renderer.cpp +++ b/src/video/sdl_renderer.cpp @@ -260,7 +260,7 @@ namespace SDL DrawingEffect effect = request.drawing_effect; if (surface->get_flipx()) effect = HORIZONTAL_FLIP; - SDL_Surface *transform = sdltexture->get_transform(Color(1.0, 1.0, 1.0), effect); + SDL_Surface *transform = sdltexture->get_transform(request.color, effect); // get and check SDL_Surface if (transform == 0) { diff --git a/src/worldmap/worldmap.cpp b/src/worldmap/worldmap.cpp index 13602da1d..1f2e377bd 100644 --- a/src/worldmap/worldmap.cpp +++ b/src/worldmap/worldmap.cpp @@ -857,10 +857,10 @@ WorldMap::draw_status(DrawingContext& context) if(level->title == "") get_level_title(*level); - context.draw_text(white_text, level->title, + context.draw_text(normal_font, level->title, Vector(SCREEN_WIDTH/2, - SCREEN_HEIGHT - white_text->get_height() - 30), - ALIGN_CENTER, LAYER_FOREGROUND1); + SCREEN_HEIGHT - normal_font->get_height() - 30), + ALIGN_CENTER, LAYER_FOREGROUND1, WorldMap::level_title_color); // if level is solved, draw level picture behind stats /* @@ -887,10 +887,10 @@ WorldMap::draw_status(DrawingContext& context) if (special_tile->pos == tux->get_tile_pos()) { /* Display an in-map message in the map, if any as been selected */ if(!special_tile->map_message.empty() && !special_tile->passive_message) - context.draw_text(gold_text, special_tile->map_message, + context.draw_text(normal_font, special_tile->map_message, Vector(SCREEN_WIDTH/2, - SCREEN_HEIGHT - white_text->get_height() - 60), - ALIGN_CENTER, LAYER_FOREGROUND1); + SCREEN_HEIGHT - normal_font->get_height() - 60), + ALIGN_CENTER, LAYER_FOREGROUND1, WorldMap::message_color); break; } } @@ -898,17 +898,17 @@ WorldMap::draw_status(DrawingContext& context) // display teleporter messages Teleporter* teleporter = at_teleporter(tux->get_tile_pos()); if (teleporter && (teleporter->message != "")) { - Vector pos = Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT - white_text->get_height() - 30); - context.draw_text(white_text, teleporter->message, pos, ALIGN_CENTER, LAYER_FOREGROUND1); + Vector pos = Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT - normal_font->get_height() - 30); + context.draw_text(normal_font, teleporter->message, pos, ALIGN_CENTER, LAYER_FOREGROUND1, WorldMap::teleporter_message_color); } } /* Display a passive message in the map, if needed */ if(passive_message_timer.started()) - context.draw_text(gold_text, passive_message, - Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT - white_text->get_height() - 60), - ALIGN_CENTER, LAYER_FOREGROUND1); + context.draw_text(normal_font, passive_message, + Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT - normal_font->get_height() - 60), + ALIGN_CENTER, LAYER_FOREGROUND1, WorldMap::message_color); context.pop_transform(); } diff --git a/src/worldmap/worldmap.hpp b/src/worldmap/worldmap.hpp index e0da9cb05..8215cda42 100644 --- a/src/worldmap/worldmap.hpp +++ b/src/worldmap/worldmap.hpp @@ -69,6 +69,9 @@ Direction reverse_dir(Direction d); */ class WorldMap : public Screen { + static Color level_title_color; + static Color message_color; + static Color teleporter_message_color; private: Tux* tux;