Tal's picture

[Solved] Can't draw properly T2fV3f vertex format under Linux(/Mono)

I've been writing this code to examine this problem that originally was in my engine(MaxDream).
If I draw T2fV3f vertex format, it shows the triangle not in it's position(it should be in the middle). The strange thing is that if I go to T2fV3f, it's work great.
Now in windows, it's work great too for all the formats.
So here is the code:
Game.cs:

// Released to the public domain. Use, modify and relicense at will.
 
 
 
using System;
 
using OpenTK;
 
using OpenTK.Graphics;
 
using OpenTK.Graphics.OpenGL;
 
using OpenTK.Audio;
 
using OpenTK.Audio.OpenAL;
 
using OpenTK.Input;
 
 
 
namespace StarterKit
 
{
 
    class Game : GameWindow
 
    {
 
		int vertexBuffer;
 
		int verticesCount;
 
        /// <summary>Creates a 800x600 window with the specified title.</summary>
 
        public Game()
 
            : base(800, 600, GraphicsMode.Default, "OpenTK Quick Start Sample")
 
        {
 
            VSync = VSyncMode.On;
 
        }
 
 
 
        /// <summary>Load resources here.</summary>
 
        /// <param name="e">Not used.</param>
 
        protected override void OnLoad(EventArgs e)
 
        {
 
            base.OnLoad(e);
 
 
 
            GL.ClearColor(0.1f, 0.2f, 0.5f, 0.0f);
 
            GL.Enable(EnableCap.DepthTest);
 
 
 
			GL.GenBuffers(1, out vertexBuffer);
 
			VertexTextureFormat[] vertices = {
 
				new VertexTextureFormat(new Vector2(0f, 0f), new Vector3(-1.0f, -1.0f, 4.0f)),
 
				new VertexTextureFormat(new Vector2(1f, 0f), new Vector3(1.0f, -1.0f, 4.0f)),
 
				new VertexTextureFormat(new Vector2(0f, 1f), new Vector3(0.0f, 1.0f, 4.0f))
 
			};
 
			verticesCount = 3;
 
			GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBuffer);
 
            GL.BufferData(BufferTarget.ArrayBuffer,
 
                (IntPtr)(verticesCount * VertexTextureFormat.SizeInBytes), vertices,
 
                BufferUsageHint.StaticDraw);
 
			GL.InterleavedArrays(InterleavedArrayFormat.T2fV3f, 0, IntPtr.Zero);
 
        }
 
 
 
        /// <summary>
 
        /// Called when your window is resized. Set your viewport here. It is also
 
        /// a good place to set up your projection matrix (which probably changes
 
        /// along when the aspect ratio of your window).
 
        /// </summary>
 
        /// <param name="e">Not used.</param>
 
        protected override void OnResize(EventArgs e)
 
        {
 
            base.OnResize(e);
 
 
 
            GL.Viewport(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height);
 
 
 
            Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, Width / (float)Height, 1.0f, 64.0f);
 
            GL.MatrixMode(MatrixMode.Projection);
 
            //GL.LoadMatrix(ref projection);
 
        }
 
 
 
        /// <summary>
 
        /// Called when it is time to setup the next frame. Add you game logic here.
 
        /// </summary>
 
        /// <param name="e">Contains timing information for framerate independent logic.</param>
 
        protected override void OnUpdateFrame(FrameEventArgs e)
 
        {
 
            base.OnUpdateFrame(e);
 
 
 
            if (Keyboard[Key.Escape])
 
                Exit();
 
        }
 
 
 
        /// <summary>
 
        /// Called when it is time to render the next frame. Add your rendering code here.
 
        /// </summary>
 
        /// <param name="e">Contains timing information.</param>
 
        protected override void OnRenderFrame(FrameEventArgs e)
 
        {
 
            base.OnRenderFrame(e);
 
 
 
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
 
 
			Vector3 position = Vector3.Zero;
 
			Quaternion rotation = new Quaternion(0, 1, 0, 0);
 
			Matrix4 modelViewOrRot;
 
			Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, Width / (float)Height, 1.0f, 64.0f, out modelViewOrRot);
 
			DirectedCamera cam = new DirectedCamera(ref position, ref rotation, ref modelViewOrRot);
 
 
 
			cam.GetViewProjection (out modelViewOrRot);
 
 
 
            GL.MatrixMode(MatrixMode.Modelview);
 
            GL.LoadMatrix(ref modelViewOrRot);
 
 
 
			GL.BindBuffer (BufferTarget.ArrayBuffer, vertexBuffer);
 
			VertexTextureFormat.SetOffsets();
 
			GL.DrawArrays (BeginMode.Triangles, 0, verticesCount);
 
 
 
            SwapBuffers();
 
        }
 
 
 
        /// <summary>
 
        /// The main entry point for the application.
 
        /// </summary>
 
        [STAThread]
 
        static void Main()
 
        {
 
            // The 'using' idiom guarantees proper resource cleanup.
 
            // We request 30 UpdateFrame events per second, and unlimited
 
            // RenderFrame events (as fast as the computer can handle).
 
            using (Game game = new Game())
 
            {
 
                game.Run(30.0);
 
            }
 
        }
 
    }
 
}

VertexTextureFormat.cs:

using System;
using System.Runtime.InteropServices;
using OpenTK.Graphics.OpenGL;
using OpenTK;
 
namespace StarterKit
{
    [StructLayout(LayoutKind.Sequential)]
    public struct VertexTextureFormat
    {
        public const int SizeInBytes = (2 + 3) * sizeof(float);
 
        public static InterleavedArrayFormat InterleavedFormat
        {
            get { return InterleavedArrayFormat.T2fV3f; }
        }
 
        public static void SetOffsets()
        {
            GL.InterleavedArrays(InterleavedArrayFormat.T2fV3f, 0, IntPtr.Zero);
        }
 
        public Vector2 TexCoord;
        public Vector3 Position;
 
        public VertexTextureFormat(Vector2 texCoord, Vector3 position)
        {
            TexCoord = texCoord;
            Position = position;
        }
    }
}

DirectedCamera.cs:

using System;
using System.Collections.Generic;
 
using OpenTK;
 
namespace StarterKit
{
    public class DirectedCamera
    {
        public Vector3 Position;
 
        public Quaternion Rotation;
        public void GetRotation(out Quaternion result)
        {
            result = Rotation;
        }
        public void SetRotation(ref Quaternion input)
        {
            Rotation = input;
        }
 
        public Matrix4 View
        {
            get
            {
                Matrix4 output;
                GetView(out output);
                return output;
            }
            set
            {
                SetView(ref value);
            }
        }
        public void GetView(out Matrix4 result)
        {
            Vector3 minusPosition = -Position;
            Matrix4 trans;
            Matrix4.CreateTranslation(ref minusPosition, out trans);
            Matrix4 rot = Matrix4.Rotate(Rotation);
            Matrix4.Mult(ref trans, ref rot, out result);
        }
        public void SetView(ref Matrix4 input)
        {
			Vector4 temp = Matrix4.Invert(input).Column3;
			Vector3 translation = temp.Xyz;
            Vector3.Multiply(ref translation, temp.W, out Position);
            Rotation = Quaternion.FromMatrix4(input);
        }
 
        public Matrix4 Projection;
        public void GetProjection(out Matrix4 result)
        {
            result = Projection;
        }
        public void SetProjection(ref Matrix4 input)
        {
            Projection = input;
        }
 
        public DirectedCamera(Vector3 position, Quaternion rotation, Matrix4 projection) : this(ref position, ref rotation, ref projection)
        {
        }
 
		public DirectedCamera(ref Vector3 position, ref Quaternion rotation, ref Matrix4 projection)
		{
            Position = position;
            Rotation = rotation;
            Projection = projection;
		}
 
		public bool Equals(DirectedCamera another)
		{
			return Position.Equals(another.Position) &&
				Rotation.Equals(another.Rotation) &&
					Projection.Equals(another.Projection);
		}
 
		public override bool Equals(object another)
		{
			if (another is DirectedCamera)
				return Equals((DirectedCamera)another);
			//else
			return false;
		}
 
		public override int GetHashCode ()
		{
			return Position.GetHashCode () ^ Rotation.GetHashCode () ^ Projection.GetHashCode ();
		}
 
		public static bool operator == (DirectedCamera first, DirectedCamera second)
		{
			return first.Equals(second);
		}
 
		public static bool operator != (DirectedCamera first, DirectedCamera second)
		{
			return !first.Equals(second);
		}
 
        public void GetViewProjection(out Matrix4 result)
        {
            Matrix4 view;
            GetView(out view);
            Matrix4.Mult(ref view, ref Projection, out result);
        }
        public void Move(Vector3 direction)
        {
            //direction var uses both for the direction(in) and the delta(out)
            Vector3.Transform(ref direction, ref Rotation, out direction);
            Vector3.Add(ref Position, ref direction, out Position);
        }
 
        public void Move(ref Vector3 direction)
        {
            Vector3 delta = direction;
            delta.Z = -delta.Z;
            Vector3.Transform(ref delta, ref Rotation, out delta);
            Vector3.Add(ref Position, ref delta, out Position);
        }
 
        public void MoveForward(float steps)
        {
            Vector3 delta = new Vector3(0, 0, steps);
            Move(ref delta);
        }
 
        public void MoveUp(float steps)
        {
            Vector3 delta = new Vector3(0, steps, 0);
            Move(ref delta);
        }
 
        public void MoveRight(float steps)
        {
            Vector3 delta = new Vector3(steps, 0, 0);
            Move(ref delta);
        }
 
        public void MoveBackward(float steps)
        {
            MoveForward(-steps);
        }
 
        public void MoveDown(float steps)
        {
            MoveUp(-steps);
        }
 
        public void MoveLeft(float steps)
        {
            MoveRight(-steps);
        }
 
        public void Rotate(Quaternion rotation)
        {
            Rotate(ref rotation);
        }
 
        public void Rotate(ref Quaternion rotation)
        {
            Quaternion.Multiply(ref Rotation, ref rotation, out Rotation);
        }
    }
}

I try so much(about 5 hours) to find the bug, and I found it is because the vertex format somehow.
I know you start to check the DirectedCamera.cs, but I'm very sure(5 hours sure :-) ) that the bug is not in this file.
Again, it's work in windows properly, and the bug is only in Linux and only while using T2fV3f(I tested it for C3fV3f).
Is the bug is in this code, or it's OpenTK bug, or even Mono bug?
Almost forgot- I'm Mono 2.6.7(Ubuntu 10.10), but it's also buggy in Mono 2.4(Ubuntu 10.04 LTS).


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

Try setting the packing explicitly:

[StructLayout(LayoutKind.Sequential, Pack=1)]
Tal's picture

OK, it's work now. Thanx so much Fiddler!!!
But could you tell me why should I write "Pack=1"(on windows I don't) ?

the Fiddler's picture

This is usually a x86 vs x64 difference: VS2010 runs as x86 by default (4-byte alignment) but Mono always runs as AnyCPU (4-byte alignment for x86 and 8-byte for x64). When working with OpenGL, it's generally best to set the alignment explicitly.

Boogiwoogie's picture

bahhh... did anyone ever mention that the fiddler is most capable?

Tal's picture

Sure he does! If he haven't been here I would go way over to SlimDX.
He's the one(and his awesome team) that makes .Net developers think twice about OpenGL, at least for me :)