objarni's picture

GL.LoadMatrix(Matrix4) overload..?

I wanted to use the LoadMatrix method of the GL class.. found lots of overloads, but none of them taking a Matrix4 (or ref to it ..) as an argument.

Is this a known issue or should I put up an item about it somewhere..? (where?)

Overall I'm so far very pleased with my OpenTK experience.. Keep up the good work!


Comments

Comment viewing options

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

You can use the ref/out overloads for this task. Remember that OpenTK.Math matrices are row-major, OpenGL itself expects a column-major matrix when using GL.LoadMatrix and will convert into this convention internally.

Either use this:

GL.MatrixMode( MatrixMode.Modelview );
GL.LoadTransposeMatrix( ref m1.Row0.X );
// proof
GL.GetFloat( GetPName.ModelviewMatrix, out m2.Row0.X );
m2.Transpose( );

...or manually m1.Transpose (if this is the end of the Matrix4's lifespan) before calling GL.LoadMatrix instead of using GL.LoadTransposedMatrix.

You got my support for your request for a Matrix4 overload, but I start to get afraid that Fiddler will ban me (or worse: send a horde of hamsters to assassinate me), if I keep making Wishlists ;)
Something that would be very nice too are GL.GetFloatVector2/3/4 and GL.GetFloatMatrix4 functions added to GL. I cannot currently recall what query would return a Vector2, but there's probably some (window size? texcoords?)

...pleased with my OpenTK experience
Regarding the fun using OpenTK, I can only agree.

objarni's picture

Thanks for your support Inertia!

For me, using 'ref float' and 'float*' when calling a method means different things. 'ref float' means sending a reference to a single float variable. In this case, that would mean the very first element of the first row, ie. element 0,0 of the matrix.

So, internally, GL.LoadTransposeMatrix must make some guesses about the layout of memory after that 'variable' then?

This behaviour seems not-so-C#-ish if you know what I mean.. Is there something I'm missing here?

I would really prefer sending 'ref Matrix4' or 'float*', in that order of preference. (or even better, simply Matrix4, ie. letting the matrices be of class type.. but I know I've got the performance-politics against me here! ;)

I guess this might be showing up in the next OpenTK release?

the Fiddler.'s picture

The only difference between 'float*' and 'ref float' is that the pointer is passed directly to the unmanaged function in the first case, while the object is first pinned before passing a pointer in the second version. Apart from this, they behave identically - in this case 'ref float' effectively is a managed version of a pointer.

This is actually defined in the C# specs (I didn't believe that either until someone posted a link to the actual paragraph), and is very useful in the case when you want to pass an array starting from the nth element. The only requisite for this is to define the class/struct with LayoutKind.Sequenctial attribute (IIRC, structs have this by default).

I'd like to add Matrix/Vector overloads wherever it makes sense, but I'm pressed for time (getting internet explorer to work with the new theme is taking way too much time). Even a simple list of missing overloads would help a lot.

Inertia's picture

@objarni
You're welcome, and yes: internally OpenGL uses column major matrices no matter if you used GL.LoadTransposeMatrix or manually transpose first, it's only about the order of the 16 float in memory. Knowing the difference and as long as you remember that querying the matrix will give you something column-major you should be fine :)
I don't think you are missing anything there, IMHO you should not be too worried about performance implications due to the matrix being transposed.

@Fiddler
The uses for Matrix4 I can come up with:
GL.LoadMatrix
GL.LoadTransposeMatrix
GL.MultMatrix
GL.GetFloat( Modelview/Projection/Texture Matrix
GL.UniformMatrix4* (this one accepts Matrix[] too, but I don't understand why there are so many permutations?)
Edit: Quote from orangebook on glUniformMatrix: "The number in the command name is interpreted as the dimensionality of the matrix. The number 2 indicates a 2 x 2 matrix (i.e., 4 values), the number 3 indicates a 3 x 3 matrix (i.e., 9 values), and the number 4 indicates a 4 x 4 matrix (i.e., 16 values)."

objarni's picture

Thanks for your answers, this clears things up.

Just out of curiosity: why wasn't the Matrix4 layout choosen to be the same as OpenGL's? It seems they are quite 'close' anyway (OpenTK relies on OpenGL) so that would be the "naive" choice.

(going back to my Casual 3d game in C#-project)

objarni's picture

Hmm. I saw the news about errors in the Matrix4 implementation, regarding both RotateX, Mult and Rotate, all three of which I'm using in my game to no success. I guess I'll have to wait with that part of the game until OpenTK-0.3.14 is out!

Inertia's picture

I've asked the same thing, and I remember the answer to be that row-major matrices allow some CPU optimizations. Using row-major matrices seems to be so common (DirectX uses row-major too) that most OpenGL functions accepting matrices also have a parameter to specify if the matrix should be transposed by GL when incoming to the function. My guess is that this has been requested by developers who write both, a DX renderer and a GL renderer. One matrix layout to rule them all ;)

If you don't want to wait for the update, you can still use GL.Rotate or GL.MultMatrix to calculate the orientations.

You made me curious though, a Casual 3d game? :)

objarni's picture

OK I'll just swallow that (why is it always performance that makes things complicated/ugly looking? Can't performance and elegance go hand-in-hand every once in a while..)

Thanks for the tips. I'll rewrite my "rendering interface" from using Matrix4 to using specific operations like rotate etc. so I will be able to use the ordinary GL.Rotate/Translate methods "under the hood" and skip Matrix4 altogether.

Yeah I'm doing a simple, non-original casual 3d game using OpenTK, nothing playable yet just a model viewer, but you can see a low-resolution in-game concept art image here:

http://sourceforge.net/projects/dogfight2008/

Basically it's a remake of an old classic Amiga game I loved back in the days, called "Dogfight" simply, with two instead of four human players (don't you just hate PC-keyboards..? Pressing more than two keys simultaneously is just worthless..)

Inertia's picture

Indeed, optimized code is often hard to follow if you didn't write it yourself (one of the main reasons why I never liked C(++) much).
It might be just me, but I do like the ref/out stuff in OpenTK. It has the advantage that the code is very clear about if you are passing by value or reference (which can lead to very hard-to-trace bugs if you're not careful) and it's not much more typing to do. But then I'm also one of those people who explicitly declare private members, give enums an explicit type and declare struct-layout/attribs wherever I can, no matter if it's default or not. I just believe it leads to more expressive code, which is worth the little extra typing.

Good choice regarding the game :) This is the kind of game one person can accomplish in a reasonable timeframe, I hereby thank god that Tao/OpenTK users are more sane than XNA users (half the people using XNA are (trying to) developing MMORPGs or 3D Shooters) ;)
I've had an [brag]Amiga 500 with 1MB Ram[/brag], but have to admit I've never heard of Dogfight. The image looks like it's plane vs. plane dogfight, each starting at their own tower and battling it out in the air?

Regarding multiple keystrokes, it is already quite tight when 2 players are using the same keyboard. If you play the game more than 5 minutes, it will start getting uncomfortable too. I think you should rather consider gamepads/joysticks or maybe even the mouse as control devices, rather than trying to force 4 players to use the same keyboard.

P.S. You are using VS2005, is there any reason why you're avoiding 2008?

objarni's picture

Indeed, optimized code is often hard to follow if you didn't write it yourself (one of the main reasons why I never liked C(++) much).
It might be just me, but I do like the ref/out stuff in OpenTK. It has the advantage that the code is very clear about if you are passing by value or reference (which can lead to very hard-to-trace bugs if you're not careful) and it's not much more typing to do. But then I'm also one of those people who explicitly declare private members, give enums an explicit type and declare struct-layout/attribs wherever I can, no matter if it's default or not. I just believe it leads to more expressive code, which is worth the little extra typing.

Yeah I agree about being explicit. But I am (nowadays) used to thinking "reference" when I am passing "an object" to a method in C#. I think I got into this thinking when I made a (quick) dive into java a couple of years ago, some applet-game-hack I put together. In java every object is passed by reference, never by value. So to me having a method taking a Matrix4 simple tells me it is passed by reference. I guess you can see why I dislike 'ref' -- it is already passed by reference to me! This is also one of the reasons I prefer immutable objects instead of mutable objects -- it reduces the hard-to-trace bugs you too are referring to. That kind of bugs are also known as aliasing bugs, IIRC.

Good choice regarding the game :) This is the kind of game one person can accomplish in a reasonable timeframe, I hereby thank god that Tao/OpenTK users are more sane than XNA users (half the people using XNA are (trying to) developing MMORPGs or 3D Shooters) ;)
I've had an [brag]Amiga 500 with 1MB Ram[/brag], but have to admit I've never heard of Dogfight. The image looks like it's plane vs. plane dogfight, each starting at their own tower and battling it out in the air?

Thanks! The planes are supposed to start at ground level. The towers are simply part of the background imagery. Dogfight for the Amiga was just a really small public domain game. It was nothing fancy, but it was so darn fun to play. I guess there are numerous remakes already, but I haven't seen one for OpenTK/quasi 3d yet :)

Regarding multiple keystrokes, it is already quite tight when 2 players are using the same keyboard. If you play the game more than 5 minutes, it will start getting uncomfortable too. I think you should rather consider gamepads/joysticks or maybe even the mouse as control devices, rather than trying to force 4 players to use the same keyboard.
Yeah thats why I plan keeping it at two players, and using as few keys as possible, namely three per player. Since you usually don't try to fly up and down at the same time, the usual amount of keys pushed is 0-2, with single additional strokes every now and then to fire a shot. So at most 4 keys simultaneously. I hope to use "safe keys" for the firing -- shift and such. Have to experiment a little.

I'm using Visual2005 because that's what I'm used to. And I'm targeting .NET2.0/mono1.2.6, so I see no real benefit of using VS2008 for this project. (though I like the new lambda-stuff they put into C#3.. but not enough to go through the hassle of upgrading this project to it..)