I'm going crazy trying to draw some text over an OpenGL window using OpenTK!
I followed some of the tutorials around but I can't make it work, when I enable the texture where the text is drawn, then I just have a white window and the QUAD I'm drawing for test just disappears.
If someone has the time to check the code, it is below. I can also send my test program to check it out faster. Thanks in advance for any help on this.
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using OpenTK.Graphics.OpenGL;
using System.Diagnostics;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
Bitmap textBmp;
int textTexture = -1;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
if (!glControl1.Context.IsCurrent)
{
glControl1.MakeCurrent();
}
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(0, glControl1.Width, 0, glControl1.Height, -1000, 1000);
GL.Scale(1, 1, 1);
GL.Viewport(0, 0, glControl1.Width, glControl1.Height);
GL.ClearColor(Color.White);
// Better point and line drawing
GL.Hint(HintTarget.PointSmoothHint, HintMode.Nicest);
GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha);
GL.Enable(EnableCap.PointSmooth);
GL.Enable(EnableCap.LineSmooth);
GL.Enable(EnableCap.Blend);
// Hide stuff behind in 3D
GL.Enable(EnableCap.DepthTest);
// Enable the texture
GL.Enable(EnableCap.Texture2D);
// Create Bitmap and OpenGL texture
textBmp = new Bitmap((int)glControl1.Width, (int)glControl1.Height);
textTexture = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, textTexture);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, textBmp.Width, textBmp.Height, 0,
OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
ErrorCode errorCode = GL.GetError();
Debug.Assert(errorCode == ErrorCode.NoError, "OpenTK error!");
}
private void glControl1_Paint(object sender, PaintEventArgs e)
{
ErrorCode errorCode;
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
GL.PushMatrix();
GL.Color3(Color.Black);
GL.Begin(PrimitiveType.Quads);
GL.Vertex3(10, 10, 10);
GL.Vertex3(40, 10, 10);
GL.Vertex3(40, 50, 10);
GL.Vertex3(10, 50, 10);
GL.End();
if (textBmp != null)
{
using (Graphics gfx = Graphics.FromImage(textBmp))
{
gfx.Clear(Color.Transparent);
gfx.DrawString("text", new Font("Arial", 10), Brushes.Black, new PointF(textBmp.Width / 2, textBmp.Height));
}
BitmapData data = textBmp.LockBits(new Rectangle(0, 0, textBmp.Width, textBmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, (int)glControl1.Width, (int)glControl1.Height, 0,
OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
textBmp.UnlockBits(data);
errorCode = GL.GetError();
Debug.Assert(errorCode == ErrorCode.NoError, "OpenTK error!");
GL.Begin(PrimitiveType.Quads);
GL.TexCoord2(0f, 1f); GL.Vertex2(0f, 0f);
GL.TexCoord2(1f, 1f); GL.Vertex2(1f, 0f);
GL.TexCoord2(1f, 0f); GL.Vertex2(1f, 1f);
GL.TexCoord2(0f, 0f); GL.Vertex2(0f, 1f);
GL.End();
}
errorCode = GL.GetError();
Debug.Assert(errorCode == ErrorCode.NoError, "OpenTK error!");
glControl1.SwapBuffers();
}
}
}
Ok, I finally managed to make it work.
On initialization I just did:
if (!control.Context.IsCurrent)
{
control.MakeCurrent();
}
GL.Ortho(0, controlWidth, 0, controlHeight, -1000, 1000);
GL.Scale(1, -1, 1); // I work with a top/left image and openGL is bottom/left
GL.Viewport(0, 0, controlWidth, controlHeight);
GL.ClearColor(Color.White);
GL.Hint(HintTarget.PointSmoothHint, HintMode.Nicest);
GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
GL.PolygonMode(MaterialFace.Front, PolygonMode.Line);
GL.Enable(EnableCap.PointSmooth);
GL.Enable(EnableCap.LineSmooth);
GL.Enable(EnableCap.Blend);
GL.Enable(EnableCap.DepthTest);
GL.ShadeModel(ShadingModel.Smooth);
GL.Enable(EnableCap.AutoNormal);
bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
gfx = Graphics.FromImage(bmp);
gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
texture = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, texture);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmp.Width, bmp.Height, 0,
OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
Then to write text in the bitmap:
gfx.DrawString(text, font, brush, new PointF(x, y));
And to render:
if (!control.Context.IsCurrent)
{
control.MakeCurrent();
}
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.MatrixMode(MatrixMode.Modelview);
GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, Texture);
GL.Begin(PrimitiveType.Quads);
GL.TexCoord3(0.0f, 0.0f, 0f); GL.Vertex3(0f, 0f, 0f);
GL.TexCoord3(1.0f, 0.0f, 0f); GL.Vertex3(realWidth, 0f, 0f);
GL.TexCoord3(1.0f, 1.0f, 0f); GL.Vertex3(realWidth, realHeight, 0f);
GL.TexCoord3(0.0f, 1.0f, 0f); GL.Vertex3(0f, realHeight, 0f);
GL.End();
GL.Disable(EnableCap.Texture2D);
control.SwapBuffers();
That did the trick.
Very important (at least I think it is):
- the GL.Enable(EnableCap.Texture2D) just before rendering the quad with the texture and GL.Disable(EnableCap.Texture2D) afterwords.
- the GL.BindTexture(TextureTarget.Texture2D, Texture) after enabling GL.Enable(EnableCap.Texture2D).
Hope this helps someone. If I manage to have some time I'll make a C# class with it and post it here.
Related
I am working on C# and using OpenTK(OpenGL wrapper) and EmguCV(OpenCV wrapper).
What I want to do is easy to understand: Grab the webcam video stream and put it on a GLControl.
I have a static class called Capturer which has a method that captures a frame and returns it as a cv::Mat wrapped object:
internal static void Initialize()
{
cap = new VideoCapture(1);
cap.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.Fps, 25);
cap.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameWidth, 1920);
cap.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameHeight, 1080);
}
internal static Mat GetCurrentFrame()
{
mat = cap.QueryFrame();
if (!mat.IsEmpty)
{
return mat;
}
return null;
}
Now in my GLControl Load event I initialize the capturer and OpenGL:
Capturer.Initialize();
GL.ClearColor(Color.Blue);
GL.Enable(EnableCap.Texture2D);
GL.Viewport(-glControl1.Width, -glControl1.Height, glControl1.Width * 2, glControl1.Height * 2);
And finally, in the GLControl Paint event:
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
Mat m = Capturer.GetCurrentFrame();
if (m != null)
{
GL.GenTextures(1, out textureId);
GL.BindTexture(TextureTarget.Texture2D, this.textureId);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (float)TextureWrapMode.Clamp);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (float)TextureWrapMode.Clamp);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, 1920, 1080, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgr, PixelType.UnsignedByte, m.DataPointer);
}
m.Dispose();
glControl1.SwapBuffers();
glControl1.Invalidate();
This is showing a full Blue screen. I think the error is on m.DataPointer.
(I have tried rendering the frames with Bitmap using the property m.Bitmapand it works but the performance is so bad.)
Drawing a rectangle bounding the GLControl solved it:
GL.Begin(PrimitiveType.Quads);
GL.TexCoord2(0, 0); GL.Vertex2(0, 0);
GL.TexCoord2(0, 1); GL.Vertex2(0, 1);
GL.TexCoord2(1, 1); GL.Vertex2(1, 1);
GL.TexCoord2(1, 0); GL.Vertex2(1, 0);
GL.End();
m.Dispose();
Be sure to dispose the object after drawing the frame so you will not run out of memory.
I'm having trouble setting up my camera in 3D space.
Here's my code:
private void SetupViewPort()
{
GL.Viewport(0, 0, glControl1.Width, glControl1.Height);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(0, 1000,0,1000, 0, 1);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
Vector3d eyePos = new Vector3d(0, 0, 1);
Vector3d point = new Vector3d(500, 500, 0.01);
Vector3d up = new Vector3d(0, 0 , 1);
Matrix4d mat = Matrix4d.LookAt(eyePos, point, up);
//mat.Invert();
GL.LoadMatrix(ref mat);
}
I'm expecting to see shapes that I've drawn onto the 2D plane. But I get a blank screen every time.
Here's the code where my shapes are drawn:
private void glControl1_Paint(object sender, PaintEventArgs e)
{
if (!loaded)
return;
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Enable(EnableCap.DepthTest);
GL.DepthMask(true);
GL.ClearDepth(1.0);
GL.Color3(Color.Yellow);
GL.Begin(PrimitiveType.Triangles);
GL.Vertex2(0, 0);
GL.Vertex2(0, 600);
GL.Vertex2(600, 600);
GL.Vertex2(100, 100);
GL.Vertex2(50, 70);
GL.Vertex2(200, 100);
GL.End();
glControl1.SwapBuffers();
}
An orthonormal projection matrix and a lookAt view matrix don't play well together. Since you are drawing 2D just leave the lookAt matrix out and use the identity matrix.
I cannot render triangles for the life of me with a VBO in OpenTK. I am loading my data to the VBO in glControl_Load() event. I get a background screen with no triangles when running. The data is a from a mesh m.OpenGLArrays(out data, out indices) outputs a list of floats and ints. The list of floats for the vertices T1v1, T1v2, T1v3, T2v1, T2v2, T2v3, .... , all three vertices for each triangle back to back.
However given a blank screen with the code when I comment the "intermediate" rendering code everything renders fine....??? What am I doing wrong?
private void glControl_Load(object sender, EventArgs e)
{
loaded = true;
glControl.MouseMove += new MouseEventHandler(glControl_MouseMove);
glControl.MouseWheel += new MouseEventHandler(glControl_MouseWheel);
GL.ClearColor(Color.DarkSlateGray);
GL.Color3(1f, 1f, 1f);
m.OpenGLArrays(out data, out indices);
this.indicesSize = (uint)indices.Length;
GL.GenBuffers(1, out VBOid[0]);
GL.GenBuffers(1, out VBOid[1]);
SetupViewport();
}
private void SetupViewport()
{
if (this.WindowState == FormWindowState.Minimized) return;
glControl.Width = this.Width - 32;
glControl.Height = this.Height - 80;
Frame_label.Location = new System.Drawing.Point(glControl.Width / 2, glControl.Height + 25);
GL.MatrixMode(MatrixMode.Projection);
//GL.LoadIdentity();
GL.Ortho(0, glControl.Width, 0, glControl.Height, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
GL.Viewport(0, 0, glControl.Width, glControl.Height); // Use all of the glControl painting area
GL.Enable(EnableCap.DepthTest);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBOid[0]);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(data.Length * sizeof(float)), data, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
float aspect_ratio = this.Width / (float)this.Height;
projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 1024);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref projection);
}
private void glControl_Paint(object sender, PaintEventArgs e)
{
if (loaded)
{
GL.Clear(ClearBufferMask.ColorBufferBit |
ClearBufferMask.DepthBufferBit |
ClearBufferMask.StencilBufferBit);
modelview = Matrix4.LookAt(0f, 0f, -200f + zoomFactor, 0, 0, 0, 0.0f, 1.0f, 0.0f);
var aspect_ratio = Width / (float)Height;
projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 512);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref projection);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadMatrix(ref modelview);
GL.Rotate(angleY, 1.0f, 0, 0);
GL.Rotate(angleX, 0, 1.0f, 0);
GL.EnableClientState(ArrayCap.VertexArray);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBOid[0]);
GL.Color3(Color.Yellow);
GL.VertexPointer(3, VertexPointerType.Float, Vector3.SizeInBytes, new IntPtr(0));
GL.DrawArrays(PrimitiveType.Triangles, 0, data.Length);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.DisableClientState(ArrayCap.VertexArray);
//GL.Color3(Color.Yellow);
//GL.PolygonMode(MaterialFace.Front, PolygonMode.Fill);
//GL.Begin(PrimitiveType.Triangles);
//for (int i = 0; i < this.md.mesh.Count; i++)
//{
// GL.Normal3(this.md.mesh[i].normal);
// GL.Vertex3(this.md.mesh[i].vertices[0]);
// GL.Vertex3(this.md.mesh[i].vertices[1]);
// GL.Vertex3(this.md.mesh[i].vertices[2]);
//}
//GL.End();
//GL.EndList();
glControl.SwapBuffers();
Frame_label.Text = "Frame: " + frameNum++;
}
}
If something doesn't seem right, then it probably isn't. I seriously questioned my understanding of opengl and spent hours looking at this. However it was just a simple error of forgetting to iterate a count variable in a for loop to transfer the mesh from one object to another. Each triangle had identical vertices! Always expect the unexpected when it comes to debugging!
Lately I have been trying to learn/use OpenGL 3+. I have looked through tutorials and examples but I've run into a wall trying to get textures and 2D projection to work without problems.
The goal for now is to have a function which can draw a textured quad to the screen with it's position specified by pixels (not [-1,1]).
For readability and testing I made a new barebones program with the knowledge I currently have, and it exhibits nearly the same problems. Help would be appreciated since i'm starting to go bald over this :(..
The current code shows a garbled texture instead of the image itself (texture is 128x128px).
[Program.cs]
namespace OpenGLTester
{
static class Program
{
public static GameWindow window;
public static String programDirectory = Directory.GetCurrentDirectory();
public static int testTexture;
public static int uniform_fragment_texture;
public static int shaderProgram;
[STAThread]
static void Main()
{
window = new GameWindow(1024, 768, new GraphicsMode(new ColorFormat(8, 8, 8, 8), 0, 8), "OpenGLTester", GameWindowFlags.Default, DisplayDevice.Default, 3, 1, GraphicsContextFlags.Default);
GL.Viewport(new Size(1024,768));
shaderProgram = GL.CreateProgram();
int vertexShader = GL.CreateShader(ShaderType.VertexShader);
int fragmentShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(vertexShader, File.ReadAllText(programDirectory + #"\vertex.vert"));
GL.ShaderSource(fragmentShader, File.ReadAllText(programDirectory + #"\fragment.frag"));
GL.CompileShader(vertexShader);
GL.CompileShader(fragmentShader);
GL.AttachShader(shaderProgram, vertexShader);
GL.AttachShader(shaderProgram, fragmentShader);
GL.LinkProgram(shaderProgram);
if (GL.GetError() != ErrorCode.NoError) { System.Diagnostics.Debugger.Break(); }
Console.WriteLine(GL.GetProgramInfoLog(shaderProgram));
GL.UseProgram(shaderProgram);
Matrix4 projectionMatrix = Matrix4.CreateOrthographic(1024, 768, 0, 1);
GL.UniformMatrix4(GL.GetUniformLocation(shaderProgram, "vertex_projection"), false, ref projectionMatrix);
uniform_fragment_texture = GL.GetUniformLocation(shaderProgram, "fragment_texture");
testTexture = loadTexture(programDirectory + #"\test.png");
GL.Disable(EnableCap.DepthTest);
GL.Disable(EnableCap.Lighting);
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha);
window.UpdateFrame += window_UpdateFrame;
window.RenderFrame += window_RenderFrame;
window.Resize += window_Resize;
window.TargetRenderFrequency = 60;
window.Run();
}
static void window_Resize(object sender, EventArgs e)
{
//Don't allow resizing for now.
window.Size = new Size(1024, 768);
}
static void window_UpdateFrame(object sender, FrameEventArgs e)
{
ErrorCode currentError = GL.GetError();
if (currentError != ErrorCode.NoError)
{
Console.WriteLine(Enum.GetName(typeof(ErrorCode), currentError));
System.Diagnostics.Debugger.Break();
}
}
static void window_RenderFrame(object sender, FrameEventArgs e)
{
GL.ClearColor(0, 0, 0, 0);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit);
//test texture is 128x128pixels.
drawTexRect(100, 228, 100, 228, testTexture);
window.SwapBuffers();
}
static int loadTexture(String filePath)
{
GL.Enable(EnableCap.Texture2D);
int id = GL.GenTexture();
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, id);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
Bitmap bmp = new Bitmap(filePath);
BitmapData bmp_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmp_data.Width, bmp_data.Height, 0,
OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, bmp_data.Scan0);
bmp.UnlockBits(bmp_data);
bmp.Dispose();
return id;
}
static void drawTexRect(float top, float bottom, float left, float right, int texture)
{
//topLeft,bottomLeft,bottomRight,topRight
float[] vertices = new float[] {
left, top, 0, 0,
left, bottom, 0, 1,
right, bottom, 1, 1,
right, top, 1, 0,
};
int buffer = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.BufferData<float>(BufferTarget.ArrayBuffer, new IntPtr(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
//vec2 - screen position
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4, 0);
//vec2 - texture coordinates
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4, 2 * sizeof(float));
GL.Enable(EnableCap.Texture2D);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, texture);
GL.Uniform1(uniform_fragment_texture, 0);
GL.DrawArrays(PrimitiveType.Quads, 0, 4);
GL.DeleteBuffer(buffer);
}
}
}
[vertex.vert]
#version 330
in vec2 vertex_position;
in vec2 vertex_texturePosition;
uniform mat4 vertex_projection;
out vec2 fragment_texturePosition;
void main()
{
gl_Position = vec4(vertex_position,0.0,1.0) * vertex_projection;
fragment_texturePosition = vertex_texturePosition;
}
[fragment.frag]
#version 330
in vec2 fragment_texturePosition;
uniform sampler2D fragment_texture;
out vec4 output_color;
void main()
{
output_color = texture(fragment_texture,fragment_texturePosition);
}
After changes suggested by #j-p one problem remains:
After texture position change suggested by #j-p:
The projection is also wrong given the position i expect it to be 100 px from the left and 100 px from the top, don't see how i can fix this..
The stride parameter is in byte:
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 0);
//vec2 - texture coordinates
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 2 * sizeof(float));
Also,the corresponding opengl pixel format for windows argb bitmap is BGRA. (link)
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,**OpenTK.Graphics.OpenGL.PixelFormat.Bgra**, PixelType.UnsignedByte, data.Scan0);
And finally, your texture coordinates should be adjusted as follow:
float[] vertices = new float[] {
left, top, 0, 1,
left, bottom, 0, 0,
right, bottom, 1, 0,
right, top, 1, 1
};
I am having issues drawing a texture onto my quad but it remains white. I have looked through a number of guides and I don't seem to be doing anything different from them.
To load the texture:
Bitmap bitmap = new Bitmap("Textures/Sprite_Can.png");
GL.GenTextures(1, out textureID);
GL.BindTexture(TextureTarget.Texture2D, textureID);
BitmapData data = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,
OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
bitmap.UnlockBits(data);
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);
Setup and apply an orthographic projection:
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(0, control.Width, 0, control.Height, -1, 1);
GL.Viewport(0, 0, control.Width, control.Height);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
GL.ClearColor(Color4.CornflowerBlue);
And finally the draw:
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.LoadIdentity();
GL.Translate(30, 30, 0);
GL.BindTexture(TextureTarget.Texture2D, textureID);
GL.Begin(BeginMode.Quads);
GL.TexCoord2(0, 0);
GL.Vertex2(-1 * width / 2, 1 * height / 2);
GL.TexCoord2(1, 0);
GL.Vertex2(1 * width / 2, 1 * height / 2);
GL.TexCoord2(1, 1);
GL.Vertex2(1 * width / 2, -1 * height / 2);
GL.TexCoord2(0, 1);
GL.Vertex2(-1 * width / 2, -1 * height / 2);
GL.End();
GL.Flush();
control.SwapBuffers();
So basically, the quad draws just fine. However, the texture is not rendered. As a result, all I have is just a white square.
In the fixed-function OpenGL pipeline, you must also Enable texture units before a texture bound to one will be applied to anything you draw.
The normal OpenGL API binding for this is glEnable (GL_TEXTURE_2D). The OpenTK equivalent would be: GL.Enable (EnableCap.Texture2D).