I am writing an application with OpenTK and got to the point where i want to render text. From examples i patched together a version that creates a bitmap with the characters i need, using Graphics.DrawString()
. That version works quite okay, but i am annoyed that it relies on GL.Begin(BeginMode.Quads)
and GL.End() to render the text, which is why i want to use VAOs and VBOs from now on.
I am having a problem somewhere in my program, because i always get single colored squares, where the text should appear.
What i did so far to update my functions is the following: I create the bitmap the same as before, i don't see why the problem should lie there. After that i create a list of "Char" Objects, each creating a VBO, storing the position and texture coordinates like this:
float u_step = (float)GlyphWidth / (float)TextureWidth; float v_step = (float)GlyphHeight / (float)TextureHeight; float u = (float)(character % GlyphsPerLine) * u_step; float v = (float)(character / GlyphsPerLine) * v_step; float x = -GlyphWidth / 2, y = 0; _vertices = new float[]{ x/rect.Width, -GlyphHeight/rect.Height, u, v, -x/rect.Width, -GlyphHeight/rect.Height, u + u_step, v, -x/rect.Width, y/rect.Height, u + u_step, v + v_step, x/rect.Width, -GlyphHeight/rect.Height, u, v, -x/rect.Width, y/rect.Height, u + u_step, v + v_step, x/rect.Width, y/rect.Height, u, v + v_step }; _VBO = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, _VBO); GL.BufferData<float>(BufferTarget.ArrayBuffer, (IntPtr)(sizeof(float) * _vertices.Length), _vertices, BufferUsageHint.DynamicDraw);
Next i generate a Texture, set texture0 as active and bind the Texture as TextureTarget.Texture2D. Then i load the bitmap to the texture doing the following:
_shader.Use();
_vertexLocation = _shader.GetAttribLocation("aPosition");
_texCoordLocation = _shader.GetAttribLocation("aTexCoord");
_fontTextureID = GL.GenTexture();
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, _fontTextureID);
using (var image = new Bitmap("container.png")) //_fontBitmapFilename))//
{
var data = image.LockBits(
new Rectangle(0, 0, image.Width, image.Height),
ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D,
0,
PixelInternalFormat.Rgba,
image.Width,
image.Height,
0,
OpenTK.Graphics.OpenGL.PixelFormat.Bgra,
PixelType.UnsignedByte,
data.Scan0);
}
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
I create a VAO now, bind it, and bind one VBO to it. Then i set up the VertexAttribPointers to interpret the VBO Data:
_VAO = GL.GenVertexArray(); GL.BindVertexArray(_VAO); GL.BindBuffer(BufferTarget.ArrayBuffer, _charSheet[87].VBO); GL.EnableVertexAttribArray(_vertexLocation); GL.VertexAttribPointer(_vertexLocation, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 0); GL.EnableVertexAttribArray(_texCoordLocation); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, _fontTextureID); GL.VertexAttribPointer(_texCoordLocation, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 2); GL.BindVertexArray(0); _shader.StopUse();
My Render function starts by using the shader, binding the VAO and enabling the VertexAttribArrays. Then i bind the VBO, in this function a fixed one for testing, and reuse the VertexAttribPointer functions, so that the VAO updates its data (i might also be wrong thinking so..). At the end i draw two triangles, which makes a square, where the letter should appear.
_shader.Use(); GL.BindVertexArray(_VAO); GL.EnableVertexAttribArray(_texCoordLocation); GL.EnableVertexAttribArray(_vertexLocation); GL.BindBuffer(BufferTarget.ArrayBuffer, _charSheet[87].VBO); GL.VertexAttribPointer(_vertexLocation, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 0); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, _fontTextureID); GL.VertexAttribPointer(_texCoordLocation, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 2); GL.DrawArrays(PrimitiveType.Triangles, 0, 6); GL.BindVertexArray(0); _shader.StopUse();
I do not know, where I'm doing something wrong in my program, maybe someone has a tip for me.
Vertex Shader
#version 330 core
layout(location = 0) in vec2 aPosition;
layout(location = 1) in vec2 aTexCoord;
out vec2 texCoord;
void main(void)
{
texCoord = aTexCoord;
gl_Position = vec4(aPosition, 0.0, 1.0);
}
Fragment Shader:
#version 330
out vec4 outputColor;
in vec2 texCoord;
uniform sampler2D texture0;
void main()
{
outputColor = texture(texture0, texCoord);
}