Having finished cleaning up the concepts above, I though't I'd take a moment
To summarize and clarify the answer to the question for future readers, while the memory is fresh.
If you have a TESR or FastTESR that doesn't change its vertices every frame, or that only translates the vertices every frame, then you have at least two options for improving performance. As I stated in previous posts, I actually managed a 7-10 times performance improvement.
The first option is to use call lists, while the second is to adapt the Tessellator slightly (from now on, the adapted Tessellator will be referenced as ATess). In both cases, you can reuse the Tessellator rendering code you've probably already got.
I should note that you can also take advantage of VBOs with the call list system, and gain a bit of extra performance, but only when the graphics card supports them. Because of that, you can't rely on VBOs alone. I never got them working well, and so I won't be discussing them further, but there's "example" code in RenderGlobal.
The benefit of using call lists over ATess is that you won't impact performance (or at least, you will impact it much less) when the player isn't looking at the object being rendered.
The benefit of using ATess is that it is about 25% faster than the call lists (in my experience) when you are looking at the object, and it allows you to sort vertices to weed out transparency issues.
Call lists are stored by OpenGL, and accessed through integer IDs. To create and use call lists, you can do the following:
- Check to see if the list has already been created, and destroy it if so, using GlAllocation#deleteDisplayLists().
- Get an instance of the Tessellator and its BufferBuilder.
- Allocate a rendering ID through GlAllocation#generateDisplayLists().
- Create a new list with the generated ID by using GlStateManager#glNewList().
- Begin drawing with your BufferBuilder.
- Add vertices to the buffer in the same manner as with the Tessellator.
- Call Tessellator#draw().
- Finish the list with GlStateManager#glEndList().
- You can now render this call list by using GlStateManager#callList(), and passing in the ID you stored earlier.
The adapted Tessellator (ATess) and adapted BufferBuilder (ABuff from now on) are only different in that you can swap the ABuff into and out from the ATess, and in that the ABuff doesn't reset when drawn. This allows you to not constantly reload all the data into the buffer. The code for these adaptations is shown below. To use them:
- Create a new ATess instance, and get its ABuff.
- I ended up storing the ABuffs within an array, which allowed me to mostly reuse the render ID system stated above in the call list section. This isn't necessary, though.
- Begin drawing with the ABuff.
- Add vertices as you would with the standard Tessellator and BufferBuilder.
- Call ATess#draw().
- Save the ABuff somewhere for later use. It now contains your rendering data.
- You can now render this ABuff by swapping it into an ATess and calling ATess#draw(). You can also sort the vertex data, since ABuff extends BufferBuilder.
ATess and ABuff classes: