Mapping GL intermediate mode style to hardware buffers

· by Steve · Read in about 3 min · (485 Words)

A lot of people like GL intermediate-mode style code for building custom objects. Unfortunately, it’s very inefficient for large objects or those which are rendered multiple times. OGRE gives you a full render API independent interface to the wonders of hardware vertex and index buffers, and all the super-flexible vertex declarations and shared buffer bindings that allows, but a lot of people find it intimidating. So I’ve decided to write a class for Dagon which allows a user to build a piece of custom geometry which is both efficient and hardware-friendly, whilst at the same time being very simple to define.

ManualObject is basically a builder helper class which adapts itself as you give it more and more information, finally coalescing the whole shebang into standard OGRE hardware stylee at the end. You just call simple methods like:


manualObject->begin(RenderOperation::OT_TRIANGLE_LIST);
manualObject->vertex(100, 0, 0);
manualObject->normal(1, 0, 0);
manualObject->textureCoord(0, 0);
manualObject->vertex(100, 100, 0);
manualObject->normal(1, 0, 0);
manualObject->textureCoord(0, 1);
... more vertices
manualObject->end();

That’s a lot easier for people used to the most basic GL interface to get to grips with, even though internally what it’s doing is:

  1. determining a vertex declaration based on the vertex elements you used, and sorting out portable declaration orderings etc

  2. creating a vertex buffer of the right size on the GPU and uploading the data

  3. binding this vertex buffer to the declaration source

Using this object won’t be as flexible as using the full hardware vertex decl/buffer API - for example there’s no point trying to do dynamic buffers this way - but for the largely trivial things that people often want to do, I think it will help. When they want to do more specialised things users can move on to the Mesh API and even into defining their own pluggable MovableObject and Renderable implementations for the ultimate in flexibility.

I’ve been addressing a non-power-of-two texture issue on 1.0.4 (D3D9 only) too; since a fix to one issue has led to hardware-generated mipmaps being used more frequently, and people using NPOT textures have found their mipmaps don’t work. Seems that D3D9 mostly can’t hardware generate mip levels for NPOT textures, even though there appears to be no way to detect that, since the method to determine whether hardware mip generation is supported doesn’t take dimension parameters. So we’re having to detect NPOT ourselves and rule out hardware generation in D3D9, falling back on software generation (no big deal, although it’s a bit slower to initialise) to avoid the issues. The moral of the story of course is to use power-of-two sized textures, since they are the most reliably supported by graphics hardware. If you use pixel shaders you could well find you can’t do dependent texture lookups with NPOT textures for example. Allowing NPOT textures in your app is generally A Bad Idea ™. Repeat after me: “I will use textures whose dimensions are a power of two.”. Got it? Good. 😀