Rich's picture

OpenTK instead of Tao

Hello there!

I'm currently using Tao & Mono for my Project to rebuild a 10 year old 2D game.
I came to your side once in a while and I think that OpenTK is much more serious than Tao.

My question is now:

Is OpenTK a good choice for that? Are there more advantages than less cryptic code (which is a present from heaven for me)?

thx rich


Comments

Comment viewing options

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

k thx for support. Another question came up to me yesterday. I read the short guide on the site and i saw that because of compability time from .net/mono to c there shouldn't be more than 600 GL.X calls for every frame.
My game has a tile terrain which means i have about 600 quads (basically 44x44) building up just my terrain (i can upload a image if you want to tomorrow). I'm having serious problem with performance because the game seems to eat all power of the CPU. Is there a workaround that i use something like a vertex buffer or indexbuffer like in DirectX and not to call more than 600 times my render statement GL.Begin(BeginContex.Quads); .... GL.End() ?

thx rich

objarni's picture

VertexBufferObjects, or VBOs for short. See this tutorial:

http://www.opentk.com/doc/chapter/2/opengl/geometry/vbo

Note: VertexArrays are a good and easy way to draw things a lot faster in C/C++. But it is neither easy nor fast in C#/.NET! VBOs is what you are looking for!

the Fiddler's picture

The 600 calls is not a hard limit, just a rule of thumb. You will get a nice speed boost if you switch to Vertex Buffer Objects, but I don't think the GL.Begin() - GL.End() is the cause of the high CPU usage here (each OpenGL call has an additional overhead in the order of 8-15ns compared to C code, so it's not that bad).

Are you using the debug or the release version of OpenTK? The debug version hits the cpu hard: it calls GL.GetError() automatically, which causes the OpenGL command-queue to flush.

It's also normal to see 100% CPU usage if you don't enable vsync, because then you are drawing as fast as possible. Enable vsync and CPU usage should drop significantly.

Rich's picture

Ok i now have a constant low CPU usage without any VBO... I do not really know how to write my data into the VBO and at the same time use the index buffer. (Picture in attachments)

1,2,3 and 4 are the vertices i'm using on each drawn tile.

How would you use the index buffer?

thx rich

AttachmentSize
Bildschirmfoto.png416.16 KB
the Fiddler's picture

You'll have to use the index buffer to connect the 4 vertices so that they form two triangles. Assuming the vertices are like this:

34
12

You can connect them like this:

1, 2, 3
3, 2, 4

Make sure that you preserve the normal between the two triangles (123 and 324 have normals that face the same way. 123 and 342 have normals that face in opposite ways).

If performance is adequate, I wouldn't worry about using VBOs just yet. When building a 2d game, you'll probably want to keep hardware requirements as low as possible, which usually translates in an OpenGL 1.1 code path (i.e. immediate-mode and display lists). OpenGL 1.1 won't go away any time soon and even plain old immediate-mode can be fast enough for old-school 2d games with a little care.

If possible, just try to decouple the data structures for your map (tiles, layers, regions) from their rendering method. This way you'll be able to add a VBO render path later on, if you decide it's necessary.

Inertia's picture

http://www.opentk.com/doc/chapter/2/opengl/geometry

Is there anything we can do to make these kinds of articles easier to find? I still intend to add custom Vertex attribs and VAO explanation to these pages, but there shouldn't be a single person visiting this website who does not know about VBO. Or spell it VOB. ;-)

If you want my 2c why OpenTK is superior to Tao: (Besides what was mentioned above, which is all true) OpenTK saves you alot of time looking up function parameters in manuals. OpenTK does not spare you reading the red book or a similar introduction to GL, but if you are familiar with the usage patterns it is very helpful to have the enums. The enums take away your little "Woot! I wrote 10 lines of GL code without using the manual and it produces no GLError!" victory, but that's something one can live without.

Rich's picture

I finally gave VBOs a try and the performance is much more adequat.

But still some questions :) :
I have about 600 "maptiles" every frame.... (see picture above from previous post).
Now with the VBO i have to bind for every tile a the texture id.
Isn't there faster way? Can't i just store the texture ids for each quad in GL and
destroy this loop with mean about ~1200 GL calls?

for (int i=0;i < 600;i++)
{
  Textures.BindTexture(todraw[i]); //todraw[i] is the texture id i want to bind
  GL.DrawArrays(BeginMode.Quads,i*4,4); //here i draw one of the 600 quads
}

EDIT:
Another question came up to me. I read about the PBO (Pixel Buffer Object). I didn't
really understand why to use it. I can use it to store texture via the DMA (Direct Memory Access).
This procedure relieves the CPU usage.
But when i bind my texture the bytes are already stored in GL? why should i use the PBO?

thx rich

the Fiddler's picture

The best solution way is to use tile sheets, were multiple tiles are stored in a single texture. This way you can change a tile by simply changing the texture coordinates of its quad.

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct VertexPositionTexture
{
    Vector2 Position;
    Vector2 TexCoords;
}
 
// Load 'tiles' into the VBO afterwards.
var tiles = new VertexPositionTexture[MapWidth, MapHeight, 4];
for (int x = 0; x < Map.Width; x++)
{
    for (int y = 0; y < Map.Height; y++)
    {
        tiles[x, y, 0] = new VertexPositionTexture()
        {
            Position = { X = x * TileWidth, Y = y * TileHeight },
            TexCoords = { X = tile_coordinates_in_texture.X, tile_coordinates_in_texture.Y }
        };
 
        tiles[x, y, 1] = new VertexPositionTexture()
        {
            Position = { X = (x + 1) * TileWidth, Y = y * TileHeight },
            TexCoords = { X = tile_coordinates_in_texture.X + TileWidth / TextureWidth, tile_coordinates_in_texture.Y }
        };
 
        // Likewise for the other two vertices of the quad.
    }
}

This way, assuming that all your textures fit inside a single tile sheet, you'll be able to draw all 600 tiles with a single draw call:

Textures.BindTexture(tile_sheet);
GL.DrawArrays(BeginMode.Quads, 0, 600*4);

If they don't fit in a single tile sheet, you can use as many draw calls as the number of tile sheets you have. It's slightly more complicated (not much), but it is going to be *much* faster than 600 texture binds & draw calls.

Edit: PBOs can help you write or read textures from GL memory asynchronously. They also have other uses that aren't really relevant here.

Rich's picture

Hey there,

I'm still having some problems with performance (or i think i can code it much faster).
First look at picture in attachments pls!

What about if i make for each 8x8 block on the map a drawing list and move arround with GL.Translate(x,y,z); ? would that be faster?
what you think

thx rich

AttachmentSize
8x8.png464.51 KB
objarni's picture

Display lists are a good option to speed up non-dynamic rendering, as your grass tiles (they look the same all the time).

During the load of your level, create a display list by "recording" the rendering of 8x8 block of grass tiles. The display list (DL for short) will get an integer "name" just like texture objects do.

Note: DO NOT re-create the display list at every paint! That is a common beginners-mistake. Re-creating the display list every paint is likely to be slower than using ordinary immediate mode.

In your paint method:
1. clear the color buffer (this step might be skipped if your grass block covers 100%, but your image says otherwise - there is some pixel row between each tile shining through whatever is behind the grass)
2. blit the DL all over the background, with as few CallList as possible.
3. draw images of the tree, mushroom ontop of this.

Here's a random tutorial I found to get you started:

http://www.songho.ca/opengl/gl_displaylist.html