OpenGL doesn't render to Framebuffer but to Window - c#

My problem is that OpenGL renders to the Main-Window, although I bound the Framebuffer I want to use.
This is my Main Rendering-Method
protected override void OnRenderFrame(FrameEventArgs e)
{
base.OnRenderFrame(e);
renderer.BeginFrame();
renderer.RenderEntity(testEntity);
renderer.EndFrame();
SwapBuffers();
}
This is my Renderer
class Renderer
{
List<Vertex> screenQuadVertecies = new List<Vertex>
{
new Vertex(new Vector3(-1, 1, 0), new Vector3()),
new Vertex(new Vector3(1, 1, 0), new Vector3()),
new Vertex(new Vector3(-1, -1, 0), new Vector3()),
new Vertex(new Vector3(1, -1, 0), new Vector3())
};
List<int> screenQuadIndices = new List<int>
{
0, 1, 2,
1, 2, 3
};
List<Vector2> screenQuadUVs = new List<Vector2>
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
TexturedMesh screenQuad;
Framebuffer mainPassFramebuffer;
Camera activeCamera;
Shader ModelShader;
Shader PostProcessingShader;
int width, height;
public Renderer(int width, int height)
{
this.width = width;
this.height = height;
ModelShader = new MainShader();
PostProcessingShader = new PostProcessingShader();
mainPassFramebuffer = new Framebuffer(width, height);
screenQuad = new TexturedMesh(screenQuadVertecies, screenQuadIndices, screenQuadUVs);
}
public void BeginFrame()
{
mainPassFramebuffer.EndRendering();
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
mainPassFramebuffer.ClearBuffer();
mainPassFramebuffer.BeginRendering();
}
public void EndFrame()
{
mainPassFramebuffer.EndRendering();
mainPassFramebuffer.BindTexture();
PostProcessingShader.UseShader();
screenQuad.PrepareRendering();
GL.DrawElements(PrimitiveType.Triangles, 6, DrawElementsType.UnsignedInt, 0);
screenQuad.EndRendering();
PostProcessingShader.UnuseShader();
}
public void RenderEntity(Entity e)
{
e.Mesh.PrepareRendering();
ModelShader.UseShader();
ModelShader.LoadCamera(activeCamera);
ModelShader.LoadModel(e.GetModelMatrix());
GL.DrawElements(PrimitiveType.Triangles, e.Mesh.GetSize(), DrawElementsType.UnsignedInt, 0);
ModelShader.UnuseShader();
}
public void RenderTerrain(Terrain t)
{
foreach (var chunk in t.chunks)
{
RenderEntity(chunk.GetEntity());
}
}
public void SetActiveCamera(Camera camera)
{
activeCamera = camera;
}
}
And this is my Framebuffer Class
class Framebuffer
{
int frameBufferID;
int textureID;
int width, height;
public Framebuffer(int width, int height)
{
this.width = width;
this.height = height;
frameBufferID = GL.GenRenderbuffer();
GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBufferID);
textureID = CreateTexture();
GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, textureID, 0);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
}
protected int CreateTexture()
{
int returnID;
returnID = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, returnID);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, width, height, 0, PixelFormat.Rgb, PixelType.UnsignedByte, (IntPtr)0);
int nearest = (int)TextureMagFilter.Nearest;
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, ref nearest);
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, ref nearest);
return returnID;
}
public void BeginRendering()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBufferID);
GL.Viewport(new System.Drawing.Point(0, 0), new System.Drawing.Size(width, height));
}
public void EndRendering()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
}
public void BindTexture()
{
GL.BindTexture(TextureTarget.Texture2D, textureID);
}
public void ClearBuffer()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBufferID);
GL.Viewport(new System.Drawing.Point(0, 0), new System.Drawing.Size(width, height));
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
}
}
The expected result is a black quad because I have been implementing Texturing when I discovered that my Model still renders to the screen. I found that out when I commentend out the GL.DrawElements call in EndRendering() which should render the quad to the screen. When I now don't draw that quad the image still appears.
What am I doing wrong?

A render buffer is not a framebuffer object:
frameBufferID = GL.GenRenderbuffer();
When you try to bind an ID you got from glGenRenderbuffers as a framebuffer, you will get an GL_INVALID_OPERATION error from glBindFramebuffer(), and the command will have no further effect (leaving the default framebuffer bound).
New FBO names are generated via glGenFramebuffers, so you should use that.

Related

Monogame, why wont the block move even if there is an function for it?

I need some help, I have this labyrinth game where I need to push a block. If I intersect with the block the first one is supposed to move to the right and the second one is supposed to move to the left. The problem is that I can't get either of them to move when I intersect. Help would be appreciated.
Game1.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Collections.Generic;
namespace Labyrintspel
{
public class Game1 : Game
{
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
Texture2D pixelTexture;
Texture2D playerTexture;
List<Block> blocks = new List<Block>();
Player player;
Color backgroundColor = Color.CornflowerBlue;
Block door;
Block door2;
int i = 0;
int i2 = 0;
int speed1 = 1;
int speed2 = -1;
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
_graphics.PreferredBackBufferWidth = 800;
_graphics.PreferredBackBufferHeight = 500;
_graphics.ApplyChanges();
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void Initialize()
{
base.Initialize();
blocks.Add(BlockFactory.CreateEatableBlock(70, 300));
blocks.Add(BlockFactory.CreateEatableBlock(190, 300));
blocks.Add(BlockFactory.CreateEatableBlock(490, 300));
blocks.Add(BlockFactory.CreateWall(0, 460, 800, 40));
blocks.Add(BlockFactory.CreateWall(0, 0, 800, 30));
blocks.Add(BlockFactory.CreateWall(0, 0, 40, 460));
blocks.Add(BlockFactory.CreateWall(760, 0, 40, 460));
blocks.Add(BlockFactory.CreateWall(640, 200, 40, 260));
blocks.Add(BlockFactory.CreateWall(140, 100, 700, 40));
blocks.Add(BlockFactory.CreateWall(540, 130, 40, 250));
blocks.Add(BlockFactory.CreateWall(440, 200, 40, 260));
blocks.Add(BlockFactory.CreateWall(340, 130, 40, 250));
blocks.Add(BlockFactory.CreateWall(240, 200, 40, 260));
blocks.Add(BlockFactory.CreateWall(140, 130, 40, 250));
blocks.Add(BlockFactory.RemovableWall(600, 0, 40, 100));
blocks.Add(BlockFactory.CreateWall(650, 375, 150, 200));
door = new Block(720, 40, 30, 50, Color.SaddleBrown);
blocks.Add(door);
door2 = new Block(700, 400, 30, 50, Color.SaddleBrown);
player = new Player(700, 300, playerTexture.Width, playerTexture.Height);
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
pixelTexture = Content.Load<Texture2D>("pixel");
playerTexture = Content.Load<Texture2D>("player");
}
protected override void Update(GameTime gameTime)
{
var keyState = Keyboard.GetState();
base.Update(gameTime);
player.StorePosition();
if (keyState.IsKeyDown(Keys.Left)) player.MoveLeft();
if (keyState.IsKeyDown(Keys.Right)) player.MoveRight();
if (keyState.IsKeyDown(Keys.Up)) player.MoveUp();
if (keyState.IsKeyDown(Keys.Down)) player.MoveDown();
if (player.GetRectangle().Intersects(door.Rectangle))
{
i = 0;
blocks.RemoveAll(block => block.IsVisible);
blocks.Add(BlockFactory.CreateWall(0, 460, 800, 40));
blocks.Add(BlockFactory.CreateWall(0, 0, 800, 30));
blocks.Add(BlockFactory.CreateWall(0, 0, 40, 460));
blocks.Add(BlockFactory.CreateWall(760, 0, 40, 460));
blocks.Add(BlockFactory.CreateWall(100, 100, 800, 40));
blocks.Add(BlockFactory.CreateWall(0, 200, 400, 40));
blocks.Add(BlockFactory.CreateWall(500, 200, 400, 40));
blocks.Add(BlockFactory.CreateWall(0, 300, 200, 40));
blocks.Add(BlockFactory.CreateWall(300, 300, 500, 40));
blocks.Add(BlockFactory.RemovableWall(600, 300, 40, 300));
blocks.Add(BlockFactory.CreateEatableBlock(700, 250));
blocks.Add(BlockFactory.CreateEatableBlock(190, 150));
blocks.Add(BlockFactory.CreateEatableBlock(500, 400));
blocks.Add(BlockFactory.CreatePushableBlock(50, 150));
blocks.Add(BlockFactory.CreatePushableBlock(50, 400));
blocks.Add(door2);
}
if (player.GetRectangle().Intersects(door2.Rectangle))
{
this.Exit();
}
backgroundColor = Color.CornflowerBlue;
foreach (var block in blocks)
{
if (player.GetRectangle().Intersects(block.Rectangle))
{
if (block.IsPushable && keyState.IsKeyDown(Keys.Space) && i2 == 0)
{
block.MoveRight();
i2++;
}
if (block.IsSolid) player.RestorePosition();
if (block.IsEatable)
{
block.IsVisible = false;
i++;
}
}
if (i == 3)
{
if (block.IsRemovable)
{
block.IsSolid = false;
block.IsVisible = false;
}
}
}
blocks.RemoveAll(block => !block.IsVisible);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(backgroundColor);
_spriteBatch.Begin();
blocks.ForEach(block => block.Draw(_spriteBatch, pixelTexture));
player.Draw(_spriteBatch, playerTexture);
_spriteBatch.End();
Window.Title = "Antal block: " + blocks.Count;
base.Draw(gameTime);
}
}
Block.cs
public class Block
{
public Rectangle Rectangle { get; set; }
public Color Color { get; set; }
public bool IsSolid { get; set; } = true;
public bool IsEatable { get; set; } = false;
public bool IsVisible { get; set; } = true;
public bool IsRemovable { get; set; } = false;
public bool IsPushable { get; set; } = false;
private Vector2 position;
private Rectangle rectangle;
public Block(int x, int y, int w, int h, Color color)
{
Color = color;
position.X = x;
position.Y = y;
Rectangle = new Rectangle(x, y, w, h);
}
public void Move(float dx, float dy)
{
position.X += dx;
position.Y += dy;
}
public Rectangle PushabelRectangle()
{
rectangle.X = (int)position.X;
rectangle.Y = (int)position.Y;
return rectangle;
}
internal void MoveLeft() => Move(-10, 0);
internal void MoveRight() => Move(100, 0);
public void Draw(SpriteBatch spriteBatch, Texture2D texture)
{
if (IsVisible)
{
spriteBatch.Draw(texture, Rectangle, Color);
}
}
}
blockfactory.cs
internal class BlockFactory
{
internal static Block CreateEatableBlock(int x, int y)
{
var block = new Block(x, y, 40, 40, Color.Yellow);
block.IsSolid = false;
block.IsEatable = true;
return block;
}
internal static Block CreatePushableBlock(int x, int y)
{
var block = new Block(x, y, 40, 40, Color.Orange);
block.IsPushable = true;
return block;
}
internal static Block CreateWall(int x, int y, int w, int h)
{
return new Block(x, y, w, h, Color.Black);
}
internal static Block RemovableWall(int x, int y, int w, int h)
{
var block = new Block(x, y, w, h, Color.Black);
block.IsSolid = true;
block.IsEatable = false;
block.IsVisible = true;
block.IsRemovable = true;
return block;
}
internal static Block CreatePushBlock(int x, int y, int w, int h)
{
return new Block(x, y, w, h, Color.Orange);
}
}
This code shows no error but nothing happens when I intersect and press spacebar.
Move() is changing the position variable, but the block is drawing from the Rectangle field, which is not changed to reflect the movement.
I would suggest the following correlation:
public Rectangle Rectangle { get{return rectangle; } set {rectangle = value;} })
public void Move(float dx, float dy)
{
position.X += dx;
position.Y += dy;
Rectangle = new Rectangle((int)position.X, (int)position.Y, Rectangle.Width, Rectangle.Height);
// you cannot set the X and Y of field structures directly.
}

Texturing triangles

I am trying to texture triangle with OpenTK ES with this code
using System;
using OpenTK;
using OpenTK.Graphics.ES11;
using OpenTK.Platform.Android;
using Android.Content;
namespace TexturedTriangle
{
class GLView1 AndroidGameView
{
public GLView1(Context context) base(context)
{ }
protected override void CreateFrameBuffer()
{
base.CreateFrameBuffer();
}
Vector2[] TexCoords =
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
};
Vector2[] Vertices =
{
new Vector2(0f, 0f),
new Vector2(1f, 0f),
new Vector2(0f, 1f),
};
int[] Tex = new int[1];
int[] VBOs = new int[2];
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
GL.ClearColor(0, 0, 0, 1f);
GL.Clear((int)All.ColorBufferBit);
GL.MatrixMode(All.Projection);
GL.LoadIdentity();
GL.MatrixMode(All.Modelview);
GL.LoadIdentity();
GL.Enable(All.Texture2D);
GL.GenBuffers(2, VBOs);
GL.BindBuffer(All.ArrayBuffer, VBOs[0]);
GL.BufferData(All.ArrayBuffer,
new IntPtr(Vertices.Length Vector2.SizeInBytes),
Vertices, All.StaticDraw);
GL.BindBuffer(All.ArrayBuffer, VBOs[1]);
GL.BufferData(All.ArrayBuffer,
new IntPtr(TexCoords.Length Vector2.SizeInBytes),
TexCoords, All.StaticDraw);
int[] Data = new int[32 32];
for (int I = 0; I 32 32; I++)
{
if (I % 3 == 0) Data[I] = 255;
if (I % 3 == 1) Data[I] = 65280;
if (I % 3 == 2) Data[I] = 16711680;
}
GL.GenTextures(1, Tex);
GL.BindTexture(All.Texture2D, Tex[0]);
GL.TexParameter(All.Texture2D, All.TextureMinFilter,
(int)All.Nearest);
GL.TexParameter(All.Texture2D, All.TextureMagFilter,
(int)All.Nearest);
GL.TexImage2D(All.Texture2D, 0, 3, 32, 32, 0, All.Rgba,
All.UnsignedByte, Data);
GL.EnableClientState(All.VertexArray);
GL.EnableClientState(All.TextureCoordArray);
Run();
}
protected override void OnRenderFrame(FrameEventArgs e)
{
base.OnRenderFrame(e);
GL.BindBuffer(All.ArrayBuffer, VBOs[0]);
GL.VertexPointer(2, All.Float,
BlittableValueType.StrideOf(Vertices)
IntPtr.Zero);
GL.BindBuffer(All.ArrayBuffer, VBOs[1]);
GL.TexCoordPointer(2, All.Float,
BilittableValueType.StrideOf(TexCoords),
IntPtr.Zero);
GL.DrawArrays(All.Triangles, 0, 3);
SwapBuffers();
}
}
}
But there is only a white triangle
Textured triangle OpenGL ES
Meanwhile this code:
using System;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenTK;
namespace TexturedTriangle
{
class Program
{
static void Main()
{
GameWindow Window = new GameWindow(512, 512, GraphicsMode.Default, "Textured Triangle");
int[] Tex = new int[1];
int[] VBOs = new int[2];
Vector2[] TexCoords =
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
};
Vector2[] Vertices =
{
new Vector2(0f, 0f),
new Vector2(1f, 0f),
new Vector2(0f, 1f),
};
Window.Load += (sender, e) =>
{
GL.ClearColor(0, 0, 0, 1f);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
GL.Enable(EnableCap.Texture2D);
GL.GenBuffers(2, VBOs);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBOs[0]);
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(Vertices.Length * Vector2.SizeInBytes), Vertices, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBOs[1]);
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(TexCoords.Length * Vector2.SizeInBytes), TexCoords, BufferUsageHint.StaticDraw);
int[] Data = new int[32 * 32];
for (int I = 0; I < 32 * 32; I++)
{
if (I % 3 == 0) Data[I] = 255;
if (I % 3 == 1) Data[I] = 65280;
if (I % 3 == 2) Data[I] = 16711680;
}
GL.GenTextures(1, Tex);
GL.BindTexture(TextureTarget.Texture2D, Tex[0]);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Three, 32, 32, 0, PixelFormat.Rgba, PixelType.UnsignedByte, Data);
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.TextureCoordArray);
};
Window.RenderFrame += (sender, e) =>
{
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBOs[0]);
GL.VertexPointer(2, VertexPointerType.Float, BlittableValueType.StrideOf(Vertices), IntPtr.Zero);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBOs[1]);
GL.TexCoordPointer(2, TexCoordPointerType.Float, BlittableValueType.StrideOf(TexCoords), IntPtr.Zero);
GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
Window.SwapBuffers();
};
Window.Run();
}
}
}
Works and output is
Textured triangle OpenTK
After GL.TexImage2D();
GL.GetError(); gives InvalidValue
Documentation: www.khronos.org/opengles/sdk/docs/man/xhtml/glTexImage2D.xml
What the problem can be?
I find an error, InternalFormat and Format must match, else InvalidValue is given.

How to render image properly

My image appears too large when it is rendered using SharpGL. How do I load it properly? The image's dimension is only 313 x 79 pixels but it almost occupy the rest of the screen when it renders.
I got this code from codeplex. The example given is how to render images in 3D (name of project is NativeTexturesSample).
https://sharpgl.codeplex.com/downloads/get/614989. I manage to make the rendering in 2D but I think I'm not doing it correctly.
private void openGLControl1_OpenGLDraw(object sender, RenderEventArgs e)
{
const int screenWidth = 1920;
const int screenHeight = 1080;
SharpGL.OpenGL gl = this.openGLControl1.OpenGL;
gl.MatrixMode(OpenGL.GL_PROJECTION);
gl.Ortho2D(0, screenWidth , screenHeight , 0);
gl.Disable(OpenGL.GL_DEPTH_TEST);
gl.LoadIdentity();
texture.Create(gl, #"C:\image\footerlogo.bmp");
texture.Bind(gl);
gl.Begin(OpenGL.GL_QUADS);
gl.TexCoord(0.0f, 1.0f); gl.Vertex(-2.0f, 0.0f);
gl.TexCoord(1.0f, 1.0f); gl.Vertex(1.0f, 0.0f);
gl.TexCoord(1.0f, 0.0f); gl.Vertex(1.0f, 1.0f);
gl.TexCoord(0.0f, 0.0f); gl.Vertex(-2.0f, 1.0f);
gl.End();
gl.Flush();
}
Try this code:
public partial class SharpGLForm : Form
{
private bool TexturesInitialised = false;
private float rotation = 0.0f;
private float Scale = 1;
private Bitmap gImage1;
private System.Drawing.Imaging.BitmapData gbitmapdata;
private uint[] gtexture = new uint[1];
/// <summary>
/// Initializes a new instance of the <see cref="SharpGLForm"/> class.
/// </summary>
public SharpGLForm()
{
InitializeComponent();
}
private void InitialiseTexture(ref OpenGL gl)
{
gImage1 = new Bitmap(#"C:\Jess1.bmp");// Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
Rectangle rect = new Rectangle(0, 0, gImage1.Width, gImage1.Height);
gbitmapdata = gImage1.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
gImage1.UnlockBits(gbitmapdata);
gl.GenTextures(1, gtexture);
gl.BindTexture(OpenGL.GL_TEXTURE_2D, gtexture[0]);
gl.TexImage2D(OpenGL.GL_TEXTURE_2D, 0, (int)OpenGL.GL_RGB8, gImage1.Width, gImage1.Height, 0, OpenGL.GL_BGR_EXT, OpenGL.GL_UNSIGNED_BYTE, gbitmapdata.Scan0);
uint[] array = new uint[] { OpenGL.GL_NEAREST };
gl.TexParameterI(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MIN_FILTER, array);
gl.TexParameterI(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MAG_FILTER, array);
TexturesInitialised = true;
}
private void openGLControl_OpenGLDraw(object sender, RenderEventArgs e)
{
// Get the OpenGL object.
OpenGL gl = openGLControl.OpenGL;
// Clear the color and depth buffer.
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
// Load the identity matrix.
gl.LoadIdentity();
if (!TexturesInitialised)
{
InitialiseTexture(ref gl);
}
gl.Enable(OpenGL.GL_TEXTURE_2D);
gl.BindTexture(OpenGL.GL_TEXTURE_2D, gtexture[0]);
gl.Color(1.0f, 1.0f, 1.0f, 0.1f); //Must have, weirdness!
gl.Begin(OpenGL.GL_QUADS);
gl.TexCoord(1.0f, 1.0f);
gl.Vertex(gImage1.Width, gImage1.Height, 1.0f);
gl.TexCoord(0.0f, 1.0f);
gl.Vertex(0.0f, gImage1.Height, 1.0f);
gl.TexCoord(0.0f, 0.0f);
gl.Vertex(0.0f, 0.0f, 1.0f);
gl.TexCoord(1.0f, 0.0f);
gl.Vertex(gImage1.Width, 0.0f, 1.0f);
gl.End();
gl.Disable(OpenGL.GL_TEXTURE_2D);
}
private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
{
OpenGL gl = openGLControl.OpenGL;
gl.ClearColor(0, 0, 0, 0);
}
private void openGLControl_Resized(object sender, EventArgs e)
{
OpenGL gl = openGLControl.OpenGL;
gl.MatrixMode(OpenGL.GL_PROJECTION);
gl.LoadIdentity();
gl.Perspective(60.0f, (double)Width / (double)Height, 0.01, 10000.0);
gl.LookAt(0, 0, -500, 0, 0, 0, 0, 1, 0);
gl.MatrixMode(OpenGL.GL_MODELVIEW);
}
}

Beginner troubles with 2D projection and textures in OpenGL

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
};

Why my tiles became small?

I'm currently doing a game that I will present for my software engineering subject in school. To be truth, I am not experienced in C# that's why I'm following this TileEngine tutorial. But when I'm in the part of adding the tiles to the game, my tile are rendered so small. I even used 256 x 256 image. Just like in the tutorial video.
You can see a screenshot of the problem here. Here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace TileEngine
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
List<Texture2D> tileTextures = new List<Texture2D>();
int[,] tileMap = new int[,]
{
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
};
int tileWidth = 64;
int tileHeight = 64;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
Texture2D texture;
texture = Content.Load<Texture2D>("Tiles/se_free_dirt_texture");
tileTextures.Add(texture);
texture = Content.Load<Texture2D>("Tiles/se_free_grass_texture");
tileTextures.Add(texture);
texture = Content.Load<Texture2D>("Tiles/se_free_ground_texture");
tileTextures.Add(texture);
texture = Content.Load<Texture2D>("Tiles/se_free_mud_texture");
tileTextures.Add(texture);
texture = Content.Load<Texture2D>("Tiles/se_free_road_texture");
tileTextures.Add(texture);
texture = Content.Load<Texture2D>("Tiles/se_free_rock_texture");
tileTextures.Add(texture);
texture = Content.Load<Texture2D>("Tiles/se_free_wood_texture");
tileTextures.Add(texture);
}
protected override void UnloadContent() { }
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
int tileMapWidth = tileMap.GetLength(1);
int tileMapHeight = tileMap.GetLength(0);
for (int x = 0; x < tileMapWidth; x++)
{
for (int y = 0; y < tileMapHeight; y++)
{
int textureIndex = tileMap[y, x];
Texture2D texture = tileTextures[textureIndex];
spriteBatch.Draw(
texture,
new Rectangle(x * tileWidth, y * tileHeight, tileMapWidth, tileMapHeight),
Color.White);
}
}
spriteBatch.End();
base.Draw(gameTime);
}
}
}
You just need to replace 3rd line in below block:
spriteBatch.Draw(
texture,
new Rectangle(x * tileWidth, y * tileHeight, tileMapWidth, tileMapHeight),
Color.White);
so that it is like 3rd line in next block:
spriteBatch.Draw(
texture,
new Rectangle(x * tileWidth, y * tileHeight, tileWidth, tileHeight),
Color.White);
So problem was: in your code texture's rectangle width and height was set to your map's width and height - which appears to be much smaller than size of your texture's image.
Change the width and height of each tile to make it bigger:
int tileWidth = 300;
int tileHeight = 300;
Basically add whatever number produces the size you please.
Also the rectangle is formed by adding start point + size so the size needs to match the points as well otherwise they will be drawn on top of each other.
If you want to render it in squares for example then titleWidth should be the same as tileMapWidth.
Currently it looks like it is the length of the matrix which is certainly wrong because that number is small (10) and would render small squares (10x10).
Therefore do this:
int tileMapWidth = tileWidth;
int tileMapHeight = tileHeight;
Instead of
int tileMapWidth = tileMap.GetLength(1);
int tileMapHeight = tileMap.GetLength(0);
you can try like this
width = 64 ' or texture.width
height = 64 ' or texture.height
pos = new vector2d(x * width , y * height)
spriteBatch.Draw(texture, pos, Color.White);
if x starts from 0 then first texture will be at 0,0 second at 64,0 ....

Categories

Resources