diff options
author | David Walter Seikel | 2013-01-13 18:54:10 +1000 |
---|---|---|
committer | David Walter Seikel | 2013-01-13 18:54:10 +1000 |
commit | 959831f4ef5a3e797f576c3de08cd65032c997ad (patch) | |
tree | e7351908be5995f0b325b2ebeaa02d5a34b82583 /libraries/irrlicht-1.8/source/Irrlicht/CTerrainSceneNode.cpp | |
parent | Add info about changes to Irrlicht. (diff) | |
download | SledjHamr-959831f4ef5a3e797f576c3de08cd65032c997ad.zip SledjHamr-959831f4ef5a3e797f576c3de08cd65032c997ad.tar.gz SledjHamr-959831f4ef5a3e797f576c3de08cd65032c997ad.tar.bz2 SledjHamr-959831f4ef5a3e797f576c3de08cd65032c997ad.tar.xz |
Remove damned ancient DOS line endings from Irrlicht. Hopefully I did not go overboard.
Diffstat (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CTerrainSceneNode.cpp')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CTerrainSceneNode.cpp | 3004 |
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 | ||
26 | namespace irr | 26 | namespace irr |
27 | { | 27 | { |
28 | namespace scene | 28 | namespace 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 | ||