|
To display symbols it's first necessary to convert their internal representation into the form suitable for OpenGL.
This conversion is performed once on startup, when Draw::Ifc implementation is initialized. init_font() function in draw_simple_ogl.cpp is intended to perform this task. The function is currently empty and can be implemented like this:
static void init_font() {
Draw::Font* pFont = s_pFont;
if (pFont != nullptr) {
glGenBuffers(1, &s_fontVBO);
glGenBuffers(1, &s_fontIBO);
if (s_fontVBO && s_fontIBO) {
glBindBuffer(GL_ARRAY_BUFFER, s_fontVBO);
glBufferData(GL_ARRAY_BUFFER,
pFont->numPnts * sizeof(xt_float2),
pFont->pPnts,
GL_STATIC_DRAW
);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_fontIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
pFont->numTris * 3 * sizeof(uint16_t),
pFont->pTris,
GL_STATIC_DRAW
);
}
}
}
The entire set of symbol shapes is represented by Draw::Font structure. When init_font() is called, the pointer to this data is already assigned to static variable s_pFont. Font vertices are stored as pairs of floating-point (x, y) coordinates, represented by xt_float2 type. Triangles stored as an array of uint16_t indices. Overall Draw::Font structure is this:
// needed for initalization
pPnts -> vertex coordinates
numPnts: how many vertices
pTris -> triangles
numTris: how many triagles
// needed for drawing
pSyms -> info about individual symbols
Working with a buffer in OpenGL starts with assigning a handle (also known as "name") to it. This is done with a call to glGenBuffers. Ths function can assign several handles at once, for simplicity this implementation uses separate calls for VB (stored in s_fontVBO) and IB (s_fontIBO). Such named entities are commonly known as Buffer Objects, hence VBO for VB, IBO for IB. To populate a buffer with data, it must first be activated at a particular binding point, by calling glBindBuffer. For VB the binding point is GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER for IB. glBufferData is then used to transfer font geometry to GL-accessible memory. GL_STATIC_DRAW specifies here that this data will be created once and then used without modifications. TODO: !! -> VS !!
symbol.vert
attribute vec2 vtx_pos;
uniform vec4 prm_xform;
void main() {
vec2 pos = vtx_pos;
vec2 offs = prm_xform.xy;
vec2 scl = prm_xform.zw;
pos *= scl;
pos += offs;
gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);
}
TODO: !! Explain vtx_pos, prm_xform !!
draw_simple_ogl.cpp
void symbol_impl(const Draw::Symbol* pSym) {
Draw::Font* pFont = s_pFont;
GPUProgram* pProg = &s_progSymbol;
if (pFont != nullptr && pSym && pProg->is_valid()) {
int sym = pSym->sym;
Draw::Font::SymInfo* pInfo = &pFont->pSyms[sym];
/* set geometry buffers and vertex description */
glBindBuffer(GL_ARRAY_BUFFER, s_fontVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_fontIBO);
pProg->enable_vertex_vec2("vtx_pos", sizeof(xt_float2), 0);
/* set parameters */
float ox = pSym->ox*2.0f - 1.0f;
float oy = pSym->oy*2.0f - 1.0f;
float sx = pSym->sx*2.0f;
float sy = pSym->sy*2.0f;
pProg->set_vector("prm_xform", ox, oy, sx, sy);
pProg->draw_triangles(pInfo->numTris, pInfo->idxOrg);
pProg->disable_vertex_inputs();
}
}
TODO: !! enable_vertex_*, set_vector !!
./run.sh -draw:simple_ogl
symbol.frag
uniform vec4 prm_color;
void main() {
gl_FragColor = prm_color;
}
draw_simple_ogl.cpp
void symbol_impl(const Draw::Symbol* pSym) {
Draw::Font* pFont = s_pFont;
GPUProgram* pProg = &s_progSymbol;
if (pFont != nullptr && pSym && pProg->is_valid()) {
int sym = pSym->sym;
Draw::Font::SymInfo* pInfo = &pFont->pSyms[sym];
/* set rendering options */
/* enable semi-transparency */
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* backface culling, frontfacing triangles defined clockwise */
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CW);
/* disable depth-buffer */
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
/* set geometry buffers and vertex description */
glBindBuffer(GL_ARRAY_BUFFER, s_fontVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_fontIBO);
pProg->enable_vertex_vec2("vtx_pos", sizeof(xt_float2), 0);
/* set parameters */
float ox = pSym->ox*2.0f - 1.0f;
float oy = pSym->oy*2.0f - 1.0f;
float sx = pSym->sx*2.0f;
float sy = pSym->sy*2.0f;
pProg->set_vector("prm_xform", ox, oy, sx, sy);
pProg->set_color("prm_color", pSym->clr);
pProg->draw_triangles(pInfo->numTris, pInfo->idxOrg);
pProg->disable_vertex_inputs();
}
}
./run.sh -draw:simple_ogl
|