// Copyright (C) 2002-2007 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. #ifndef __C_TERRAIN_SCENE_NODE_H__ #define __C_TERRAIN_SCENE_NODE_H__ #include "ITerrainSceneNode.h" #include "SMesh.h" namespace irr { namespace io { class IFileSystem; class IReadFile; } namespace scene { class ITextSceneNode; //! A scene node for displaying terrain using the geo mip map algorithm. class CTerrainSceneNode : public ITerrainSceneNode { public: //! constructor //! \param parent: The node which this node is a child of. Making this node a child of another node, or //! making it a parent of another node is yet untested and most likely does not work properly. //! \param mgr: Pointer to the scene manager. //! \param id: The id of the node //! \param maxLOD: The maximum LOD ( Level of Detail ) for the node. //! \param patchSize: An E_GEOMIPMAP_PATCH_SIZE enumeration defining the size of each patch of the terrain. //! \param position: The absolute position of this node. //! \param rotation: The absolute rotation of this node. ( NOT YET IMPLEMENTED ) //! \param scale: The scale factor for the terrain. If you're using a heightmap of size 128x128 and would like //! your terrain to be 12800x12800 in game units, then use a scale factor of ( core::vector ( 100.0f, 100.0f, 100.0f ). //! If you use a Y scaling factor of 0.0f, then your terrain will be flat. CTerrainSceneNode(ISceneNode* parent, ISceneManager* mgr, io::IFileSystem* fs, s32 id, s32 maxLOD = 4, E_TERRAIN_PATCH_SIZE patchSize = ETPS_17, const core::vector3df& position = core::vector3df(0.0f, 0.0f, 0.0f), const core::vector3df& rotation = core::vector3df(0.0f, 0.0f, 0.0f), const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)); virtual ~CTerrainSceneNode(); //! Initializes the terrain data. Loads the vertices from the heightMapFile. virtual bool loadHeightMap(io::IReadFile* file, video::SColor vertexColor = video::SColor ( 255, 255, 255, 255 ), s32 smoothFactor = 0 ); //! Initializes the terrain data. Loads the vertices from the heightMapFile. virtual bool loadHeightMapRAW(io::IReadFile* file, s32 bitsPerPixel = 16, video::SColor vertexColor = video::SColor ( 255, 255, 255, 255 ), s32 smoothFactor = 0 ); //! Returns the material based on the zero based index i. This scene node only uses //! 1 material. //! \param i: Zero based index i. UNUSED, left in for virtual purposes. //! \return Returns the single material this scene node uses. virtual video::SMaterial& getMaterial ( u32 i ) { return Mesh.getMeshBuffer(i)->getMaterial(); } //! Returns amount of materials used by this scene node ( always 1 ) //! \return Returns current count of materials used by this scene node ( always 1 ) virtual u32 getMaterialCount() const { return Mesh.getMeshBufferCount(); } //! Gets the last scaling factor applied to the scene node. This value only represents the //! last scaling factor presented to the node. For instance, if you make create the node //! with a scale factor of ( 1.0f, 1.0f, 1.0f ) then call setScale ( 50.0f, 5.0f, 50.0f ), //! then make another call to setScale with the values ( 2.0f, 2.0f, 2.0f ), this will return //! core::vector3df ( 2.0f, 2.0f, 2.0f ), although the total scaling of the scene node is //! core::vector3df ( 100.0f, 10.0f, 100.0f ). //! \return Returns the last scaling factor passed to the scene node. virtual const core::vector3df& getScale() const { return TerrainData.Scale; } //! Scales the scene nodes vertices by the vector specified. //! \param scale: Scaling factor to apply to the node. virtual void setScale(const core::vector3df& scale); //! Gets the last rotation factor applied to the scene node. //! \return Returns the last rotation factor applied to the scene node. virtual const core::vector3df& getRotation() const { return TerrainData.Rotation; } //! Rotates the node. This only modifies the relative rotation of the node. //! \param rotation: New rotation of the node in degrees. virtual void setRotation(const core::vector3df& rotation); //! Sets the pivot point for rotation of this node. //! NOTE: The default for the RotationPivot will be the center of the individual tile. virtual void setRotationPivot( const core::vector3df& pivot ); //! Gets the last positioning vector applied to the scene node. //! \return Returns the last position vector applied to the scene node. virtual const core::vector3df& getPosition() const { return TerrainData.Position; } //! Moves the scene nodes vertices by the vector specified. //! \param newpos: Vector specifying how much to move each vertex of the scene node. virtual void setPosition(const core::vector3df& newpos); //! 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. virtual void OnRegisterSceneNode(); //! Render the scene node virtual void render(); //! Return the bounding box of the entire terrain. virtual const core::aabbox3d& getBoundingBox() const; //! Return the bounding box of a patch virtual const core::aabbox3d& getBoundingBox(s32 patchX, s32 patchZ) const; //! Return the number of indices currently used to draw the scene node. virtual u32 getIndexCount() const { return IndicesToRender; } //! Returns the mesh virtual IMesh* getMesh() { return &Mesh; } //! Returns a pointer to the buffer used by the terrain (most users will not need this) virtual IMeshBuffer* getRenderBuffer() { return &RenderBuffer; } //! Gets the meshbuffer data based on a specified Level of Detail. //! \param mb: A reference to an SMeshBufferLightMap object //! \param LOD: The Level Of Detail you want the indices from. virtual void getMeshBufferForLOD(SMeshBufferLightMap& mb, s32 LOD ) const; //! Gets the indices for a specified patch at a specified Level of Detail. //! \param indices: 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 of indices put into the buffer. virtual s32 getIndicesForPatch(core::array& indices, s32 patchX, s32 patchZ, s32 LOD = 0 ); //! Populates an array with the CurrentLOD of each patch. //! \param LODs: A reference to a core::array to hold the values //! \return Returns the number of elements in the array virtual s32 getCurrentLODOfPatches(core::array& LODs) const; //! 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. virtual void setLODOfPatch( s32 patchX, s32 patchZ, s32 LOD ); //! Returns center of terrain. virtual const core::vector3df& getTerrainCenter() const { return TerrainData.Center; } //! Returns center of terrain. virtual f32 getHeight( f32 x, f32 y ) const; //! Sets the movement camera threshold which is used to determine when to recalculate //! indices for the scene node. The default value is 10.0f. virtual void setCameraMovementDelta(f32 delta) { CameraMovementDelta = delta; } //! Sets the rotation camera threshold which is used to determine when to recalculate //! indices for the scene node. The default value is 1.0f. virtual void setCameraRotationDelta(f32 delta) { CameraRotationDelta = delta; } //! Sets whether or not the node should dynamically update it's associated selector when //! the geomipmap data changes. //! param bVal: Boolean value representing whether or not to update selector dynamically. //! NOTE: Temporarily disabled while working out issues with DynamicSelectorUpdate virtual void setDynamicSelectorUpdate(bool bVal ) { DynamicSelectorUpdate = false; } //virtual void setDynamicSelectorUpdate ( bool bVal ) { DynamicSelectorUpdate = bVal; } //! Override the default generation of distance thresholds for determining the LOD a patch //! is rendered at. If any LOD is overridden, then the scene node will no longer apply //! scaling factors to these values. If you override these distances, and then apply //! a scale to the scene node, it is your responsibility to update the new distances to //! work best with your new terrain size. virtual bool overrideLODDistance( s32 LOD, f64 newDistance ); //! Scales the two textures virtual void scaleTexture(f32 scale = 1.0f, f32 scale2 = 0.0f); //! Returns type of the scene node virtual ESCENE_NODE_TYPE getType() const {return ESNT_TERRAIN;} //! Writes attributes of the scene node. virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const; //! Reads attributes of the scene node. virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0); //! Creates a clone of this scene node and its children. virtual ISceneNode* clone(ISceneNode* newParent, ISceneManager* newManager); private: friend class CTerrainTriangleSelector; struct SPatch { SPatch() : CurrentLOD(-1), Top(0), Bottom(0), Right(0), Left(0) { } s32 CurrentLOD; core::aabbox3df BoundingBox; core::vector3df Center; SPatch* Top; SPatch* Bottom; SPatch* Right; SPatch* Left; }; struct STerrainData { STerrainData() : Size(0), PatchSize(0), CalcPatchSize(0), PatchCount(0), MaxLOD(0), BoundingBox(core::aabbox3df( 99999.9f, 99999.9f, 99999.9f, -99999.9f, -99999.9f, -99999.9f)), LODDistanceThreshold(0), Patches(0) { } STerrainData(s32 patchSize, s32 maxLOD, const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale) : Size(0), Position(position), Rotation(rotation), Scale(scale), PatchSize(patchSize), CalcPatchSize(patchSize-1), PatchCount(0), MaxLOD(maxLOD), BoundingBox(core::aabbox3df( 99999.9f, 99999.9f, 99999.9f, -99999.9f, -99999.9f, -99999.9f)), LODDistanceThreshold(0), Patches(0) { } s32 Size; core::vector3df Position; core::vector3df Rotation; core::vector3df RotationPivot; core::vector3df Scale; core::vector3df Center; s32 PatchSize; s32 CalcPatchSize; s32 PatchCount; s32 MaxLOD; core::aabbox3df BoundingBox; f64* LODDistanceThreshold; SPatch* Patches; }; virtual void preRenderLODCalculations(); virtual void preRenderIndicesCalculations(); //! get indices when generating index data for patches at varying levels of detail. u32 getIndex(const s32 PatchX, const s32 PatchZ, const s32 PatchIndex, u32 vX, u32 vZ) const; //! smooth the terrain void smoothTerrain(SMeshBufferLightMap* mb, s32 smoothFactor); //! calculate smooth normals void calculateNormals(SMeshBufferLightMap* mb); //! create patches, stuff that needs to only be done once for patches goes here. void createPatches(); //! calculate the internal STerrainData structure void calculatePatchData(); //! calculate or recalculate the distance thresholds void calculateDistanceThresholds(bool scalechanged = false); //! sets the CurrentLOD of all patches to the specified LOD void setCurrentLODOfPatches(s32 i); //! sets the CurrentLOD of TerrainData patches to the LODs specified in the array void setCurrentLODOfPatches(const core::array& lodarray); //! Apply transformation changes( scale, position, rotation ) void applyTransformation(); STerrainData TerrainData; SMesh Mesh; SMeshBufferLightMap RenderBuffer; u32 VerticesToRender; u32 IndicesToRender; bool DynamicSelectorUpdate; bool OverrideDistanceThreshold; bool UseDefaultRotationPivot; bool ForceRecalculation; core::vector3df OldCameraPosition; core::vector3df OldCameraRotation; f32 CameraMovementDelta; f32 CameraRotationDelta; // needed for (de)serialization f32 TCoordScale1; f32 TCoordScale2; core::stringc HeightmapFile; io::IFileSystem* FileSystem; }; } // end namespace scene } // end namespace irr #endif // __C_TERRAIN_SCENE_NODE_H__