I want to render text in LWJGL by using modern OpenGL (rendering with VBO and shader) but I have no idea how to do it.
Here is an approach:
class CharCoords {
public int x, y, width, height;
}
(0,0), (0,1), (1,0), (1,1)
#version 120
uniform mat4 PVMmat; // The projection-view-model matrix
uniform vec4 charCoords; // The CharCoord struct for the character you are rendering, {x, y, w, h}
uniform float texSize; // The size of the texture which contains the rasterized characters (assuming it is square)
uniform vec2 offset; // The offset at which to paint, w.r.t the first character
attribute vec2 vertex;
varying vec2 tc;
void main(){
// Transform from absolute texture coordinates to normalized texture coordinates
// This works because the rectangle spans [0,1] x [0,1]
// Depending on where the origin lies in your texture (i.e. topleft or bottom left corner), you need to replace "1. - vertex.y" with just "vertex.y"
tc = (charCoords.xy + charCoords.zw * vec2(vertex.x, 1. - vertex.y)) / texSize;
// Map the vertices of the unit square to a rectangle with correct aspect ratio and positioned at the correct offset
float x = (charCoords[2] * vertex.x + offset.x) / charCoords[3];
float y = vertex.y + offset.y / charCoords[3];
// Apply the model, view and projection transformations
gl_Position = PVMmat * vec4(x, y, 0., 1.);
}
#version 120
uniform vec4 color;
uniform sampler2D tex;
varying vec2 tc;
void main() {
gl_FragColor = color * texture2D(tex, tc);
}
public void drawString(Matrix4f PVMmat, String text, Color color, HAlign halign, VAlign valign) {
Vector2f offset = new Vector2f();
// Font alignment
if(halign == HAlign.Center){
offset.x = -(int) (0.5f * getWidth(text));
}else if(halign == HAlign.Right){
offset.x = -getWidth(text);
}
if(valign == VAlign.Middle){
offset.y = -(int) (0.5f * getHeight());
}else if(valign == VAlign.Top){
offset.y = -getHeight();
}
m_shader.bind();
m_shader.setAttributeBuffer("vertex", m_vertexBuffer, 2);
m_shader.setUniformMatrix("PVMmat", PVMmat);
m_shader.setUniformVector("color", color);
m_shader.setUniformScalar("texSize", (float)m_textureSize);
m_shader.setTexture("tex", m_fontTexture, GL11.GL_TEXTURE_2D);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, m_model.getIndexBuffer());
for(int i = 0; i < text.length(); ++i) {
CharCoords coo = m_charMap.get(text.charAt(i));
m_shader.setUniformVector("charCoords", new Vector4f(coo.x, coo.y, coo.width, coo.height));
m_shader.setUniformVector("offset", offset);
GL11.glDrawElements(GL11.GL_TRIANGLES, m_indexCount, GL11.GL_UNSIGNED_INT, 0);
offset.x += coo.width;
}
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
m_shader.unbind();
}
where the functions getHeigth
and getWidth
are:
public int getWidth(String text) {
int totalwidth = 0;
for (int i = 0; i < text.length(); i++) {
CharCoords coo = m_charMap.get(text.charAt(i));
totalwidth += coo.width;
}
return totalwidth;
}
public int getHeight() {
return m_fontMetrics.getHeight();
}