Yuck - code restructuring

Published April 02, 2006
Advertisement
Well it's been a long time since my last journal entry. I've finally refactored the code in my terrain engine. I moved stuff into their own classes, cleaned up the code, and found and squashed numerous bugs. Tedious as hell, but it had to be done.

Here's the Land-o-Rama library architecture so far:

Height-map class

A height map stores elevation values (you've probably figured this out :-) It contains an uncompressed m x n buffer.

There is an equivalent image class that stores pixels instead of elevation values.

Terrain class

When developing Land-o-Rama, I wanted it to support gigantic terrains (32k x 32k or greater). Of course, you cannot fit all this data in a height map -- a 32k x 32k height map would take up 4 gigabytes of RAM. So I needed a way to generate elevation points without storing all of the terrain in memory. Enter the terrain class.

A terrain class is the source of all elevation values used by Land-o-Rama. A terrain class fills a buffer with elevation values from a rectangular area of the terrain. The class also supports LOD.

A terrain class is an abstract base class. Currently, I have a derived class that stores a height-map object and applies artificial detail to it using a displacement map.

You could write a terrain class that doesn't even use a height map at all -- it could output Perlin noise, for example. I'm thinking at some point of creating a terrain class that outputs values generated from my libnoise library. You could even have a terrain class that used data compression to store a massive terrain in RAM.

There is an equivalent terrain image class that outputs pixels instead of elevation values.

Patch class

A patch stores a 2n+1 x 2n+1 square area of the terrain. (I'm currently using a patch size of 33 x 33.) It contains a vertex buffer, two normal buffers, and two color buffers. Land-o-Rama maintains a quadtree of patches.

The two normal buffers contain normals for the same area of the terrain, but one of these buffers is used by the triangle mesh at the next coarser LOD. These normals are blended together with the appropriate morph weights.

The two color buffers are morphed in the same way as the two normal buffers.

Renderer class

A renderer class renders the contents of a terrain object. It is also responsible for the following:
  • Maintaining the quadtree of patch objects by adding/removing patches as the user moves around the terrain.

  • Performing quadtree frustum culling.

  • Generating the terrain normals

The renderer class is an abstract base class. It doesn't actually render anything; its derived classes do the rendering. This allows me to easily experiment with different rendering techniques (or even different graphics libraries) without modifying the base renderer class. The base renderer class does not care whether you're using OpenGL, DirectX, or Joe-Blow's Software Renderer v0.67b(TM).

The base renderer code calls derived methods at appropriate times while rendering:
  • After a new patch is created: This is where you use the terrain object to fill the contents of the patch, allocate the appropriate buffers on the graphics hardware, and upload the contents of that patch to those buffers.

  • When a patch is deleted: This is where you free the allocated buffer on the graphics hardware.

  • When the terrain is about to be rendered: This is where you set up things that need to be done before rendering, such as uploading texture maps, setting shader parameters, etc.

  • When a patch needs to be rendered: Here is where you make the actual graphics-library calls to render the patch.

Currently, the only renderer class I've created is one that uses OpenGL 1.1. In this class, the vertex, normal, and color morphing are all done (very slowly) in software! I wanted to make sure my code worked before moving to GLSL.

Here's what the OpenGL 1.1 renderer looks like:



This is a 1024 x 1024 height map with a 2048 x 2048 image. The terrain size is 32k x 32k. OpenGL does the lighting. The terrain image is created from a vegetation map of the area. (The vegetation map is generated from the red and near-IR channels of a Landsat image of the area, with a brown-to-green gradient applied to the results.)

While all of this is fresh in my mind, I'm going to document the classes, their members, etc. This will probably take me awhile since I hate documenting stuff, but it must be done. When it's done, I can begin to apply GLSL to Land-o-Rama, w00t! I just got the OpenGL Shading Language orange book in the mail, so it'll be hard to do the documentation while it is sitting on my desk.
0 likes 2 comments

Comments

HopeDagger
Wow. Looks very nice. Wish I saw this journal earlier! :)
April 02, 2006 10:40 PM
Telastyn
Yay, design discussion!
April 24, 2006 10:58 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement