aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8/source/Irrlicht/CTerrainSceneNode.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/irrlicht-1.8/source/Irrlicht/CTerrainSceneNode.cpp3004
1 files changed, 1502 insertions, 1502 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CTerrainSceneNode.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CTerrainSceneNode.cpp
index 35e9211..a7e6bbf 100644
--- a/libraries/irrlicht-1.8/source/Irrlicht/CTerrainSceneNode.cpp
+++ b/libraries/irrlicht-1.8/source/Irrlicht/CTerrainSceneNode.cpp
@@ -1,1502 +1,1502 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt 1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine". 2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h 3// For conditions of distribution and use, see copyright notice in irrlicht.h
4 4
5// The code for the TerrainSceneNode is based on the GeoMipMapSceneNode 5// The code for the TerrainSceneNode is based on the GeoMipMapSceneNode
6// developed by Spintz. He made it available for Irrlicht and allowed it to be 6// developed by Spintz. He made it available for Irrlicht and allowed it to be
7// distributed under this licence. I only modified some parts. A lot of thanks 7// distributed under this licence. I only modified some parts. A lot of thanks
8// go to him. 8// go to him.
9 9
10#include "CTerrainSceneNode.h" 10#include "CTerrainSceneNode.h"
11#include "CTerrainTriangleSelector.h" 11#include "CTerrainTriangleSelector.h"
12#include "IVideoDriver.h" 12#include "IVideoDriver.h"
13#include "ISceneManager.h" 13#include "ISceneManager.h"
14#include "ICameraSceneNode.h" 14#include "ICameraSceneNode.h"
15#include "SViewFrustum.h" 15#include "SViewFrustum.h"
16#include "irrMath.h" 16#include "irrMath.h"
17#include "os.h" 17#include "os.h"
18#include "IGUIFont.h" 18#include "IGUIFont.h"
19#include "IFileSystem.h" 19#include "IFileSystem.h"
20#include "IReadFile.h" 20#include "IReadFile.h"
21#include "ITextSceneNode.h" 21#include "ITextSceneNode.h"
22#include "IAnimatedMesh.h" 22#include "IAnimatedMesh.h"
23#include "SMesh.h" 23#include "SMesh.h"
24#include "CDynamicMeshBuffer.h" 24#include "CDynamicMeshBuffer.h"
25 25
26namespace irr 26namespace irr
27{ 27{
28namespace scene 28namespace scene
29{ 29{
30 30
31 //! constructor 31 //! constructor
32 CTerrainSceneNode::CTerrainSceneNode(ISceneNode* parent, ISceneManager* mgr, 32 CTerrainSceneNode::CTerrainSceneNode(ISceneNode* parent, ISceneManager* mgr,
33 io::IFileSystem* fs, s32 id, s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize, 33 io::IFileSystem* fs, s32 id, s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize,
34 const core::vector3df& position, 34 const core::vector3df& position,
35 const core::vector3df& rotation, 35 const core::vector3df& rotation,
36 const core::vector3df& scale) 36 const core::vector3df& scale)
37 : ITerrainSceneNode(parent, mgr, id, position, rotation, scale), 37 : ITerrainSceneNode(parent, mgr, id, position, rotation, scale),
38 TerrainData(patchSize, maxLOD, position, rotation, scale), RenderBuffer(0), 38 TerrainData(patchSize, maxLOD, position, rotation, scale), RenderBuffer(0),
39 VerticesToRender(0), IndicesToRender(0), DynamicSelectorUpdate(false), 39 VerticesToRender(0), IndicesToRender(0), DynamicSelectorUpdate(false),
40 OverrideDistanceThreshold(false), UseDefaultRotationPivot(true), ForceRecalculation(true), 40 OverrideDistanceThreshold(false), UseDefaultRotationPivot(true), ForceRecalculation(true),
41 CameraMovementDelta(10.0f), CameraRotationDelta(1.0f),CameraFOVDelta(0.1f), 41 CameraMovementDelta(10.0f), CameraRotationDelta(1.0f),CameraFOVDelta(0.1f),
42 TCoordScale1(1.0f), TCoordScale2(1.0f), SmoothFactor(0), FileSystem(fs) 42 TCoordScale1(1.0f), TCoordScale2(1.0f), SmoothFactor(0), FileSystem(fs)
43 { 43 {
44 #ifdef _DEBUG 44 #ifdef _DEBUG
45 setDebugName("CTerrainSceneNode"); 45 setDebugName("CTerrainSceneNode");
46 #endif 46 #endif
47 47
48 Mesh = new SMesh(); 48 Mesh = new SMesh();
49 RenderBuffer = new CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT); 49 RenderBuffer = new CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
50 RenderBuffer->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX); 50 RenderBuffer->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX);
51 RenderBuffer->setHardwareMappingHint(scene::EHM_DYNAMIC, scene::EBT_INDEX); 51 RenderBuffer->setHardwareMappingHint(scene::EHM_DYNAMIC, scene::EBT_INDEX);
52 52
53 if (FileSystem) 53 if (FileSystem)
54 FileSystem->grab(); 54 FileSystem->grab();
55 55
56 setAutomaticCulling(scene::EAC_OFF); 56 setAutomaticCulling(scene::EAC_OFF);
57 } 57 }
58 58
59 59
60 //! destructor 60 //! destructor
61 CTerrainSceneNode::~CTerrainSceneNode() 61 CTerrainSceneNode::~CTerrainSceneNode()
62 { 62 {
63 delete [] TerrainData.Patches; 63 delete [] TerrainData.Patches;
64 64
65 if (FileSystem) 65 if (FileSystem)
66 FileSystem->drop(); 66 FileSystem->drop();
67 67
68 if (Mesh) 68 if (Mesh)
69 Mesh->drop(); 69 Mesh->drop();
70 70
71 if (RenderBuffer) 71 if (RenderBuffer)
72 RenderBuffer->drop(); 72 RenderBuffer->drop();
73 } 73 }
74 74
75 75
76 //! Initializes the terrain data. Loads the vertices from the heightMapFile 76 //! Initializes the terrain data. Loads the vertices from the heightMapFile
77 bool CTerrainSceneNode::loadHeightMap(io::IReadFile* file, video::SColor vertexColor, 77 bool CTerrainSceneNode::loadHeightMap(io::IReadFile* file, video::SColor vertexColor,
78 s32 smoothFactor) 78 s32 smoothFactor)
79 { 79 {
80 if (!file) 80 if (!file)
81 return false; 81 return false;
82 82
83 Mesh->MeshBuffers.clear(); 83 Mesh->MeshBuffers.clear();
84 const u32 startTime = os::Timer::getRealTime(); 84 const u32 startTime = os::Timer::getRealTime();
85 video::IImage* heightMap = SceneManager->getVideoDriver()->createImageFromFile(file); 85 video::IImage* heightMap = SceneManager->getVideoDriver()->createImageFromFile(file);
86 86
87 if (!heightMap) 87 if (!heightMap)
88 { 88 {
89 os::Printer::log("Unable to load heightmap."); 89 os::Printer::log("Unable to load heightmap.");
90 return false; 90 return false;
91 } 91 }
92 92
93 HeightmapFile = file->getFileName(); 93 HeightmapFile = file->getFileName();
94 SmoothFactor = smoothFactor; 94 SmoothFactor = smoothFactor;
95 95
96 // Get the dimension of the heightmap data 96 // Get the dimension of the heightmap data
97 TerrainData.Size = heightMap->getDimension().Width; 97 TerrainData.Size = heightMap->getDimension().Width;
98 98
99 switch (TerrainData.PatchSize) 99 switch (TerrainData.PatchSize)
100 { 100 {
101 case ETPS_9: 101 case ETPS_9:
102 if (TerrainData.MaxLOD > 3) 102 if (TerrainData.MaxLOD > 3)
103 { 103 {
104 TerrainData.MaxLOD = 3; 104 TerrainData.MaxLOD = 3;
105 } 105 }
106 break; 106 break;
107 case ETPS_17: 107 case ETPS_17:
108 if (TerrainData.MaxLOD > 4) 108 if (TerrainData.MaxLOD > 4)
109 { 109 {
110 TerrainData.MaxLOD = 4; 110 TerrainData.MaxLOD = 4;
111 } 111 }
112 break; 112 break;
113 case ETPS_33: 113 case ETPS_33:
114 if (TerrainData.MaxLOD > 5) 114 if (TerrainData.MaxLOD > 5)
115 { 115 {
116 TerrainData.MaxLOD = 5; 116 TerrainData.MaxLOD = 5;
117 } 117 }
118 break; 118 break;
119 case ETPS_65: 119 case ETPS_65:
120 if (TerrainData.MaxLOD > 6) 120 if (TerrainData.MaxLOD > 6)
121 { 121 {
122 TerrainData.MaxLOD = 6; 122 TerrainData.MaxLOD = 6;
123 } 123 }
124 break; 124 break;
125 case ETPS_129: 125 case ETPS_129:
126 if (TerrainData.MaxLOD > 7) 126 if (TerrainData.MaxLOD > 7)
127 { 127 {
128 TerrainData.MaxLOD = 7; 128 TerrainData.MaxLOD = 7;
129 } 129 }
130 break; 130 break;
131 } 131 }
132 132
133 // --- Generate vertex data from heightmap ---- 133 // --- Generate vertex data from heightmap ----
134 // resize the vertex array for the mesh buffer one time (makes loading faster) 134 // resize the vertex array for the mesh buffer one time (makes loading faster)
135 scene::CDynamicMeshBuffer *mb=0; 135 scene::CDynamicMeshBuffer *mb=0;
136 136
137 const u32 numVertices = TerrainData.Size * TerrainData.Size; 137 const u32 numVertices = TerrainData.Size * TerrainData.Size;
138 if (numVertices <= 65536) 138 if (numVertices <= 65536)
139 { 139 {
140 //small enough for 16bit buffers 140 //small enough for 16bit buffers
141 mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT); 141 mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
142 RenderBuffer->getIndexBuffer().setType(video::EIT_16BIT); 142 RenderBuffer->getIndexBuffer().setType(video::EIT_16BIT);
143 } 143 }
144 else 144 else
145 { 145 {
146 //we need 32bit buffers 146 //we need 32bit buffers
147 mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_32BIT); 147 mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_32BIT);
148 RenderBuffer->getIndexBuffer().setType(video::EIT_32BIT); 148 RenderBuffer->getIndexBuffer().setType(video::EIT_32BIT);
149 } 149 }
150 150
151 mb->getVertexBuffer().set_used(numVertices); 151 mb->getVertexBuffer().set_used(numVertices);
152 152
153 // Read the heightmap to get the vertex data 153 // Read the heightmap to get the vertex data
154 // Apply positions changes, scaling changes 154 // Apply positions changes, scaling changes
155 const f32 tdSize = 1.0f/(f32)(TerrainData.Size-1); 155 const f32 tdSize = 1.0f/(f32)(TerrainData.Size-1);
156 s32 index = 0; 156 s32 index = 0;
157 float fx=0.f; 157 float fx=0.f;
158 float fx2=0.f; 158 float fx2=0.f;
159 for (s32 x = 0; x < TerrainData.Size; ++x) 159 for (s32 x = 0; x < TerrainData.Size; ++x)
160 { 160 {
161 float fz=0.f; 161 float fz=0.f;
162 float fz2=0.f; 162 float fz2=0.f;
163 for (s32 z = 0; z < TerrainData.Size; ++z) 163 for (s32 z = 0; z < TerrainData.Size; ++z)
164 { 164 {
165 video::S3DVertex2TCoords& vertex= static_cast<video::S3DVertex2TCoords*>(mb->getVertexBuffer().pointer())[index++]; 165 video::S3DVertex2TCoords& vertex= static_cast<video::S3DVertex2TCoords*>(mb->getVertexBuffer().pointer())[index++];
166 vertex.Normal.set(0.0f, 1.0f, 0.0f); 166 vertex.Normal.set(0.0f, 1.0f, 0.0f);
167 vertex.Color = vertexColor; 167 vertex.Color = vertexColor;
168 vertex.Pos.X = fx; 168 vertex.Pos.X = fx;
169 vertex.Pos.Y = (f32) heightMap->getPixel(TerrainData.Size-x-1,z).getLightness(); 169 vertex.Pos.Y = (f32) heightMap->getPixel(TerrainData.Size-x-1,z).getLightness();
170 vertex.Pos.Z = fz; 170 vertex.Pos.Z = fz;
171 171
172 vertex.TCoords.X = vertex.TCoords2.X = 1.f-fx2; 172 vertex.TCoords.X = vertex.TCoords2.X = 1.f-fx2;
173 vertex.TCoords.Y = vertex.TCoords2.Y = fz2; 173 vertex.TCoords.Y = vertex.TCoords2.Y = fz2;
174 174
175 ++fz; 175 ++fz;
176 fz2 += tdSize; 176 fz2 += tdSize;
177 } 177 }
178 ++fx; 178 ++fx;
179 fx2 += tdSize; 179 fx2 += tdSize;
180 } 180 }
181 181
182 // drop heightMap, no longer needed 182 // drop heightMap, no longer needed
183 heightMap->drop(); 183 heightMap->drop();
184 184
185 smoothTerrain(mb, smoothFactor); 185 smoothTerrain(mb, smoothFactor);
186 186
187 // calculate smooth normals for the vertices 187 // calculate smooth normals for the vertices
188 calculateNormals(mb); 188 calculateNormals(mb);
189 189
190 // add the MeshBuffer to the mesh 190 // add the MeshBuffer to the mesh
191 Mesh->addMeshBuffer(mb); 191 Mesh->addMeshBuffer(mb);
192 192
193 // We copy the data to the renderBuffer, after the normals have been calculated. 193 // We copy the data to the renderBuffer, after the normals have been calculated.
194 RenderBuffer->getVertexBuffer().set_used(numVertices); 194 RenderBuffer->getVertexBuffer().set_used(numVertices);
195 195
196 for (u32 i = 0; i < numVertices; ++i) 196 for (u32 i = 0; i < numVertices; ++i)
197 { 197 {
198 RenderBuffer->getVertexBuffer()[i] = mb->getVertexBuffer()[i]; 198 RenderBuffer->getVertexBuffer()[i] = mb->getVertexBuffer()[i];
199 RenderBuffer->getVertexBuffer()[i].Pos *= TerrainData.Scale; 199 RenderBuffer->getVertexBuffer()[i].Pos *= TerrainData.Scale;
200 RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.Position; 200 RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.Position;
201 } 201 }
202 202
203 // We no longer need the mb 203 // We no longer need the mb
204 mb->drop(); 204 mb->drop();
205 205
206 // calculate all the necessary data for the patches and the terrain 206 // calculate all the necessary data for the patches and the terrain
207 calculateDistanceThresholds(); 207 calculateDistanceThresholds();
208 createPatches(); 208 createPatches();
209 calculatePatchData(); 209 calculatePatchData();
210 210
211 // set the default rotation pivot point to the terrain nodes center 211 // set the default rotation pivot point to the terrain nodes center
212 TerrainData.RotationPivot = TerrainData.Center; 212 TerrainData.RotationPivot = TerrainData.Center;
213 213
214 // Rotate the vertices of the terrain by the rotation 214 // Rotate the vertices of the terrain by the rotation
215 // specified. Must be done after calculating the terrain data, 215 // specified. Must be done after calculating the terrain data,
216 // so we know what the current center of the terrain is. 216 // so we know what the current center of the terrain is.
217 setRotation(TerrainData.Rotation); 217 setRotation(TerrainData.Rotation);
218 218
219 // Pre-allocate memory for indices 219 // Pre-allocate memory for indices
220 220
221 RenderBuffer->getIndexBuffer().set_used( 221 RenderBuffer->getIndexBuffer().set_used(
222 TerrainData.PatchCount * TerrainData.PatchCount * 222 TerrainData.PatchCount * TerrainData.PatchCount *
223 TerrainData.CalcPatchSize * TerrainData.CalcPatchSize * 6); 223 TerrainData.CalcPatchSize * TerrainData.CalcPatchSize * 6);
224 224
225 RenderBuffer->setDirty(); 225 RenderBuffer->setDirty();
226 226
227 const u32 endTime = os::Timer::getRealTime(); 227 const u32 endTime = os::Timer::getRealTime();
228 228
229 c8 tmp[255]; 229 c8 tmp[255];
230 snprintf(tmp, 255, "Generated terrain data (%dx%d) in %.4f seconds", 230 snprintf(tmp, 255, "Generated terrain data (%dx%d) in %.4f seconds",
231 TerrainData.Size, TerrainData.Size, (endTime - startTime) / 1000.0f ); 231 TerrainData.Size, TerrainData.Size, (endTime - startTime) / 1000.0f );
232 os::Printer::log(tmp); 232 os::Printer::log(tmp);
233 233
234 return true; 234 return true;
235 } 235 }
236 236
237 237
238 //! Initializes the terrain data. Loads the vertices from the heightMapFile 238 //! Initializes the terrain data. Loads the vertices from the heightMapFile
239 bool CTerrainSceneNode::loadHeightMapRAW(io::IReadFile* file, 239 bool CTerrainSceneNode::loadHeightMapRAW(io::IReadFile* file,
240 s32 bitsPerPixel, bool signedData, bool floatVals, 240 s32 bitsPerPixel, bool signedData, bool floatVals,
241 s32 width, video::SColor vertexColor, s32 smoothFactor) 241 s32 width, video::SColor vertexColor, s32 smoothFactor)
242 { 242 {
243 if (!file) 243 if (!file)
244 return false; 244 return false;
245 if (floatVals && bitsPerPixel != 32) 245 if (floatVals && bitsPerPixel != 32)
246 return false; 246 return false;
247 247
248 // start reading 248 // start reading
249 const u32 startTime = os::Timer::getTime(); 249 const u32 startTime = os::Timer::getTime();
250 250
251 Mesh->MeshBuffers.clear(); 251 Mesh->MeshBuffers.clear();
252 252
253 const s32 bytesPerPixel = bitsPerPixel / 8; 253 const s32 bytesPerPixel = bitsPerPixel / 8;
254 254
255 // Get the dimension of the heightmap data 255 // Get the dimension of the heightmap data
256 const s32 filesize = file->getSize(); 256 const s32 filesize = file->getSize();
257 if (!width) 257 if (!width)
258 TerrainData.Size = core::floor32(sqrtf((f32)(filesize / bytesPerPixel))); 258 TerrainData.Size = core::floor32(sqrtf((f32)(filesize / bytesPerPixel)));
259 else 259 else
260 { 260 {
261 if ((filesize-file->getPos())/bytesPerPixel>width*width) 261 if ((filesize-file->getPos())/bytesPerPixel>width*width)
262 { 262 {
263 os::Printer::log("Error reading heightmap RAW file", "File is too small."); 263 os::Printer::log("Error reading heightmap RAW file", "File is too small.");
264 return false; 264 return false;
265 } 265 }
266 TerrainData.Size = width; 266 TerrainData.Size = width;
267 } 267 }
268 268
269 switch (TerrainData.PatchSize) 269 switch (TerrainData.PatchSize)
270 { 270 {
271 case ETPS_9: 271 case ETPS_9:
272 if (TerrainData.MaxLOD > 3) 272 if (TerrainData.MaxLOD > 3)
273 { 273 {
274 TerrainData.MaxLOD = 3; 274 TerrainData.MaxLOD = 3;
275 } 275 }
276 break; 276 break;
277 case ETPS_17: 277 case ETPS_17:
278 if (TerrainData.MaxLOD > 4) 278 if (TerrainData.MaxLOD > 4)
279 { 279 {
280 TerrainData.MaxLOD = 4; 280 TerrainData.MaxLOD = 4;
281 } 281 }
282 break; 282 break;
283 case ETPS_33: 283 case ETPS_33:
284 if (TerrainData.MaxLOD > 5) 284 if (TerrainData.MaxLOD > 5)
285 { 285 {
286 TerrainData.MaxLOD = 5; 286 TerrainData.MaxLOD = 5;
287 } 287 }
288 break; 288 break;
289 case ETPS_65: 289 case ETPS_65:
290 if (TerrainData.MaxLOD > 6) 290 if (TerrainData.MaxLOD > 6)
291 { 291 {
292 TerrainData.MaxLOD = 6; 292 TerrainData.MaxLOD = 6;
293 } 293 }
294 break; 294 break;
295 case ETPS_129: 295 case ETPS_129:
296 if (TerrainData.MaxLOD > 7) 296 if (TerrainData.MaxLOD > 7)
297 { 297 {
298 TerrainData.MaxLOD = 7; 298 TerrainData.MaxLOD = 7;
299 } 299 }
300 break; 300 break;
301 } 301 }
302 302
303 // --- Generate vertex data from heightmap ---- 303 // --- Generate vertex data from heightmap ----
304 // resize the vertex array for the mesh buffer one time (makes loading faster) 304 // resize the vertex array for the mesh buffer one time (makes loading faster)
305 scene::CDynamicMeshBuffer *mb=0; 305 scene::CDynamicMeshBuffer *mb=0;
306 const u32 numVertices = TerrainData.Size * TerrainData.Size; 306 const u32 numVertices = TerrainData.Size * TerrainData.Size;
307 if (numVertices <= 65536) 307 if (numVertices <= 65536)
308 { 308 {
309 //small enough for 16bit buffers 309 //small enough for 16bit buffers
310 mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT); 310 mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
311 RenderBuffer->getIndexBuffer().setType(video::EIT_16BIT); 311 RenderBuffer->getIndexBuffer().setType(video::EIT_16BIT);
312 } 312 }
313 else 313 else
314 { 314 {
315 //we need 32bit buffers 315 //we need 32bit buffers
316 mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_32BIT); 316 mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_32BIT);
317 RenderBuffer->getIndexBuffer().setType(video::EIT_32BIT); 317 RenderBuffer->getIndexBuffer().setType(video::EIT_32BIT);
318 } 318 }
319 319
320 mb->getVertexBuffer().reallocate(numVertices); 320 mb->getVertexBuffer().reallocate(numVertices);
321 321
322 video::S3DVertex2TCoords vertex; 322 video::S3DVertex2TCoords vertex;
323 vertex.Normal.set(0.0f, 1.0f, 0.0f); 323 vertex.Normal.set(0.0f, 1.0f, 0.0f);
324 vertex.Color = vertexColor; 324 vertex.Color = vertexColor;
325 325
326 // Read the heightmap to get the vertex data 326 // Read the heightmap to get the vertex data
327 // Apply positions changes, scaling changes 327 // Apply positions changes, scaling changes
328 const f32 tdSize = 1.0f/(f32)(TerrainData.Size-1); 328 const f32 tdSize = 1.0f/(f32)(TerrainData.Size-1);
329 float fx=0.f; 329 float fx=0.f;
330 float fx2=0.f; 330 float fx2=0.f;
331 for (s32 x = 0; x < TerrainData.Size; ++x) 331 for (s32 x = 0; x < TerrainData.Size; ++x)
332 { 332 {
333 float fz=0.f; 333 float fz=0.f;
334 float fz2=0.f; 334 float fz2=0.f;
335 for (s32 z = 0; z < TerrainData.Size; ++z) 335 for (s32 z = 0; z < TerrainData.Size; ++z)
336 { 336 {
337 bool failure=false; 337 bool failure=false;
338 vertex.Pos.X = fx; 338 vertex.Pos.X = fx;
339 if (floatVals) 339 if (floatVals)
340 { 340 {
341 if (file->read(&vertex.Pos.Y, bytesPerPixel) != bytesPerPixel) 341 if (file->read(&vertex.Pos.Y, bytesPerPixel) != bytesPerPixel)
342 failure=true; 342 failure=true;
343 } 343 }
344 else if (signedData) 344 else if (signedData)
345 { 345 {
346 switch (bytesPerPixel) 346 switch (bytesPerPixel)
347 { 347 {
348 case 1: 348 case 1:
349 { 349 {
350 s8 val; 350 s8 val;
351 if (file->read(&val, bytesPerPixel) != bytesPerPixel) 351 if (file->read(&val, bytesPerPixel) != bytesPerPixel)
352 failure=true; 352 failure=true;
353 vertex.Pos.Y=val; 353 vertex.Pos.Y=val;
354 } 354 }
355 break; 355 break;
356 case 2: 356 case 2:
357 { 357 {
358 s16 val; 358 s16 val;
359 if (file->read(&val, bytesPerPixel) != bytesPerPixel) 359 if (file->read(&val, bytesPerPixel) != bytesPerPixel)
360 failure=true; 360 failure=true;
361 vertex.Pos.Y=val/256.f; 361 vertex.Pos.Y=val/256.f;
362 } 362 }
363 break; 363 break;
364 case 4: 364 case 4:
365 { 365 {
366 s32 val; 366 s32 val;
367 if (file->read(&val, bytesPerPixel) != bytesPerPixel) 367 if (file->read(&val, bytesPerPixel) != bytesPerPixel)
368 failure=true; 368 failure=true;
369 vertex.Pos.Y=val/16777216.f; 369 vertex.Pos.Y=val/16777216.f;
370 } 370 }
371 break; 371 break;
372 } 372 }
373 } 373 }
374 else 374 else
375 { 375 {
376 switch (bytesPerPixel) 376 switch (bytesPerPixel)
377 { 377 {
378 case 1: 378 case 1:
379 { 379 {
380 u8 val; 380 u8 val;
381 if (file->read(&val, bytesPerPixel) != bytesPerPixel) 381 if (file->read(&val, bytesPerPixel) != bytesPerPixel)
382 failure=true; 382 failure=true;
383 vertex.Pos.Y=val; 383 vertex.Pos.Y=val;
384 } 384 }
385 break; 385 break;
386 case 2: 386 case 2:
387 { 387 {
388 u16 val; 388 u16 val;
389 if (file->read(&val, bytesPerPixel) != bytesPerPixel) 389 if (file->read(&val, bytesPerPixel) != bytesPerPixel)
390 failure=true; 390 failure=true;
391 vertex.Pos.Y=val/256.f; 391 vertex.Pos.Y=val/256.f;
392 } 392 }
393 break; 393 break;
394 case 4: 394 case 4:
395 { 395 {
396 u32 val; 396 u32 val;
397 if (file->read(&val, bytesPerPixel) != bytesPerPixel) 397 if (file->read(&val, bytesPerPixel) != bytesPerPixel)
398 failure=true; 398 failure=true;
399 vertex.Pos.Y=val/16777216.f; 399 vertex.Pos.Y=val/16777216.f;
400 } 400 }
401 break; 401 break;
402 } 402 }
403 } 403 }
404 if (failure) 404 if (failure)
405 { 405 {
406 os::Printer::log("Error reading heightmap RAW file."); 406 os::Printer::log("Error reading heightmap RAW file.");
407 mb->drop(); 407 mb->drop();
408 return false; 408 return false;
409 } 409 }
410 vertex.Pos.Z = fz; 410 vertex.Pos.Z = fz;
411 411
412 vertex.TCoords.X = vertex.TCoords2.X = 1.f-fx2; 412 vertex.TCoords.X = vertex.TCoords2.X = 1.f-fx2;
413 vertex.TCoords.Y = vertex.TCoords2.Y = fz2; 413 vertex.TCoords.Y = vertex.TCoords2.Y = fz2;
414 414
415 mb->getVertexBuffer().push_back(vertex); 415 mb->getVertexBuffer().push_back(vertex);
416 ++fz; 416 ++fz;
417 fz2 += tdSize; 417 fz2 += tdSize;
418 } 418 }
419 ++fx; 419 ++fx;
420 fx2 += tdSize; 420 fx2 += tdSize;
421 } 421 }
422 422
423 smoothTerrain(mb, smoothFactor); 423 smoothTerrain(mb, smoothFactor);
424 424
425 // calculate smooth normals for the vertices 425 // calculate smooth normals for the vertices
426 calculateNormals(mb); 426 calculateNormals(mb);
427 427
428 // add the MeshBuffer to the mesh 428 // add the MeshBuffer to the mesh
429 Mesh->addMeshBuffer(mb); 429 Mesh->addMeshBuffer(mb);
430 const u32 vertexCount = mb->getVertexCount(); 430 const u32 vertexCount = mb->getVertexCount();
431 431
432 // We copy the data to the renderBuffer, after the normals have been calculated. 432 // We copy the data to the renderBuffer, after the normals have been calculated.
433 RenderBuffer->getVertexBuffer().set_used(vertexCount); 433 RenderBuffer->getVertexBuffer().set_used(vertexCount);
434 434
435 for (u32 i = 0; i < vertexCount; i++) 435 for (u32 i = 0; i < vertexCount; i++)
436 { 436 {
437 RenderBuffer->getVertexBuffer()[i] = mb->getVertexBuffer()[i]; 437 RenderBuffer->getVertexBuffer()[i] = mb->getVertexBuffer()[i];
438 RenderBuffer->getVertexBuffer()[i].Pos *= TerrainData.Scale; 438 RenderBuffer->getVertexBuffer()[i].Pos *= TerrainData.Scale;
439 RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.Position; 439 RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.Position;
440 } 440 }
441 441
442 // We no longer need the mb 442 // We no longer need the mb
443 mb->drop(); 443 mb->drop();
444 444
445 // calculate all the necessary data for the patches and the terrain 445 // calculate all the necessary data for the patches and the terrain
446 calculateDistanceThresholds(); 446 calculateDistanceThresholds();
447 createPatches(); 447 createPatches();
448 calculatePatchData(); 448 calculatePatchData();
449 449
450 // set the default rotation pivot point to the terrain nodes center 450 // set the default rotation pivot point to the terrain nodes center
451 TerrainData.RotationPivot = TerrainData.Center; 451 TerrainData.RotationPivot = TerrainData.Center;
452 452
453 // Rotate the vertices of the terrain by the rotation specified. Must be done 453 // Rotate the vertices of the terrain by the rotation specified. Must be done
454 // after calculating the terrain data, so we know what the current center of the 454 // after calculating the terrain data, so we know what the current center of the
455 // terrain is. 455 // terrain is.
456 setRotation(TerrainData.Rotation); 456 setRotation(TerrainData.Rotation);
457 457
458 // Pre-allocate memory for indices 458 // Pre-allocate memory for indices
459 RenderBuffer->getIndexBuffer().set_used( 459 RenderBuffer->getIndexBuffer().set_used(
460 TerrainData.PatchCount*TerrainData.PatchCount* 460 TerrainData.PatchCount*TerrainData.PatchCount*
461 TerrainData.CalcPatchSize*TerrainData.CalcPatchSize*6); 461 TerrainData.CalcPatchSize*TerrainData.CalcPatchSize*6);
462 462
463 const u32 endTime = os::Timer::getTime(); 463 const u32 endTime = os::Timer::getTime();
464 464
465 c8 tmp[255]; 465 c8 tmp[255];
466 snprintf(tmp, 255, "Generated terrain data (%dx%d) in %.4f seconds", 466 snprintf(tmp, 255, "Generated terrain data (%dx%d) in %.4f seconds",
467 TerrainData.Size, TerrainData.Size, (endTime - startTime) / 1000.0f); 467 TerrainData.Size, TerrainData.Size, (endTime - startTime) / 1000.0f);
468 os::Printer::log(tmp); 468 os::Printer::log(tmp);
469 469
470 return true; 470 return true;
471 } 471 }
472 472
473 473
474 //! Returns the mesh 474 //! Returns the mesh
475 IMesh* CTerrainSceneNode::getMesh() { return Mesh; } 475 IMesh* CTerrainSceneNode::getMesh() { return Mesh; }
476 476
477 477
478 //! Returns the material based on the zero based index i. 478 //! Returns the material based on the zero based index i.
479 video::SMaterial& CTerrainSceneNode::getMaterial(u32 i) 479 video::SMaterial& CTerrainSceneNode::getMaterial(u32 i)
480 { 480 {
481 return Mesh->getMeshBuffer(i)->getMaterial(); 481 return Mesh->getMeshBuffer(i)->getMaterial();
482 } 482 }
483 483
484 484
485 //! Returns amount of materials used by this scene node ( always 1 ) 485 //! Returns amount of materials used by this scene node ( always 1 )
486 u32 CTerrainSceneNode::getMaterialCount() const 486 u32 CTerrainSceneNode::getMaterialCount() const
487 { 487 {
488 return Mesh->getMeshBufferCount(); 488 return Mesh->getMeshBufferCount();
489 } 489 }
490 490
491 491
492 //! Sets the scale of the scene node. 492 //! Sets the scale of the scene node.
493 //! \param scale: New scale of the node 493 //! \param scale: New scale of the node
494 void CTerrainSceneNode::setScale(const core::vector3df& scale) 494 void CTerrainSceneNode::setScale(const core::vector3df& scale)
495 { 495 {
496 TerrainData.Scale = scale; 496 TerrainData.Scale = scale;
497 applyTransformation(); 497 applyTransformation();
498 calculateNormals(RenderBuffer); 498 calculateNormals(RenderBuffer);
499 ForceRecalculation = true; 499 ForceRecalculation = true;
500 } 500 }
501 501
502 502
503 //! Sets the rotation of the node. This only modifies 503 //! Sets the rotation of the node. This only modifies
504 //! the relative rotation of the node. 504 //! the relative rotation of the node.
505 //! \param rotation: New rotation of the node in degrees. 505 //! \param rotation: New rotation of the node in degrees.
506 void CTerrainSceneNode::setRotation(const core::vector3df& rotation) 506 void CTerrainSceneNode::setRotation(const core::vector3df& rotation)
507 { 507 {
508 TerrainData.Rotation = rotation; 508 TerrainData.Rotation = rotation;
509 applyTransformation(); 509 applyTransformation();
510 ForceRecalculation = true; 510 ForceRecalculation = true;
511 } 511 }
512 512
513 513
514 //! Sets the pivot point for rotation of this node. This is useful for the TiledTerrainManager to 514 //! Sets the pivot point for rotation of this node. This is useful for the TiledTerrainManager to
515 //! rotate all terrain tiles around a global world point. 515 //! rotate all terrain tiles around a global world point.
516 //! NOTE: The default for the RotationPivot will be the center of the individual tile. 516 //! NOTE: The default for the RotationPivot will be the center of the individual tile.
517 void CTerrainSceneNode::setRotationPivot(const core::vector3df& pivot) 517 void CTerrainSceneNode::setRotationPivot(const core::vector3df& pivot)
518 { 518 {
519 UseDefaultRotationPivot = false; 519 UseDefaultRotationPivot = false;
520 TerrainData.RotationPivot = pivot; 520 TerrainData.RotationPivot = pivot;
521 } 521 }
522 522
523 523
524 //! Sets the position of the node. 524 //! Sets the position of the node.
525 //! \param newpos: New postition of the scene node. 525 //! \param newpos: New postition of the scene node.
526 void CTerrainSceneNode::setPosition(const core::vector3df& newpos) 526 void CTerrainSceneNode::setPosition(const core::vector3df& newpos)
527 { 527 {
528 TerrainData.Position = newpos; 528 TerrainData.Position = newpos;
529 applyTransformation(); 529 applyTransformation();
530 ForceRecalculation = true; 530 ForceRecalculation = true;
531 } 531 }
532 532
533 533
534 //! Apply transformation changes(scale, position, rotation) 534 //! Apply transformation changes(scale, position, rotation)
535 void CTerrainSceneNode::applyTransformation() 535 void CTerrainSceneNode::applyTransformation()
536 { 536 {
537 if (!Mesh->getMeshBufferCount()) 537 if (!Mesh->getMeshBufferCount())
538 return; 538 return;
539 539
540 core::matrix4 rotMatrix; 540 core::matrix4 rotMatrix;
541 rotMatrix.setRotationDegrees(TerrainData.Rotation); 541 rotMatrix.setRotationDegrees(TerrainData.Rotation);
542 542
543 const s32 vtxCount = Mesh->getMeshBuffer(0)->getVertexCount(); 543 const s32 vtxCount = Mesh->getMeshBuffer(0)->getVertexCount();
544 for (s32 i = 0; i < vtxCount; ++i) 544 for (s32 i = 0; i < vtxCount; ++i)
545 { 545 {
546 RenderBuffer->getVertexBuffer()[i].Pos = Mesh->getMeshBuffer(0)->getPosition(i) * TerrainData.Scale + TerrainData.Position; 546 RenderBuffer->getVertexBuffer()[i].Pos = Mesh->getMeshBuffer(0)->getPosition(i) * TerrainData.Scale + TerrainData.Position;
547 547
548 RenderBuffer->getVertexBuffer()[i].Pos -= TerrainData.RotationPivot; 548 RenderBuffer->getVertexBuffer()[i].Pos -= TerrainData.RotationPivot;
549 rotMatrix.inverseRotateVect(RenderBuffer->getVertexBuffer()[i].Pos); 549 rotMatrix.inverseRotateVect(RenderBuffer->getVertexBuffer()[i].Pos);
550 RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.RotationPivot; 550 RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.RotationPivot;
551 } 551 }
552 552
553 calculateDistanceThresholds(true); 553 calculateDistanceThresholds(true);
554 calculatePatchData(); 554 calculatePatchData();
555 555
556 RenderBuffer->setDirty(EBT_VERTEX); 556 RenderBuffer->setDirty(EBT_VERTEX);
557 } 557 }
558 558
559 559
560 //! Updates the scene nodes indices if the camera has moved or rotated by a certain 560 //! Updates the scene nodes indices if the camera has moved or rotated by a certain
561 //! threshold, which can be changed using the SetCameraMovementDeltaThreshold and 561 //! threshold, which can be changed using the SetCameraMovementDeltaThreshold and
562 //! SetCameraRotationDeltaThreshold functions. This also determines if a given patch 562 //! SetCameraRotationDeltaThreshold functions. This also determines if a given patch
563 //! for the scene node is within the view frustum and if it's not the indices are not 563 //! for the scene node is within the view frustum and if it's not the indices are not
564 //! generated for that patch. 564 //! generated for that patch.
565 void CTerrainSceneNode::OnRegisterSceneNode() 565 void CTerrainSceneNode::OnRegisterSceneNode()
566 { 566 {
567 if (!IsVisible || !SceneManager->getActiveCamera()) 567 if (!IsVisible || !SceneManager->getActiveCamera())
568 return; 568 return;
569 569
570 SceneManager->registerNodeForRendering(this); 570 SceneManager->registerNodeForRendering(this);
571 571
572 preRenderCalculationsIfNeeded(); 572 preRenderCalculationsIfNeeded();
573 573
574 // Do Not call ISceneNode::OnRegisterSceneNode(), this node should have no children (luke: is this comment still true, as ISceneNode::OnRegisterSceneNode() is called?) 574 // Do Not call ISceneNode::OnRegisterSceneNode(), this node should have no children (luke: is this comment still true, as ISceneNode::OnRegisterSceneNode() is called?)
575 575
576 ISceneNode::OnRegisterSceneNode(); 576 ISceneNode::OnRegisterSceneNode();
577 ForceRecalculation = false; 577 ForceRecalculation = false;
578 } 578 }
579 579
580 void CTerrainSceneNode::preRenderCalculationsIfNeeded() 580 void CTerrainSceneNode::preRenderCalculationsIfNeeded()
581 { 581 {
582 scene::ICameraSceneNode * camera = SceneManager->getActiveCamera(); 582 scene::ICameraSceneNode * camera = SceneManager->getActiveCamera();
583 if (!camera) 583 if (!camera)
584 return; 584 return;
585 585
586 // Determine the camera rotation, based on the camera direction. 586 // Determine the camera rotation, based on the camera direction.
587 const core::vector3df cameraPosition = camera->getAbsolutePosition(); 587 const core::vector3df cameraPosition = camera->getAbsolutePosition();
588 const core::vector3df cameraRotation = core::line3d<f32>(cameraPosition, camera->getTarget()).getVector().getHorizontalAngle(); 588 const core::vector3df cameraRotation = core::line3d<f32>(cameraPosition, camera->getTarget()).getVector().getHorizontalAngle();
589 core::vector3df cameraUp = camera->getUpVector(); 589 core::vector3df cameraUp = camera->getUpVector();
590 cameraUp.normalize(); 590 cameraUp.normalize();
591 const f32 CameraFOV = SceneManager->getActiveCamera()->getFOV(); 591 const f32 CameraFOV = SceneManager->getActiveCamera()->getFOV();
592 592
593 // Only check on the Camera's Y Rotation 593 // Only check on the Camera's Y Rotation
594 if (!ForceRecalculation) 594 if (!ForceRecalculation)
595 { 595 {
596 if ((fabsf(cameraRotation.X - OldCameraRotation.X) < CameraRotationDelta) && 596 if ((fabsf(cameraRotation.X - OldCameraRotation.X) < CameraRotationDelta) &&
597 (fabsf(cameraRotation.Y - OldCameraRotation.Y) < CameraRotationDelta)) 597 (fabsf(cameraRotation.Y - OldCameraRotation.Y) < CameraRotationDelta))
598 { 598 {
599 if ((fabs(cameraPosition.X - OldCameraPosition.X) < CameraMovementDelta) && 599 if ((fabs(cameraPosition.X - OldCameraPosition.X) < CameraMovementDelta) &&
600 (fabs(cameraPosition.Y - OldCameraPosition.Y) < CameraMovementDelta) && 600 (fabs(cameraPosition.Y - OldCameraPosition.Y) < CameraMovementDelta) &&
601 (fabs(cameraPosition.Z - OldCameraPosition.Z) < CameraMovementDelta)) 601 (fabs(cameraPosition.Z - OldCameraPosition.Z) < CameraMovementDelta))
602 { 602 {
603 if (fabs(CameraFOV-OldCameraFOV) < CameraFOVDelta && 603 if (fabs(CameraFOV-OldCameraFOV) < CameraFOVDelta &&
604 cameraUp.dotProduct(OldCameraUp) > (1.f - (cos(core::DEGTORAD * CameraRotationDelta)))) 604 cameraUp.dotProduct(OldCameraUp) > (1.f - (cos(core::DEGTORAD * CameraRotationDelta))))
605 { 605 {
606 return; 606 return;
607 } 607 }
608 } 608 }
609 } 609 }
610 } 610 }
611 611
612 //we need to redo calculations... 612 //we need to redo calculations...
613 613
614 OldCameraPosition = cameraPosition; 614 OldCameraPosition = cameraPosition;
615 OldCameraRotation = cameraRotation; 615 OldCameraRotation = cameraRotation;
616 OldCameraUp = cameraUp; 616 OldCameraUp = cameraUp;
617 OldCameraFOV = CameraFOV; 617 OldCameraFOV = CameraFOV;
618 618
619 preRenderLODCalculations(); 619 preRenderLODCalculations();
620 preRenderIndicesCalculations(); 620 preRenderIndicesCalculations();
621 } 621 }
622 622
623 void CTerrainSceneNode::preRenderLODCalculations() 623 void CTerrainSceneNode::preRenderLODCalculations()
624 { 624 {
625 scene::ICameraSceneNode * camera = SceneManager->getActiveCamera(); 625 scene::ICameraSceneNode * camera = SceneManager->getActiveCamera();
626 626
627 if (!camera) 627 if (!camera)
628 return; 628 return;
629 629
630 const core::vector3df cameraPosition = camera->getAbsolutePosition(); 630 const core::vector3df cameraPosition = camera->getAbsolutePosition();
631 631
632 const SViewFrustum* frustum = camera->getViewFrustum(); 632 const SViewFrustum* frustum = camera->getViewFrustum();
633 633
634 // Determine each patches LOD based on distance from camera (and whether or not they are in 634 // Determine each patches LOD based on distance from camera (and whether or not they are in
635 // the view frustum). 635 // the view frustum).
636 const s32 count = TerrainData.PatchCount * TerrainData.PatchCount; 636 const s32 count = TerrainData.PatchCount * TerrainData.PatchCount;
637 for (s32 j = 0; j < count; ++j) 637 for (s32 j = 0; j < count; ++j)
638 { 638 {
639 if (frustum->getBoundingBox().intersectsWithBox(TerrainData.Patches[j].BoundingBox)) 639 if (frustum->getBoundingBox().intersectsWithBox(TerrainData.Patches[j].BoundingBox))
640 { 640 {
641 const f32 distance = cameraPosition.getDistanceFromSQ(TerrainData.Patches[j].Center); 641 const f32 distance = cameraPosition.getDistanceFromSQ(TerrainData.Patches[j].Center);
642 642
643 TerrainData.Patches[j].CurrentLOD = 0; 643 TerrainData.Patches[j].CurrentLOD = 0;
644 for (s32 i = TerrainData.MaxLOD - 1; i>0; --i) 644 for (s32 i = TerrainData.MaxLOD - 1; i>0; --i)
645 { 645 {
646 if (distance >= TerrainData.LODDistanceThreshold[i]) 646 if (distance >= TerrainData.LODDistanceThreshold[i])
647 { 647 {
648 TerrainData.Patches[j].CurrentLOD = i; 648 TerrainData.Patches[j].CurrentLOD = i;
649 break; 649 break;
650 } 650 }
651 } 651 }
652 } 652 }
653 else 653 else
654 { 654 {
655 TerrainData.Patches[j].CurrentLOD = -1; 655 TerrainData.Patches[j].CurrentLOD = -1;
656 } 656 }
657 } 657 }
658 } 658 }
659 659
660 660
661 void CTerrainSceneNode::preRenderIndicesCalculations() 661 void CTerrainSceneNode::preRenderIndicesCalculations()
662 { 662 {
663 scene::IIndexBuffer& indexBuffer = RenderBuffer->getIndexBuffer(); 663 scene::IIndexBuffer& indexBuffer = RenderBuffer->getIndexBuffer();
664 IndicesToRender = 0; 664 IndicesToRender = 0;
665 indexBuffer.set_used(0); 665 indexBuffer.set_used(0);
666 666
667 s32 index = 0; 667 s32 index = 0;
668 // Then generate the indices for all patches that are visible. 668 // Then generate the indices for all patches that are visible.
669 for (s32 i = 0; i < TerrainData.PatchCount; ++i) 669 for (s32 i = 0; i < TerrainData.PatchCount; ++i)
670 { 670 {
671 for (s32 j = 0; j < TerrainData.PatchCount; ++j) 671 for (s32 j = 0; j < TerrainData.PatchCount; ++j)
672 { 672 {
673 if (TerrainData.Patches[index].CurrentLOD >= 0) 673 if (TerrainData.Patches[index].CurrentLOD >= 0)
674 { 674 {
675 s32 x = 0; 675 s32 x = 0;
676 s32 z = 0; 676 s32 z = 0;
677 677
678 // calculate the step we take this patch, based on the patches current LOD 678 // calculate the step we take this patch, based on the patches current LOD
679 const s32 step = 1 << TerrainData.Patches[index].CurrentLOD; 679 const s32 step = 1 << TerrainData.Patches[index].CurrentLOD;
680 680
681 // Loop through patch and generate indices 681 // Loop through patch and generate indices
682 while (z < TerrainData.CalcPatchSize) 682 while (z < TerrainData.CalcPatchSize)
683 { 683 {
684 const s32 index11 = getIndex(j, i, index, x, z); 684 const s32 index11 = getIndex(j, i, index, x, z);
685 const s32 index21 = getIndex(j, i, index, x + step, z); 685 const s32 index21 = getIndex(j, i, index, x + step, z);
686 const s32 index12 = getIndex(j, i, index, x, z + step); 686 const s32 index12 = getIndex(j, i, index, x, z + step);
687 const s32 index22 = getIndex(j, i, index, x + step, z + step); 687 const s32 index22 = getIndex(j, i, index, x + step, z + step);
688 688
689 indexBuffer.push_back(index12); 689 indexBuffer.push_back(index12);
690 indexBuffer.push_back(index11); 690 indexBuffer.push_back(index11);
691 indexBuffer.push_back(index22); 691 indexBuffer.push_back(index22);
692 indexBuffer.push_back(index22); 692 indexBuffer.push_back(index22);
693 indexBuffer.push_back(index11); 693 indexBuffer.push_back(index11);
694 indexBuffer.push_back(index21); 694 indexBuffer.push_back(index21);
695 IndicesToRender+=6; 695 IndicesToRender+=6;
696 696
697 // increment index position horizontally 697 // increment index position horizontally
698 x += step; 698 x += step;
699 699
700 // we've hit an edge 700 // we've hit an edge
701 if (x >= TerrainData.CalcPatchSize) 701 if (x >= TerrainData.CalcPatchSize)
702 { 702 {
703 x = 0; 703 x = 0;
704 z += step; 704 z += step;
705 } 705 }
706 } 706 }
707 } 707 }
708 ++index; 708 ++index;
709 } 709 }
710 } 710 }
711 711
712 RenderBuffer->setDirty(EBT_INDEX); 712 RenderBuffer->setDirty(EBT_INDEX);
713 713
714 if (DynamicSelectorUpdate && TriangleSelector) 714 if (DynamicSelectorUpdate && TriangleSelector)
715 { 715 {
716 CTerrainTriangleSelector* selector = (CTerrainTriangleSelector*)TriangleSelector; 716 CTerrainTriangleSelector* selector = (CTerrainTriangleSelector*)TriangleSelector;
717 selector->setTriangleData(this, -1); 717 selector->setTriangleData(this, -1);
718 } 718 }
719 } 719 }
720 720
721 721
722 //! Render the scene node 722 //! Render the scene node
723 void CTerrainSceneNode::render() 723 void CTerrainSceneNode::render()
724 { 724 {
725 if (!IsVisible || !SceneManager->getActiveCamera()) 725 if (!IsVisible || !SceneManager->getActiveCamera())
726 return; 726 return;
727 727
728 if (!Mesh->getMeshBufferCount()) 728 if (!Mesh->getMeshBufferCount())
729 return; 729 return;
730 730
731 video::IVideoDriver* driver = SceneManager->getVideoDriver(); 731 video::IVideoDriver* driver = SceneManager->getVideoDriver();
732 732
733 driver->setTransform (video::ETS_WORLD, core::IdentityMatrix); 733 driver->setTransform (video::ETS_WORLD, core::IdentityMatrix);
734 driver->setMaterial(Mesh->getMeshBuffer(0)->getMaterial()); 734 driver->setMaterial(Mesh->getMeshBuffer(0)->getMaterial());
735 735
736 RenderBuffer->getIndexBuffer().set_used(IndicesToRender); 736 RenderBuffer->getIndexBuffer().set_used(IndicesToRender);
737 737
738 // For use with geomorphing 738 // For use with geomorphing
739 driver->drawMeshBuffer(RenderBuffer); 739 driver->drawMeshBuffer(RenderBuffer);
740 740
741 RenderBuffer->getIndexBuffer().set_used(RenderBuffer->getIndexBuffer().allocated_size()); 741 RenderBuffer->getIndexBuffer().set_used(RenderBuffer->getIndexBuffer().allocated_size());
742 742
743 // for debug purposes only: 743 // for debug purposes only:
744 if (DebugDataVisible) 744 if (DebugDataVisible)
745 { 745 {
746 video::SMaterial m; 746 video::SMaterial m;
747 m.Lighting = false; 747 m.Lighting = false;
748 driver->setMaterial(m); 748 driver->setMaterial(m);
749 if (DebugDataVisible & scene::EDS_BBOX) 749 if (DebugDataVisible & scene::EDS_BBOX)
750 driver->draw3DBox(TerrainData.BoundingBox, video::SColor(255,255,255,255)); 750 driver->draw3DBox(TerrainData.BoundingBox, video::SColor(255,255,255,255));
751 751
752 const s32 count = TerrainData.PatchCount * TerrainData.PatchCount; 752 const s32 count = TerrainData.PatchCount * TerrainData.PatchCount;
753 s32 visible = 0; 753 s32 visible = 0;
754 if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) 754 if (DebugDataVisible & scene::EDS_BBOX_BUFFERS)
755 { 755 {
756 for (s32 j = 0; j < count; ++j) 756 for (s32 j = 0; j < count; ++j)
757 { 757 {
758 driver->draw3DBox(TerrainData.Patches[j].BoundingBox, video::SColor(255,255,0,0)); 758 driver->draw3DBox(TerrainData.Patches[j].BoundingBox, video::SColor(255,255,0,0));
759 visible += (TerrainData.Patches[j].CurrentLOD >= 0); 759 visible += (TerrainData.Patches[j].CurrentLOD >= 0);
760 } 760 }
761 } 761 }
762 762
763 if (DebugDataVisible & scene::EDS_NORMALS) 763 if (DebugDataVisible & scene::EDS_NORMALS)
764 { 764 {
765 // draw normals 765 // draw normals
766 const f32 debugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(DEBUG_NORMAL_LENGTH); 766 const f32 debugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(DEBUG_NORMAL_LENGTH);
767 const video::SColor debugNormalColor = SceneManager->getParameters()->getAttributeAsColor(DEBUG_NORMAL_COLOR); 767 const video::SColor debugNormalColor = SceneManager->getParameters()->getAttributeAsColor(DEBUG_NORMAL_COLOR);
768 driver->drawMeshBufferNormals(RenderBuffer, debugNormalLength, debugNormalColor); 768 driver->drawMeshBufferNormals(RenderBuffer, debugNormalLength, debugNormalColor);
769 } 769 }
770 770
771 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); 771 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
772 772
773 static u32 lastTime = 0; 773 static u32 lastTime = 0;
774 774
775 const u32 now = os::Timer::getRealTime(); 775 const u32 now = os::Timer::getRealTime();
776 if (now - lastTime > 1000) 776 if (now - lastTime > 1000)
777 { 777 {
778 char buf[64]; 778 char buf[64];
779 snprintf(buf, 64, "Count: %d, Visible: %d", count, visible); 779 snprintf(buf, 64, "Count: %d, Visible: %d", count, visible);
780 os::Printer::log(buf); 780 os::Printer::log(buf);
781 781
782 lastTime = now; 782 lastTime = now;
783 } 783 }
784 } 784 }
785 } 785 }
786 786
787 787
788 //! Return the bounding box of the entire terrain. 788 //! Return the bounding box of the entire terrain.
789 const core::aabbox3d<f32>& CTerrainSceneNode::getBoundingBox() const 789 const core::aabbox3d<f32>& CTerrainSceneNode::getBoundingBox() const
790 { 790 {
791 return TerrainData.BoundingBox; 791 return TerrainData.BoundingBox;
792 } 792 }
793 793
794 794
795 //! Return the bounding box of a patch 795 //! Return the bounding box of a patch
796 const core::aabbox3d<f32>& CTerrainSceneNode::getBoundingBox(s32 patchX, s32 patchZ) const 796 const core::aabbox3d<f32>& CTerrainSceneNode::getBoundingBox(s32 patchX, s32 patchZ) const
797 { 797 {
798 return TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].BoundingBox; 798 return TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].BoundingBox;
799 } 799 }
800 800
801 801
802 //! Gets the meshbuffer data based on a specified Level of Detail. 802 //! Gets the meshbuffer data based on a specified Level of Detail.
803 //! \param mb: A reference to an SMeshBuffer object 803 //! \param mb: A reference to an SMeshBuffer object
804 //! \param LOD: The Level Of Detail you want the indices from. 804 //! \param LOD: The Level Of Detail you want the indices from.
805 void CTerrainSceneNode::getMeshBufferForLOD(IDynamicMeshBuffer& mb, s32 LOD ) const 805 void CTerrainSceneNode::getMeshBufferForLOD(IDynamicMeshBuffer& mb, s32 LOD ) const
806 { 806 {
807 if (!Mesh->getMeshBufferCount()) 807 if (!Mesh->getMeshBufferCount())
808 return; 808 return;
809 809
810 LOD = core::clamp(LOD, 0, TerrainData.MaxLOD - 1); 810 LOD = core::clamp(LOD, 0, TerrainData.MaxLOD - 1);
811 811
812 const u32 numVertices = Mesh->getMeshBuffer(0)->getVertexCount(); 812 const u32 numVertices = Mesh->getMeshBuffer(0)->getVertexCount();
813 mb.getVertexBuffer().reallocate(numVertices); 813 mb.getVertexBuffer().reallocate(numVertices);
814 video::S3DVertex2TCoords* vertices = (video::S3DVertex2TCoords*)Mesh->getMeshBuffer(0)->getVertices(); 814 video::S3DVertex2TCoords* vertices = (video::S3DVertex2TCoords*)Mesh->getMeshBuffer(0)->getVertices();
815 815
816 for (u32 n=0; n<numVertices; ++n) 816 for (u32 n=0; n<numVertices; ++n)
817 mb.getVertexBuffer().push_back(vertices[n]); 817 mb.getVertexBuffer().push_back(vertices[n]);
818 818
819 mb.getIndexBuffer().setType(RenderBuffer->getIndexBuffer().getType()); 819 mb.getIndexBuffer().setType(RenderBuffer->getIndexBuffer().getType());
820 820
821 // calculate the step we take for all patches, since LOD is the same 821 // calculate the step we take for all patches, since LOD is the same
822 const s32 step = 1 << LOD; 822 const s32 step = 1 << LOD;
823 823
824 // Generate the indices for all patches at the specified LOD 824 // Generate the indices for all patches at the specified LOD
825 s32 index = 0; 825 s32 index = 0;
826 for (s32 i=0; i<TerrainData.PatchCount; ++i) 826 for (s32 i=0; i<TerrainData.PatchCount; ++i)
827 { 827 {
828 for (s32 j=0; j<TerrainData.PatchCount; ++j) 828 for (s32 j=0; j<TerrainData.PatchCount; ++j)
829 { 829 {
830 s32 x = 0; 830 s32 x = 0;
831 s32 z = 0; 831 s32 z = 0;
832 832
833 // Loop through patch and generate indices 833 // Loop through patch and generate indices
834 while (z < TerrainData.CalcPatchSize) 834 while (z < TerrainData.CalcPatchSize)
835 { 835 {
836 const s32 index11 = getIndex(j, i, index, x, z); 836 const s32 index11 = getIndex(j, i, index, x, z);
837 const s32 index21 = getIndex(j, i, index, x + step, z); 837 const s32 index21 = getIndex(j, i, index, x + step, z);
838 const s32 index12 = getIndex(j, i, index, x, z + step); 838 const s32 index12 = getIndex(j, i, index, x, z + step);
839 const s32 index22 = getIndex(j, i, index, x + step, z + step); 839 const s32 index22 = getIndex(j, i, index, x + step, z + step);
840 840
841 mb.getIndexBuffer().push_back(index12); 841 mb.getIndexBuffer().push_back(index12);
842 mb.getIndexBuffer().push_back(index11); 842 mb.getIndexBuffer().push_back(index11);
843 mb.getIndexBuffer().push_back(index22); 843 mb.getIndexBuffer().push_back(index22);
844 mb.getIndexBuffer().push_back(index22); 844 mb.getIndexBuffer().push_back(index22);
845 mb.getIndexBuffer().push_back(index11); 845 mb.getIndexBuffer().push_back(index11);
846 mb.getIndexBuffer().push_back(index21); 846 mb.getIndexBuffer().push_back(index21);
847 847
848 // increment index position horizontally 848 // increment index position horizontally
849 x += step; 849 x += step;
850 850
851 if (x >= TerrainData.CalcPatchSize) // we've hit an edge 851 if (x >= TerrainData.CalcPatchSize) // we've hit an edge
852 { 852 {
853 x = 0; 853 x = 0;
854 z += step; 854 z += step;
855 } 855 }
856 } 856 }
857 ++index; 857 ++index;
858 } 858 }
859 } 859 }
860 } 860 }
861 861
862 862
863 //! Gets the indices for a specified patch at a specified Level of Detail. 863 //! Gets the indices for a specified patch at a specified Level of Detail.
864 //! \param mb: A reference to an array of u32 indices. 864 //! \param mb: A reference to an array of u32 indices.
865 //! \param patchX: Patch x coordinate. 865 //! \param patchX: Patch x coordinate.
866 //! \param patchZ: Patch z coordinate. 866 //! \param patchZ: Patch z coordinate.
867 //! \param LOD: The level of detail to get for that patch. If -1, then get 867 //! \param LOD: The level of detail to get for that patch. If -1, then get
868 //! the CurrentLOD. If the CurrentLOD is set to -1, meaning it's not shown, 868 //! the CurrentLOD. If the CurrentLOD is set to -1, meaning it's not shown,
869 //! then it will retrieve the triangles at the highest LOD (0). 869 //! then it will retrieve the triangles at the highest LOD (0).
870 //! \return: Number if indices put into the buffer. 870 //! \return: Number if indices put into the buffer.
871 s32 CTerrainSceneNode::getIndicesForPatch(core::array<u32>& indices, s32 patchX, s32 patchZ, s32 LOD) 871 s32 CTerrainSceneNode::getIndicesForPatch(core::array<u32>& indices, s32 patchX, s32 patchZ, s32 LOD)
872 { 872 {
873 if (patchX < 0 || patchX > TerrainData.PatchCount-1 || 873 if (patchX < 0 || patchX > TerrainData.PatchCount-1 ||
874 patchZ < 0 || patchZ > TerrainData.PatchCount-1) 874 patchZ < 0 || patchZ > TerrainData.PatchCount-1)
875 return -1; 875 return -1;
876 876
877 if (LOD < -1 || LOD > TerrainData.MaxLOD - 1) 877 if (LOD < -1 || LOD > TerrainData.MaxLOD - 1)
878 return -1; 878 return -1;
879 879
880 core::array<s32> cLODs; 880 core::array<s32> cLODs;
881 bool setLODs = false; 881 bool setLODs = false;
882 882
883 // If LOD of -1 was passed in, use the CurrentLOD of the patch specified 883 // If LOD of -1 was passed in, use the CurrentLOD of the patch specified
884 if (LOD == -1) 884 if (LOD == -1)
885 { 885 {
886 LOD = TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].CurrentLOD; 886 LOD = TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].CurrentLOD;
887 } 887 }
888 else 888 else
889 { 889 {
890 getCurrentLODOfPatches(cLODs); 890 getCurrentLODOfPatches(cLODs);
891 setCurrentLODOfPatches(LOD); 891 setCurrentLODOfPatches(LOD);
892 setLODs = true; 892 setLODs = true;
893 } 893 }
894 894
895 if (LOD < 0) 895 if (LOD < 0)
896 return -2; // Patch not visible, don't generate indices. 896 return -2; // Patch not visible, don't generate indices.
897 897
898 // calculate the step we take for this LOD 898 // calculate the step we take for this LOD
899 const s32 step = 1 << LOD; 899 const s32 step = 1 << LOD;
900 900
901 // Generate the indices for the specified patch at the specified LOD 901 // Generate the indices for the specified patch at the specified LOD
902 const s32 index = patchX * TerrainData.PatchCount + patchZ; 902 const s32 index = patchX * TerrainData.PatchCount + patchZ;
903 903
904 s32 x = 0; 904 s32 x = 0;
905 s32 z = 0; 905 s32 z = 0;
906 906
907 indices.set_used(TerrainData.PatchSize * TerrainData.PatchSize * 6); 907 indices.set_used(TerrainData.PatchSize * TerrainData.PatchSize * 6);
908 908
909 // Loop through patch and generate indices 909 // Loop through patch and generate indices
910 s32 rv=0; 910 s32 rv=0;
911 while (z<TerrainData.CalcPatchSize) 911 while (z<TerrainData.CalcPatchSize)
912 { 912 {
913 const s32 index11 = getIndex(patchZ, patchX, index, x, z); 913 const s32 index11 = getIndex(patchZ, patchX, index, x, z);
914 const s32 index21 = getIndex(patchZ, patchX, index, x + step, z); 914 const s32 index21 = getIndex(patchZ, patchX, index, x + step, z);
915 const s32 index12 = getIndex(patchZ, patchX, index, x, z + step); 915 const s32 index12 = getIndex(patchZ, patchX, index, x, z + step);
916 const s32 index22 = getIndex(patchZ, patchX, index, x + step, z + step); 916 const s32 index22 = getIndex(patchZ, patchX, index, x + step, z + step);
917 917
918 indices[rv++] = index12; 918 indices[rv++] = index12;
919 indices[rv++] = index11; 919 indices[rv++] = index11;
920 indices[rv++] = index22; 920 indices[rv++] = index22;
921 indices[rv++] = index22; 921 indices[rv++] = index22;
922 indices[rv++] = index11; 922 indices[rv++] = index11;
923 indices[rv++] = index21; 923 indices[rv++] = index21;
924 924
925 // increment index position horizontally 925 // increment index position horizontally
926 x += step; 926 x += step;
927 927
928 if (x >= TerrainData.CalcPatchSize) // we've hit an edge 928 if (x >= TerrainData.CalcPatchSize) // we've hit an edge
929 { 929 {
930 x = 0; 930 x = 0;
931 z += step; 931 z += step;
932 } 932 }
933 } 933 }
934 934
935 if (setLODs) 935 if (setLODs)
936 setCurrentLODOfPatches(cLODs); 936 setCurrentLODOfPatches(cLODs);
937 937
938 return rv; 938 return rv;
939 } 939 }
940 940
941 941
942 //! Populates an array with the CurrentLOD of each patch. 942 //! Populates an array with the CurrentLOD of each patch.
943 //! \param LODs: A reference to a core::array<s32> to hold the values 943 //! \param LODs: A reference to a core::array<s32> to hold the values
944 //! \return Returns the number of elements in the array 944 //! \return Returns the number of elements in the array
945 s32 CTerrainSceneNode::getCurrentLODOfPatches(core::array<s32>& LODs) const 945 s32 CTerrainSceneNode::getCurrentLODOfPatches(core::array<s32>& LODs) const
946 { 946 {
947 s32 numLODs; 947 s32 numLODs;
948 LODs.clear(); 948 LODs.clear();
949 949
950 const s32 count = TerrainData.PatchCount * TerrainData.PatchCount; 950 const s32 count = TerrainData.PatchCount * TerrainData.PatchCount;
951 for (numLODs = 0; numLODs < count; numLODs++) 951 for (numLODs = 0; numLODs < count; numLODs++)
952 LODs.push_back(TerrainData.Patches[numLODs].CurrentLOD); 952 LODs.push_back(TerrainData.Patches[numLODs].CurrentLOD);
953 953
954 return LODs.size(); 954 return LODs.size();
955 } 955 }
956 956
957 957
958 //! Manually sets the LOD of a patch 958 //! Manually sets the LOD of a patch
959 //! \param patchX: Patch x coordinate. 959 //! \param patchX: Patch x coordinate.
960 //! \param patchZ: Patch z coordinate. 960 //! \param patchZ: Patch z coordinate.
961 //! \param LOD: The level of detail to set the patch to. 961 //! \param LOD: The level of detail to set the patch to.
962 void CTerrainSceneNode::setLODOfPatch(s32 patchX, s32 patchZ, s32 LOD) 962 void CTerrainSceneNode::setLODOfPatch(s32 patchX, s32 patchZ, s32 LOD)
963 { 963 {
964 TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].CurrentLOD = LOD; 964 TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].CurrentLOD = LOD;
965 } 965 }
966 966
967 967
968 //! Override the default generation of distance thresholds for determining the LOD a patch 968 //! Override the default generation of distance thresholds for determining the LOD a patch
969 //! is rendered at. 969 //! is rendered at.
970 bool CTerrainSceneNode::overrideLODDistance(s32 LOD, f64 newDistance) 970 bool CTerrainSceneNode::overrideLODDistance(s32 LOD, f64 newDistance)
971 { 971 {
972 OverrideDistanceThreshold = true; 972 OverrideDistanceThreshold = true;
973 973
974 if (LOD < 0 || LOD > TerrainData.MaxLOD - 1) 974 if (LOD < 0 || LOD > TerrainData.MaxLOD - 1)
975 return false; 975 return false;
976 976
977 TerrainData.LODDistanceThreshold[LOD] = newDistance * newDistance; 977 TerrainData.LODDistanceThreshold[LOD] = newDistance * newDistance;
978 978
979 return true; 979 return true;
980 } 980 }
981 981
982 982
983 //! Creates a planar texture mapping on the terrain 983 //! Creates a planar texture mapping on the terrain
984 //! \param resolution: resolution of the planar mapping. This is the value 984 //! \param resolution: resolution of the planar mapping. This is the value
985 //! specifying the relation between world space and texture coordinate space. 985 //! specifying the relation between world space and texture coordinate space.
986 void CTerrainSceneNode::scaleTexture(f32 resolution, f32 resolution2) 986 void CTerrainSceneNode::scaleTexture(f32 resolution, f32 resolution2)
987 { 987 {
988 TCoordScale1 = resolution; 988 TCoordScale1 = resolution;
989 TCoordScale2 = resolution2; 989 TCoordScale2 = resolution2;
990 990
991 const f32 resBySize = resolution / (f32)(TerrainData.Size-1); 991 const f32 resBySize = resolution / (f32)(TerrainData.Size-1);
992 const f32 res2BySize = resolution2 / (f32)(TerrainData.Size-1); 992 const f32 res2BySize = resolution2 / (f32)(TerrainData.Size-1);
993 u32 index = 0; 993 u32 index = 0;
994 f32 xval = 0.f; 994 f32 xval = 0.f;
995 f32 x2val = 0.f; 995 f32 x2val = 0.f;
996 for (s32 x=0; x<TerrainData.Size; ++x) 996 for (s32 x=0; x<TerrainData.Size; ++x)
997 { 997 {
998 f32 zval=0.f; 998 f32 zval=0.f;
999 f32 z2val=0.f; 999 f32 z2val=0.f;
1000 for (s32 z=0; z<TerrainData.Size; ++z) 1000 for (s32 z=0; z<TerrainData.Size; ++z)
1001 { 1001 {
1002 RenderBuffer->getVertexBuffer()[index].TCoords.X = 1.f-xval; 1002 RenderBuffer->getVertexBuffer()[index].TCoords.X = 1.f-xval;
1003 RenderBuffer->getVertexBuffer()[index].TCoords.Y = zval; 1003 RenderBuffer->getVertexBuffer()[index].TCoords.Y = zval;
1004 1004
1005 if (RenderBuffer->getVertexType()==video::EVT_2TCOORDS) 1005 if (RenderBuffer->getVertexType()==video::EVT_2TCOORDS)
1006 { 1006 {
1007 if (resolution2 == 0) 1007 if (resolution2 == 0)
1008 { 1008 {
1009 ((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2 = RenderBuffer->getVertexBuffer()[index].TCoords; 1009 ((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2 = RenderBuffer->getVertexBuffer()[index].TCoords;
1010 } 1010 }
1011 else 1011 else
1012 { 1012 {
1013 ((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2.X = 1.f-x2val; 1013 ((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2.X = 1.f-x2val;
1014 ((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2.Y = z2val; 1014 ((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2.Y = z2val;
1015 } 1015 }
1016 } 1016 }
1017 1017
1018 ++index; 1018 ++index;
1019 zval += resBySize; 1019 zval += resBySize;
1020 z2val += res2BySize; 1020 z2val += res2BySize;
1021 } 1021 }
1022 xval += resBySize; 1022 xval += resBySize;
1023 x2val += res2BySize; 1023 x2val += res2BySize;
1024 } 1024 }
1025 1025
1026 RenderBuffer->setDirty(EBT_VERTEX); 1026 RenderBuffer->setDirty(EBT_VERTEX);
1027 } 1027 }
1028 1028
1029 1029
1030 //! used to get the indices when generating index data for patches at varying levels of detail. 1030 //! used to get the indices when generating index data for patches at varying levels of detail.
1031 u32 CTerrainSceneNode::getIndex(const s32 PatchX, const s32 PatchZ, 1031 u32 CTerrainSceneNode::getIndex(const s32 PatchX, const s32 PatchZ,
1032 const s32 PatchIndex, u32 vX, u32 vZ) const 1032 const s32 PatchIndex, u32 vX, u32 vZ) const
1033 { 1033 {
1034 // top border 1034 // top border
1035 if (vZ == 0) 1035 if (vZ == 0)
1036 { 1036 {
1037 if (TerrainData.Patches[PatchIndex].Top && 1037 if (TerrainData.Patches[PatchIndex].Top &&
1038 TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Top->CurrentLOD && 1038 TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Top->CurrentLOD &&
1039 (vX % (1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD)) != 0 ) 1039 (vX % (1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD)) != 0 )
1040 { 1040 {
1041 vX -= vX % (1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD); 1041 vX -= vX % (1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD);
1042 } 1042 }
1043 } 1043 }
1044 else 1044 else
1045 if (vZ == (u32)TerrainData.CalcPatchSize) // bottom border 1045 if (vZ == (u32)TerrainData.CalcPatchSize) // bottom border
1046 { 1046 {
1047 if (TerrainData.Patches[PatchIndex].Bottom && 1047 if (TerrainData.Patches[PatchIndex].Bottom &&
1048 TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Bottom->CurrentLOD && 1048 TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Bottom->CurrentLOD &&
1049 (vX % (1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD)) != 0) 1049 (vX % (1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD)) != 0)
1050 { 1050 {
1051 vX -= vX % (1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD); 1051 vX -= vX % (1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD);
1052 } 1052 }
1053 } 1053 }
1054 1054
1055 // left border 1055 // left border
1056 if (vX == 0) 1056 if (vX == 0)
1057 { 1057 {
1058 if (TerrainData.Patches[PatchIndex].Left && 1058 if (TerrainData.Patches[PatchIndex].Left &&
1059 TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Left->CurrentLOD && 1059 TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Left->CurrentLOD &&
1060 (vZ % (1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD)) != 0) 1060 (vZ % (1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD)) != 0)
1061 { 1061 {
1062 vZ -= vZ % (1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD); 1062 vZ -= vZ % (1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD);
1063 } 1063 }
1064 } 1064 }
1065 else 1065 else
1066 if (vX == (u32)TerrainData.CalcPatchSize) // right border 1066 if (vX == (u32)TerrainData.CalcPatchSize) // right border
1067 { 1067 {
1068 if (TerrainData.Patches[PatchIndex].Right && 1068 if (TerrainData.Patches[PatchIndex].Right &&
1069 TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Right->CurrentLOD && 1069 TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Right->CurrentLOD &&
1070 (vZ % (1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD)) != 0) 1070 (vZ % (1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD)) != 0)
1071 { 1071 {
1072 vZ -= vZ % (1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD); 1072 vZ -= vZ % (1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD);
1073 } 1073 }
1074 } 1074 }
1075 1075
1076 if (vZ >= (u32)TerrainData.PatchSize) 1076 if (vZ >= (u32)TerrainData.PatchSize)
1077 vZ = TerrainData.CalcPatchSize; 1077 vZ = TerrainData.CalcPatchSize;
1078 1078
1079 if (vX >= (u32)TerrainData.PatchSize) 1079 if (vX >= (u32)TerrainData.PatchSize)
1080 vX = TerrainData.CalcPatchSize; 1080 vX = TerrainData.CalcPatchSize;
1081 1081
1082 return (vZ + ((TerrainData.CalcPatchSize) * PatchZ)) * TerrainData.Size + 1082 return (vZ + ((TerrainData.CalcPatchSize) * PatchZ)) * TerrainData.Size +
1083 (vX + ((TerrainData.CalcPatchSize) * PatchX)); 1083 (vX + ((TerrainData.CalcPatchSize) * PatchX));
1084 } 1084 }
1085 1085
1086 1086
1087 //! smooth the terrain 1087 //! smooth the terrain
1088 void CTerrainSceneNode::smoothTerrain(IDynamicMeshBuffer* mb, s32 smoothFactor) 1088 void CTerrainSceneNode::smoothTerrain(IDynamicMeshBuffer* mb, s32 smoothFactor)
1089 { 1089 {
1090 for (s32 run = 0; run < smoothFactor; ++run) 1090 for (s32 run = 0; run < smoothFactor; ++run)
1091 { 1091 {
1092 s32 yd = TerrainData.Size; 1092 s32 yd = TerrainData.Size;
1093 for (s32 y = 1; y < TerrainData.Size - 1; ++y) 1093 for (s32 y = 1; y < TerrainData.Size - 1; ++y)
1094 { 1094 {
1095 for (s32 x = 1; x < TerrainData.Size - 1; ++x) 1095 for (s32 x = 1; x < TerrainData.Size - 1; ++x)
1096 { 1096 {
1097 mb->getVertexBuffer()[x + yd].Pos.Y = 1097 mb->getVertexBuffer()[x + yd].Pos.Y =
1098 (mb->getVertexBuffer()[x-1 + yd].Pos.Y + //left 1098 (mb->getVertexBuffer()[x-1 + yd].Pos.Y + //left
1099 mb->getVertexBuffer()[x+1 + yd].Pos.Y + //right 1099 mb->getVertexBuffer()[x+1 + yd].Pos.Y + //right
1100 mb->getVertexBuffer()[x + yd - TerrainData.Size].Pos.Y + //above 1100 mb->getVertexBuffer()[x + yd - TerrainData.Size].Pos.Y + //above
1101 mb->getVertexBuffer()[x + yd + TerrainData.Size].Pos.Y) * 0.25f; //below 1101 mb->getVertexBuffer()[x + yd + TerrainData.Size].Pos.Y) * 0.25f; //below
1102 } 1102 }
1103 yd += TerrainData.Size; 1103 yd += TerrainData.Size;
1104 } 1104 }
1105 } 1105 }
1106 } 1106 }
1107 1107
1108 1108
1109 //! calculate smooth normals 1109 //! calculate smooth normals
1110 void CTerrainSceneNode::calculateNormals(IDynamicMeshBuffer* mb) 1110 void CTerrainSceneNode::calculateNormals(IDynamicMeshBuffer* mb)
1111 { 1111 {
1112 s32 count; 1112 s32 count;
1113 core::vector3df a, b, c, t; 1113 core::vector3df a, b, c, t;
1114 1114
1115 for (s32 x=0; x<TerrainData.Size; ++x) 1115 for (s32 x=0; x<TerrainData.Size; ++x)
1116 { 1116 {
1117 for (s32 z=0; z<TerrainData.Size; ++z) 1117 for (s32 z=0; z<TerrainData.Size; ++z)
1118 { 1118 {
1119 count = 0; 1119 count = 0;
1120 core::vector3df normal; 1120 core::vector3df normal;
1121 1121
1122 // top left 1122 // top left
1123 if (x>0 && z>0) 1123 if (x>0 && z>0)
1124 { 1124 {
1125 a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z-1].Pos; 1125 a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z-1].Pos;
1126 b = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z].Pos; 1126 b = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z].Pos;
1127 c = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos; 1127 c = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos;
1128 b -= a; 1128 b -= a;
1129 c -= a; 1129 c -= a;
1130 t = b.crossProduct(c); 1130 t = b.crossProduct(c);
1131 t.normalize(); 1131 t.normalize();
1132 normal += t; 1132 normal += t;
1133 1133
1134 a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z-1].Pos; 1134 a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z-1].Pos;
1135 b = mb->getVertexBuffer()[x*TerrainData.Size+z-1].Pos; 1135 b = mb->getVertexBuffer()[x*TerrainData.Size+z-1].Pos;
1136 c = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos; 1136 c = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos;
1137 b -= a; 1137 b -= a;
1138 c -= a; 1138 c -= a;
1139 t = b.crossProduct(c); 1139 t = b.crossProduct(c);
1140 t.normalize(); 1140 t.normalize();
1141 normal += t; 1141 normal += t;
1142 1142
1143 count += 2; 1143 count += 2;
1144 } 1144 }
1145 1145
1146 // top right 1146 // top right
1147 if (x>0 && z<TerrainData.Size-1) 1147 if (x>0 && z<TerrainData.Size-1)
1148 { 1148 {
1149 a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z].Pos; 1149 a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z].Pos;
1150 b = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z+1].Pos; 1150 b = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z+1].Pos;
1151 c = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos; 1151 c = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos;
1152 b -= a; 1152 b -= a;
1153 c -= a; 1153 c -= a;
1154 t = b.crossProduct(c); 1154 t = b.crossProduct(c);
1155 t.normalize(); 1155 t.normalize();
1156 normal += t; 1156 normal += t;
1157 1157
1158 a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z].Pos; 1158 a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z].Pos;
1159 b = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos; 1159 b = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos;
1160 c = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos; 1160 c = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos;
1161 b -= a; 1161 b -= a;
1162 c -= a; 1162 c -= a;
1163 t = b.crossProduct(c); 1163 t = b.crossProduct(c);
1164 t.normalize(); 1164 t.normalize();
1165 normal += t; 1165 normal += t;
1166 1166
1167 count += 2; 1167 count += 2;
1168 } 1168 }
1169 1169
1170 // bottom right 1170 // bottom right
1171 if (x<TerrainData.Size-1 && z<TerrainData.Size-1) 1171 if (x<TerrainData.Size-1 && z<TerrainData.Size-1)
1172 { 1172 {
1173 a = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos; 1173 a = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos;
1174 b = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos; 1174 b = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos;
1175 c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z+1].Pos; 1175 c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z+1].Pos;
1176 b -= a; 1176 b -= a;
1177 c -= a; 1177 c -= a;
1178 t = b.crossProduct(c); 1178 t = b.crossProduct(c);
1179 t.normalize(); 1179 t.normalize();
1180 normal += t; 1180 normal += t;
1181 1181
1182 a = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos; 1182 a = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos;
1183 b = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z+1].Pos; 1183 b = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z+1].Pos;
1184 c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z].Pos; 1184 c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z].Pos;
1185 b -= a; 1185 b -= a;
1186 c -= a; 1186 c -= a;
1187 t = b.crossProduct(c); 1187 t = b.crossProduct(c);
1188 t.normalize(); 1188 t.normalize();
1189 normal += t; 1189 normal += t;
1190 1190
1191 count += 2; 1191 count += 2;
1192 } 1192 }
1193 1193
1194 // bottom left 1194 // bottom left
1195 if (x<TerrainData.Size-1 && z>0) 1195 if (x<TerrainData.Size-1 && z>0)
1196 { 1196 {
1197 a = mb->getVertexBuffer()[x*TerrainData.Size+z-1].Pos; 1197 a = mb->getVertexBuffer()[x*TerrainData.Size+z-1].Pos;
1198 b = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos; 1198 b = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos;
1199 c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z].Pos; 1199 c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z].Pos;
1200 b -= a; 1200 b -= a;
1201 c -= a; 1201 c -= a;
1202 t = b.crossProduct(c); 1202 t = b.crossProduct(c);
1203 t.normalize(); 1203 t.normalize();
1204 normal += t; 1204 normal += t;
1205 1205
1206 a = mb->getVertexBuffer()[x*TerrainData.Size+z-1].Pos; 1206 a = mb->getVertexBuffer()[x*TerrainData.Size+z-1].Pos;
1207 b = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z].Pos; 1207 b = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z].Pos;
1208 c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z-1].Pos; 1208 c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z-1].Pos;
1209 b -= a; 1209 b -= a;
1210 c -= a; 1210 c -= a;
1211 t = b.crossProduct(c); 1211 t = b.crossProduct(c);
1212 t.normalize(); 1212 t.normalize();
1213 normal += t; 1213 normal += t;
1214 1214
1215 count += 2; 1215 count += 2;
1216 } 1216 }
1217 1217
1218 if (count != 0) 1218 if (count != 0)
1219 { 1219 {
1220 normal.normalize(); 1220 normal.normalize();
1221 } 1221 }
1222 else 1222 else
1223 { 1223 {
1224 normal.set(0.0f, 1.0f, 0.0f); 1224 normal.set(0.0f, 1.0f, 0.0f);
1225 } 1225 }
1226 1226
1227 mb->getVertexBuffer()[x * TerrainData.Size + z].Normal = normal; 1227 mb->getVertexBuffer()[x * TerrainData.Size + z].Normal = normal;
1228 } 1228 }
1229 } 1229 }
1230 } 1230 }
1231 1231
1232 1232
1233 //! create patches, stuff that needs to be done only once for patches goes here. 1233 //! create patches, stuff that needs to be done only once for patches goes here.
1234 void CTerrainSceneNode::createPatches() 1234 void CTerrainSceneNode::createPatches()
1235 { 1235 {
1236 TerrainData.PatchCount = (TerrainData.Size - 1) / (TerrainData.CalcPatchSize); 1236 TerrainData.PatchCount = (TerrainData.Size - 1) / (TerrainData.CalcPatchSize);
1237 1237
1238 if (TerrainData.Patches) 1238 if (TerrainData.Patches)
1239 delete [] TerrainData.Patches; 1239 delete [] TerrainData.Patches;
1240 1240
1241 TerrainData.Patches = new SPatch[TerrainData.PatchCount * TerrainData.PatchCount]; 1241 TerrainData.Patches = new SPatch[TerrainData.PatchCount * TerrainData.PatchCount];
1242 } 1242 }
1243 1243
1244 1244
1245 //! used to calculate the internal STerrainData structure both at creation and after scaling/position calls. 1245 //! used to calculate the internal STerrainData structure both at creation and after scaling/position calls.
1246 void CTerrainSceneNode::calculatePatchData() 1246 void CTerrainSceneNode::calculatePatchData()
1247 { 1247 {
1248 // Reset the Terrains Bounding Box for re-calculation 1248 // Reset the Terrains Bounding Box for re-calculation
1249 TerrainData.BoundingBox.reset(RenderBuffer->getPosition(0)); 1249 TerrainData.BoundingBox.reset(RenderBuffer->getPosition(0));
1250 1250
1251 for (s32 x = 0; x < TerrainData.PatchCount; ++x) 1251 for (s32 x = 0; x < TerrainData.PatchCount; ++x)
1252 { 1252 {
1253 for (s32 z = 0; z < TerrainData.PatchCount; ++z) 1253 for (s32 z = 0; z < TerrainData.PatchCount; ++z)
1254 { 1254 {
1255 const s32 index = x * TerrainData.PatchCount + z; 1255 const s32 index = x * TerrainData.PatchCount + z;
1256 SPatch& patch = TerrainData.Patches[index]; 1256 SPatch& patch = TerrainData.Patches[index];
1257 patch.CurrentLOD = 0; 1257 patch.CurrentLOD = 0;
1258 1258
1259 const s32 xstart = x*TerrainData.CalcPatchSize; 1259 const s32 xstart = x*TerrainData.CalcPatchSize;
1260 const s32 xend = xstart+TerrainData.CalcPatchSize; 1260 const s32 xend = xstart+TerrainData.CalcPatchSize;
1261 const s32 zstart = z*TerrainData.CalcPatchSize; 1261 const s32 zstart = z*TerrainData.CalcPatchSize;
1262 const s32 zend = zstart+TerrainData.CalcPatchSize; 1262 const s32 zend = zstart+TerrainData.CalcPatchSize;
1263 // For each patch, calculate the bounding box (mins and maxes) 1263 // For each patch, calculate the bounding box (mins and maxes)
1264 patch.BoundingBox.reset(RenderBuffer->getPosition(xstart*TerrainData.Size + zstart)); 1264 patch.BoundingBox.reset(RenderBuffer->getPosition(xstart*TerrainData.Size + zstart));
1265 1265
1266 for (s32 xx = xstart; xx <= xend; ++xx) 1266 for (s32 xx = xstart; xx <= xend; ++xx)
1267 for (s32 zz = zstart; zz <= zend; ++zz) 1267 for (s32 zz = zstart; zz <= zend; ++zz)
1268 patch.BoundingBox.addInternalPoint(RenderBuffer->getVertexBuffer()[xx * TerrainData.Size + zz].Pos); 1268 patch.BoundingBox.addInternalPoint(RenderBuffer->getVertexBuffer()[xx * TerrainData.Size + zz].Pos);
1269 1269
1270 // Reconfigure the bounding box of the terrain as a whole 1270 // Reconfigure the bounding box of the terrain as a whole
1271 TerrainData.BoundingBox.addInternalBox(patch.BoundingBox); 1271 TerrainData.BoundingBox.addInternalBox(patch.BoundingBox);
1272 1272
1273 // get center of Patch 1273 // get center of Patch
1274 patch.Center = patch.BoundingBox.getCenter(); 1274 patch.Center = patch.BoundingBox.getCenter();
1275 1275
1276 // Assign Neighbours 1276 // Assign Neighbours
1277 // Top 1277 // Top
1278 if (x > 0) 1278 if (x > 0)
1279 patch.Top = &TerrainData.Patches[(x-1) * TerrainData.PatchCount + z]; 1279 patch.Top = &TerrainData.Patches[(x-1) * TerrainData.PatchCount + z];
1280 else 1280 else
1281 patch.Top = 0; 1281 patch.Top = 0;
1282 1282
1283 // Bottom 1283 // Bottom
1284 if (x < TerrainData.PatchCount - 1) 1284 if (x < TerrainData.PatchCount - 1)
1285 patch.Bottom = &TerrainData.Patches[(x+1) * TerrainData.PatchCount + z]; 1285 patch.Bottom = &TerrainData.Patches[(x+1) * TerrainData.PatchCount + z];
1286 else 1286 else
1287 patch.Bottom = 0; 1287 patch.Bottom = 0;
1288 1288
1289 // Left 1289 // Left
1290 if (z > 0) 1290 if (z > 0)
1291 patch.Left = &TerrainData.Patches[x * TerrainData.PatchCount + z - 1]; 1291 patch.Left = &TerrainData.Patches[x * TerrainData.PatchCount + z - 1];
1292 else 1292 else
1293 patch.Left = 0; 1293 patch.Left = 0;
1294 1294
1295 // Right 1295 // Right
1296 if (z < TerrainData.PatchCount - 1) 1296 if (z < TerrainData.PatchCount - 1)
1297 patch.Right = &TerrainData.Patches[x * TerrainData.PatchCount + z + 1]; 1297 patch.Right = &TerrainData.Patches[x * TerrainData.PatchCount + z + 1];
1298 else 1298 else
1299 patch.Right = 0; 1299 patch.Right = 0;
1300 } 1300 }
1301 } 1301 }
1302 1302
1303 // get center of Terrain 1303 // get center of Terrain
1304 TerrainData.Center = TerrainData.BoundingBox.getCenter(); 1304 TerrainData.Center = TerrainData.BoundingBox.getCenter();
1305 1305
1306 // if the default rotation pivot is still being used, update it. 1306 // if the default rotation pivot is still being used, update it.
1307 if (UseDefaultRotationPivot) 1307 if (UseDefaultRotationPivot)
1308 { 1308 {
1309 TerrainData.RotationPivot = TerrainData.Center; 1309 TerrainData.RotationPivot = TerrainData.Center;
1310 } 1310 }
1311 } 1311 }
1312 1312
1313 1313
1314 //! used to calculate or recalculate the distance thresholds 1314 //! used to calculate or recalculate the distance thresholds
1315 void CTerrainSceneNode::calculateDistanceThresholds(bool scalechanged) 1315 void CTerrainSceneNode::calculateDistanceThresholds(bool scalechanged)
1316 { 1316 {
1317 // Only update the LODDistanceThreshold if it's not manually changed 1317 // Only update the LODDistanceThreshold if it's not manually changed
1318 if (!OverrideDistanceThreshold) 1318 if (!OverrideDistanceThreshold)
1319 { 1319 {
1320 TerrainData.LODDistanceThreshold.set_used(0); 1320 TerrainData.LODDistanceThreshold.set_used(0);
1321 // Determine new distance threshold for determining what LOD to draw patches at 1321 // Determine new distance threshold for determining what LOD to draw patches at
1322 TerrainData.LODDistanceThreshold.reallocate(TerrainData.MaxLOD); 1322 TerrainData.LODDistanceThreshold.reallocate(TerrainData.MaxLOD);
1323 1323
1324 const f64 size = TerrainData.PatchSize * TerrainData.PatchSize * 1324 const f64 size = TerrainData.PatchSize * TerrainData.PatchSize *
1325 TerrainData.Scale.X * TerrainData.Scale.Z; 1325 TerrainData.Scale.X * TerrainData.Scale.Z;
1326 for (s32 i=0; i<TerrainData.MaxLOD; ++i) 1326 for (s32 i=0; i<TerrainData.MaxLOD; ++i)
1327 { 1327 {
1328 TerrainData.LODDistanceThreshold.push_back(size * ((i+1+ i / 2) * (i+1+ i / 2))); 1328 TerrainData.LODDistanceThreshold.push_back(size * ((i+1+ i / 2) * (i+1+ i / 2)));
1329 } 1329 }
1330 } 1330 }
1331 } 1331 }
1332 1332
1333 1333
1334 void CTerrainSceneNode::setCurrentLODOfPatches(s32 lod) 1334 void CTerrainSceneNode::setCurrentLODOfPatches(s32 lod)
1335 { 1335 {
1336 const s32 count = TerrainData.PatchCount * TerrainData.PatchCount; 1336 const s32 count = TerrainData.PatchCount * TerrainData.PatchCount;
1337 for (s32 i=0; i< count; ++i) 1337 for (s32 i=0; i< count; ++i)
1338 TerrainData.Patches[i].CurrentLOD = lod; 1338 TerrainData.Patches[i].CurrentLOD = lod;
1339 } 1339 }
1340 1340
1341 1341
1342 void CTerrainSceneNode::setCurrentLODOfPatches(const core::array<s32>& lodarray) 1342 void CTerrainSceneNode::setCurrentLODOfPatches(const core::array<s32>& lodarray)
1343 { 1343 {
1344 const s32 count = TerrainData.PatchCount * TerrainData.PatchCount; 1344 const s32 count = TerrainData.PatchCount * TerrainData.PatchCount;
1345 for (s32 i=0; i<count; ++i) 1345 for (s32 i=0; i<count; ++i)
1346 TerrainData.Patches[i].CurrentLOD = lodarray[i]; 1346 TerrainData.Patches[i].CurrentLOD = lodarray[i];
1347 } 1347 }
1348 1348
1349 1349
1350 //! Gets the height 1350 //! Gets the height
1351 f32 CTerrainSceneNode::getHeight(f32 x, f32 z) const 1351 f32 CTerrainSceneNode::getHeight(f32 x, f32 z) const
1352 { 1352 {
1353 if (!Mesh->getMeshBufferCount()) 1353 if (!Mesh->getMeshBufferCount())
1354 return 0; 1354 return 0;
1355 1355
1356 core::matrix4 rotMatrix; 1356 core::matrix4 rotMatrix;
1357 rotMatrix.setRotationDegrees(TerrainData.Rotation); 1357 rotMatrix.setRotationDegrees(TerrainData.Rotation);
1358 core::vector3df pos(x, 0.0f, z); 1358 core::vector3df pos(x, 0.0f, z);
1359 rotMatrix.rotateVect(pos); 1359 rotMatrix.rotateVect(pos);
1360 pos -= TerrainData.Position; 1360 pos -= TerrainData.Position;
1361 pos /= TerrainData.Scale; 1361 pos /= TerrainData.Scale;
1362 1362
1363 s32 X(core::floor32(pos.X)); 1363 s32 X(core::floor32(pos.X));
1364 s32 Z(core::floor32(pos.Z)); 1364 s32 Z(core::floor32(pos.Z));
1365 1365
1366 f32 height = -FLT_MAX; 1366 f32 height = -FLT_MAX;
1367 if (X >= 0 && X < TerrainData.Size-1 && 1367 if (X >= 0 && X < TerrainData.Size-1 &&
1368 Z >= 0 && Z < TerrainData.Size-1) 1368 Z >= 0 && Z < TerrainData.Size-1)
1369 { 1369 {
1370 const video::S3DVertex2TCoords* Vertices = (const video::S3DVertex2TCoords*)Mesh->getMeshBuffer(0)->getVertices(); 1370 const video::S3DVertex2TCoords* Vertices = (const video::S3DVertex2TCoords*)Mesh->getMeshBuffer(0)->getVertices();
1371 const core::vector3df& a = Vertices[X * TerrainData.Size + Z].Pos; 1371 const core::vector3df& a = Vertices[X * TerrainData.Size + Z].Pos;
1372 const core::vector3df& b = Vertices[(X + 1) * TerrainData.Size + Z].Pos; 1372 const core::vector3df& b = Vertices[(X + 1) * TerrainData.Size + Z].Pos;
1373 const core::vector3df& c = Vertices[X * TerrainData.Size + (Z + 1)].Pos; 1373 const core::vector3df& c = Vertices[X * TerrainData.Size + (Z + 1)].Pos;
1374 const core::vector3df& d = Vertices[(X + 1) * TerrainData.Size + (Z + 1)].Pos; 1374 const core::vector3df& d = Vertices[(X + 1) * TerrainData.Size + (Z + 1)].Pos;
1375 1375
1376 // offset from integer position 1376 // offset from integer position
1377 const f32 dx = pos.X - X; 1377 const f32 dx = pos.X - X;
1378 const f32 dz = pos.Z - Z; 1378 const f32 dz = pos.Z - Z;
1379 1379
1380 if (dx > dz) 1380 if (dx > dz)
1381 height = a.Y + (d.Y - b.Y)*dz + (b.Y - a.Y)*dx; 1381 height = a.Y + (d.Y - b.Y)*dz + (b.Y - a.Y)*dx;
1382 else 1382 else
1383 height = a.Y + (d.Y - c.Y)*dx + (c.Y - a.Y)*dz; 1383 height = a.Y + (d.Y - c.Y)*dx + (c.Y - a.Y)*dz;
1384 1384
1385 height *= TerrainData.Scale.Y; 1385 height *= TerrainData.Scale.Y;
1386 height += TerrainData.Position.Y; 1386 height += TerrainData.Position.Y;
1387 } 1387 }
1388 1388
1389 return height; 1389 return height;
1390 } 1390 }
1391 1391
1392 1392
1393 //! Writes attributes of the scene node. 1393 //! Writes attributes of the scene node.
1394 void CTerrainSceneNode::serializeAttributes(io::IAttributes* out, 1394 void CTerrainSceneNode::serializeAttributes(io::IAttributes* out,
1395 io::SAttributeReadWriteOptions* options) const 1395 io::SAttributeReadWriteOptions* options) const
1396 { 1396 {
1397 ISceneNode::serializeAttributes(out, options); 1397 ISceneNode::serializeAttributes(out, options);
1398 1398
1399 out->addString("Heightmap", HeightmapFile.c_str()); 1399 out->addString("Heightmap", HeightmapFile.c_str());
1400 out->addFloat("TextureScale1", TCoordScale1); 1400 out->addFloat("TextureScale1", TCoordScale1);
1401 out->addFloat("TextureScale2", TCoordScale2); 1401 out->addFloat("TextureScale2", TCoordScale2);
1402 out->addInt("SmoothFactor", SmoothFactor); 1402 out->addInt("SmoothFactor", SmoothFactor);
1403 } 1403 }
1404 1404
1405 1405
1406 //! Reads attributes of the scene node. 1406 //! Reads attributes of the scene node.
1407 void CTerrainSceneNode::deserializeAttributes(io::IAttributes* in, 1407 void CTerrainSceneNode::deserializeAttributes(io::IAttributes* in,
1408 io::SAttributeReadWriteOptions* options) 1408 io::SAttributeReadWriteOptions* options)
1409 { 1409 {
1410 io::path newHeightmap = in->getAttributeAsString("Heightmap"); 1410 io::path newHeightmap = in->getAttributeAsString("Heightmap");
1411 f32 tcoordScale1 = in->getAttributeAsFloat("TextureScale1"); 1411 f32 tcoordScale1 = in->getAttributeAsFloat("TextureScale1");
1412 f32 tcoordScale2 = in->getAttributeAsFloat("TextureScale2"); 1412 f32 tcoordScale2 = in->getAttributeAsFloat("TextureScale2");
1413 s32 smoothFactor = in->getAttributeAsInt("SmoothFactor"); 1413 s32 smoothFactor = in->getAttributeAsInt("SmoothFactor");
1414 1414
1415 // set possible new heightmap 1415 // set possible new heightmap
1416 1416
1417 if (newHeightmap.size() != 0 && newHeightmap != HeightmapFile) 1417 if (newHeightmap.size() != 0 && newHeightmap != HeightmapFile)
1418 { 1418 {
1419 io::IReadFile* file = FileSystem->createAndOpenFile(newHeightmap.c_str()); 1419 io::IReadFile* file = FileSystem->createAndOpenFile(newHeightmap.c_str());
1420 if (file) 1420 if (file)
1421 { 1421 {
1422 loadHeightMap(file, video::SColor(255,255,255,255), smoothFactor); 1422 loadHeightMap(file, video::SColor(255,255,255,255), smoothFactor);
1423 file->drop(); 1423 file->drop();
1424 } 1424 }
1425 else 1425 else
1426 os::Printer::log("could not open heightmap", newHeightmap.c_str()); 1426 os::Printer::log("could not open heightmap", newHeightmap.c_str());
1427 } 1427 }
1428 1428
1429 // set possible new scale 1429 // set possible new scale
1430 1430
1431 if (core::equals(tcoordScale1, 0.f)) 1431 if (core::equals(tcoordScale1, 0.f))
1432 tcoordScale1 = 1.0f; 1432 tcoordScale1 = 1.0f;
1433 1433
1434 if (core::equals(tcoordScale2, 0.f)) 1434 if (core::equals(tcoordScale2, 0.f))
1435 tcoordScale2 = 1.0f; 1435 tcoordScale2 = 1.0f;
1436 1436
1437 if (!core::equals(tcoordScale1, TCoordScale1) || 1437 if (!core::equals(tcoordScale1, TCoordScale1) ||
1438 !core::equals(tcoordScale2, TCoordScale2)) 1438 !core::equals(tcoordScale2, TCoordScale2))
1439 { 1439 {
1440 scaleTexture(tcoordScale1, tcoordScale2); 1440 scaleTexture(tcoordScale1, tcoordScale2);
1441 } 1441 }
1442 1442
1443 ISceneNode::deserializeAttributes(in, options); 1443 ISceneNode::deserializeAttributes(in, options);
1444 } 1444 }
1445 1445
1446 1446
1447 //! Creates a clone of this scene node and its children. 1447 //! Creates a clone of this scene node and its children.
1448 ISceneNode* CTerrainSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) 1448 ISceneNode* CTerrainSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
1449 { 1449 {
1450 if (!newParent) 1450 if (!newParent)
1451 newParent = Parent; 1451 newParent = Parent;
1452 if (!newManager) 1452 if (!newManager)
1453 newManager = SceneManager; 1453 newManager = SceneManager;
1454 1454
1455 CTerrainSceneNode* nb = new CTerrainSceneNode( 1455 CTerrainSceneNode* nb = new CTerrainSceneNode(
1456 newParent, newManager, FileSystem, ID, 1456 newParent, newManager, FileSystem, ID,
1457 4, ETPS_17, getPosition(), getRotation(), getScale()); 1457 4, ETPS_17, getPosition(), getRotation(), getScale());
1458 1458
1459 nb->cloneMembers(this, newManager); 1459 nb->cloneMembers(this, newManager);
1460 1460
1461 // instead of cloning the data structures, recreate the terrain. 1461 // instead of cloning the data structures, recreate the terrain.
1462 // (temporary solution) 1462 // (temporary solution)
1463 1463
1464 // load file 1464 // load file
1465 1465
1466 io::IReadFile* file = FileSystem->createAndOpenFile(HeightmapFile.c_str()); 1466 io::IReadFile* file = FileSystem->createAndOpenFile(HeightmapFile.c_str());
1467 if (file) 1467 if (file)
1468 { 1468 {
1469 nb->loadHeightMap(file, video::SColor(255,255,255,255), 0); 1469 nb->loadHeightMap(file, video::SColor(255,255,255,255), 0);
1470 file->drop(); 1470 file->drop();
1471 } 1471 }
1472 1472
1473 // scale textures 1473 // scale textures
1474 1474
1475 nb->scaleTexture(TCoordScale1, TCoordScale2); 1475 nb->scaleTexture(TCoordScale1, TCoordScale2);
1476 1476
1477 // copy materials 1477 // copy materials
1478 1478
1479 for (unsigned int m = 0; m<Mesh->getMeshBufferCount(); ++m) 1479 for (unsigned int m = 0; m<Mesh->getMeshBufferCount(); ++m)
1480 { 1480 {
1481 if (nb->Mesh->getMeshBufferCount()>m && 1481 if (nb->Mesh->getMeshBufferCount()>m &&
1482 nb->Mesh->getMeshBuffer(m) && 1482 nb->Mesh->getMeshBuffer(m) &&
1483 Mesh->getMeshBuffer(m)) 1483 Mesh->getMeshBuffer(m))
1484 { 1484 {
1485 nb->Mesh->getMeshBuffer(m)->getMaterial() = 1485 nb->Mesh->getMeshBuffer(m)->getMaterial() =
1486 Mesh->getMeshBuffer(m)->getMaterial(); 1486 Mesh->getMeshBuffer(m)->getMaterial();
1487 } 1487 }
1488 } 1488 }
1489 1489
1490 nb->RenderBuffer->getMaterial() = RenderBuffer->getMaterial(); 1490 nb->RenderBuffer->getMaterial() = RenderBuffer->getMaterial();
1491 1491
1492 // finish 1492 // finish
1493 1493
1494 if ( newParent ) 1494 if ( newParent )
1495 nb->drop(); 1495 nb->drop();
1496 return nb; 1496 return nb;
1497 } 1497 }
1498 1498
1499} // end namespace scene 1499} // end namespace scene
1500} // end namespace irr 1500} // end namespace irr
1501 1501
1502 1502