basic font redering

This commit is contained in:
Eduardo Bart 2011-04-06 21:58:36 -03:00
parent b1ec45783e
commit 9464f99c90
12 changed files with 263 additions and 40 deletions

View File

@ -32,31 +32,46 @@ typedef uint32 RGBA;
class Color class Color
{ {
public: public:
Color() : color(0) { } enum {
Color(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : color(((r & 0xff)<<24) | ((g & 0xff)<<16) | ((b & 0xff)<<8) | (a & 0xff)) { } white = 0xFFFFFFFF,
Color(const Color& other) : color(other.color) { } pink = 0xFF00FFFF
Color(RGBA rgba) : color(rgba) { } };
uint8 red() const { return (color >> 24) & 0xFF; } inline Color() : color(0) { }
uint8 green() const { return (color >> 16) & 0xFF; } inline Color(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : color(((r & 0xff)<<24) | ((g & 0xff)<<16) | ((b & 0xff)<<8) | (a & 0xff)) { }
uint8 blue() const { return (color >> 8) & 0xFF; } inline Color(const Color& other) : color(other.color) { }
uint8 alpha() const { return color & 0xFF; } inline Color(RGBA rgba) : color(rgba) { }
RGBA rgba() const { return color; }
const uint8* rgbaPtr() const { return (const uint8*)&color; }
void setRed(uint8 r) { color = ((r & 0xff)<<24) | (color & 0x00ffffff); } inline uint8 red() const { return (color >> 24) & 0xFF; }
void setGreen(uint8 g) { color = ((g & 0xff)<<16) | (color & 0xff00ffff); } inline uint8 green() const { return (color >> 16) & 0xFF; }
void setBlue(uint8 b) { color = ((b & 0xff)<<8) | (color & 0xffff00ff); } inline uint8 blue() const { return (color >> 8) & 0xFF; }
void setAlpha(uint8 a) { color = (a & 0xff) | (color & 0xffffff00); } inline uint8 alpha() const { return color & 0xFF; }
void setRGBA(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) { color = ((r & 0xff)<<24) | ((g & 0xff)<<16) | ((b & 0xff)<<8) | (a & 0xff); } inline RGBA rgba() const { return color; }
void setRGBA(uint32 rgba) { color = rgba; } inline const uint8* rgbaPtr() const { return (const uint8*)&color; }
Color& operator=(const Color& other) { color = other.color; return *this; } inline void setRed(uint8 r) { color = ((r & 0xff)<<24) | (color & 0x00ffffff); }
bool operator==(const Color& other) const { return other.color == color; } inline void setGreen(uint8 g) { color = ((g & 0xff)<<16) | (color & 0xff00ffff); }
bool operator!=(const Color& other) const { return other.color != color; } 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: private:
RGBA color; 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 #endif // COLOR_H

View File

@ -25,8 +25,6 @@
#include "configs.h" #include "configs.h"
#include "resources.h" #include "resources.h"
#include <yaml-cpp/yaml.h>
Configs g_configs; Configs g_configs;
bool Configs::load(const std::string& fileName) bool Configs::load(const std::string& fileName)
@ -48,7 +46,7 @@ bool Configs::load(const std::string& fileName)
YAML::Node doc; YAML::Node doc;
parser.GetNextDocument(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; std::string key, value;
it.first() >> key; it.first() >> key;
it.second() >> value; it.second() >> value;

View File

@ -23,8 +23,145 @@
#include "font.h" #include "font.h"
#include "resources.h"
#include "textures.h"
#include "graphics.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glext.h>
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) 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;
} }

View File

@ -26,20 +26,56 @@
#define FONT_H #define FONT_H
#include "prerequisites.h" #include "prerequisites.h"
#include "color.h"
#include "texture.h"
class Font class Font
{ {
public: public:
Font() { } Font();
virtual ~Font() { } virtual ~Font() { }
/// Load font from file /// Load font from file
bool load(const std::string &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; } const std::string& getName() const { return m_name; }
int renderGlyph(const Point& pos, int glyph);
private: private:
std::string m_name; 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 #endif // FONT_H

View File

@ -34,7 +34,7 @@ void Fonts::init()
foreach(const std::string& file, files) { foreach(const std::string& file, files) {
if(boost::ends_with(file, ".yml")) { if(boost::ends_with(file, ".yml")) {
std::shared_ptr<Font> font(new Font); std::shared_ptr<Font> font(new Font);
font->load(file); font->load("fonts/" + file);
m_fonts[font->getName()] = font; m_fonts[font->getName()] = font;
} }
} }
@ -43,7 +43,9 @@ void Fonts::init()
Font* Fonts::get(const std::string& fontName) Font* Fonts::get(const std::string& fontName)
{ {
auto it = m_fonts.find(fontName); auto it = m_fonts.find(fontName);
if(it != m_fonts.end()) if(it != m_fonts.end()) {
return it->second.get(); return it->second.get();
}
error("Font \"%s\" not found", fontName.c_str());
return NULL; return NULL;
} }

View File

@ -140,7 +140,6 @@ void Graphics::drawTexturedRect(const Rect& screenCoords, const Texture *texture
if(!textureCoords.isEmpty()) { if(!textureCoords.isEmpty()) {
const Size& textureSize = texture->getSize(); const Size& textureSize = texture->getSize();
textureRight = (float)(textureCoords.right() + 1) / textureSize.width(); textureRight = (float)(textureCoords.right() + 1) / textureSize.width();
textureBottom = (float)(textureCoords.bottom() + 1) / textureSize.height(); textureBottom = (float)(textureCoords.bottom() + 1) / textureSize.height();
textureTop = (float)textureCoords.top() / textureSize.height(); textureTop = (float)textureCoords.top() / textureSize.height();

View File

@ -59,6 +59,6 @@ private:
std::ostringstream m_buf; std::ostringstream m_buf;
}; };
#define dump() Dump() #define dump Dump()
#endif #endif

View File

@ -77,4 +77,12 @@ public:
typedef TPoint<int> Point; typedef TPoint<int> Point;
typedef TPoint<float> PointF; typedef TPoint<float> PointF;
template <class T>
inline void operator>>(const YAML::Node& node, TPoint<T>& point)
{
T x, y;
node[0] >> point.x;
node[1] >> point.y;
}
#endif #endif

View File

@ -65,6 +65,9 @@ typedef int8_t int8;
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#define foreach BOOST_FOREACH #define foreach BOOST_FOREACH
// yaml
#include <yaml-cpp/yaml.h>
// internal logger // internal logger
#include "logger.h" #include "logger.h"

View File

@ -98,7 +98,7 @@ public:
inline TRect<T> translated(int x, int y) const { return TRect<T>(TPoint<T>(x1 + x, y1 + y), TPoint<T>(x2 + x, y2 + y)); } inline TRect<T> translated(int x, int y) const { return TRect<T>(TPoint<T>(x1 + x, y1 + y), TPoint<T>(x2 + x, y2 + y)); }
inline TRect<T> translated(const TPoint<T> &p) const { return TRect<T>(TPoint<T>(x1 + p.x(), y1 + p.y()), TPoint<T>(x2 + p.x(), y2 + p.y())); } inline TRect<T> translated(const TPoint<T> &p) const { return TRect<T>(TPoint<T>(x1 + p.x(), y1 + p.y()), TPoint<T>(x2 + p.x(), y2 + p.y())); }
void moveCenter(const TPoint<T> &p) { inline void moveCenter(const TPoint<T> &p) {
T w = x2 - x1; T w = x2 - x1;
T h = y2 - y1; T h = y2 - y1;
x1 = p.x() - w/2; x1 = p.x() - w/2;
@ -107,7 +107,7 @@ public:
y2 = y1 + h; y2 = y1 + h;
} }
bool contains(const TPoint<T> &p, bool insideOnly = false) const { inline bool contains(const TPoint<T> &p, bool insideOnly = false) const {
T l, r; T l, r;
if(x2 < x1 - 1) { if(x2 < x1 - 1) {
l = x2; l = x2;
@ -141,7 +141,7 @@ public:
return true; return true;
} }
bool intersects(const TRect<T> &r) const { inline bool intersects(const TRect<T> &r) const {
if(isNull() || r.isNull()) if(isNull() || r.isNull())
return false; return false;
@ -182,7 +182,7 @@ public:
return true; return true;
} }
TRect<T> united(const TRect<T> &r) const { inline TRect<T> united(const TRect<T> &r) const {
if(isNull() || r.isNull()) if(isNull() || r.isNull())
return TRect<T>(); return TRect<T>();
@ -228,7 +228,7 @@ public:
return tmp; return tmp;
} }
TRect<T> intersection(const TRect<T> &r) const { inline TRect<T> intersection(const TRect<T> &r) const {
if(isNull()) if(isNull())
return r; return r;
if(r.isNull()) if(r.isNull())
@ -281,4 +281,15 @@ private:
typedef TRect<int> Rect; typedef TRect<int> Rect;
typedef TRect<float> RectF; typedef TRect<float> RectF;
template <class T>
inline void operator>>(const YAML::Node& node, TRect<T>& 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 #endif // RECT_H

View File

@ -38,9 +38,9 @@ template <class T>
class TSize class TSize
{ {
public: public:
TSize() : wd(-1), ht(-1) {}; inline TSize() : wd(-1), ht(-1) {};
TSize(T width, T height) : wd(width), ht(height) { }; inline TSize(T width, T height) : wd(width), ht(height) { };
TSize(const TSize<T>& other) : wd(other.wd), ht(other.ht) { }; inline TSize(const TSize<T>& other) : wd(other.wd), ht(other.ht) { };
inline TPoint<T> toPoint() const { return TPoint<T>(wd, ht); } inline TPoint<T> toPoint() const { return TPoint<T>(wd, ht); }
@ -51,6 +51,7 @@ public:
inline int width() const { return wd; } inline int width() const { return wd; }
inline int height() const { return ht; } 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 setWidth(T w) { wd = w; }
inline void setHeight(T h) { ht = h; } inline void setHeight(T h) { ht = h; }
@ -76,7 +77,7 @@ public:
inline TSize<T> expandedTo(const TSize<T>& other) const { return TSize<T>(std::max(wd,other.wd), std::max(ht,other.ht)); } inline TSize<T> expandedTo(const TSize<T>& other) const { return TSize<T>(std::max(wd,other.wd), std::max(ht,other.ht)); }
inline TSize<T> boundedTo(const TSize<T>& other) const { return TSize<T>(std::min(wd,other.wd), std::min(ht,other.ht)); } inline TSize<T> boundedTo(const TSize<T>& other) const { return TSize<T>(std::min(wd,other.wd), std::min(ht,other.ht)); }
void scale(const TSize<T>& s, ESizeScaleMode mode) { inline void scale(const TSize<T>& s, ESizeScaleMode mode) {
if(mode == IGNORE_ASPECT_RATIO || wd == 0 || ht == 0) { if(mode == IGNORE_ASPECT_RATIO || wd == 0 || ht == 0) {
wd = s.wd; wd = s.wd;
ht = s.ht; ht = s.ht;
@ -98,7 +99,7 @@ public:
} }
} }
} }
void scale(int w, int h, ESizeScaleMode mode) { scale(TSize<T>(w, h)); } inline void scale(int w, int h, ESizeScaleMode mode) { scale(TSize<T>(w, h)); }
inline float ratio() const { return (float)wd/ht; } inline float ratio() const { return (float)wd/ht; }
inline T area() const { return wd*ht; } inline T area() const { return wd*ht; }
@ -110,4 +111,13 @@ private:
typedef TSize<int> Size; typedef TSize<int> Size;
typedef TSize<float> SizeF; typedef TSize<float> SizeF;
template <class T>
inline void operator>>(const YAML::Node& node, TSize<T>& size)
{
T w, h;
node[0] >> w;
node[1] >> h;
size.setSize(w, h);
}
#endif #endif

View File

@ -29,6 +29,7 @@
#include "framework/logger.h" #include "framework/logger.h"
#include "framework/engine.h" #include "framework/engine.h"
#include "framework/rect.h" #include "framework/rect.h"
#include "framework/fonts.h"
TexturePtr background; TexturePtr background;
@ -65,8 +66,11 @@ void MenuState::render()
Rect texCoords(0, 0, texCoordsSize); Rect texCoords(0, 0, texCoordsSize);
texCoords.moveBottomRight(texSize.toPoint()); texCoords.moveBottomRight(texSize.toPoint());
g_graphics.drawTexturedRect(Rect(0, 0, screenSize), m_background.get(), texCoords); 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) void MenuState::update(int ticks, int elapsedTicks)