diff options
Diffstat (limited to 'source/Irrlicht/CTerrainSceneNode.cpp')
-rw-r--r-- | source/Irrlicht/CTerrainSceneNode.cpp | 1518 |
1 files changed, 0 insertions, 1518 deletions
diff --git a/source/Irrlicht/CTerrainSceneNode.cpp b/source/Irrlicht/CTerrainSceneNode.cpp deleted file mode 100644 index 395a45d..0000000 --- a/source/Irrlicht/CTerrainSceneNode.cpp +++ /dev/null @@ -1,1518 +0,0 @@ -// Copyright (C) 2002-2012 Nikolaus Gebhardt
-// This file is part of the "Irrlicht Engine".
-// For conditions of distribution and use, see copyright notice in irrlicht.h
-
-// The code for the TerrainSceneNode is based on the GeoMipMapSceneNode
-// developed by Spintz. He made it available for Irrlicht and allowed it to be
-// distributed under this licence. I only modified some parts. A lot of thanks
-// go to him.
-
-#include "IrrCompileConfig.h"
-
-#ifdef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_
-
-#include "CTerrainSceneNode.h"
-#include "CTerrainTriangleSelector.h"
-#include "IVideoDriver.h"
-#include "ISceneManager.h"
-#include "ICameraSceneNode.h"
-#include "SViewFrustum.h"
-#include "irrMath.h"
-#include "os.h"
-#include "IGUIFont.h"
-#include "IFileSystem.h"
-#include "IReadFile.h"
-#include "ITextSceneNode.h"
-#include "IAnimatedMesh.h"
-#include "SMesh.h"
-#include "CDynamicMeshBuffer.h"
-
-namespace irr
-{
-namespace scene
-{
-
- //! constructor
- CTerrainSceneNode::CTerrainSceneNode(ISceneNode* parent, ISceneManager* mgr,
- io::IFileSystem* fs, s32 id, s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize,
- const core::vector3df& position,
- const core::vector3df& rotation,
- const core::vector3df& scale)
- : ITerrainSceneNode(parent, mgr, id, position, rotation, scale),
- TerrainData(patchSize, maxLOD, position, rotation, scale), RenderBuffer(0),
- VerticesToRender(0), IndicesToRender(0), DynamicSelectorUpdate(false),
- OverrideDistanceThreshold(false), UseDefaultRotationPivot(true), ForceRecalculation(true),
- FixedBorderLOD(-1),
- CameraMovementDelta(10.0f), CameraRotationDelta(1.0f),CameraFOVDelta(0.1f),
- TCoordScale1(1.0f), TCoordScale2(1.0f), SmoothFactor(0), FileSystem(fs)
- {
- #ifdef _DEBUG
- setDebugName("CTerrainSceneNode");
- #endif
-
- Mesh = new SMesh();
- RenderBuffer = new CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
- RenderBuffer->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX);
- RenderBuffer->setHardwareMappingHint(scene::EHM_DYNAMIC, scene::EBT_INDEX);
-
- if (FileSystem)
- FileSystem->grab();
-
- setAutomaticCulling(scene::EAC_OFF);
- }
-
-
- //! destructor
- CTerrainSceneNode::~CTerrainSceneNode()
- {
- delete [] TerrainData.Patches;
-
- if (FileSystem)
- FileSystem->drop();
-
- if (Mesh)
- Mesh->drop();
-
- if (RenderBuffer)
- RenderBuffer->drop();
- }
-
-
- //! Initializes the terrain data. Loads the vertices from the heightMapFile
- bool CTerrainSceneNode::loadHeightMap(io::IReadFile* file, video::SColor vertexColor,
- s32 smoothFactor)
- {
- if (!file)
- return false;
-
- Mesh->MeshBuffers.clear();
- const u32 startTime = os::Timer::getRealTime();
- video::IImage* heightMap = SceneManager->getVideoDriver()->createImageFromFile(file);
-
- if (!heightMap)
- {
- os::Printer::log("Unable to load heightmap.");
- return false;
- }
-
- HeightmapFile = file->getFileName();
- SmoothFactor = smoothFactor;
-
- // Get the dimension of the heightmap data
- TerrainData.Size = heightMap->getDimension().Width;
-
- switch (TerrainData.PatchSize)
- {
- case ETPS_9:
- if (TerrainData.MaxLOD > 3)
- {
- TerrainData.MaxLOD = 3;
- }
- break;
- case ETPS_17:
- if (TerrainData.MaxLOD > 4)
- {
- TerrainData.MaxLOD = 4;
- }
- break;
- case ETPS_33:
- if (TerrainData.MaxLOD > 5)
- {
- TerrainData.MaxLOD = 5;
- }
- break;
- case ETPS_65:
- if (TerrainData.MaxLOD > 6)
- {
- TerrainData.MaxLOD = 6;
- }
- break;
- case ETPS_129:
- if (TerrainData.MaxLOD > 7)
- {
- TerrainData.MaxLOD = 7;
- }
- break;
- }
-
- // --- Generate vertex data from heightmap ----
- // resize the vertex array for the mesh buffer one time (makes loading faster)
- scene::CDynamicMeshBuffer *mb=0;
-
- const u32 numVertices = TerrainData.Size * TerrainData.Size;
- if (numVertices <= 65536)
- {
- //small enough for 16bit buffers
- mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
- RenderBuffer->getIndexBuffer().setType(video::EIT_16BIT);
- }
- else
- {
- //we need 32bit buffers
- mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_32BIT);
- RenderBuffer->getIndexBuffer().setType(video::EIT_32BIT);
- }
-
- mb->getVertexBuffer().set_used(numVertices);
-
- // Read the heightmap to get the vertex data
- // Apply positions changes, scaling changes
- const f32 tdSize = 1.0f/(f32)(TerrainData.Size-1);
- s32 index = 0;
- float fx=0.f;
- float fx2=0.f;
- for (s32 x = 0; x < TerrainData.Size; ++x)
- {
- float fz=0.f;
- float fz2=0.f;
- for (s32 z = 0; z < TerrainData.Size; ++z)
- {
- video::S3DVertex2TCoords& vertex= static_cast<video::S3DVertex2TCoords*>(mb->getVertexBuffer().pointer())[index++];
- vertex.Normal.set(0.0f, 1.0f, 0.0f);
- vertex.Color = vertexColor;
- vertex.Pos.X = fx;
- vertex.Pos.Y = (f32) heightMap->getPixel(TerrainData.Size-x-1,z).getLightness();
- vertex.Pos.Z = fz;
-
- vertex.TCoords.X = vertex.TCoords2.X = 1.f-fx2;
- vertex.TCoords.Y = vertex.TCoords2.Y = fz2;
-
- ++fz;
- fz2 += tdSize;
- }
- ++fx;
- fx2 += tdSize;
- }
-
- // drop heightMap, no longer needed
- heightMap->drop();
-
- smoothTerrain(mb, smoothFactor);
-
- // calculate smooth normals for the vertices
- calculateNormals(mb);
-
- // add the MeshBuffer to the mesh
- Mesh->addMeshBuffer(mb);
-
- // We copy the data to the renderBuffer, after the normals have been calculated.
- RenderBuffer->getVertexBuffer().set_used(numVertices);
-
- for (u32 i = 0; i < numVertices; ++i)
- {
- RenderBuffer->getVertexBuffer()[i] = mb->getVertexBuffer()[i];
- RenderBuffer->getVertexBuffer()[i].Pos *= TerrainData.Scale;
- RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.Position;
- }
-
- // We no longer need the mb
- mb->drop();
-
- // calculate all the necessary data for the patches and the terrain
- calculateDistanceThresholds();
- createPatches();
- calculatePatchData();
-
- // set the default rotation pivot point to the terrain nodes center
- TerrainData.RotationPivot = TerrainData.Center;
-
- // Rotate the vertices of the terrain by the rotation
- // specified. Must be done after calculating the terrain data,
- // so we know what the current center of the terrain is.
- setRotation(TerrainData.Rotation);
-
- // Pre-allocate memory for indices
-
- RenderBuffer->getIndexBuffer().set_used(
- TerrainData.PatchCount * TerrainData.PatchCount *
- TerrainData.CalcPatchSize * TerrainData.CalcPatchSize * 6);
-
- RenderBuffer->setDirty();
-
- const u32 endTime = os::Timer::getRealTime();
-
- c8 tmp[255];
- snprintf_irr(tmp, 255, "Generated terrain data (%dx%d) in %.4f seconds",
- TerrainData.Size, TerrainData.Size, (endTime - startTime) / 1000.0f );
- os::Printer::log(tmp);
-
- return true;
- }
-
-
- //! Initializes the terrain data. Loads the vertices from the heightMapFile
- bool CTerrainSceneNode::loadHeightMapRAW(io::IReadFile* file,
- s32 bitsPerPixel, bool signedData, bool floatVals,
- s32 width, video::SColor vertexColor, s32 smoothFactor)
- {
- if (!file)
- return false;
- if (floatVals && bitsPerPixel != 32)
- return false;
-
- // start reading
- const u32 startTime = os::Timer::getTime();
-
- Mesh->MeshBuffers.clear();
-
- const size_t bytesPerPixel = (size_t)bitsPerPixel / 8;
-
- // Get the dimension of the heightmap data
- const long filesize = file->getSize();
- if (!width)
- TerrainData.Size = core::floor32(sqrtf((f32)(filesize / bytesPerPixel)));
- else
- {
- if ((filesize-file->getPos())/bytesPerPixel>(size_t)(width*width))
- {
- os::Printer::log("Error reading heightmap RAW file", "File is too small.");
- return false;
- }
- TerrainData.Size = width;
- }
-
- switch (TerrainData.PatchSize)
- {
- case ETPS_9:
- if (TerrainData.MaxLOD > 3)
- {
- TerrainData.MaxLOD = 3;
- }
- break;
- case ETPS_17:
- if (TerrainData.MaxLOD > 4)
- {
- TerrainData.MaxLOD = 4;
- }
- break;
- case ETPS_33:
- if (TerrainData.MaxLOD > 5)
- {
- TerrainData.MaxLOD = 5;
- }
- break;
- case ETPS_65:
- if (TerrainData.MaxLOD > 6)
- {
- TerrainData.MaxLOD = 6;
- }
- break;
- case ETPS_129:
- if (TerrainData.MaxLOD > 7)
- {
- TerrainData.MaxLOD = 7;
- }
- break;
- }
-
- // --- Generate vertex data from heightmap ----
- // resize the vertex array for the mesh buffer one time (makes loading faster)
- scene::CDynamicMeshBuffer *mb=0;
- const u32 numVertices = TerrainData.Size * TerrainData.Size;
- if (numVertices <= 65536)
- {
- //small enough for 16bit buffers
- mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
- RenderBuffer->getIndexBuffer().setType(video::EIT_16BIT);
- }
- else
- {
- //we need 32bit buffers
- mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_32BIT);
- RenderBuffer->getIndexBuffer().setType(video::EIT_32BIT);
- }
-
- mb->getVertexBuffer().reallocate(numVertices);
-
- video::S3DVertex2TCoords vertex;
- vertex.Normal.set(0.0f, 1.0f, 0.0f);
- vertex.Color = vertexColor;
-
- // Read the heightmap to get the vertex data
- // Apply positions changes, scaling changes
- const f32 tdSize = 1.0f/(f32)(TerrainData.Size-1);
- float fx=0.f;
- float fx2=0.f;
- for (s32 x = 0; x < TerrainData.Size; ++x)
- {
- float fz=0.f;
- float fz2=0.f;
- for (s32 z = 0; z < TerrainData.Size; ++z)
- {
- bool failure=false;
- vertex.Pos.X = fx;
- if (floatVals)
- {
- if (file->read(&vertex.Pos.Y, bytesPerPixel) != bytesPerPixel)
- failure=true;
- }
- else if (signedData)
- {
- switch (bytesPerPixel)
- {
- case 1:
- {
- s8 val;
- if (file->read(&val, bytesPerPixel) != bytesPerPixel)
- failure=true;
- vertex.Pos.Y=val;
- }
- break;
- case 2:
- {
- s16 val;
- if (file->read(&val, bytesPerPixel) != bytesPerPixel)
- failure=true;
- vertex.Pos.Y=val/256.f;
- }
- break;
- case 4:
- {
- s32 val;
- if (file->read(&val, bytesPerPixel) != bytesPerPixel)
- failure=true;
- vertex.Pos.Y=val/16777216.f;
- }
- break;
- }
- }
- else
- {
- switch (bytesPerPixel)
- {
- case 1:
- {
- u8 val;
- if (file->read(&val, bytesPerPixel) != bytesPerPixel)
- failure=true;
- vertex.Pos.Y=val;
- }
- break;
- case 2:
- {
- u16 val;
- if (file->read(&val, bytesPerPixel) != bytesPerPixel)
- failure=true;
- vertex.Pos.Y=val/256.f;
- }
- break;
- case 4:
- {
- u32 val;
- if (file->read(&val, bytesPerPixel) != bytesPerPixel)
- failure=true;
- vertex.Pos.Y=val/16777216.f;
- }
- break;
- }
- }
- if (failure)
- {
- os::Printer::log("Error reading heightmap RAW file.");
- mb->drop();
- return false;
- }
- vertex.Pos.Z = fz;
-
- vertex.TCoords.X = vertex.TCoords2.X = 1.f-fx2;
- vertex.TCoords.Y = vertex.TCoords2.Y = fz2;
-
- mb->getVertexBuffer().push_back(vertex);
- ++fz;
- fz2 += tdSize;
- }
- ++fx;
- fx2 += tdSize;
- }
-
- smoothTerrain(mb, smoothFactor);
-
- // calculate smooth normals for the vertices
- calculateNormals(mb);
-
- // add the MeshBuffer to the mesh
- Mesh->addMeshBuffer(mb);
- const u32 vertexCount = mb->getVertexCount();
-
- // We copy the data to the renderBuffer, after the normals have been calculated.
- RenderBuffer->getVertexBuffer().set_used(vertexCount);
-
- for (u32 i = 0; i < vertexCount; i++)
- {
- RenderBuffer->getVertexBuffer()[i] = mb->getVertexBuffer()[i];
- RenderBuffer->getVertexBuffer()[i].Pos *= TerrainData.Scale;
- RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.Position;
- }
-
- // We no longer need the mb
- mb->drop();
-
- // calculate all the necessary data for the patches and the terrain
- calculateDistanceThresholds();
- createPatches();
- calculatePatchData();
-
- // set the default rotation pivot point to the terrain nodes center
- TerrainData.RotationPivot = TerrainData.Center;
-
- // Rotate the vertices of the terrain by the rotation specified. Must be done
- // after calculating the terrain data, so we know what the current center of the
- // terrain is.
- setRotation(TerrainData.Rotation);
-
- // Pre-allocate memory for indices
- RenderBuffer->getIndexBuffer().set_used(
- TerrainData.PatchCount*TerrainData.PatchCount*
- TerrainData.CalcPatchSize*TerrainData.CalcPatchSize*6);
-
- const u32 endTime = os::Timer::getTime();
-
- c8 tmp[255];
- snprintf_irr(tmp, 255, "Generated terrain data (%dx%d) in %.4f seconds",
- TerrainData.Size, TerrainData.Size, (endTime - startTime) / 1000.0f);
- os::Printer::log(tmp);
-
- return true;
- }
-
-
- //! Returns the mesh
- IMesh* CTerrainSceneNode::getMesh() { return Mesh; }
-
-
- //! Returns the material based on the zero based index i.
- video::SMaterial& CTerrainSceneNode::getMaterial(u32 i)
- {
- return Mesh->getMeshBuffer(i)->getMaterial();
- }
-
-
- //! Returns amount of materials used by this scene node ( always 1 )
- u32 CTerrainSceneNode::getMaterialCount() const
- {
- return Mesh->getMeshBufferCount();
- }
-
-
- //! Sets the scale of the scene node.
- //! \param scale: New scale of the node
- void CTerrainSceneNode::setScale(const core::vector3df& scale)
- {
- TerrainData.Scale = scale;
- applyTransformation();
- calculateNormals(RenderBuffer);
- ForceRecalculation = true;
- }
-
-
- //! Sets the rotation of the node. This only modifies
- //! the relative rotation of the node.
- //! \param rotation: New rotation of the node in degrees.
- void CTerrainSceneNode::setRotation(const core::vector3df& rotation)
- {
- TerrainData.Rotation = rotation;
- applyTransformation();
- ForceRecalculation = true;
- }
-
-
- //! Sets the pivot point for rotation of this node. This is useful for the TiledTerrainManager to
- //! rotate all terrain tiles around a global world point.
- //! NOTE: The default for the RotationPivot will be the center of the individual tile.
- void CTerrainSceneNode::setRotationPivot(const core::vector3df& pivot)
- {
- UseDefaultRotationPivot = false;
- TerrainData.RotationPivot = pivot;
- }
-
-
- //! Sets the position of the node.
- //! \param newpos: New postition of the scene node.
- void CTerrainSceneNode::setPosition(const core::vector3df& newpos)
- {
- TerrainData.Position = newpos;
- applyTransformation();
- ForceRecalculation = true;
- }
-
-
- //! Apply transformation changes(scale, position, rotation)
- void CTerrainSceneNode::applyTransformation()
- {
- if (!Mesh->getMeshBufferCount())
- return;
-
- core::matrix4 rotMatrix;
- rotMatrix.setRotationDegrees(TerrainData.Rotation);
-
- const s32 vtxCount = Mesh->getMeshBuffer(0)->getVertexCount();
- for (s32 i = 0; i < vtxCount; ++i)
- {
- RenderBuffer->getVertexBuffer()[i].Pos = Mesh->getMeshBuffer(0)->getPosition(i) * TerrainData.Scale + TerrainData.Position;
-
- RenderBuffer->getVertexBuffer()[i].Pos -= TerrainData.RotationPivot;
- rotMatrix.inverseRotateVect(RenderBuffer->getVertexBuffer()[i].Pos);
- RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.RotationPivot;
- }
-
- calculateDistanceThresholds(true);
- calculatePatchData();
-
- RenderBuffer->setDirty(EBT_VERTEX);
- }
-
-
- //! Updates the scene nodes indices if the camera has moved or rotated by a certain
- //! threshold, which can be changed using the SetCameraMovementDeltaThreshold and
- //! SetCameraRotationDeltaThreshold functions. This also determines if a given patch
- //! for the scene node is within the view frustum and if it's not the indices are not
- //! generated for that patch.
- void CTerrainSceneNode::OnRegisterSceneNode()
- {
- if (!IsVisible || !SceneManager->getActiveCamera())
- return;
-
- SceneManager->registerNodeForRendering(this);
-
- preRenderCalculationsIfNeeded();
-
- // Do Not call ISceneNode::OnRegisterSceneNode(), this node should have no children (luke: is this comment still true, as ISceneNode::OnRegisterSceneNode() is called?)
-
- ISceneNode::OnRegisterSceneNode();
- ForceRecalculation = false;
- }
-
- void CTerrainSceneNode::preRenderCalculationsIfNeeded()
- {
- scene::ICameraSceneNode * camera = SceneManager->getActiveCamera();
- if (!camera)
- return;
-
- // Determine the camera rotation, based on the camera direction.
- const core::vector3df cameraPosition = camera->getAbsolutePosition();
- const core::vector3df cameraRotation = core::line3d<f32>(cameraPosition, camera->getTarget()).getVector().getHorizontalAngle();
- core::vector3df cameraUp = camera->getUpVector();
- cameraUp.normalize();
- const f32 CameraFOV = SceneManager->getActiveCamera()->getFOV();
-
- // Only check on the Camera's Y Rotation
- if (!ForceRecalculation)
- {
- if ((fabsf(cameraRotation.X - OldCameraRotation.X) < CameraRotationDelta) &&
- (fabsf(cameraRotation.Y - OldCameraRotation.Y) < CameraRotationDelta))
- {
- if ((fabs(cameraPosition.X - OldCameraPosition.X) < CameraMovementDelta) &&
- (fabs(cameraPosition.Y - OldCameraPosition.Y) < CameraMovementDelta) &&
- (fabs(cameraPosition.Z - OldCameraPosition.Z) < CameraMovementDelta))
- {
- if (fabs(CameraFOV-OldCameraFOV) < CameraFOVDelta &&
- cameraUp.dotProduct(OldCameraUp) > (1.f - (cos(core::DEGTORAD * CameraRotationDelta))))
- {
- return;
- }
- }
- }
- }
-
- //we need to redo calculations...
-
- OldCameraPosition = cameraPosition;
- OldCameraRotation = cameraRotation;
- OldCameraUp = cameraUp;
- OldCameraFOV = CameraFOV;
-
- preRenderLODCalculations();
- preRenderIndicesCalculations();
- }
-
- void CTerrainSceneNode::preRenderLODCalculations()
- {
- scene::ICameraSceneNode * camera = SceneManager->getActiveCamera();
-
- if (!camera)
- return;
-
- const core::vector3df cameraPosition = camera->getAbsolutePosition();
-
- const SViewFrustum* frustum = camera->getViewFrustum();
-
- // Determine each patches LOD based on distance from camera (and whether or not they are in
- // the view frustum).
- const s32 count = TerrainData.PatchCount * TerrainData.PatchCount;
- for (s32 j = 0; j < count; ++j)
- {
- if (frustum->getBoundingBox().intersectsWithBox(TerrainData.Patches[j].BoundingBox))
- {
- const f32 distance = cameraPosition.getDistanceFromSQ(TerrainData.Patches[j].Center);
-
- if ( FixedBorderLOD >= 0 )
- {
- TerrainData.Patches[j].CurrentLOD = FixedBorderLOD;
- if (j < TerrainData.PatchCount
- || j >= (count - TerrainData.PatchCount)
- || (j % TerrainData.PatchCount) == 0
- || (j % TerrainData.PatchCount) == TerrainData.PatchCount-1)
- continue;
- }
-
- TerrainData.Patches[j].CurrentLOD = 0;
-
- for (s32 i = TerrainData.MaxLOD - 1; i>0; --i)
- {
- if (distance >= TerrainData.LODDistanceThreshold[i])
- {
- TerrainData.Patches[j].CurrentLOD = i;
- break;
- }
- }
- }
- else
- {
- TerrainData.Patches[j].CurrentLOD = -1;
- }
- }
- }
-
-
- void CTerrainSceneNode::preRenderIndicesCalculations()
- {
- scene::IIndexBuffer& indexBuffer = RenderBuffer->getIndexBuffer();
- IndicesToRender = 0;
- indexBuffer.set_used(0);
-
- s32 index = 0;
- // Then generate the indices for all patches that are visible.
- for (s32 i = 0; i < TerrainData.PatchCount; ++i)
- {
- for (s32 j = 0; j < TerrainData.PatchCount; ++j)
- {
- if (TerrainData.Patches[index].CurrentLOD >= 0)
- {
- s32 x = 0;
- s32 z = 0;
-
- // calculate the step we take this patch, based on the patches current LOD
- const s32 step = 1 << TerrainData.Patches[index].CurrentLOD;
-
- // Loop through patch and generate indices
- while (z < TerrainData.CalcPatchSize)
- {
- const s32 index11 = getIndex(j, i, index, x, z);
- const s32 index21 = getIndex(j, i, index, x + step, z);
- const s32 index12 = getIndex(j, i, index, x, z + step);
- const s32 index22 = getIndex(j, i, index, x + step, z + step);
-
- indexBuffer.push_back(index12);
- indexBuffer.push_back(index11);
- indexBuffer.push_back(index22);
- indexBuffer.push_back(index22);
- indexBuffer.push_back(index11);
- indexBuffer.push_back(index21);
- IndicesToRender+=6;
-
- // increment index position horizontally
- x += step;
-
- // we've hit an edge
- if (x >= TerrainData.CalcPatchSize)
- {
- x = 0;
- z += step;
- }
- }
- }
- ++index;
- }
- }
-
- RenderBuffer->setDirty(EBT_INDEX);
-
- if (DynamicSelectorUpdate && TriangleSelector)
- {
- CTerrainTriangleSelector* selector = (CTerrainTriangleSelector*)TriangleSelector;
- selector->setTriangleData(this, -1);
- }
- }
-
-
- //! Render the scene node
- void CTerrainSceneNode::render()
- {
- if (!IsVisible || !SceneManager->getActiveCamera())
- return;
-
- if (!Mesh->getMeshBufferCount())
- return;
-
- video::IVideoDriver* driver = SceneManager->getVideoDriver();
-
- driver->setTransform (video::ETS_WORLD, core::IdentityMatrix);
- driver->setMaterial(Mesh->getMeshBuffer(0)->getMaterial());
-
- RenderBuffer->getIndexBuffer().set_used(IndicesToRender);
-
- // For use with geomorphing
- driver->drawMeshBuffer(RenderBuffer);
-
- RenderBuffer->getIndexBuffer().set_used(RenderBuffer->getIndexBuffer().allocated_size());
-
- // for debug purposes only:
- if (DebugDataVisible)
- {
- video::SMaterial m;
- m.Lighting = false;
- driver->setMaterial(m);
- if (DebugDataVisible & scene::EDS_BBOX)
- driver->draw3DBox(TerrainData.BoundingBox, video::SColor(255,255,255,255));
-
- const s32 count = TerrainData.PatchCount * TerrainData.PatchCount;
- s32 visible = 0;
- if (DebugDataVisible & scene::EDS_BBOX_BUFFERS)
- {
- for (s32 j = 0; j < count; ++j)
- {
- driver->draw3DBox(TerrainData.Patches[j].BoundingBox, video::SColor(255,255,0,0));
- visible += (TerrainData.Patches[j].CurrentLOD >= 0);
- }
- }
-
- if (DebugDataVisible & scene::EDS_NORMALS)
- {
- // draw normals
- const f32 debugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(DEBUG_NORMAL_LENGTH);
- const video::SColor debugNormalColor = SceneManager->getParameters()->getAttributeAsColor(DEBUG_NORMAL_COLOR);
- driver->drawMeshBufferNormals(RenderBuffer, debugNormalLength, debugNormalColor);
- }
-
- driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
-
- static u32 lastTime = 0;
-
- const u32 now = os::Timer::getRealTime();
- if (now - lastTime > 1000)
- {
- char buf[64];
- snprintf_irr(buf, 64, "Count: %d, Visible: %d", count, visible);
- os::Printer::log(buf);
-
- lastTime = now;
- }
- }
- }
-
-
- //! Return the bounding box of the entire terrain.
- const core::aabbox3d<f32>& CTerrainSceneNode::getBoundingBox() const
- {
- return TerrainData.BoundingBox;
- }
-
-
- //! Return the bounding box of a patch
- const core::aabbox3d<f32>& CTerrainSceneNode::getBoundingBox(s32 patchX, s32 patchZ) const
- {
- return TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].BoundingBox;
- }
-
-
- //! Gets the meshbuffer data based on a specified Level of Detail.
- //! \param mb: A reference to an SMeshBuffer object
- //! \param LOD: The Level Of Detail you want the indices from.
- void CTerrainSceneNode::getMeshBufferForLOD(IDynamicMeshBuffer& mb, s32 LOD ) const
- {
- if (!Mesh->getMeshBufferCount())
- return;
-
- LOD = core::clamp(LOD, 0, TerrainData.MaxLOD - 1);
-
- const u32 numVertices = Mesh->getMeshBuffer(0)->getVertexCount();
- mb.getVertexBuffer().reallocate(numVertices);
- video::S3DVertex2TCoords* vertices = (video::S3DVertex2TCoords*)Mesh->getMeshBuffer(0)->getVertices();
-
- for (u32 n=0; n<numVertices; ++n)
- mb.getVertexBuffer().push_back(vertices[n]);
-
- mb.getIndexBuffer().setType(RenderBuffer->getIndexBuffer().getType());
-
- // calculate the step we take for all patches, since LOD is the same
- const s32 step = 1 << LOD;
-
- // Generate the indices for all patches at the specified LOD
- s32 index = 0;
- for (s32 i=0; i<TerrainData.PatchCount; ++i)
- {
- for (s32 j=0; j<TerrainData.PatchCount; ++j)
- {
- s32 x = 0;
- s32 z = 0;
-
- // Loop through patch and generate indices
- while (z < TerrainData.CalcPatchSize)
- {
- const s32 index11 = getIndex(j, i, index, x, z);
- const s32 index21 = getIndex(j, i, index, x + step, z);
- const s32 index12 = getIndex(j, i, index, x, z + step);
- const s32 index22 = getIndex(j, i, index, x + step, z + step);
-
- mb.getIndexBuffer().push_back(index12);
- mb.getIndexBuffer().push_back(index11);
- mb.getIndexBuffer().push_back(index22);
- mb.getIndexBuffer().push_back(index22);
- mb.getIndexBuffer().push_back(index11);
- mb.getIndexBuffer().push_back(index21);
-
- // increment index position horizontally
- x += step;
-
- if (x >= TerrainData.CalcPatchSize) // we've hit an edge
- {
- x = 0;
- z += step;
- }
- }
- ++index;
- }
- }
- }
-
-
- //! Gets the indices for a specified patch at a specified Level of Detail.
- //! \param mb: A reference to an array of u32 indices.
- //! \param patchX: Patch x coordinate.
- //! \param patchZ: Patch z coordinate.
- //! \param LOD: The level of detail to get for that patch. If -1, then get
- //! the CurrentLOD. If the CurrentLOD is set to -1, meaning it's not shown,
- //! then it will retrieve the triangles at the highest LOD (0).
- //! \return: Number if indices put into the buffer.
- s32 CTerrainSceneNode::getIndicesForPatch(core::array<u32>& indices, s32 patchX, s32 patchZ, s32 LOD)
- {
- if (patchX < 0 || patchX > TerrainData.PatchCount-1 ||
- patchZ < 0 || patchZ > TerrainData.PatchCount-1)
- return -1;
-
- if (LOD < -1 || LOD > TerrainData.MaxLOD - 1)
- return -1;
-
- core::array<s32> cLODs;
- bool setLODs = false;
-
- // If LOD of -1 was passed in, use the CurrentLOD of the patch specified
- if (LOD == -1)
- {
- LOD = TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].CurrentLOD;
- }
- else
- {
- getCurrentLODOfPatches(cLODs);
- setCurrentLODOfPatches(LOD);
- setLODs = true;
- }
-
- if (LOD < 0)
- return -2; // Patch not visible, don't generate indices.
-
- // calculate the step we take for this LOD
- const s32 step = 1 << LOD;
-
- // Generate the indices for the specified patch at the specified LOD
- const s32 index = patchX * TerrainData.PatchCount + patchZ;
-
- s32 x = 0;
- s32 z = 0;
-
- indices.set_used(TerrainData.PatchSize * TerrainData.PatchSize * 6);
-
- // Loop through patch and generate indices
- s32 rv=0;
- while (z<TerrainData.CalcPatchSize)
- {
- const s32 index11 = getIndex(patchZ, patchX, index, x, z);
- const s32 index21 = getIndex(patchZ, patchX, index, x + step, z);
- const s32 index12 = getIndex(patchZ, patchX, index, x, z + step);
- const s32 index22 = getIndex(patchZ, patchX, index, x + step, z + step);
-
- indices[rv++] = index12;
- indices[rv++] = index11;
- indices[rv++] = index22;
- indices[rv++] = index22;
- indices[rv++] = index11;
- indices[rv++] = index21;
-
- // increment index position horizontally
- x += step;
-
- if (x >= TerrainData.CalcPatchSize) // we've hit an edge
- {
- x = 0;
- z += step;
- }
- }
-
- if (setLODs)
- setCurrentLODOfPatches(cLODs);
-
- return rv;
- }
-
-
- //! Populates an array with the CurrentLOD of each patch.
- //! \param LODs: A reference to a core::array<s32> to hold the values
- //! \return Returns the number of elements in the array
- s32 CTerrainSceneNode::getCurrentLODOfPatches(core::array<s32>& LODs) const
- {
- s32 numLODs;
- LODs.clear();
-
- const s32 count = TerrainData.PatchCount * TerrainData.PatchCount;
- for (numLODs = 0; numLODs < count; numLODs++)
- LODs.push_back(TerrainData.Patches[numLODs].CurrentLOD);
-
- return LODs.size();
- }
-
-
- //! Manually sets the LOD of a patch
- //! \param patchX: Patch x coordinate.
- //! \param patchZ: Patch z coordinate.
- //! \param LOD: The level of detail to set the patch to.
- void CTerrainSceneNode::setLODOfPatch(s32 patchX, s32 patchZ, s32 LOD)
- {
- TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].CurrentLOD = LOD;
- }
-
-
- //! Override the default generation of distance thresholds for determining the LOD a patch
- //! is rendered at.
- bool CTerrainSceneNode::overrideLODDistance(s32 LOD, f64 newDistance)
- {
- OverrideDistanceThreshold = true;
-
- if (LOD < 0 || LOD > TerrainData.MaxLOD - 1)
- return false;
-
- TerrainData.LODDistanceThreshold[LOD] = newDistance * newDistance;
-
- return true;
- }
-
-
- //! Creates a planar texture mapping on the terrain
- //! \param resolution: resolution of the planar mapping. This is the value
- //! specifying the relation between world space and texture coordinate space.
- void CTerrainSceneNode::scaleTexture(f32 resolution, f32 resolution2)
- {
- TCoordScale1 = resolution;
- TCoordScale2 = resolution2;
-
- const f32 resBySize = resolution / (f32)(TerrainData.Size-1);
- const f32 res2BySize = resolution2 / (f32)(TerrainData.Size-1);
- u32 index = 0;
- f32 xval = 0.f;
- f32 x2val = 0.f;
- for (s32 x=0; x<TerrainData.Size; ++x)
- {
- f32 zval=0.f;
- f32 z2val=0.f;
- for (s32 z=0; z<TerrainData.Size; ++z)
- {
- RenderBuffer->getVertexBuffer()[index].TCoords.X = 1.f-xval;
- RenderBuffer->getVertexBuffer()[index].TCoords.Y = zval;
-
- if (RenderBuffer->getVertexType()==video::EVT_2TCOORDS)
- {
- if (resolution2 == 0)
- {
- ((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2 = RenderBuffer->getVertexBuffer()[index].TCoords;
- }
- else
- {
- ((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2.X = 1.f-x2val;
- ((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2.Y = z2val;
- }
- }
-
- ++index;
- zval += resBySize;
- z2val += res2BySize;
- }
- xval += resBySize;
- x2val += res2BySize;
- }
-
- RenderBuffer->setDirty(EBT_VERTEX);
- }
-
-
- //! used to get the indices when generating index data for patches at varying levels of detail.
- u32 CTerrainSceneNode::getIndex(const s32 PatchX, const s32 PatchZ,
- const s32 PatchIndex, u32 vX, u32 vZ) const
- {
- // top border
- if (vZ == 0)
- {
- if (TerrainData.Patches[PatchIndex].Top &&
- TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Top->CurrentLOD &&
- (vX % (1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD)) != 0 )
- {
- vX -= vX % (1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD);
- }
- }
- else
- if (vZ == (u32)TerrainData.CalcPatchSize) // bottom border
- {
- if (TerrainData.Patches[PatchIndex].Bottom &&
- TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Bottom->CurrentLOD &&
- (vX % (1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD)) != 0)
- {
- vX -= vX % (1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD);
- }
- }
-
- // left border
- if (vX == 0)
- {
- if (TerrainData.Patches[PatchIndex].Left &&
- TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Left->CurrentLOD &&
- (vZ % (1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD)) != 0)
- {
- vZ -= vZ % (1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD);
- }
- }
- else
- if (vX == (u32)TerrainData.CalcPatchSize) // right border
- {
- if (TerrainData.Patches[PatchIndex].Right &&
- TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Right->CurrentLOD &&
- (vZ % (1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD)) != 0)
- {
- vZ -= vZ % (1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD);
- }
- }
-
- if (vZ >= (u32)TerrainData.PatchSize)
- vZ = TerrainData.CalcPatchSize;
-
- if (vX >= (u32)TerrainData.PatchSize)
- vX = TerrainData.CalcPatchSize;
-
- return (vZ + ((TerrainData.CalcPatchSize) * PatchZ)) * TerrainData.Size +
- (vX + ((TerrainData.CalcPatchSize) * PatchX));
- }
-
-
- //! smooth the terrain
- void CTerrainSceneNode::smoothTerrain(IDynamicMeshBuffer* mb, s32 smoothFactor)
- {
- for (s32 run = 0; run < smoothFactor; ++run)
- {
- s32 yd = TerrainData.Size;
- for (s32 y = 1; y < TerrainData.Size - 1; ++y)
- {
- for (s32 x = 1; x < TerrainData.Size - 1; ++x)
- {
- mb->getVertexBuffer()[x + yd].Pos.Y =
- (mb->getVertexBuffer()[x-1 + yd].Pos.Y + //left
- mb->getVertexBuffer()[x+1 + yd].Pos.Y + //right
- mb->getVertexBuffer()[x + yd - TerrainData.Size].Pos.Y + //above
- mb->getVertexBuffer()[x + yd + TerrainData.Size].Pos.Y) * 0.25f; //below
- }
- yd += TerrainData.Size;
- }
- }
- }
-
-
- //! calculate smooth normals
- void CTerrainSceneNode::calculateNormals(IDynamicMeshBuffer* mb)
- {
- s32 count;
- core::vector3df a, b, c, t;
-
- for (s32 x=0; x<TerrainData.Size; ++x)
- {
- for (s32 z=0; z<TerrainData.Size; ++z)
- {
- count = 0;
- core::vector3df normal;
-
- // top left
- if (x>0 && z>0)
- {
- a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z-1].Pos;
- b = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z].Pos;
- c = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos;
- b -= a;
- c -= a;
- t = b.crossProduct(c);
- t.normalize();
- normal += t;
-
- a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z-1].Pos;
- b = mb->getVertexBuffer()[x*TerrainData.Size+z-1].Pos;
- c = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos;
- b -= a;
- c -= a;
- t = b.crossProduct(c);
- t.normalize();
- normal += t;
-
- count += 2;
- }
-
- // top right
- if (x>0 && z<TerrainData.Size-1)
- {
- a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z].Pos;
- b = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z+1].Pos;
- c = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos;
- b -= a;
- c -= a;
- t = b.crossProduct(c);
- t.normalize();
- normal += t;
-
- a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z].Pos;
- b = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos;
- c = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos;
- b -= a;
- c -= a;
- t = b.crossProduct(c);
- t.normalize();
- normal += t;
-
- count += 2;
- }
-
- // bottom right
- if (x<TerrainData.Size-1 && z<TerrainData.Size-1)
- {
- a = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos;
- b = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos;
- c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z+1].Pos;
- b -= a;
- c -= a;
- t = b.crossProduct(c);
- t.normalize();
- normal += t;
-
- a = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos;
- b = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z+1].Pos;
- c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z].Pos;
- b -= a;
- c -= a;
- t = b.crossProduct(c);
- t.normalize();
- normal += t;
-
- count += 2;
- }
-
- // bottom left
- if (x<TerrainData.Size-1 && z>0)
- {
- a = mb->getVertexBuffer()[x*TerrainData.Size+z-1].Pos;
- b = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos;
- c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z].Pos;
- b -= a;
- c -= a;
- t = b.crossProduct(c);
- t.normalize();
- normal += t;
-
- a = mb->getVertexBuffer()[x*TerrainData.Size+z-1].Pos;
- b = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z].Pos;
- c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z-1].Pos;
- b -= a;
- c -= a;
- t = b.crossProduct(c);
- t.normalize();
- normal += t;
-
- count += 2;
- }
-
- if (count != 0)
- {
- normal.normalize();
- }
- else
- {
- normal.set(0.0f, 1.0f, 0.0f);
- }
-
- mb->getVertexBuffer()[x * TerrainData.Size + z].Normal = normal;
- }
- }
- }
-
-
- //! create patches, stuff that needs to be done only once for patches goes here.
- void CTerrainSceneNode::createPatches()
- {
- TerrainData.PatchCount = (TerrainData.Size - 1) / (TerrainData.CalcPatchSize);
-
- if (TerrainData.Patches)
- delete [] TerrainData.Patches;
-
- TerrainData.Patches = new SPatch[TerrainData.PatchCount * TerrainData.PatchCount];
- }
-
-
- //! used to calculate the internal STerrainData structure both at creation and after scaling/position calls.
- void CTerrainSceneNode::calculatePatchData()
- {
- // Reset the Terrains Bounding Box for re-calculation
- TerrainData.BoundingBox.reset(RenderBuffer->getPosition(0));
-
- for (s32 x = 0; x < TerrainData.PatchCount; ++x)
- {
- for (s32 z = 0; z < TerrainData.PatchCount; ++z)
- {
- const s32 index = x * TerrainData.PatchCount + z;
- SPatch& patch = TerrainData.Patches[index];
- patch.CurrentLOD = 0;
-
- const s32 xstart = x*TerrainData.CalcPatchSize;
- const s32 xend = xstart+TerrainData.CalcPatchSize;
- const s32 zstart = z*TerrainData.CalcPatchSize;
- const s32 zend = zstart+TerrainData.CalcPatchSize;
- // For each patch, calculate the bounding box (mins and maxes)
- patch.BoundingBox.reset(RenderBuffer->getPosition(xstart*TerrainData.Size + zstart));
-
- for (s32 xx = xstart; xx <= xend; ++xx)
- for (s32 zz = zstart; zz <= zend; ++zz)
- patch.BoundingBox.addInternalPoint(RenderBuffer->getVertexBuffer()[xx * TerrainData.Size + zz].Pos);
-
- // Reconfigure the bounding box of the terrain as a whole
- TerrainData.BoundingBox.addInternalBox(patch.BoundingBox);
-
- // get center of Patch
- patch.Center = patch.BoundingBox.getCenter();
-
- // Assign Neighbours
- // Top
- if (x > 0)
- patch.Top = &TerrainData.Patches[(x-1) * TerrainData.PatchCount + z];
- else
- patch.Top = 0;
-
- // Bottom
- if (x < TerrainData.PatchCount - 1)
- patch.Bottom = &TerrainData.Patches[(x+1) * TerrainData.PatchCount + z];
- else
- patch.Bottom = 0;
-
- // Left
- if (z > 0)
- patch.Left = &TerrainData.Patches[x * TerrainData.PatchCount + z - 1];
- else
- patch.Left = 0;
-
- // Right
- if (z < TerrainData.PatchCount - 1)
- patch.Right = &TerrainData.Patches[x * TerrainData.PatchCount + z + 1];
- else
- patch.Right = 0;
- }
- }
-
- // get center of Terrain
- TerrainData.Center = TerrainData.BoundingBox.getCenter();
-
- // if the default rotation pivot is still being used, update it.
- if (UseDefaultRotationPivot)
- {
- TerrainData.RotationPivot = TerrainData.Center;
- }
- }
-
-
- //! used to calculate or recalculate the distance thresholds
- void CTerrainSceneNode::calculateDistanceThresholds(bool scalechanged)
- {
- // Only update the LODDistanceThreshold if it's not manually changed
- if (!OverrideDistanceThreshold)
- {
- TerrainData.LODDistanceThreshold.set_used(0);
- // Determine new distance threshold for determining what LOD to draw patches at
- TerrainData.LODDistanceThreshold.reallocate(TerrainData.MaxLOD);
-
- const f64 size = TerrainData.PatchSize * TerrainData.PatchSize *
- TerrainData.Scale.X * TerrainData.Scale.Z;
- for (s32 i=0; i<TerrainData.MaxLOD; ++i)
- {
- TerrainData.LODDistanceThreshold.push_back(size * ((i+1+ i / 2) * (i+1+ i / 2)));
- }
- }
- }
-
-
- void CTerrainSceneNode::setCurrentLODOfPatches(s32 lod)
- {
- const s32 count = TerrainData.PatchCount * TerrainData.PatchCount;
- for (s32 i=0; i< count; ++i)
- TerrainData.Patches[i].CurrentLOD = lod;
- }
-
-
- void CTerrainSceneNode::setCurrentLODOfPatches(const core::array<s32>& lodarray)
- {
- const s32 count = TerrainData.PatchCount * TerrainData.PatchCount;
- for (s32 i=0; i<count; ++i)
- TerrainData.Patches[i].CurrentLOD = lodarray[i];
- }
-
-
- //! Gets the height
- f32 CTerrainSceneNode::getHeight(f32 x, f32 z) const
- {
- if (!Mesh->getMeshBufferCount())
- return 0;
-
- core::matrix4 rotMatrix;
- rotMatrix.setRotationDegrees(TerrainData.Rotation);
- core::vector3df pos(x, 0.0f, z);
- rotMatrix.rotateVect(pos);
- pos -= TerrainData.Position;
- pos /= TerrainData.Scale;
-
- s32 X(core::floor32(pos.X));
- s32 Z(core::floor32(pos.Z));
-
- f32 height = -FLT_MAX;
- if (X >= 0 && X < TerrainData.Size-1 &&
- Z >= 0 && Z < TerrainData.Size-1)
- {
- const video::S3DVertex2TCoords* Vertices = (const video::S3DVertex2TCoords*)Mesh->getMeshBuffer(0)->getVertices();
- const core::vector3df& a = Vertices[X * TerrainData.Size + Z].Pos;
- const core::vector3df& b = Vertices[(X + 1) * TerrainData.Size + Z].Pos;
- const core::vector3df& c = Vertices[X * TerrainData.Size + (Z + 1)].Pos;
- const core::vector3df& d = Vertices[(X + 1) * TerrainData.Size + (Z + 1)].Pos;
-
- // offset from integer position
- const f32 dx = pos.X - X;
- const f32 dz = pos.Z - Z;
-
- if (dx > dz)
- height = a.Y + (d.Y - b.Y)*dz + (b.Y - a.Y)*dx;
- else
- height = a.Y + (d.Y - c.Y)*dx + (c.Y - a.Y)*dz;
-
- height *= TerrainData.Scale.Y;
- height += TerrainData.Position.Y;
- }
-
- return height;
- }
-
-
- //! Writes attributes of the scene node.
- void CTerrainSceneNode::serializeAttributes(io::IAttributes* out,
- io::SAttributeReadWriteOptions* options) const
- {
- ISceneNode::serializeAttributes(out, options);
-
- out->addString("Heightmap", HeightmapFile.c_str());
- out->addFloat("TextureScale1", TCoordScale1);
- out->addFloat("TextureScale2", TCoordScale2);
- out->addInt("SmoothFactor", SmoothFactor);
- }
-
-
- //! Reads attributes of the scene node.
- void CTerrainSceneNode::deserializeAttributes(io::IAttributes* in,
- io::SAttributeReadWriteOptions* options)
- {
- io::path newHeightmap = in->getAttributeAsString("Heightmap");
- f32 tcoordScale1 = in->getAttributeAsFloat("TextureScale1");
- f32 tcoordScale2 = in->getAttributeAsFloat("TextureScale2");
- s32 smoothFactor = in->getAttributeAsInt("SmoothFactor");
-
- // set possible new heightmap
-
- if (newHeightmap.size() != 0 && newHeightmap != HeightmapFile)
- {
- io::IReadFile* file = FileSystem->createAndOpenFile(newHeightmap.c_str());
- if (file)
- {
- loadHeightMap(file, video::SColor(255,255,255,255), smoothFactor);
- file->drop();
- }
- else
- os::Printer::log("could not open heightmap", newHeightmap.c_str());
- }
-
- // set possible new scale
-
- if (core::equals(tcoordScale1, 0.f))
- tcoordScale1 = 1.0f;
-
- if (core::equals(tcoordScale2, 0.f))
- tcoordScale2 = 1.0f;
-
- if (!core::equals(tcoordScale1, TCoordScale1) ||
- !core::equals(tcoordScale2, TCoordScale2))
- {
- scaleTexture(tcoordScale1, tcoordScale2);
- }
-
- ISceneNode::deserializeAttributes(in, options);
- }
-
-
- //! Creates a clone of this scene node and its children.
- ISceneNode* CTerrainSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
- {
- if (!newParent)
- newParent = Parent;
- if (!newManager)
- newManager = SceneManager;
-
- CTerrainSceneNode* nb = new CTerrainSceneNode(
- newParent, newManager, FileSystem, ID,
- 4, ETPS_17, getPosition(), getRotation(), getScale());
-
- nb->cloneMembers(this, newManager);
-
- // instead of cloning the data structures, recreate the terrain.
- // (temporary solution)
-
- // load file
-
- io::IReadFile* file = FileSystem->createAndOpenFile(HeightmapFile.c_str());
- if (file)
- {
- nb->loadHeightMap(file, video::SColor(255,255,255,255), 0);
- file->drop();
- }
-
- // scale textures
-
- nb->scaleTexture(TCoordScale1, TCoordScale2);
-
- // copy materials
-
- for (unsigned int m = 0; m<Mesh->getMeshBufferCount(); ++m)
- {
- if (nb->Mesh->getMeshBufferCount()>m &&
- nb->Mesh->getMeshBuffer(m) &&
- Mesh->getMeshBuffer(m))
- {
- nb->Mesh->getMeshBuffer(m)->getMaterial() =
- Mesh->getMeshBuffer(m)->getMaterial();
- }
- }
-
- nb->RenderBuffer->getMaterial() = RenderBuffer->getMaterial();
-
- // finish
-
- if ( newParent )
- nb->drop();
- return nb;
- }
-
-} // end namespace scene
-} // end namespace irr
-
-#endif // _IRR_COMPILE_WITH_TERRAIN_SCENENODE_
|