OGRE and terrain modeling
Posted: Thu May 20, 2004 2:49 am
Reworking Comtois former code which generates an animated waved texture, we, Cederavic and me, did something that may interest some of you :
Load the France.JPG bitmap file representing a geographical area with colored altitudes at the following address :
http://perso.wanadoo.fr/francois.weil/France.JPG
Copy this file to a data\ folder you will have under the point were you will save the following code.
The jpeg comes from an USGS to Terragen file re-exported and saved as a bitmap using Wilbur (just for those who understand what I am talking about). Whatever is the way I got the bitmap, you just have to look at it to understand it is a regular map. Just the pixels have a given color linked to altitude.
Such a color set is frequently used so that if you start to analyze pixels, you will understand quickly how to approximate the altitude of a given point by looking RGB value of the point.
The only trick I do there except other coding for OGRE arrays, is to consider the blue as the lowest level and the red as the highest. By inverting from RGB to BGR and converting color values to a 0-1 float makes easy to produce an altitude array that can be thrown to the OGRE array containing W, Y, Z.
That's it.
Now a bit about Comtois's code. He did a good work. I just changed some ways to present the code, but the basic algorithm used to load arrays works well. I even check for possible optimization that I have not found right now.
The present code shows also some good milestones I did not fixed before using OGRE engine :
- you can use any graphic file to be loaded using an available image decoder (here UseEC_OLEImageDecoder())
- you can resize the bitmap in memory to adapt to terrain / texture requirements in your app.
- by getting altitude infos and putting in directly to OGRE arrays, it becomes possible to think to something like a "path finder" to travel around the terrain (not demonstrated here, but ... it is possible).
It was a mess for me before, to undesrtand how to manage OGRE engine arrays in a "usual way". Now it is more clear for me.
Hope you will enjoy this code.
Load the France.JPG bitmap file representing a geographical area with colored altitudes at the following address :
http://perso.wanadoo.fr/francois.weil/France.JPG
Copy this file to a data\ folder you will have under the point were you will save the following code.
The jpeg comes from an USGS to Terragen file re-exported and saved as a bitmap using Wilbur (just for those who understand what I am talking about). Whatever is the way I got the bitmap, you just have to look at it to understand it is a regular map. Just the pixels have a given color linked to altitude.
Such a color set is frequently used so that if you start to analyze pixels, you will understand quickly how to approximate the altitude of a given point by looking RGB value of the point.
The only trick I do there except other coding for OGRE arrays, is to consider the blue as the lowest level and the red as the highest. By inverting from RGB to BGR and converting color values to a 0-1 float makes easy to produce an altitude array that can be thrown to the OGRE array containing W, Y, Z.
That's it.
Now a bit about Comtois's code. He did a good work. I just changed some ways to present the code, but the basic algorithm used to load arrays works well. I even check for possible optimization that I have not found right now.
The present code shows also some good milestones I did not fixed before using OGRE engine :
- you can use any graphic file to be loaded using an available image decoder (here UseEC_OLEImageDecoder())
- you can resize the bitmap in memory to adapt to terrain / texture requirements in your app.
- by getting altitude infos and putting in directly to OGRE arrays, it becomes possible to think to something like a "path finder" to travel around the terrain (not demonstrated here, but ... it is possible).
It was a mess for me before, to undesrtand how to manage OGRE engine arrays in a "usual way". Now it is more clear for me.
Hope you will enjoy this code.
Code: Select all
;
; D'après le source de Comtois
;
; France.pb
;
; Cederavic et FWeil 20040520
;
Global PointIDMemory.l, TriangleIDMemory.l, TextureIDMemory.l
Dim Altitudes.f(1000, 1000)
Enumeration
#PointID
#TriangleID
#TextureID
#NbX = 80
#NbZ = 80
EndEnumeration
Global xrot.f, yrot.f, zrot.f
Global CamLocateX.l, CamLocateY.l, CamLocateZ.l, CamLookAtX.l, CamLookAtY.l, CamLookAtZ.l
Global Mode.b
#ScreenWidth = 1024
#ScreenHeight = 768
#ScreenDepth = 32
Procedure Label(x.l, y.l, text.s)
Locate(x, y)
DrawText(text)
EndProcedure
Procedure Matrice(FX.l, FZ.l)
address = PointIDMemory
For b = 0 To FZ
For a = 0 To FX
PokeF(address, a - FX / 2)
PokeF(address + 4, 0)
PokeF(address + 8, b - FZ / 2)
address + 12
Next
Next
address = TriangleIDMemory
Nb = FX + 1
For b = 0 To FZ - 1
For a = 0 To FX - 1
P1 = a + (b * Nb)
P2 = P1 + 1
P3 = a + (b + 1) * Nb
P4 = P3 + 1
PokeW(address, P3)
PokeW(address + 2, P2)
PokeW(address + 4, P1)
PokeW(address + 6, P2)
PokeW(address + 8, P3)
PokeW(address + 10, P4)
PokeW(address + 12, P1)
PokeW(address + 14, P2)
PokeW(address + 16, P3)
PokeW(address + 18, P4)
PokeW(address + 20, P3)
PokeW(address + 22, P2)
address + 24
Next
Next
address = TextureIDMemory
For b = 0 To FZ
For a = 0 To FX
PokeF(address, a / FX)
PokeF(address + 4, b / FZ)
address + 8
Next
Next
EndProcedure
Procedure TerragenExport()
address = PointIDMemory + 4
For z = 0 To #NbZ
For x = 0 To #NbX
Sommet.f = 100 * Altitudes(x, z)
PokeF(address, Sommet)
address + 12
Next
Next
SetMeshData(0, 0, PointIDMemory, (#NbX + 1) * (#NbZ + 1))
EndProcedure
Procedure ShowTextAndKeyTest()
StartDrawing(ScreenOutput())
DrawingMode(1)
FrontColor(20, 180, 115)
Label(0, 0, "[F1] => Toggle Mode affichage")
Label(0, 20, "[PageUp] / [PageDown] => Wave Amplitude : " + StrF(WaveAmplitude))
Label(0, 40, "[Up Arrow] / [Down Arrow] => Wave Period on Z axis : " + Str(WavePeriodZ))
Label(0, 60, "[Right Arrow] / [Left Arrow] => Wave Period on X axis : " + Str(WavePeriodX))
Label(0, 80, "[Home key] / [End key] => Wave speed : " + Str(WaveFrequency))
Label(0, 100, "[F2] / [Shift+F2] => X rotation speed : " + StrF(xrot))
Label(0, 120, "[F3] / [Shift+F3] => Y rotation speed : " + StrF(yrot))
Label(0, 140, "[F4] / [Shift+F4] => Z rotation speed : " + StrF(zrot))
Label(0, 160, "[F5] / [Shift+F5] => X Camera location : " + Str(CamLocateX))
Label(0, 180, "[F6] / [Shift+F6] => Y Camera location : " + Str(CamLocateY))
Label(0, 200, "[F7] / [Shift+F7] => Z Camera location : " + Str(CamLocateZ))
Label(0, 220, "[F8] / [Shift+F8] => X Camera look at : " + Str(CamLookAtX))
Label(0, 240, "[F9] / [Shift+F9] => Y Camera look at : " + Str(CamLookAtY))
Label(0, 260, "[F10] / [Shift+F10] => Z Camera look at : " + Str(CamLookAtZ))
StopDrawing()
If KeyboardReleased(#PB_Key_F1)
Mode = #PB_Camera_Wireframe - Mode
CameraRenderMode(0, Mode)
EndIf
If KeyboardPushed(#PB_Key_LeftShift) Or KeyboardPushed(#PB_Key_RightShift)
Coeff = -1
Else
Coeff = 1
EndIf
xrot + 0.1 * Coeff * KeyboardPushed(#PB_Key_F2) / 128
yrot + 0.1 * Coeff * KeyboardPushed(#PB_Key_F3) / 128
zrot + 0.1 * Coeff * KeyboardPushed(#PB_Key_F4) / 128
CamLocateX + 1 * Coeff * KeyboardPushed(#PB_Key_F5) / 128
CamLocateY + 1 * Coeff * KeyboardPushed(#PB_Key_F6) / 128
CamLocateZ + 1 * Coeff * KeyboardPushed(#PB_Key_F7) / 128
CamLookAtX + 1 * Coeff * KeyboardPushed(#PB_Key_F8) / 128
CamLookAtY + 1 * Coeff * KeyboardPushed(#PB_Key_F9) / 128
CamLookAtZ + 1 * Coeff * KeyboardPushed(#PB_Key_F10) / 128
EndProcedure
;
; Main starts here
;
If InitEngine3D() And InitSprite() And InitKeyboard() And OpenScreen(#ScreenWidth, #ScreenHeight, #ScreenDepth, "FRW Matrix")
circle.l = 360
xrot = -0.6
yrot = -0.8
zrot = 0.2
CamLocateX.l = 0
CamLocateY.l = 0
CamLocateZ.l = 250
CamLookAtX.l = 0
CamLookAtY.l = 0
CamLookAtZ.l = 0
PointIDMemory = AllocateMemory(12 * (#NbX + 1) * (#NbZ + 1)) ; Mémoires Mesh
TriangleIDMemory = AllocateMemory(12 * #NbX * #NbZ * 4)
TextureIDMemory = AllocateMemory(12 * (#NbX + 1) * (#NbZ + 1))
Matrice(#NbX, #NbZ)
CreateMesh(0) ; Mesh
SetMeshData(0, 0, PointIDMemory, (#NbX + 1) * (#NbZ + 1))
SetMeshData(0, 1, TriangleIDMemory, (#NbX) * (#NbZ) * 4)
SetMeshData(0, 2, TextureIDMemory, (#NbX + 1) * (#NbZ + 1))
UseEC_OLEImageDecoder()
TextureXSize = 512
TextureYSize = 512
ImageID1 = LoadImage(0, "data\France 1024x1024.jpg")
ImageID1 = ResizeImage(0, TextureXSize, TextureYSize)
ImageID2 = CreateImage(1, TextureXSize, TextureYSize)
StartDrawing(ImageOutput())
DrawImage(ImageID1, 0, 0)
For x = 0 To ImageWidth() - 1
For y = 0 To ImageHeight() - 1
Color = Point(x, y)
Red = Red(Color)
Green = Green(Color)
Blue = Blue(Color)
Altitudes(x, y) = (Red * $1000 + Green * $100 + Blue) / $1000000
Next
Next
DrawingMode(1)
FontSize = 32
DrawingFont(LoadFont(#PB_Any, "Verdana", FontSize, #PB_Font_Bold | #PB_Font_HighQuality))
FrontColor(0, 0, 0)
Text.s = "La France"
Label((TextureXSize - TextLength(Text) + 2) / 2, TextureYSize - 30, Text)
FontSize = 28
DrawingFont(LoadFont(#PB_Any, "Verdana", FontSize, #PB_Font_Bold | #PB_Font_HighQuality))
FrontColor(255, 255, 255)
Label((TextureYSize - TextLength(Text)) / 2, TextureYSize - 30, Text)
StopDrawing()
CreateTexture(0, TextureXSize, TextureYSize)
StartDrawing(TextureOutput(0))
DrawImage(ImageID2, 0, 0)
DrawingMode(4)
Box(0, 0, TextureXSize - 1, TextureYSize - 1, #White)
Box(1, 1, TextureXSize - 3, TextureYSize - 3, #White)
StopDrawing()
CreateMaterial(0, TextureID(0)) ; Material
MaterialBlendingMode(0, #PB_Material_Color)
MaterialFilteringMode(0, #PB_Material_Trilinear)
CreateEntity(0, MeshID(0), MaterialID(0)) ; Entity
CreateCamera(0, 0, 0, 100, 100) ; Camera
AmbientColor(#White)
TerragenExport()
Repeat
ClearScreen(0, 0, 0)
ExamineKeyboard()
ShowTextAndKeyTest()
CameraLocate(0, CamLocateX, CamLocateY, CamLocateZ)
CameraLookAt(0, CamLookAtX, CamLookAtY, CamLookAtZ)
RotateEntity(0, xrot, yrot, zrot)
RenderWorld()
FlipBuffers()
If GetTickCount_() - tz >= 1000
Debug ipt
ipt = 0
tz = GetTickCount_()
EndIf
ipt + 1
Until KeyboardPushed(#PB_Key_Escape)
Else
MessageRequester("Error", "Something fails to initialize 3D engine", 0)
EndIf
End