Building Comanche 3D in less than 100 lines of code (UPDATE)

You can download Franklin 3D from here:

Unfortunately doesn’t support Linux (yet?).

I’ve been working on how to tile this terrain in OpenGL. The problem was a full tile is two million triangles and drawing just two of them slows framerate. Instead the tile is broken 4x4 into 16 ‘cells’ and only those cells in view are drawn. There’s still a limit to how many can be drawn, currently it can handle a grid up to 8 cells away from the camera. Depending how the camera’s Far value is set the horizon is either slicing through geometry or cells pop in as you get closer. This is something I really want to improve somehow but if you stay low within the mountains it can be effective.

To further improve performance each cells geometry has medium and low res versions used at distance (mipmap). This part isn’t finished yet, there’s a seam between different res cells, but it can be turned off and only full res cells are drawn which fit seamlessly while keeping framerate somehow.

Thanks to Alain for the maps listing, they’re all included. Now if I could just find a chopper model…

Download 21.4MB from this page
At the very top is the actual download icon/link. You may have to wiggle your mouse for it to show up.

Look in WindowFramingMip3 for a Note with more info.

Works on Mac, should work on Windows with Glu32.dll installed and App.getResourcesFolder edited to return the right folder. Linux will need declare work, not sure.

Looking very nice Will! Running smooth :slight_smile:

Had to change some things for windows:

  1. In Windows enable GdiPlus (for new picture(w,h) to work)

  2. in new EZFont() had to change Monaco to Arial as this font does not exist on Windows

  3. added in the GetResourcesFolder()

    #if DebugBuild then
    'return ? //update these to locate the Resources on Windows
    return GetFolderItem("").Parent.Child(“Resources”)
    return GetFolderItem("").Child(“Resources”)
    'return ?

btw, did you read about the Memoryblock trick to get the BGRA data into a memoryblock without using a RGBsurface? Note that this data is flipped upside down (OpenGl can solve this by changing coordinate systems, but I don’t know the impact on the rest of this)

Dim mb as MemoryBlock

’ get the pixel data, but as it is in BMP it is flipped upside down and in BGRA format
’ the first 54 bytes are the header, so remove them. the rest is BGRA data

mb = texture.GetData(Picture.FormatBMP)
dim BGRABitmap as Memoryblock = mb.StringValue(54, Height * Width * 4)

Not sure it’s usefull, but who knows :slight_smile:

Thanks for tips on getting it to work on Windows Alain.

I had to add one more change to prevent a runtime error on Windows. In the EZFont.drawString I had to add a boundary check with an “if” statement to prevent a runtime error.

  //========================== draw each char/glyph/quad
  dim charIdx As integer
  for i As integer = 0 to sa.Ubound
    charIdx = sa(i).AscB - 32
    if charIdx <= glyphXOffset.Ubound then // <<<<< to prevent potential runtime error
      x0 = baseCharX - glyphXOffset(charIdx)
      x1 = x0 + glyphXWidth(charIdx)
      vertData.set(0, x0, y0)
      vertData.set(1, x1, y0)
      vertData.set(2, x1, y1)
      vertData.set(3, x0, y1)
      u0 = glyphU0Coords(charIdx)
      u1 = glyphU1Coords(charIdx)
      uvData.set(0, u0, 0.0)
      uvData.set(1, u1, 0.0)
      uvData.set(2, u1, 1.0)
      uvData.set(3, u0, 1.0)
      OpenGL.glDrawArrays(OpenGL.GL_QUADS, 0, 4) 'g.arrays.drawArrays(0, 3)
      baseCharX = baseCharX + charXAdvance(charIdx)
    end if 

Will, your method of compiling true 3D scenes from voxel data is remarkable, KUDOS! Would you mind if I used some of your ideas and code in my own X3 engine (will give credit where I do so)?

For those who haven’t runned the code yet, here is a sceenshot of what the mountains looks like rendered with the EZGL framework:

Thanks for this, I’ll update my projects :slight_smile:

Yes, this is a very cool insight. BMP format contains raw pixel data perfect for passing to OpenGL! Going the other way with FromData seems to lose the alpha information though, it always comes back opaque.

Anyways I’ve been looking at the format generated by GetData and find it comes in 2 forms: 4 bytes per pixel (bpp) or 3 bpp. You get 3bpp format with masked pictures that are fully opaque and never had their Mask property touched. BMP’s 3bpp format has a fatal flaw being passed to OpenGL, pixel rows are padded out to a 4 byte boundary while OpenGL doesn’t pad.

To turn a Picture that would generate a 3bpp format into one that generates 4bpp all you have to do is access the Mask property; it’s almost a Schrodingers Cat situation. There’s some internal mask object that isn’t created unless needed and if it’s not there you get 3bpp format. But you can’t really check to know it’s state beforehand, you can only touch it to confirm it’ll be 4bpp like so…

[code]if not pic.HasAlphaChannel then //only affects masked pictures
call pic.Mask //touch the mask to ensure 4bpp

dim bmpMem As MemoryBlock = pic.GetData(Picture.FormatBMP)

dim pixMem As MemoryBlock = bmpMem.StringValue(54, pic.Width * pic.Height * 4)[/code]

Thanks Alwyn, I’ll add this fix but I don’t understand why it’s crashing. I mean I know drawString is lazy, it assumes the input string only contains ‘ascii’ values 32 to 126 which should work with the UTF8 literals in Xojo. I guess Str() or Format() is introducing higher code points somehow on Windows. Looking over the code there’s a lot more to do to unlazy it.

edit: looking at the screenshot I see commas are missing from the triangle count so Format must be using something other than Chr(44).

The crash occurs in EZFont.drawString at…

x0 = baseCharX - glyphXOffset(charIdx)

where charIdx = 162, and glyphXOffset.UBound = 94. This is on Windows 7 with Arial font.

Not sure if the info helps?

It helps me remember to be less assumptive :slight_smile:

charIdx 162 would come from a string where AscB(s) = 194 which is Â, or maybe it’s part of a multibyte letter. I think it’s the comma that’s messing up which is ascii 44 = &b00101100. 194 = &b11000010, that’s 44 with it’s nibbles flipped. Probably nothing, been watching lots of X-files.

This version has all the Windows fixes implemented so it should work with just Glu32.dll installed.

Very nice!

On my Windows 7 64bit i5 4GB machine the framerate of the built application is extremely low when the sky is rendered. If I go lower and make the sky disappear, the framerate increases and I get smooth flying, although the framerate is still somewhat low.

I think what’s happening is that when you angle down and don’t see the sky there’s less terrain ‘cells’ in view to draw. In Alwyns picture above there’s 41 cells being drawn at full mesh resolution of 130000 triangles each for a total of 5.34 million triangles. If you’re facing downwards there might be only 4 cells in view and those 500000 triangles will draw much faster. Basically I think it’s the number and size/area of triangles that are the limiting speed factor. Another way to reduce triangle count is to turn on geometry mipmapping from the menu Options > Geo MipMap. Then cells farther away use lower resolution meshes and the average triangle count when looking towards the horizon is around 1.5 million. This feature isn’t finished yet though and you’ll see seams where different resolution cells meet.


accidently found this website when I searched for Voxel Space.
I am the author of the website, which motivated this project:
Great work. It is always nice see to inspire people.

Are you interested in the code to extract these maps from Comanche? The other graphics from the game are probably in the same format.