Related
I want to draw multiple images in to framebuffer and then also draw framebuffer on screen.
I also want to ReadPixels from frame buffer to store image on disk.
Is there some tutorial or example how to use framebuffer in OpenTK.
I found one example but is not in C# openTK
https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/minimalfbo/minimalfbo.c
Currently my code crashes application, and the ReadPixels returns an empty image.
namespace test
{
class Class1
{
int FramebufferName = -1;
int depthrenderbuffer;
int fbo_width = 0;
int fbo_height = 0;
public bool createImage = false;
DirectBitmap masterBitmap = null;
object masterBitmapSync = new object();
public int renderedTexture = 0;
public override void OnRender()
{
//https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/minimalfbo/minimalfbo.c
calculateMasterBitmapSize();
#region init
if (FramebufferName == -1)
{
//do this only once
//Framebuffer
GL.GenFramebuffers(1, out FramebufferName);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, FramebufferName);
checkGlError();
//Color renderbuffer.
lock (masterBitmapSync)
{
if (masterBitmap != null)
createTexture();
}
if (renderedTexture <= 0 || FramebufferName < 0)
{
Console.WriteLine("ERROR:");
}
checkGlError();
GL.BindTexture(TextureTarget.Texture2D, renderedTexture);
checkGlError();
//GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderedTexture);
//checkGlError();
/* Storage must be one of: */
/* GL_RGBA4, GL_RGB565, GL_RGB5_A1, GL_DEPTH_COMPONENT16, GL_STENCIL_INDEX8. */
//GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthComponent16, fbo_width, fbo_height);
//checkGlError();
//GL.FramebufferRenderbuffer(FramebufferTarget.DrawFramebuffer, FramebufferAttachment.ColorAttachment0, RenderbufferTarget.Renderbuffer, renderedTexture);
//checkGlError();
/* Depth renderbuffer. */
GL.GenRenderbuffers(1, out depthrenderbuffer);
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depthrenderbuffer);
GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthComponent16, fbo_width, fbo_height);
GL.FramebufferRenderbuffer(FramebufferTarget.DrawFramebuffer, FramebufferAttachment.DepthAttachment, RenderbufferTarget.Renderbuffer, depthrenderbuffer);
checkGlError();
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
checkGlError();
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, fbo_width, fbo_height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.FramebufferTexture2D(FramebufferTarget.DrawFramebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, renderedTexture, 0); //original texture 1280x720
checkGlError();
FramebufferErrorCode errorCode = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
if (errorCode != FramebufferErrorCode.FramebufferComplete)
{
if (errorCode == FramebufferErrorCode.FramebufferUnsupported)
Console.WriteLine("FramebufferUnsupported");
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
GL.DeleteFramebuffers(1, ref FramebufferName);
GL.DeleteFramebuffers(1, ref depthrenderbuffer);
return;
}
checkGlError();
}
#endregion
#region drawInFramebuffer
checkGlError();
lock (masterBitmapSync)
{
if (masterBitmap != null)
createTexture();
}
checkGlError();
GL.BindTexture(TextureTarget.Texture2D, 0);
GL.Enable(EnableCap.Texture2D);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, FramebufferName);
checkGlError();
//GL.ColorMask(true, true, true, true);
GL.ClearColor(0, 0, 0, 0);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
checkGlError();
GL.Enable(EnableCap.Texture2D);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, renderedTexture);
checkGlError();
GL.Begin(PrimitiveType.Quads);
{
GL.TexCoord2(0.0f, 0.0f); GL.Vertex2(LocalPoints[0].X, LocalPoints[0].Y);
GL.TexCoord2(1.0f, 0.0f); GL.Vertex2(LocalPoints[1].X, LocalPoints[1].Y);
GL.TexCoord2(1.0f, 1.0f); GL.Vertex2(LocalPoints[2].X, LocalPoints[2].Y);
GL.TexCoord2(0.0f, 1.0f); GL.Vertex2(LocalPoints[3].X, LocalPoints[3].Y);
}
GL.End();
GL.Disable(EnableCap.Texture2D);
//TODO draw multipla images
//loop over all images and calling OnRender2()
if (createImage)
{
createImage = false;
GPoint p = new GPoint(0, 0); //TODO get correct x,y
using (Bitmap bitmap = new Bitmap(fbo_width, fbo_height))
{
BitmapData bits = bitmap.LockBits(new Rectangle(0, 0, fbo_width, fbo_height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
checkGlError();
GL.ReadPixels((int)p.X, (int)p.Y, fbo_width, fbo_height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bits.Scan0);
checkGlError();
bitmap.UnlockBits(bits);
bitmap.RotateFlip(RotateFlipType.Rotate180FlipX);
bitmap.Save(#"c:\Downloads\aaa\ReadPixels_" + DateTime.Now.ToString("HHmmss_fff") + ".png", ImageFormat.Png);
}
}
checkGlError();
//does command in next line, draw framebuffer on the screen?
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); //would draw to the default framebuffer again, basically finishing the drawing to the other framebuffer(the backbuffer which will be brought to front by SwapBuffers)
checkGlError();
#endregion
}
private void calculateMasterBitmapSize()
{
//for test example
fbo_width = 256;
fbo_height = 256 * 2;
DirectBitmap newBitmap = new DirectBitmap(fbo_width, fbo_height);
newBitmap.Bitmap.MakeTransparent();
setBitmap(newBitmap);
}
public void setBitmap(DirectBitmap bmp)
{
lock (masterBitmapSync)
{
if (masterBitmap != null)
masterBitmap.Dispose();
masterBitmap = bmp;
if (masterBitmap == null)
deleteTexture();
}
}
void deleteTexture()
{
if (renderedTexture > 0)
{
GL.DeleteTexture(renderedTexture);
renderedTexture = 0;
}
}
public void createTexture()
{
if (masterBitmap == null)
return;
int t = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, t);
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.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, masterBitmap.Width, masterBitmap.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
Rectangle rect = new Rectangle(0, 0, masterBitmap.Width, masterBitmap.Height);
System.Drawing.Imaging.BitmapData data = masterBitmap.Bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.BindTexture(TextureTarget.Texture2D, t);
GL.TexSubImage2D(TextureTarget.Texture2D, 0, rect.X, rect.Y, rect.Width, rect.Height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
masterBitmap.Bitmap.UnlockBits(data);
masterBitmap.Dispose();
masterBitmap = null;
if (renderedTexture > 0)
GL.DeleteTexture(renderedTexture);
renderedTexture = t;
}
private void checkGlError()
{
ErrorCode errorCode = GL.GetError();
if (errorCode != ErrorCode.NoError)
{
Console.WriteLine("ERROR: " + errorCode);
}
}
public void OnRender2()
{
/*
//this is example only
lock (bitmapSync)
{
if (bitmap != null)
createTexture();
}
GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, texture);
GL.Begin(PrimitiveType.Quads);
{
GL.TexCoord4(texCoords[0]); GL.Vertex4(LocalPoints[0].X, LocalPoints[0].Y, 1, 1); //UL
GL.TexCoord4(texCoords[1]); GL.Vertex4(LocalPoints[1].X, LocalPoints[1].Y, 1, 1); //UR
GL.TexCoord4(texCoords[2]); GL.Vertex4(LocalPoints[2].X, LocalPoints[2].Y, 1, 1); //LR
GL.TexCoord4(texCoords[3]); GL.Vertex4(LocalPoints[3].X, LocalPoints[3].Y, 1, 1); //LL
}
GL.End();
GL.Disable(EnableCap.Texture2D);
*/
}
}
}
"framebuffer" usually means memory on the graphics device used for final output to the screen. This is typically tricky to access from c#.
If you simply want to combine multiple images, and do not have any strict performance requirements, it would be much simpler to use a regular buffer to do the combining and then draw this buffer to the screen. The oldschool way to do this is to use a GDI graphics object to do the drawing.
An example using GDI & winforms
public class BitmapPaint : Control
{
private Bitmap buffer;
public BitmapPaint()
{
// Find out how large you want the output image to be
// This example does not handle disposal or resizing etc
buffer = new Bitmap(this.Width, this.Height);
}
public void Compose(IEnumerable<Bitmap> images)
{
using (var g = Graphics.FromImage(buffer))
{
foreach (var img in images)
{
// Adjust position etc if you need to
g.DrawImageUnscaled(img, 0, 0);
}
}
buffer.Save(#"c:\myFilename.bmp");
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Draw the buffer to the screen
e.Graphics.DrawImageUnscaled(buffer, 0, 0);
}
}
If you want higher performance it might be more appropriate to look for something like a 2D game engine that can manage the blitting and much more internally. Doing low level buffer manipulation is not a great fit for .Net since it typically involves raw pointers and resource management that is often easier to manage in C/C++.
I'm completely new to openGL.
I have to show two images side by side using shader code.
It shows properly using below code. But throws an
out of memory
exception and the entire system gets hangs.
Can you please check my code to see what might be the cause?
I think the problem is that I'm not properly deallocating memory from openTK textures after I don't need them, so I'm generating massive amounts of images, but I don't know how to fix this.
public partial class Form7ImageOnly : Form
{
string file = "opentksquare.png";
string file1 = "img_smile.png";
int program;
int vertShader;
int fragShader;
int buffer;
int positionLocation;
int positionLocation1;
int positionLocation2;
int texture;
int texture1;
int ScreenWidth;
int ScreenHeight;
float[] vertices = {
// Left bottom triangle
-1f, -1f, 0f,
1f, -1f, 0f,
1f, 1f, 0f,
// Right top triangle
1f, 1f, 0f,
-1f, 1f, 0f,
-1f, -1f, 0f
};
public Form7ImageOnly()
{
InitializeComponent();
}
private void Form7ImageOnly_Load(object sender, EventArgs e)
{
glControl.Resize += new EventHandler(glControl_Resize);
glControl.Paint += new PaintEventHandler(glControl_Paint);
GL.Enable(EnableCap.DepthTest);
Application.Idle += Application_Idle;
glControl_Resize(glControl, EventArgs.Empty);
}
void Application_Idle(object sender, EventArgs e)
{
while (glControl.IsIdle)
{
Render();
}
}
private void Render()
{
ScreenWidth = Screen.PrimaryScreen.Bounds.Width;
ScreenHeight = Screen.PrimaryScreen.Bounds.Height;
glControl.Size = new System.Drawing.Size(ScreenWidth, ScreenHeight);//full screen
texture = LoadTexture(file);
texture1 = LoadTexture(file1);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
DrawImage(texture,texture1);
}
private void glControl_Paint(object sender, PaintEventArgs e)
{
Render();
}
private void glControl_Resize(object sender, EventArgs e)
{
Init();
}
private void Init()
{
CreateShaders();
CreateProgram();
InitBuffers();
}
public void DrawImage(int image,int image1)
{
GL.Viewport(new Rectangle(0, 0, ScreenWidth, ScreenHeight));
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadIdentity();
GL.Disable(EnableCap.Lighting);
GL.Enable(EnableCap.Texture2D);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, image);
GL.Uniform1(positionLocation1, 0);
GL.ActiveTexture(TextureUnit.Texture1);
GL.BindTexture(TextureTarget.Texture2D, image1);
GL.Uniform1(positionLocation2, 1);
RunShaders();
//GL.Begin(PrimitiveType.Quads);
//GL.TexCoord2(0, 1);
//GL.Vertex3(0, 0, 0);
//GL.TexCoord2(1, 1);
//GL.Vertex3(1920, 0, 0);
//GL.TexCoord2(1, 0);
//GL.Vertex3(1920, 1080, 0);
//GL.TexCoord2(0, 0);
//GL.Vertex3(0, 1080, 0);
//GL.End();
GL.Disable(EnableCap.Texture2D);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Modelview);
ErrorCode ec = GL.GetError();
if (ec != 0)
System.Console.WriteLine(ec.ToString());
Console.Read();
glControl.SwapBuffers();
}
private void RunShaders()
{
GL.ClearColor(Color.Violet);
GL.UseProgram(program);
GL.DrawArrays(PrimitiveType.Triangles, 0, vertices.Length / 3);
ErrorCode ec = GL.GetError();
if (ec != 0)
System.Console.WriteLine(ec.ToString());
Console.Read();
}
private void CreateProgram()
{
program = GL.CreateProgram();
GL.AttachShader(program, vertShader);
GL.AttachShader(program, fragShader);
GL.LinkProgram(program);
}
private void CreateShaders()
{
/***********Vert Shader********************/
vertShader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertShader, #"attribute vec3 a_position;
varying vec2 vTexCoord;
void main() {
vTexCoord = (a_position.xy + 1) / 2;
gl_Position = vec4(a_position, 1);
}");
GL.CompileShader(vertShader);
/***********Frag Shader ****************/
fragShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragShader, #"precision highp float;
uniform sampler2D sTexture;uniform sampler2D sTexture1;
uniform int screenwidth;
varying vec2 vTexCoord;
void main ()
{
if ( vTexCoord.x<0.5 )
gl_FragColor = texture2D (sTexture, vec2(vTexCoord.x*2.0, vTexCoord.y));
else
gl_FragColor = texture2D (sTexture1, vec2(1.0- (vTexCoord.x*2.0-1.0), vTexCoord.y));
}");
GL.CompileShader(fragShader);
}
private void InitBuffers()
{
buffer = GL.GenBuffer();
positionLocation = GL.GetAttribLocation(program, "a_position");
positionLocation1 = GL.GetUniformLocation(program, "sTexture");
positionLocation2 = GL.GetUniformLocation(program, "sTexture1");
GL.EnableVertexAttribArray(positionLocation);
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(positionLocation, 3, VertexAttribPointerType.Float, false, 0,0);
}
public int LoadTexture(string file)
{
Bitmap bitmap = new Bitmap(file);
int tex = -1;
if (bitmap != null)
{
GL.DeleteTextures(1, ref tex);
GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
GL.GenTextures(1, out tex);
GL.BindTexture(TextureTarget.Texture2D, tex);
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
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.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
}
return tex;
}
}
I'm completely new to opengl. I have created a shader code for displaying an image(file1) by replacing it's dark area to red color. It is working with below code.
Not sure even this code are written properly.
Now I want to show two images (file1,file2) side by side on same openGL with same condition on shader code. For that I have to create multitexturing. How can I achieve it? What changes should made on below code?
public partial class Form7ImageOnly : Form
{
Bitmap FrameData;
bool loaded = false;
string file1 = "penguine.png";
string file2 = "dove.png";
int program;
int vertShader;
int fragShader;
int buffer;
int positionLocation;
int texture;
int ScreenWidth;
int ScreenHeight;
float[] vertices = {
// Left bottom triangle
-1f, -1f, 0f,
1f, -1f, 0f,
1f, 1f, 0f,
// Right top triangle
1f, 1f, 0f,
-1f, 1f, 0f,
-1f, -1f, 0f
};
public Form7ImageOnly()
{
InitializeComponent();
}
private void Form7ImageOnly_Load(object sender, EventArgs e)
{
glControl.Resize += new EventHandler(glControl_Resize);
glControl.Paint += new PaintEventHandler(glControl_Paint);
GL.ClearColor(Color.Yellow);
GL.Enable(EnableCap.DepthTest);
Application.Idle += Application_Idle;
// Ensure that the viewport and projection matrix are set correctly.
glControl_Resize(glControl, EventArgs.Empty);
}
void Application_Idle(object sender, EventArgs e)
{
while (glControl.IsIdle)
{
Render();
}
}
private void Render()
{
ScreenWidth = Screen.PrimaryScreen.Bounds.Width;
ScreenHeight = Screen.PrimaryScreen.Bounds.Height;
glControl.Size = new System.Drawing.Size(ScreenWidth, ScreenHeight);
texture = LoadTexture(file);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
DrawImage(texture);
}
private void glControl_Paint(object sender, PaintEventArgs e)
{
Render();
}
private void glControl_Resize(object sender, EventArgs e)
{
Init();
}
private void Init()
{
CreateShaders();
CreateProgram();
InitBuffers();
}
public void DrawImage(int image)
{
GL.Viewport(new Rectangle(0, 0, ScreenWidth, ScreenHeight));
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
//GL.Ortho(0, 1920, 0, 1080, 0, 1);
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadIdentity();
GL.Disable(EnableCap.Lighting);
GL.Enable(EnableCap.Texture2D);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, image);
//GL.Begin(PrimitiveType.Quads);
//GL.TexCoord2(0, 1);
//GL.Vertex3(0, 0, 0);
//GL.TexCoord2(1, 1);
//GL.Vertex3(1920, 0, 0);
//GL.TexCoord2(1, 0);
//GL.Vertex3(1920, 1080, 0);
//GL.TexCoord2(0, 0);
//GL.Vertex3(0, 1080, 0);
//GL.End();
RunShaders();
GL.Disable(EnableCap.Texture2D);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Modelview);
ErrorCode ec = GL.GetError();
if (ec != 0)
System.Console.WriteLine(ec.ToString());
Console.Read();
glControl.SwapBuffers();
}
private void RunShaders()
{
GL.ClearColor(Color.Yellow);
GL.UseProgram(program);
GL.DrawArrays(PrimitiveType.Triangles, 0, vertices.Length / 3);
ErrorCode ec = GL.GetError();
if (ec != 0)
System.Console.WriteLine(ec.ToString());
Console.Read();
}
private void CreateProgram()
{
program = GL.CreateProgram();
GL.AttachShader(program, vertShader);
GL.AttachShader(program, fragShader);
GL.LinkProgram(program);
}
private void CreateShaders()
{
/***********Vert Shader********************/
vertShader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertShader, #"attribute vec3 a_position;
varying vec2 vTexCoord;
void main() {
vTexCoord = (a_position.xy + 1) / 2;
gl_Position = vec4(a_position, 1);
}");
GL.CompileShader(vertShader);
/***********Frag Shader ****************/
fragShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragShader, #"precision highp float;
uniform sampler2D sTexture;
varying vec2 vTexCoord;
void main ()
{
vec4 color = texture2D (sTexture, vTexCoord);
if(color.r < 0.3){color.r = 1.0;}
// Save the result
gl_FragColor = color;
}");
GL.CompileShader(fragShader);
}
private void InitBuffers()
{
buffer = GL.GenBuffer();
positionLocation = GL.GetAttribLocation(program, "a_position");
GL.EnableVertexAttribArray(positionLocation);
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(positionLocation, 3, VertexAttribPointerType.Float, false, 0, 0);
}
public int LoadTexture(string file)
{
Bitmap bitmap = new Bitmap(file);
int tex = -1;
if (bitmap != null)
{
GL.DeleteTextures(1, ref tex);
GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
GL.GenTextures(1, out tex);
GL.BindTexture(TextureTarget.Texture2D, tex);
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
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.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
}
return tex;
}
}
public partial class Form7ImageOnly : Form
{
string file = "penguine.png";
// string file = "opentksquare.png";
string file1 = "lambo2.png";
int program;
int vertShader;
int fragShader;
int buffer;
int positionLocation;
int positionLocation1;
int positionLocation2;
int texture;
int texture1;
int ScreenWidth;
int ScreenHeight;
float[] vertices = {
// Left bottom triangle
-1f, -1f, 0f,
1f, -1f, 0f,
1f, 1f, 0f,
// Right top triangle
1f, 1f, 0f,
-1f, 1f, 0f,
-1f, -1f, 0f
};
public Form7ImageOnly()
{
InitializeComponent();
}
private void Form7ImageOnly_Load(object sender, EventArgs e)
{
glControl.Resize += new EventHandler(glControl_Resize);
glControl.Paint += new PaintEventHandler(glControl_Paint);
GL.ClearColor(Color.Yellow);
GL.Enable(EnableCap.DepthTest);
Application.Idle += Application_Idle;
// Ensure that the viewport and projection matrix are set correctly.
glControl_Resize(glControl, EventArgs.Empty);
}
void Application_Idle(object sender, EventArgs e)
{
while (glControl.IsIdle)
{
Render();
}
}
private void Render()
{
ScreenWidth = Screen.PrimaryScreen.Bounds.Width;
ScreenHeight = Screen.PrimaryScreen.Bounds.Height;
glControl.Size = new System.Drawing.Size(ScreenWidth, ScreenHeight);//full screen
texture = LoadTexture(file);
texture1 = LoadTexture(file1);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
DrawImage(texture,texture1);
}
private void glControl_Paint(object sender, PaintEventArgs e)
{
Render();
}
private void glControl_Resize(object sender, EventArgs e)
{
Init();
}
private void Init()
{
CreateShaders();
CreateProgram();
InitBuffers();
}
public void DrawImage(int image,int image1)
{
GL.Viewport(new Rectangle(0, 0, ScreenWidth, ScreenHeight));
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
//GL.Ortho(0, 1920, 0, 1080, 0, 1);
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadIdentity();
GL.Disable(EnableCap.Lighting);
GL.Enable(EnableCap.Texture2D);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, image);
GL.Uniform1(positionLocation1, 0);
GL.ActiveTexture(TextureUnit.Texture1);
GL.BindTexture(TextureTarget.Texture2D, image1);
GL.Uniform1(positionLocation2, 1);
//GL.Begin(PrimitiveType.Quads);
//GL.TexCoord2(0, 1);
//GL.Vertex3(0, 0, 0);
//GL.TexCoord2(1, 1);
//GL.Vertex3(1920, 0, 0);
//GL.TexCoord2(1, 0);
//GL.Vertex3(1920, 1080, 0);
//GL.TexCoord2(0, 0);
//GL.Vertex3(0, 1080, 0);
//GL.End();
RunShaders();
GL.Disable(EnableCap.Texture2D);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Modelview);
ErrorCode ec = GL.GetError();
if (ec != 0)
System.Console.WriteLine(ec.ToString());
Console.Read();
glControl.SwapBuffers();
}
private void RunShaders()
{
GL.ClearColor(Color.Yellow);
GL.UseProgram(program);
GL.DrawArrays(PrimitiveType.Triangles, 0, vertices.Length / 3);
ErrorCode ec = GL.GetError();
if (ec != 0)
System.Console.WriteLine(ec.ToString());
Console.Read();
}
private void CreateProgram()
{
program = GL.CreateProgram();
GL.AttachShader(program, vertShader);
GL.AttachShader(program, fragShader);
GL.LinkProgram(program);
}
private void CreateShaders()
{
/***********Vert Shader********************/
vertShader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertShader, #"attribute vec3 a_position;
varying vec2 vTexCoord;
void main() {
vTexCoord = (a_position.xy + 1) / 2;
gl_Position = vec4(a_position, 1);
}");
GL.CompileShader(vertShader);
/***********Frag Shader ****************/
fragShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragShader, #"precision highp float;
uniform sampler2D sTexture;uniform sampler2D sTexture1;
varying vec2 vTexCoord;
void main ()
{
vec4 color = texture2D (sTexture, vTexCoord);
vec4 color1=texture2D (sTexture1, vTexCoord);
// if(color.r < 0.3){color.r = 1.0;}
// Save the result
// gl_FragColor = color;
if(vTexCoord.y<0.5)
gl_FragColor = color1;
else
gl_FragColor = color;
// gl_FragColor =vec4(1.0,0.0,0.0,1.0);
}");
GL.CompileShader(fragShader);
}
private void InitBuffers()
{
buffer = GL.GenBuffer();
positionLocation = GL.GetAttribLocation(program, "a_position");
positionLocation1 = GL.GetUniformLocation(program, "sTexture");
positionLocation2 = GL.GetUniformLocation(program, "sTexture1");
GL.EnableVertexAttribArray(positionLocation);
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(positionLocation, 3, VertexAttribPointerType.Float, false, 0, 0);
}
public int LoadTexture(string file)
{
Bitmap bitmap = new Bitmap(file);
int tex = -1;
if (bitmap != null)
{
GL.DeleteTextures(1, ref tex);
GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
GL.GenTextures(1, out tex);
GL.BindTexture(TextureTarget.Texture2D, tex);
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
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.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
}
return tex;
}
}
I have a utility class for Framebuffer objects which i use to generate FBO's, bind them, render to them, and render them to screen as 2d textures.
When using this class, i can successfully make fbo textures, render to them, and render them to screen.
However, the colors seem messed up once i render them to screen.
What seems to be happening is that the color i set as drawing color ends up as the background color of the FBO (but only if i make an actual draw call after setting the color), and the drawing i made always ends up black.
What i am expecting based on my code, is a texture with a white background, and two small colored rectangles (one purple and one cyan) on them, drawn to the screen two times.
what i am getting is this :
a cyan background with two small black rectangles.
Source code follows :
FboRenderTexture.cs
public class FboRenderTexture : IDisposable
{
public int textureId = 0;
private int fboId = 0;
public int Width;
public int Height;
public FboRenderTexture(int width, int height)
{
Width = width;
Height = height;
Init();
}
//semi pseudocode
public void DrawToScreen(float xoffset = 0, float yoffset = 0)
{
if (textureId != -1)
{
GL.BindTexture(TextureTarget.Texture2D, textureId);
GL.Begin(BeginMode.Quads);
//todo : might also flip the texture since fbo's have right handed coordinate systems
GL.TexCoord2(0.0, 0.0);
GL.Vertex3(xoffset, yoffset, 0.0);
GL.TexCoord2(0.0, 1.0);
GL.Vertex3(xoffset, yoffset+Height, 0.0);
GL.TexCoord2(1.0, 1.0);
GL.Vertex3(xoffset+Width, yoffset+Height, 0.0);
GL.TexCoord2(1.0, 0.0);
GL.Vertex3(xoffset+Width, yoffset, 0.0);
GL.End();
}
}
private void Init()
{
// Generate the texture.
textureId = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, textureId);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToBorder);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToBorder);
// Create a FBO and attach the texture.
GL.Ext.GenFramebuffers(1, out fboId);
GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, fboId);
GL.Ext.FramebufferTexture2D(FramebufferTarget.FramebufferExt,
FramebufferAttachment.ColorAttachment0Ext, TextureTarget.Texture2D, textureId, 0);
// Disable rendering into the FBO
GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);
}
// Track whether Dispose has been called.
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
// Clean up what we allocated before exiting
if (textureId != 0)
GL.DeleteTextures(1, ref textureId);
if (fboId != 0)
GL.Ext.DeleteFramebuffers(1, ref fboId);
disposed = true;
}
}
}
public void BeginDrawing()
{
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, fboId);
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
GL.PushAttrib(AttribMask.ViewportBit);
GL.Viewport(0, 0, Width, Height);
}
public void EndDrawing()
{
GL.PopAttrib();
GL.Ext.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0); // disable rendering into the FBO
}
}
usage
public class Buffers : CreativeSharp.core.CSInstance //inherits from OpenTK.GameWindow, adds some simple drawing stuff.
{
private FboRenderTexture buffer;
public Buffers() : base(800, 600, "buffers")
{
GL.Enable(EnableCap.Texture2D);
buffer = new FboRenderTexture(128, 128);
NoStroke();
this.Closed += Buffers_Closed;
}
private void SetupBuffer()
{
buffer.BeginDrawing();
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
GL.ClearColor(1.0f, 1.0f, 1.0f, 1.0f);
GL.Color4(1f, 0f, 1f, 0f);
DrawRectangle(10,10, 30, 30);
GL.Color4(0f, 1f, 1f, 1f);
DrawRectangle(50, 10, 30, 30);
GL.Color4(1f, 1f, 1f);
buffer.EndDrawing();
}
void Buffers_Closed(object sender, EventArgs e)
{
buffer.Dispose();
}
public override void DrawContent()
{
SetupBuffer();
GL.ClearColor(1.0f, 1.0f, 1.0f, 1.0f);
GL.Color4(1f, 1f, 1f, 1f);
buffer.DrawToScreen(0,0);
buffer.DrawToScreen(512,0);
}
public override void Update()
{
}
private void DrawRectangle(float x, float y, float w, float h)
{
GL.Begin(PrimitiveType.Quads);
GL.Vertex3(x, y, 0);
GL.Vertex3(x + w, y, 0);
GL.Vertex3(x + w, y + h, 0);
GL.Vertex3(x, y + h, 0);
GL.End();
}
}
Somewhat embarrassingly, the cause of my problems was that i was not setting white as drawing color before drawing the fbo's texture.
This caused the colors to come out all wrong.
I have a following picture:
Window displays two textures, the left texture is generated by binding it to a FBO and rendering to FBO, 50 random triangles.
The right texture is generated by glTexImage2D with full-color image of Mona Lisa, but as you can see the image is lacking red colors, I think the problem is in OpenGL part, since I've investigated bytes that are passed to glTexImage2D and they do contain Red...
Here is C#/Mono/OpenTK source
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Platform;
using OpenTK.Platform.X11;
using OpenTK.Input;
using ManOCL;
namespace GlTest
{
public class MainClass: GameWindow
{
public MainClass()
: base(800, 600, new GraphicsMode(new ColorFormat(0, 0, 0, 0), 32, 0))
{
this.VSync = VSyncMode.Off;
}
public uint fbo;
public uint textureA;
public uint textureB;
public int textureAWidth = 1024;
public int textureAHeight = 1024;
public int textureBWidth;
public int textureBHeight;
Random rand = new Random();
protected override void OnLoad(EventArgs e)
{
GL.Enable(EnableCap.Blend);
GL.ShadeModel(ShadingModel.Smooth);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
GL.Disable(EnableCap.DepthTest);
GL.Disable(EnableCap.CullFace);
// GL.PolygonMode(MaterialFace.Back, PolygonMode.Line);
// Create Color Tex
GL.GenTextures(1, out textureA);
GL.BindTexture(TextureTarget.Texture2D, textureA);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, textureAWidth, textureAHeight, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
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.ClampToBorder);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) TextureWrapMode.ClampToBorder);
GL.GenTextures(1, out textureB);
GL.BindTexture(TextureTarget.Texture2D, textureB);
Bitmap bmp = new Bitmap("/Projects/MonaLisa/MonaLisa.bmp");
Console.WriteLine(textureBWidth = bmp.Width);
Console.WriteLine(textureBHeight = bmp.Height);
//get the data out of the bitmap
System.Drawing.Imaging.BitmapData bmpBits = bmp.LockBits
(
new System.Drawing.Rectangle(0,0,textureBWidth, textureBHeight),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppRgb
);
for (int row = 0; row < 1; row++)
{
for (int col = 0; col < 32; col++)
{
Console.WriteLine
(
"{0}, {1}, {2}, {3}",
Marshal.ReadByte(bmpBits.Scan0, (row * textureBWidth + col) * 4 + 0),
Marshal.ReadByte(bmpBits.Scan0, (row * textureBWidth + col) * 4 + 1),
Marshal.ReadByte(bmpBits.Scan0, (row * textureBWidth + col) * 4 + 2),
Marshal.ReadByte(bmpBits.Scan0, (row * textureBWidth + col) * 4 + 3)
);
}
}
Console.WriteLine(bmpBits.Width);
Console.WriteLine(bmpBits.Height);
GL.TexImage2D
(
TextureTarget.Texture2D,
0,
PixelInternalFormat.Rgba,
textureBWidth,
textureBHeight,
0,
OpenTK.Graphics.OpenGL.PixelFormat.Rgba,
PixelType.UnsignedByte,
bmpBits.Scan0
);
// GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, textureBWidth, textureBHeight, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
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.ClampToBorder);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) TextureWrapMode.ClampToBorder);
//free the bitmap data (we dont need it anymore because it has been passed to the OpenGL driver
bmp.UnlockBits(bmpBits);
// Create a FBO and attach the textures
GL.Ext.GenFramebuffers(1, out fbo);
GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, fbo);
GL.Ext.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.ColorAttachment0Ext, TextureTarget.Texture2D, textureA, 0);
#region Test for Error
switch (GL.Ext.CheckFramebufferStatus(FramebufferTarget.FramebufferExt))
{
case FramebufferErrorCode.FramebufferCompleteExt:
{
Console.WriteLine("FBO: The framebuffer is complete and valid for rendering.");
break;
}
case FramebufferErrorCode.FramebufferIncompleteAttachmentExt:
{
Console.WriteLine("FBO: One or more attachment points are not framebuffer attachment complete. This could mean there’s no texture attached or the format isn’t renderable. For color textures this means the base format must be RGB or RGBA and for depth textures it must be a DEPTH_COMPONENT format. Other causes of this error are that the width or height is zero or the z-offset is out of range in case of render to volume.");
break;
}
case FramebufferErrorCode.FramebufferIncompleteMissingAttachmentExt:
{
Console.WriteLine("FBO: There are no attachments.");
break;
}
/* case FramebufferErrorCode.GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
{
Console.WriteLine("FBO: An object has been attached to more than one attachment point.");
break;
}*/
case FramebufferErrorCode.FramebufferIncompleteDimensionsExt:
{
Console.WriteLine("FBO: Attachments are of different size. All attachments must have the same width and height.");
break;
}
case FramebufferErrorCode.FramebufferIncompleteFormatsExt:
{
Console.WriteLine("FBO: The color attachments have different format. All color attachments must have the same format.");
break;
}
case FramebufferErrorCode.FramebufferIncompleteDrawBufferExt:
{
Console.WriteLine("FBO: An attachment point referenced by GL.DrawBuffers() doesn’t have an attachment.");
break;
}
case FramebufferErrorCode.FramebufferIncompleteReadBufferExt:
{
Console.WriteLine("FBO: The attachment point referenced by GL.ReadBuffers() doesn’t have an attachment.");
break;
}
case FramebufferErrorCode.FramebufferUnsupportedExt:
{
Console.WriteLine("FBO: This particular FBO configuration is not supported by the implementation.");
break;
}
default:
{
Console.WriteLine("FBO: Status unknown. (yes, this is really bad.)");
break;
}
}
// using FBO might have changed states, e.g. the FBO might not support stereoscopic views or double buffering
int[] queryinfo = new int[6];
GL.GetInteger(GetPName.MaxColorAttachmentsExt, out queryinfo[0]);
GL.GetInteger(GetPName.AuxBuffers, out queryinfo[1]);
GL.GetInteger(GetPName.MaxDrawBuffers, out queryinfo[2]);
GL.GetInteger(GetPName.Stereo, out queryinfo[3]);
GL.GetInteger(GetPName.Samples, out queryinfo[4]);
GL.GetInteger(GetPName.Doublebuffer, out queryinfo[5]);
Console.WriteLine("max. ColorBuffers: " + queryinfo[0] + " max. AuxBuffers: " + queryinfo[1] + " max. DrawBuffers: " + queryinfo[2] +
"\nStereo: " + queryinfo[3] + " Samples: " + queryinfo[4] + " DoubleBuffer: " + queryinfo[5]);
Console.WriteLine("Last GL Error: " + GL.GetError());
#endregion Test for Error
GL.PushAttrib(AttribMask.ViewportBit);
{
GL.Viewport(0, 0, textureAWidth, textureAHeight);
OpenTK.Matrix4 orthogonal = OpenTK.Matrix4.CreateOrthographicOffCenter(0, 1, 0, 1, -3, 3);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref orthogonal);
Matrix4 lookat = Matrix4.LookAt(0, 0, 1, 0, 0, 0, 0, 1, 0);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadMatrix(ref lookat);
// clear the screen in red, to make it very obvious what the clear affected. only the FBO, not the real framebuffer
GL.ClearColor(0f, 0f, 0f, 0f);
GL.Clear(ClearBufferMask.ColorBufferBit);
// smack 50 random triangles into the FBO's textures
GL.Begin(BeginMode.Triangles);
{
for (int i = 0; i < 50; i++)
{
GL.Color4(((float)(rand.NextDouble())), ((float)(rand.NextDouble())), ((float)(rand.NextDouble())), ((float)(rand.NextDouble())));
GL.Vertex3(((float)(rand.NextDouble())), ((float)(rand.NextDouble())), 0);
GL.Color4(((float)(rand.NextDouble())), ((float)(rand.NextDouble())), ((float)(rand.NextDouble())), ((float)(rand.NextDouble())));
GL.Vertex3(((float)(rand.NextDouble())), ((float)(rand.NextDouble())), 0);
GL.Color4(((float)(rand.NextDouble())), ((float)(rand.NextDouble())), ((float)(rand.NextDouble())), ((float)(rand.NextDouble())));
GL.Vertex3(((float)(rand.NextDouble())), ((float)(rand.NextDouble())), 0);
}
}
GL.End();
}
GL.PopAttrib();
GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0); // disable rendering into the FBO
GL.ClearColor(1f, 1f, 1f, 0.0f);
GL.Color3(1f, 1f, 1f);
GL.Enable(EnableCap.Texture2D); // enable Texture Mapping
GL.BindTexture(TextureTarget.Texture2D, 0); // bind default texture
// IntPtr cglContext = Monobjc.OpenGL.CGL.GetCurrentContext();
//
// IntPtr cglShareGroup = Monobjc.OpenGL.CGL.GetShareGroup(cglContext);
//
// ManOCL.Context.ShareWithCGL(cglShareGroup);
//
// Kernel kernel = ManOCL.Kernel.Create
// (
// "kernel1",
// #"__kernel void kernel1(__global int *srcimg, __global int * output, __global int *smp)
// {
// }",
// new Argument[]
// {
// DeviceGlobalMemory.CreateFromArray(new int[1]),
// DeviceGlobalMemory.CreateFromArray(new int[2]),
// DeviceGlobalMemory.CreateFromArray(new int[1])
// }
// );
// Console.WriteLine("Success!");
// Console.WriteLine(kernel);
}
protected override void OnUnload(EventArgs e)
{
// Clean up what we allocated before exiting
GL.DeleteTextures(1, ref textureA);
GL.DeleteTextures(1, ref textureB);
GL.Ext.DeleteFramebuffers(1, ref fbo);
base.OnUnload(e);
}
protected override void OnResize (EventArgs e)
{
GL.Viewport(0, 0, Width, Height);
double aspect_ratio = Width / (double)Height;
OpenTK.Matrix4 perspective = OpenTK.Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4 * 3 / 2, (float)aspect_ratio, 1, 64);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref perspective);
Matrix4 lookat = Matrix4.LookAt(0, 0, 3, 0, 0, 0, 0, 1, 0);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadMatrix(ref lookat);
base.OnResize(e);
}
protected override void OnUpdateFrame (FrameEventArgs e)
{
base.OnUpdateFrame(e);
if (Keyboard[Key.Escape])
{
this.Exit();
}
}
protected override void OnRenderFrame(FrameEventArgs e)
{
this.Title = "Frames per Second: " + (1.0 / e.Time);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.PushMatrix();
{
// Draw the Color Texture
GL.Translate(-1f, 0f, 0f);
GL.BindTexture(TextureTarget.Texture2D, textureA);
GL.Begin(BeginMode.Quads);
{
GL.TexCoord2(0f, 1f);
GL.Vertex2(-1.0f, 1.0f);
GL.TexCoord2(0.0f, 0.0f);
GL.Vertex2(-1.0f, -1.0f);
GL.TexCoord2(1.0f, 0.0f);
GL.Vertex2(1.0f, -1.0f);
GL.TexCoord2(1.0f, 1.0f);
GL.Vertex2(1.0f, 1.0f);
}
GL.End();
GL.Translate(2f, 0f, 0f);
GL.BindTexture(TextureTarget.Texture2D, textureB);
GL.Begin(BeginMode.Quads);
{
GL.TexCoord2(0f, 0f);
GL.Vertex2(-1.0f, 1.0f);
GL.TexCoord2(0.0f, 1.0f);
GL.Vertex2(-1.0f, -1.0f);
GL.TexCoord2(1.0f, 1.0f);
GL.Vertex2(1.0f, -1.0f);
GL.TexCoord2(1.0f, 0.0f);
GL.Vertex2(1.0f, 1.0f);
}
GL.End();
GL.Translate(0f, 0f, 0f);
}
GL.PopMatrix();
this.SwapBuffers();
}
#region public static void Main()
/// <summary>
/// Entry point of this example.
/// </summary>
[STAThread]
public static void Main()
{
using (MainClass example = new MainClass())
{
example.Title = "FrameBufferObjects";
example.Run(1.0, 0.0);
}
}
#endregion
}
}
In the bit of code where you set your texture data:
GL.TexImage2D
(
TextureTarget.Texture2D,
0,
PixelInternalFormat.Rgba,
textureBWidth,
textureBHeight,
0,
OpenTK.Graphics.OpenGL.PixelFormat.Rgba,
PixelType.UnsignedByte,
bmpBits.Scan0
);
Change your pixel format to
OpenTK.Graphics.OpenGL.PixelFormat.Bgra;
Windows bitmaps and opengl have a different endianess on pixels i.e. the bytes are reversed.