this is an example of drawing 2d text as set of 2d textured images (that you load each texture for each character)
struct TFontChar
{
int id;
AnsiString txt;
AnsiString FontName;
TGLTexture texture;
};
struct TFontVertex
{
t3dpoint<float> v;
textpoint t;
};
struct TFont
{
TFont()
{
initialized = false;
font_color = vec3(0.0, 1.0, 0.0);
}
~TFont()
{
if(initialized)
{
glDeleteBuffers(1, &alphabet_vbuffer);
delete FONT_SHADER;
delete FONT_EVENT_SHADER;
}
}
AnsiString chartable;
TFontChar * Alphabet;
TFontVertex * FONT_VERTEX_BUFFER;
TShaderObject * FONT_SHADER;
TShaderObject * FONT_EVENT_SHADER;
bool initialized;
vec3 font_color;
unsigned int alphabet_vbuffer;
float sw,sh;
void initialize_char_table(AnsiString FONT_DIR, float asw, float ash, AnsiString appdir) //additionally load default font for debugging
{
sw=asw;
sh=ash;
CAN_LOG = true;
FONT_SHADER = new TShaderObject();
FONT_SHADER->LoadShaderProgram(appdir+"shaders/fonts/base_font_vp.shader",appdir+"shaders/fonts/base_font_fp.shader");
FONT_EVENT_SHADER = new TShaderObject();
FONT_EVENT_SHADER->LoadShaderProgram(appdir+"shaders/fonts/event_font_vp.shader",appdir+"shaders/fonts/event_font_fp.shader");
chartable = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-+.,=:{}()[]/*;!<>_?";
int x = chartable.length();
Alphabet = new TFontChar[ x ];
// ALOG("alphabet length: "+IntToStr(x));
for (int i=0; i < chartable.length(); i++)
{
//ALOG("FONT INDEX: "+IntToStr(i));
Alphabet[i].texture.px_height = 32;
Alphabet[i].texture.px_width = 32;
Alphabet[i].texture.LoadTGA(appdir+FONT_DIR+IntToStr(i)+".tga");
Alphabet[i].txt = chartable[i];
}
FONT_VERTEX_BUFFER = new TFontVertex[ 256*4 ]; //max 256 chars...
for (int i=0; i < 256; i++)
{
FONT_VERTEX_BUFFER[i*4+0].t = textpoint(0.0, 0.0);
FONT_VERTEX_BUFFER[i*4+0].v = t3dpoint<float>(0.0+i*18.0, 0.0, 0.0);
FONT_VERTEX_BUFFER[i*4+1].t = textpoint(1.0, 0.0);
FONT_VERTEX_BUFFER[i*4+1].v = t3dpoint<float>(0.0+i*18.0+18.0, 0.0, 0.0);
FONT_VERTEX_BUFFER[i*4+2].t = textpoint(1.0, 1.0);
FONT_VERTEX_BUFFER[i*4+2].v = t3dpoint<float>(0.0+i*18.0+18.0, 0.0 + 18.0, 0.0);
FONT_VERTEX_BUFFER[i*4+3].t = textpoint(0.0, 1.0);
FONT_VERTEX_BUFFER[i*4+3].v = t3dpoint<float>(0.0, 0.0 + 18.0, 0.0);
}
glGenBuffers(1, &alphabet_vbuffer);
glBindBuffer(GL_ARRAY_BUFFER, alphabet_vbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(TFontVertex) * 256 * 4, FONT_VERTEX_BUFFER, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
ALOG("DONE WITH LOADING FONT");
initialized = true;
}
int find_index(char txt)
{
for (int i=0; i < chartable.length(); i++)
{
if (Alphabet[i].txt[0] == txt) return i;
}
return 1;
}
void DrawEventText(float x, float y, float size, vec3 color, float alpha, AnsiString text);
void DrawText(float x, float y, float size, AnsiString atext, vec3 color)
{
glActiveTexture(GL_TEXTURE0);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
AnsiString text = UpperCase(atext);
//lets assume we draw from left top corner of text
for (int i=0; i < 256; i++)
{
FONT_VERTEX_BUFFER[i*4+0].t = textpoint(0.0, 0.0);
FONT_VERTEX_BUFFER[i*4+0].v = t3dpoint<float>(x+i*size, y, 0.0);
FONT_VERTEX_BUFFER[i*4+1].t = textpoint(1.0, 0.0);
FONT_VERTEX_BUFFER[i*4+1].v = t3dpoint<float>(x+i*size+size, y, 0.0);
FONT_VERTEX_BUFFER[i*4+2].t = textpoint(1.0, 1.0);
FONT_VERTEX_BUFFER[i*4+2].v = t3dpoint<float>(x+i*size+size, y + size, 0.0);
FONT_VERTEX_BUFFER[i*4+3].t = textpoint(0.0, 1.0);
FONT_VERTEX_BUFFER[i*4+3].v = t3dpoint<float>(x+i*size, y + size, 0.0);
}
glBindBuffer(GL_ARRAY_BUFFER, alphabet_vbuffer);
glBufferSubData(GL_ARRAY_BUFFER,0, sizeof(TFontVertex) * 256 * 4, FONT_VERTEX_BUFFER);
FONT_SHADER->Enable();
FONT_SHADER->Send1I(glGetUniformLocation(FONT_SHADER->gProgram, "font_tex"), 0 );
FONT_SHADER->Send3F(glGetUniformLocation(FONT_SHADER->gProgram, "FONT_COLOR"), color );
FONT_SHADER->Send1F(glGetUniformLocation(FONT_SHADER->gProgram, "sh"), sh );
FONT_SHADER->Send1F(glGetUniformLocation(FONT_SHADER->gProgram, "sw"), sw );
glVertexAttribPointer(FONT_SHADER->vertex_pos, 3, GL_FLOAT, GL_FALSE, sizeof(TFontVertex), (void*)(offsetof(struct TFontVertex, v)));
glVertexAttribPointer(FONT_SHADER->texture_coord, 2, GL_FLOAT, GL_FALSE, sizeof(TFontVertex), (void*)(offsetof(struct TFontVertex, t)));
glEnableVertexAttribArray(FONT_SHADER->vertex_pos);
glEnableVertexAttribArray(FONT_SHADER->texture_coord);
for (int i=0; i < text.length(); i++)
{
int index = find_index(text[i]);
glBindTexture(GL_TEXTURE_2D, Alphabet[ index ].texture.texture);
glDrawArrays(GL_TRIANGLE_FAN, i*4 , 4);
}
glDisableVertexAttribArray(FONT_SHADER->vertex_pos);
glDisableVertexAttribArray(FONT_SHADER->texture_coord);
FONT_SHADER->Disable();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
}
void DrawText(float x, float y, float size, AnsiString atext)
{
DrawText(x, y, size, atext, font_color);
}
};
fragment shader
uniform sampler2D font_tex;
varying vec2 texcoord;
uniform vec3 FONT_COLOR;
void main()
{
vec3 color = texture2D( font_tex, texcoord ).rgb;
float intensity = 0.0;
if (color.x > 0.5)
intensity = 0.0;
else
intensity = 1.0;
gl_FragColor = vec4(FONT_COLOR, intensity);
}
vertex shader
attribute vec3 Vpos;
attribute vec2 Vtexcoord;
varying vec2 texcoord;
uniform float sw;
uniform float sh;
void main()
{
float x = -1.0 + (Vpos.x / sw) * 2.0;
float y = -1.0 + (Vpos.y / sh) * 2.0;
texcoord = Vtexcoord;
gl_Position = vec4(vec2(x,y), 0.0, 1.0);
}
Important thing here is that you can define image left, top, width and height in lets say pixels (knowing opengl window size)
so you just draw a quad for (one image) that is lets say at top left corner of ogl window:
in fragment shader you calculate on screen coordinate (Vpos is vertex position, sw ogl window width, sh ogl window height)
float x = -1.0 + (Vpos.x / sw) * 2.0;
float y = -1.0 + (Vpos.y / sh) * 2.0;
since screen coordinate in ogl is from -1..1 you will put exactly sized image whereever you want