convert Font to Ruby class

This commit is contained in:
Josh Holtrop 2014-07-25 23:31:29 -04:00
parent 8d8c9adcb3
commit b7ad236b7b
3 changed files with 85 additions and 84 deletions

View File

@ -1,13 +1,44 @@
#include "Font.h" #include "Font.h"
#include "ruby.h" #include "ruby.h"
#include "GLTexture.h"
#include <iostream> #include <iostream>
#include <stdint.h> #include <stdint.h>
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include <unordered_map>
#define round_up_26_6(val) (((val) + 63) >> 6u) #define round_up_26_6(val) (((val) + 63) >> 6u)
class Glyph
{
public:
Glyph();
bool load(FT_Face face, FT_ULong char_code);
int get_advance() { return m_advance; }
void render()
{
m_texture->bind();
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
protected:
bool m_loaded;
int m_advance;
GLTextureRef m_texture;
GLuint m_vbo_id;
};
typedef Ref<Glyph> GlyphRef;
typedef struct
{
FT_Face face;
std::unordered_map<FT_ULong, GlyphRef> glyphs;
} Font;
static FT_Library ft; static FT_Library ft;
static VALUE ruby_class;
static void Init_FreeType() static void Init_FreeType()
{ {
@ -24,62 +55,87 @@ static void Init_FreeType()
initialized = true; initialized = true;
} }
Font::Font() void Font_free(void * ptr)
{ {
m_loaded = false; Font * font = (Font *)ptr;
FT_Done_Face(font->face);
delete font;
} }
Font::~Font() static VALUE Font_new(VALUE klass, VALUE fname, VALUE size)
{ {
if (m_loaded) Init_FreeType();
{
FT_Done_Face(m_face);
}
}
bool Font::load(FT_Library ft, const char * fname, size_t size) Font * font = new Font();
{
if (FT_New_Face(ft, fname, 0, &m_face) != 0) fname = rb_funcall(fname, rb_intern("to_s"), 0);
const char * fname_cstr = StringValueCStr(fname);
if (FT_New_Face(ft, fname_cstr, 0, &font->face) != 0)
{ {
std::cerr << "Could not load font " << fname << std::endl; delete font;
return false; rb_raise(rb_eRuntimeError,
"Could not load font %s",
fname_cstr);
} }
FT_Set_Pixel_Sizes(m_face, 0, size); FT_Set_Pixel_Sizes(font->face, 0, NUM2INT(size));
#if 0
GlyphRef glyph = load_glyph('g'); GlyphRef glyph = load_glyph('g');
if (glyph == NULL) if (glyph == NULL)
{ {
std::cerr << "Could not load 'g' glyph from font" << fname << std::endl;
return false; return false;
} }
m_glyphs['g'] = glyph; m_glyphs['g'] = glyph;
#endif
#if 0
m_advance = glyph->get_advance(); m_advance = glyph->get_advance();
m_line_height = round_up_26_6(m_face->size->metrics.height); m_line_height = round_up_26_6(m_face->size->metrics.height);
#endif
#if 0 #if 0
m_baseline_offset = round_up_26_6((m_face->size->metrics.height - (m_face->size->metrics.ascender - m_face->size->metrics.descender)) / 2 - m_face->size->metrics.descender); m_baseline_offset = round_up_26_6((m_face->size->metrics.height - (m_face->size->metrics.ascender - m_face->size->metrics.descender)) / 2 - m_face->size->metrics.descender);
#endif #endif
#if 0
m_baseline_offset = 1 - m_face->glyph->bitmap_top + m_face->glyph->bitmap.rows; m_baseline_offset = 1 - m_face->glyph->bitmap_top + m_face->glyph->bitmap.rows;
#endif
m_loaded = true; return Data_Wrap_Struct(klass, NULL, Font_free, font);
return true;
} }
Font::GlyphRef Font::load_glyph(FT_ULong char_code) void Font_Init()
{
ruby_class = rb_define_class("Font", rb_cObject);
rb_define_singleton_method(ruby_class, "new", (VALUE(*)(...))Font_new, 2);
}
static GlyphRef load_glyph(Font * font, FT_ULong char_code)
{ {
GlyphRef glyph = new Glyph(); GlyphRef glyph = new Glyph();
if (glyph->load(m_face, char_code)) if (glyph->load(font->face, char_code))
return glyph; return glyph;
return NULL; return NULL;
} }
Font::Glyph::Glyph() static GlyphRef get_glyph(Font * font, FT_ULong char_code)
{
auto it = font->glyphs.find(char_code);
if (it != font->glyphs.end())
return it->second;
GlyphRef g = load_glyph(font, char_code);
font->glyphs[char_code] = g;
return g;
}
Glyph::Glyph()
{ {
m_loaded = false; m_loaded = false;
} }
bool Font::Glyph::load(FT_Face face, FT_ULong char_code) bool Glyph::load(FT_Face face, FT_ULong char_code)
{ {
if (FT_Load_Char(face, char_code, FT_LOAD_RENDER) != 0) if (FT_Load_Char(face, char_code, FT_LOAD_RENDER) != 0)
return false; return false;

View File

@ -1,64 +1,6 @@
#ifndef JES_FONT_H #ifndef JES_FONT_H
#define JES_FONT_H #define JES_FONT_H
#include "Ref.h" void Font_Init();
#include <ft2build.h>
#include FT_FREETYPE_H
#include "gl3w.h"
#include <unordered_map>
#include "GLTexture.h"
class Font
{
public:
class Glyph
{
public:
Glyph();
bool load(FT_Face face, FT_ULong char_code);
int get_advance() { return m_advance; }
void render()
{
m_texture->bind();
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
protected:
bool m_loaded;
int m_advance;
GLTextureRef m_texture;
GLuint m_vbo_id;
};
typedef Ref<Glyph> GlyphRef;
Font();
~Font();
bool load(FT_Library ft, const char * fname, size_t size);
int get_line_height() { return m_line_height; }
int get_advance() { return m_advance; }
int get_baseline_offset() { return m_baseline_offset; }
GlyphRef get_glyph(FT_ULong char_code)
{
auto it = m_glyphs.find(char_code);
if (it != m_glyphs.end())
return it->second;
GlyphRef g = load_glyph(char_code);
m_glyphs[char_code] = g;
return g;
}
protected:
GlyphRef load_glyph(FT_ULong char_code);
FT_Face m_face;
int m_line_height;
int m_advance;
int m_baseline_offset;
bool m_loaded;
std::unordered_map<FT_ULong, GlyphRef> m_glyphs;
};
typedef Ref<Font> FontRef;
#endif #endif

View File

@ -1,8 +1,10 @@
#include <iostream> #include <iostream>
#include "ruby.h" #include "ruby.h"
#include "Window.h"
#include "GLShader.h" #include "Font.h"
#include "GLProgram.h" #include "GLProgram.h"
#include "GLShader.h"
#include "Window.h"
using namespace std; using namespace std;
@ -50,9 +52,10 @@ static int bootstrap()
int rv = 0; int rv = 0;
int err_state = 0; int err_state = 0;
Window_Init(); Font_Init();
GLShader_Init();
GLProgram_Init(); GLProgram_Init();
GLShader_Init();
Window_Init();
rb_eval_string_protect( rb_eval_string_protect(
"load File.expand_path('../../runtime/main.rb', $0)", "load File.expand_path('../../runtime/main.rb', $0)",