diff --git a/src/framework/color.h b/src/framework/color.h index 4d9a7bea..1943bc90 100644 --- a/src/framework/color.h +++ b/src/framework/color.h @@ -32,31 +32,46 @@ typedef uint32 RGBA; class Color { public: - Color() : color(0) { } - Color(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : color(((r & 0xff)<<24) | ((g & 0xff)<<16) | ((b & 0xff)<<8) | (a & 0xff)) { } - Color(const Color& other) : color(other.color) { } - Color(RGBA rgba) : color(rgba) { } - - uint8 red() const { return (color >> 24) & 0xFF; } - uint8 green() const { return (color >> 16) & 0xFF; } - uint8 blue() const { return (color >> 8) & 0xFF; } - uint8 alpha() const { return color & 0xFF; } - RGBA rgba() const { return color; } - const uint8* rgbaPtr() const { return (const uint8*)&color; } - - void setRed(uint8 r) { color = ((r & 0xff)<<24) | (color & 0x00ffffff); } - void setGreen(uint8 g) { color = ((g & 0xff)<<16) | (color & 0xff00ffff); } - void setBlue(uint8 b) { color = ((b & 0xff)<<8) | (color & 0xffff00ff); } - void setAlpha(uint8 a) { color = (a & 0xff) | (color & 0xffffff00); } - void setRGBA(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) { color = ((r & 0xff)<<24) | ((g & 0xff)<<16) | ((b & 0xff)<<8) | (a & 0xff); } - void setRGBA(uint32 rgba) { color = rgba; } - - Color& operator=(const Color& other) { color = other.color; return *this; } - bool operator==(const Color& other) const { return other.color == color; } - bool operator!=(const Color& other) const { return other.color != color; } + enum { + white = 0xFFFFFFFF, + pink = 0xFF00FFFF + }; + + inline Color() : color(0) { } + inline Color(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : color(((r & 0xff)<<24) | ((g & 0xff)<<16) | ((b & 0xff)<<8) | (a & 0xff)) { } + inline Color(const Color& other) : color(other.color) { } + inline Color(RGBA rgba) : color(rgba) { } + + inline uint8 red() const { return (color >> 24) & 0xFF; } + inline uint8 green() const { return (color >> 16) & 0xFF; } + inline uint8 blue() const { return (color >> 8) & 0xFF; } + inline uint8 alpha() const { return color & 0xFF; } + inline RGBA rgba() const { return color; } + inline const uint8* rgbaPtr() const { return (const uint8*)&color; } + + inline void setRed(uint8 r) { color = ((r & 0xff)<<24) | (color & 0x00ffffff); } + inline void setGreen(uint8 g) { color = ((g & 0xff)<<16) | (color & 0xff00ffff); } + inline void setBlue(uint8 b) { color = ((b & 0xff)<<8) | (color & 0xffff00ff); } + inline void setAlpha(uint8 a) { color = (a & 0xff) | (color & 0xffffff00); } + inline void setRGBA(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) { color = ((r & 0xff)<<24) | ((g & 0xff)<<16) | ((b & 0xff)<<8) | (a & 0xff); } + inline void setRGBA(uint32 rgba) { color = rgba; } + + inline Color& operator=(const Color& other) { color = other.color; return *this; } + inline bool operator==(const Color& other) const { return other.color == color; } + inline bool operator!=(const Color& other) const { return other.color != color; } private: RGBA color; }; +inline void operator>>(const YAML::Node& node, Color& color) +{ + int r, g, b, a; + node[0] >> r; + node[1] >> g; + node[2] >> b; + node[3] >> a; + color.setRGBA(r,g,b,a); +} + #endif // COLOR_H diff --git a/src/framework/configs.cpp b/src/framework/configs.cpp index 92f79bfa..c2acf814 100644 --- a/src/framework/configs.cpp +++ b/src/framework/configs.cpp @@ -25,8 +25,6 @@ #include "configs.h" #include "resources.h" -#include - Configs g_configs; bool Configs::load(const std::string& fileName) @@ -48,7 +46,7 @@ bool Configs::load(const std::string& fileName) YAML::Node doc; parser.GetNextDocument(doc); - for(YAML::Iterator it = doc.begin(); it != doc.end(); ++it) { + for(auto it = doc.begin(); it != doc.end(); ++it) { std::string key, value; it.first() >> key; it.second() >> value; diff --git a/src/framework/font.cpp b/src/framework/font.cpp index 188373e7..a26abcd5 100644 --- a/src/framework/font.cpp +++ b/src/framework/font.cpp @@ -23,8 +23,145 @@ #include "font.h" +#include "resources.h" +#include "textures.h" +#include "graphics.h" + +#include +#include +#include + +Font::Font() : + m_lineHeight(14), + m_cursorSize(14), + m_color(Color::white) +{ + bzero(m_glyphWidths, sizeof(m_glyphWidths)); +} bool Font::load(const std::string& file) { - return false; + if(!g_resources.fileExists(file)) { + error("Font file %s does not exists", file.c_str()); + return false; + } + + std::string fileContents = g_resources.loadTextFile(file); + if(!fileContents.size()) { + error("Empty font file \"%s", file.c_str()); + return false; + } + + std::istringstream fin(fileContents); + + std::string textureName; + + try { + YAML::Parser parser(fin); + + YAML::Node doc; + parser.GetNextDocument(doc); + + doc["name"] >> m_name; + doc["line height"] >> m_lineHeight; + doc["cursor size"] >> m_cursorSize; + doc["color"] >> m_color; + doc["first glyph"] >> m_firstGlyph; + doc["image"] >> textureName; + doc["image glyph size"] >> m_glyphSize; + + const YAML::Node& widthsNode = doc["widths"]; + for(auto it = widthsNode.begin(); it != widthsNode.end(); ++it) { + int id, width; + it.first() >> id; + it.second() >> width; + m_glyphWidths[id] = width; + } + } catch (YAML::ParserException& e) { + error("Malformed font file \"%s\"", file.c_str()); + return false; + } + + m_texture = g_textures.get("fonts/" + textureName); + m_numHorizontalGlyphs = m_texture->getSize().width() / m_glyphSize.width(); + m_numVerticalGlyphs = m_texture->getSize().height() / m_glyphSize.height(); + + if(!m_texture) { + error("Failed to load image for font \"%s\"", file.c_str()); + return false; + } + + return true; +} + +void Font::renderText(const Point& pos, const std::string& text) +{ + // bind font texture + glBindTexture(GL_TEXTURE_2D, m_texture->getTextureId()); + + // set font color + glColor4ubv(m_color.rgbaPtr()); + + // begin render + glBegin(GL_QUADS); + + Point currentPos = pos; + const Size& screenSize = g_graphics.getScreenSize(); + int textLenght = text.length(); + + for(int i = 0; i < textLenght; ++i) { + int c = (int)text[i]; + + // check if is visible + if(currentPos.x >= screenSize.width()) + continue; + if(currentPos.y >= screenSize.height()) + break; + + // new line + if(c == '\n') { + currentPos.y += m_lineHeight; + currentPos.x = pos.x; + } + // text eof + else if(c == '\0') { + break; + } + // normal glyph + else if(c >= 32 && c <= 255) { + currentPos.x += renderGlyph(currentPos, c); + } + } + + // end font render + glEnd(); +} + +int Font::renderGlyph(const Point& pos, int glyph) +{ + // get glyph width + int glyphWidth = m_glyphWidths[glyph]; + + // calculate glyph coords on texture font + const Size& textureSize = m_texture->getSize(); + int glyphTexCoordX = ((glyph - m_firstGlyph) % m_numHorizontalGlyphs) * m_glyphSize.width(); + int glyphTexCoordY = ((glyph - m_firstGlyph) / m_numVerticalGlyphs) * m_glyphSize.height(); + float textureRight = (float)(glyphTexCoordX + glyphWidth) / textureSize.width(); + float textureBottom = (float)(glyphTexCoordY + m_glyphSize.height()) / textureSize.height(); + float textureTop = (float)(glyphTexCoordY) / textureSize.height(); + float textureLeft = (float)(glyphTexCoordX) / textureSize.width(); + + // calculate glyph coords on screen + int right = pos.x + glyphWidth; + int bottom = pos.y + m_glyphSize.height(); + int top = pos.y; + int left = pos.x; + + // render glyph + glTexCoord2f(textureLeft, textureTop); glVertex2i(left, top); + glTexCoord2f(textureLeft, textureBottom); glVertex2i(left, bottom); + glTexCoord2f(textureRight, textureBottom); glVertex2i(right, bottom); + glTexCoord2f(textureRight, textureTop); glVertex2i(right, top); + + return glyphWidth; } diff --git a/src/framework/font.h b/src/framework/font.h index 3d5c4f77..9225a534 100644 --- a/src/framework/font.h +++ b/src/framework/font.h @@ -26,20 +26,56 @@ #define FONT_H #include "prerequisites.h" +#include "color.h" +#include "texture.h" class Font { public: - Font() { } + Font(); virtual ~Font() { } /// Load font from file bool load(const std::string &file); + /// Simple text render + void renderText(const Point& pos, const std::string& text); + + /* + enum EAlign { + ALIGN_TOP = 1 << 0, + ALIGN_BOTTOM = 1 << 1, + ALIGN_LEFT = 1 << 2, + ALIGN_RIGHT = 1 << 3, + ALIGN_HORIZONTAL_CENTER = 1 << 4, + ALIGN_VERTICAL_CENTER = 1 << 5, + ALIGN_CENTER = ALIGN_HORIZONTAL_CENTER | ALIGN_VERTICAL_CENTER, + ALIGN_TOP_RIGHT = ALIGN_TOP | ALIGN_RIGHT, + ALIGN_TOP_LEFT = ALIGN_TOP | ALIGN_LEFT, + ALIGN_BOTTOM_RIGHT = ALIGN_BOTTOM | ALIGN_RIGHT, + ALIGN_BOTTOM_LEFT = ALIGN_BOTTOM | ALIGN_LEFT + }; + /// Render a text inside a rect + void renderText(const Rect& screenCoords, EAlign align, const std::string& text); + */ + + /// Render a text const std::string& getName() const { return m_name; } + int renderGlyph(const Point& pos, int glyph); private: + std::string m_name; + int m_lineHeight; + int m_cursorSize; + Color m_color; + TexturePtr m_texture; + Size m_textureSize; + Size m_glyphSize; + int m_firstGlyph; + int m_glyphWidths[256]; + int m_numHorizontalGlyphs; + int m_numVerticalGlyphs; }; #endif // FONT_H diff --git a/src/framework/fonts.cpp b/src/framework/fonts.cpp index 387af43d..214141c8 100644 --- a/src/framework/fonts.cpp +++ b/src/framework/fonts.cpp @@ -34,7 +34,7 @@ void Fonts::init() foreach(const std::string& file, files) { if(boost::ends_with(file, ".yml")) { std::shared_ptr font(new Font); - font->load(file); + font->load("fonts/" + file); m_fonts[font->getName()] = font; } } @@ -43,7 +43,9 @@ void Fonts::init() Font* Fonts::get(const std::string& fontName) { auto it = m_fonts.find(fontName); - if(it != m_fonts.end()) + if(it != m_fonts.end()) { return it->second.get(); + } + error("Font \"%s\" not found", fontName.c_str()); return NULL; } diff --git a/src/framework/graphics.cpp b/src/framework/graphics.cpp index 42f14558..724179d0 100644 --- a/src/framework/graphics.cpp +++ b/src/framework/graphics.cpp @@ -140,13 +140,12 @@ void Graphics::drawTexturedRect(const Rect& screenCoords, const Texture *texture if(!textureCoords.isEmpty()) { const Size& textureSize = texture->getSize(); - textureRight = (float)(textureCoords.right() + 1) / textureSize.width(); textureBottom = (float)(textureCoords.bottom() + 1) / textureSize.height(); textureTop = (float)textureCoords.top() / textureSize.height(); textureLeft = (float)textureCoords.left() / textureSize.width(); } - + glBindTexture(GL_TEXTURE_2D, texture->getTextureId()); glBegin(GL_QUADS); glTexCoord2f(textureLeft, textureTop); glVertex2i(left, top); diff --git a/src/framework/logger.h b/src/framework/logger.h index 3248ec60..02b48904 100644 --- a/src/framework/logger.h +++ b/src/framework/logger.h @@ -59,6 +59,6 @@ private: std::ostringstream m_buf; }; -#define dump() Dump() +#define dump Dump() #endif diff --git a/src/framework/point.h b/src/framework/point.h index 52a75832..37a21ffd 100644 --- a/src/framework/point.h +++ b/src/framework/point.h @@ -77,4 +77,12 @@ public: typedef TPoint Point; typedef TPoint PointF; +template +inline void operator>>(const YAML::Node& node, TPoint& point) +{ + T x, y; + node[0] >> point.x; + node[1] >> point.y; +} + #endif diff --git a/src/framework/prerequisites.h b/src/framework/prerequisites.h index b04dd614..0e4d2753 100644 --- a/src/framework/prerequisites.h +++ b/src/framework/prerequisites.h @@ -65,6 +65,9 @@ typedef int8_t int8; #include #define foreach BOOST_FOREACH +// yaml +#include + // internal logger #include "logger.h" diff --git a/src/framework/rect.h b/src/framework/rect.h index 025e8dcb..065f92a2 100644 --- a/src/framework/rect.h +++ b/src/framework/rect.h @@ -98,7 +98,7 @@ public: inline TRect translated(int x, int y) const { return TRect(TPoint(x1 + x, y1 + y), TPoint(x2 + x, y2 + y)); } inline TRect translated(const TPoint &p) const { return TRect(TPoint(x1 + p.x(), y1 + p.y()), TPoint(x2 + p.x(), y2 + p.y())); } - void moveCenter(const TPoint &p) { + inline void moveCenter(const TPoint &p) { T w = x2 - x1; T h = y2 - y1; x1 = p.x() - w/2; @@ -107,7 +107,7 @@ public: y2 = y1 + h; } - bool contains(const TPoint &p, bool insideOnly = false) const { + inline bool contains(const TPoint &p, bool insideOnly = false) const { T l, r; if(x2 < x1 - 1) { l = x2; @@ -141,7 +141,7 @@ public: return true; } - bool intersects(const TRect &r) const { + inline bool intersects(const TRect &r) const { if(isNull() || r.isNull()) return false; @@ -182,7 +182,7 @@ public: return true; } - TRect united(const TRect &r) const { + inline TRect united(const TRect &r) const { if(isNull() || r.isNull()) return TRect(); @@ -228,7 +228,7 @@ public: return tmp; } - TRect intersection(const TRect &r) const { + inline TRect intersection(const TRect &r) const { if(isNull()) return r; if(r.isNull()) @@ -281,4 +281,15 @@ private: typedef TRect Rect; typedef TRect RectF; +template +inline void operator>>(const YAML::Node& node, TRect& rect) +{ + T x, y, width, height; + node[0] >> x; + node[1] >> y; + node[2] >> width; + node[3] >> height; + rect.setRect(x, y, width, height); +} + #endif // RECT_H diff --git a/src/framework/size.h b/src/framework/size.h index d088f0b4..7ea11b74 100644 --- a/src/framework/size.h +++ b/src/framework/size.h @@ -38,9 +38,9 @@ template class TSize { public: - TSize() : wd(-1), ht(-1) {}; - TSize(T width, T height) : wd(width), ht(height) { }; - TSize(const TSize& other) : wd(other.wd), ht(other.ht) { }; + inline TSize() : wd(-1), ht(-1) {}; + inline TSize(T width, T height) : wd(width), ht(height) { }; + inline TSize(const TSize& other) : wd(other.wd), ht(other.ht) { }; inline TPoint toPoint() const { return TPoint(wd, ht); } @@ -51,6 +51,7 @@ public: inline int width() const { return wd; } inline int height() const { return ht; } + inline void setSize(T w, T h) { wd = w; ht = h; } inline void setWidth(T w) { wd = w; } inline void setHeight(T h) { ht = h; } @@ -76,7 +77,7 @@ public: inline TSize expandedTo(const TSize& other) const { return TSize(std::max(wd,other.wd), std::max(ht,other.ht)); } inline TSize boundedTo(const TSize& other) const { return TSize(std::min(wd,other.wd), std::min(ht,other.ht)); } - void scale(const TSize& s, ESizeScaleMode mode) { + inline void scale(const TSize& s, ESizeScaleMode mode) { if(mode == IGNORE_ASPECT_RATIO || wd == 0 || ht == 0) { wd = s.wd; ht = s.ht; @@ -98,7 +99,7 @@ public: } } } - void scale(int w, int h, ESizeScaleMode mode) { scale(TSize(w, h)); } + inline void scale(int w, int h, ESizeScaleMode mode) { scale(TSize(w, h)); } inline float ratio() const { return (float)wd/ht; } inline T area() const { return wd*ht; } @@ -110,4 +111,13 @@ private: typedef TSize Size; typedef TSize SizeF; +template +inline void operator>>(const YAML::Node& node, TSize& size) +{ + T w, h; + node[0] >> w; + node[1] >> h; + size.setSize(w, h); +} + #endif diff --git a/src/menustate.cpp b/src/menustate.cpp index ff255580..a1e65560 100644 --- a/src/menustate.cpp +++ b/src/menustate.cpp @@ -29,6 +29,7 @@ #include "framework/logger.h" #include "framework/engine.h" #include "framework/rect.h" +#include "framework/fonts.h" TexturePtr background; @@ -65,8 +66,11 @@ void MenuState::render() Rect texCoords(0, 0, texCoordsSize); texCoords.moveBottomRight(texSize.toPoint()); - g_graphics.drawTexturedRect(Rect(0, 0, screenSize), m_background.get(), texCoords); + + Font *font = g_fonts.get("sans14"); + if(font) + font->renderText(Point(10,10), "hello\nworld!"); } void MenuState::update(int ticks, int elapsedTicks)