Skip to content

Commit

Permalink
support simple text rendering mode
Browse files Browse the repository at this point in the history
restructure the code, to make it easier to swtich between text rendering
and scene rendering modes.
  • Loading branch information
Sian Cao committed Apr 23, 2014
1 parent a12ac9a commit 5f4ffbc
Show file tree
Hide file tree
Showing 14 changed files with 520 additions and 179 deletions.
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pkg_check_modules(GLESV2 REQUIRED glesv2)
pkg_check_modules(LIBDRM REQUIRED libdrm)
pkg_check_modules(EGL REQUIRED egl)
pkg_check_modules(GBM REQUIRED gbm)
pkg_check_modules(FT2 REQUIRED freetype2)

# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
Expand All @@ -25,6 +26,7 @@ include_directories(${EGL_INCLUDE_DIRS})
include_directories(${GBM_INCLUDE_DIRS})
include_directories(${LIBDRM_INCLUDE_DIRS})
include_directories(${GLFW3_INCLUDE_DIRS})
include_directories(${FT2_INCLUDE_DIRS})


configure_file(${PROJECT_SOURCE_DIR}/config.h.in ${PROJECT_BINARY_DIR}/config.h)
Expand All @@ -34,4 +36,4 @@ file(GLOB SRCS "${PROJECT_SOURCE_DIR}/*.cc")
add_executable(${target} ${SRCS})

target_link_libraries(${target} ${GLESV2_LIBRARIES} ${EGL_LIBRARIES}
${GBM_LIBRARIES} ${LIBDRM_LIBRARIES})
${GBM_LIBRARIES} ${LIBDRM_LIBRARIES} ${FT2_LIBRARIES})
19 changes: 19 additions & 0 deletions actionmode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifndef _ACTION_MODE_H
#define _ACTION_MODE_H

#include "glutil.h"

class ActionMode {
public:
virtual bool init(int width, int height) = 0;
virtual void deinit() = 0;
virtual void render() = 0;
GLProcess& process() { return _proc; }

protected:
struct GLProcess _proc;
int _screenWidth;
int _screenHeight;
};

#endif
184 changes: 184 additions & 0 deletions atlas.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "glutil.h"
#include "atlas.h"

#include <fstream>
#include <iostream>
#include <cstdlib>

#include <sys/time.h>

using namespace std;

static FT_Library ft;
static FT_Face face;
static GLuint tex;

static void init_ft()
{
if (FT_Init_FreeType(&ft)) {
std::cerr << "init freetype failed" << std::endl;
exit(-1);
}

if (FT_New_Face(ft, "/usr/share/fonts/microsoft/msyh.ttf", 0, &face)) {
std::cerr << "load face failed" << std::endl;
exit(-1);
}
}

void TextMode::create_atlas(FT_Face face, int pointSize)
{
FT_Set_Pixel_Sizes(face, 0, pointSize);
_atlas.point_size = pointSize;
FT_GlyphSlot slot = face->glyph;
for (unsigned char i = 32; i < 128; i++) {
if (FT_Load_Char(face, (char)i, FT_LOAD_RENDER)) {
std::cerr << "load " << i << " failed\n";
continue;
}

_atlas.infos[i] = {
(float)slot->bitmap_left, (float)slot->bitmap_top,
(float)slot->bitmap.width, (float)slot->bitmap.rows,
float(slot->advance.x >> 6), float(slot->advance.y >> 6),
_atlas.width
};

_atlas.height = std::max(_atlas.height, _atlas.infos[i].height);
_atlas.width += _atlas.infos[i].width + 10;
}

//NOTE: transparent and `+10` above are anti rendering artifacts.
//since two chars in texture are close enough to blur each other's border.
GLubyte transparent[(int)_atlas.width * (int)_atlas.height];
memset(transparent, 0, sizeof transparent);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, _atlas.width, _atlas.height,
0, GL_ALPHA, GL_UNSIGNED_BYTE, transparent);

for (unsigned char i = 32; i < 128; i++) {
if (FT_Load_Char(face, (char)i, FT_LOAD_RENDER)) {
std::cerr << "load " << i << " failed\n";
continue;
}
glTexSubImage2D(GL_TEXTURE_2D, 0, _atlas.infos[i].offset, 0, _atlas.infos[i].width,
_atlas.infos[i].height, GL_ALPHA, GL_UNSIGNED_BYTE, slot->bitmap.buffer);
}
}

void TextMode::render_text(const char *text, float x, float y, float sx, float sy)
{
int len = strlen(text);

struct point_t {
GLfloat x, y, s, t;
} points[6 * len];

for (int i = 0; i < len; ++i) {
int c = text[i];
GLfloat x0 = x + _atlas.infos[c].left * sx;
GLfloat y0 = y + _atlas.infos[c].top * sy;
GLfloat w = _atlas.infos[c].width * sx, h = _atlas.infos[c].height * sy;

float tw = _atlas.infos[c].width / _atlas.width;
float tx = _atlas.infos[c].offset / _atlas.width;
float ty = _atlas.infos[c].height / _atlas.height;

int p = i * 6;
points[p++] = {x0, y0, tx, 0,};
points[p++] = {x0 + w, y0, tx + tw, 0,};
points[p++] = {x0, y0 - h, tx, ty,};

points[p++] = {x0, y0 - h, tx, ty,};
points[p++] = {x0 + w, y0, tx + tw, 0,};
points[p++] = {x0 + w, y0 - h, tx + tw, ty,};

x += _atlas.infos[c].ax * sx;
y += _atlas.infos[c].ay * sy;
}

glBindBuffer(GL_ARRAY_BUFFER, _proc.vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof points, points, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLES, 0, len * 6);

}

static timeval tv_start = {0, 0};

bool TextMode::init(int width, int height)
{
_screenWidth = width, _screenHeight = height;
init_ft();
GLProcess* proc = glprocess_create("atlas_vertex.glsl", "atlas_frag.glsl");
if (!proc) return false;
_proc = *proc;
GLuint program = _proc.program;
glUseProgram(program);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glGenBuffers(1, &_proc.vbo);
glBindBuffer(GL_ARRAY_BUFFER, _proc.vbo);

GLint pos_attrib = glGetAttribLocation(program, "position");
glEnableVertexAttribArray(pos_attrib);
glVertexAttribPointer(pos_attrib, 4, GL_FLOAT, GL_FALSE, 0, NULL);

glGenTextures(1, &tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(glGetUniformLocation(program, "tex"), 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

create_atlas(face, 28);

glClearColor(1.0, 1.0, 1.0, 1.0);
return true;
}

void TextMode::deinit()
{
glprocess_release(&_proc);
_proc.program = 0;
//...
}

void TextMode::render()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

struct timeval tv;
gettimeofday(&tv, NULL);
if (!tv_start.tv_sec) tv_start = tv;
float t = (tv.tv_sec - tv_start.tv_sec) + (tv.tv_usec - tv_start.tv_usec) / 1000000.0;

GLfloat bgcolor[] = {
float((glm::cos(t) + 1.0)/2.0), float((glm::sin(t)+1.0)/2.0), 0, 1
};
glUniform4fv(glGetUniformLocation(_proc.program, "bgcolor"), 1, bgcolor);

float ps1 = 24.0, ps2 = 38.0;
float sx = 2.0 / _screenWidth, sy = 2.0 / _screenHeight;

float x = -1.0, y = 1.0 - ps1 * sy;
render_text("this is freetype2 rendered text", x, y, sx, sy);

x = -1.0, y = 1.0 - (ps1+ps2) * sy;
render_text("this is freetype2 rendered text again", x, y, sx, sy);

GLfloat bgcolor2[] = {
0, float((glm::cos(t) + 1.0)/2.0), float((glm::sin(t)+1.0)/2.0), 0.5
};
glUniform4fv(glGetUniformLocation(_proc.program, "bgcolor"), 1, bgcolor2);
x = -1.0 + 0.002, y = 1.0 - (ps1+ps2+ps2/3) * sy;
render_text("overrided transparent line", x, y, sx, sy);
}

41 changes: 41 additions & 0 deletions atlas.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#ifndef _ATLASH_H
#define _ATLASH_H

#include "glutil.h"
#include "actionmode.h"

#include <freetype2/ft2build.h>
#include FT_FREETYPE_H


struct char_info_t {
float left, top;
float width, height;
float ax, ay; //advanced
float offset; // horizontal offset inside atlas
};

struct atlas_t {
float width, height;
struct char_info_t infos[128];
int point_size;
};

struct text_mode_t {
struct atlas_t atlas;
GLProcess proc;
};

class TextMode: public ActionMode {
public:
bool init(int width, int height);
void deinit();
void render();

private:
atlas_t _atlas;
void create_atlas(FT_Face face, int pointSize);
void render_text(const char *text, float x, float y, float sx, float sy);
};

#endif
10 changes: 10 additions & 0 deletions atlas_frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
precision mediump float;
uniform vec4 bgcolor;
uniform sampler2D tex;

varying vec2 texcoord;

void main()
{
gl_FragColor = vec4(1.0, 1.0, 1.0, texture2D(tex, texcoord).a) * bgcolor;
}
7 changes: 7 additions & 0 deletions atlas_vertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
attribute vec4 position;
varying vec2 texcoord;

void main() {
gl_Position = vec4(position.xy, 0.0, 1.0);
texcoord = position.zw;
}
Loading

0 comments on commit 5f4ffbc

Please sign in to comment.