basic font redering
This commit is contained in:
parent
b1ec45783e
commit
9464f99c90
|
@ -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) { }
|
||||
enum {
|
||||
white = 0xFFFFFFFF,
|
||||
pink = 0xFF00FFFF
|
||||
};
|
||||
|
||||
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; }
|
||||
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) { }
|
||||
|
||||
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; }
|
||||
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; }
|
||||
|
||||
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; }
|
||||
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
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
#include "configs.h"
|
||||
#include "resources.h"
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
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;
|
||||
|
|
|
@ -23,8 +23,145 @@
|
|||
|
||||
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -34,7 +34,7 @@ void Fonts::init()
|
|||
foreach(const std::string& file, files) {
|
||||
if(boost::ends_with(file, ".yml")) {
|
||||
std::shared_ptr<Font> 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;
|
||||
}
|
||||
|
|
|
@ -140,7 +140,6 @@ 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();
|
||||
|
|
|
@ -59,6 +59,6 @@ private:
|
|||
std::ostringstream m_buf;
|
||||
};
|
||||
|
||||
#define dump() Dump()
|
||||
#define dump Dump()
|
||||
|
||||
#endif
|
||||
|
|
|
@ -77,4 +77,12 @@ public:
|
|||
typedef TPoint<int> Point;
|
||||
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
|
||||
|
|
|
@ -65,6 +65,9 @@ typedef int8_t int8;
|
|||
#include <boost/foreach.hpp>
|
||||
#define foreach BOOST_FOREACH
|
||||
|
||||
// yaml
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
// internal logger
|
||||
#include "logger.h"
|
||||
|
||||
|
|
|
@ -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(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 h = y2 - y1;
|
||||
x1 = p.x() - w/2;
|
||||
|
@ -107,7 +107,7 @@ public:
|
|||
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;
|
||||
if(x2 < x1 - 1) {
|
||||
l = x2;
|
||||
|
@ -141,7 +141,7 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool intersects(const TRect<T> &r) const {
|
||||
inline bool intersects(const TRect<T> &r) const {
|
||||
if(isNull() || r.isNull())
|
||||
return false;
|
||||
|
||||
|
@ -182,7 +182,7 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
TRect<T> united(const TRect<T> &r) const {
|
||||
inline TRect<T> united(const TRect<T> &r) const {
|
||||
if(isNull() || r.isNull())
|
||||
return TRect<T>();
|
||||
|
||||
|
@ -228,7 +228,7 @@ public:
|
|||
return tmp;
|
||||
}
|
||||
|
||||
TRect<T> intersection(const TRect<T> &r) const {
|
||||
inline TRect<T> intersection(const TRect<T> &r) const {
|
||||
if(isNull())
|
||||
return r;
|
||||
if(r.isNull())
|
||||
|
@ -281,4 +281,15 @@ private:
|
|||
typedef TRect<int> Rect;
|
||||
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
|
||||
|
|
|
@ -38,9 +38,9 @@ template <class T>
|
|||
class TSize
|
||||
{
|
||||
public:
|
||||
TSize() : wd(-1), ht(-1) {};
|
||||
TSize(T width, T height) : wd(width), ht(height) { };
|
||||
TSize(const TSize<T>& 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<T>& other) : wd(other.wd), ht(other.ht) { };
|
||||
|
||||
inline TPoint<T> toPoint() const { return TPoint<T>(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<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)); }
|
||||
|
||||
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) {
|
||||
wd = s.wd;
|
||||
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 T area() const { return wd*ht; }
|
||||
|
@ -110,4 +111,13 @@ private:
|
|||
typedef TSize<int> Size;
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue