terrains can now use VBOs, but index and vertex data will need to be updated independently for any speed gain

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@1269 dfc29bdd-3216-0410-991c-e03cc46cb475
master
lukeph 2008-02-27 14:07:27 +00:00
parent ee6f54877e
commit 580c3f5365
10 changed files with 100 additions and 57 deletions

View File

@ -189,7 +189,7 @@ namespace scene
}
//! flags the mesh as changed, reloads hardware buffers
virtual void setDirty() {ChangedID++;}
virtual void setDirty(E_BUFFER_TYPE Buffer=EBT_VERTEX_AND_INDEX) {ChangedID++;}
virtual const u32 getChangedID() const {return ChangedID;}

View File

@ -137,7 +137,10 @@ namespace scene
virtual void setHardwareMappingHint( E_HARDWARE_MAPPING NewMappingHint ) = 0;
//! flags the meshbuffer as changed, reloads hardware buffers
virtual void setDirty() = 0;
virtual void setDirty(E_BUFFER_TYPE Buffer=EBT_VERTEX_AND_INDEX) = 0;
virtual const u32 getChangedID() const = 0;

View File

@ -3,9 +3,9 @@
// For conditions of distribution and use, see copyright notice in irrlicht.h
// The code for the TerrainSceneNode is based on the terrain renderer by Soconne and
// the GeoMipMapSceneNode developed by Spintz. They made their code available for Irrlicht
// the GeoMipMapSceneNode developed by Spintz. They made their code available for Irrlicht
// and allowed it to be distributed under this licence. I only modified some parts.
// A lot of thanks go to them.
// A lot of thanks go to them.
#ifndef __I_TERRAIN_SCENE_NODE_H__
#define __I_TERRAIN_SCENE_NODE_H__
@ -22,14 +22,14 @@ namespace scene
class IMesh;
//! A scene node for displaying terrain using the geo mip map algorithm.
/** The code for the TerrainSceneNode is based on the Terrain renderer by Soconne and
* the GeoMipMapSceneNode developed by Spintz. They made their code available for Irrlicht
/** The code for the TerrainSceneNode is based on the Terrain renderer by Soconne and
* the GeoMipMapSceneNode developed by Spintz. They made their code available for Irrlicht
* and allowed it to be distributed under this licence. I only modified some parts.
* A lot of thanks go to them.
* A lot of thanks go to them.
*
* This scene node is capable of very quickly loading
* terrains and updating the indices at runtime to enable viewing very large terrains. It uses a
* CLOD ( Continuous Level of Detail ) algorithm which updates the indices for each patch based on
* CLOD ( Continuous Level of Detail ) algorithm which updates the indices for each patch based on
* a LOD ( Level of Detail ) which is determined based on a patch's distance from the camera.
*
* The Patch Size of the terrain must always be a size of ( 2^N+1, i.e. 8+1(9), 16+1(17), etc. ).
@ -37,7 +37,7 @@ namespace scene
* of the indices to draw all the triangles at the max detail for a patch. As each LOD goes up by 1
* the step taken, in generating indices increases by - 2^LOD, so for LOD 1, the step taken is 2, for
* LOD 2, the step taken is 4, LOD 3 - 8, etc. The step can be no larger than the size of the patch,
* so having a LOD of 8, with a patch size of 17, is asking the algoritm to generate indices every
* so having a LOD of 8, with a patch size of 17, is asking the algoritm to generate indices every
* 2^8 ( 256 ) vertices, which is not possible with a patch size of 17. The maximum LOD for a patch
* size of 17 is 2^4 ( 16 ). So, with a MaxLOD of 5, you'll have LOD 0 ( full detail ), LOD 1 ( every
* 2 vertices ), LOD 2 ( every 4 vertices ), LOD 3 ( every 8 vertices ) and LOD 4 ( every 16 vertices ).
@ -47,10 +47,10 @@ namespace scene
public:
//! constructor
ITerrainSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
ITerrainSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
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) )
const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f) )
: ISceneNode (parent, mgr, id, position, rotation, scale) {}
//! destructor
@ -66,22 +66,27 @@ namespace scene
virtual u32 getIndexCount() const = 0;
//! Returns pointer to the mesh
virtual IMesh* getMesh() = 0;
virtual IMesh* getMesh() = 0;
//! Returns a pointer to the buffer used by the terrain (most users will not need this)
virtual IMeshBuffer* getRenderBuffer() = 0;
//! 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. */
virtual void getMeshBufferForLOD(SMeshBufferLightMap& mb, s32 LOD) const = 0;
//! Gets the indices for a specified patch at a specified Level of Detail.
//! 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
\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. */
virtual s32 getIndicesForPatch(core::array<u32>& indices,
virtual s32 getIndicesForPatch(core::array<u32>& indices,
s32 patchX, s32 patchZ, s32 LOD = 0 ) = 0;
//! Populates an array with the CurrentLOD of each patch.
@ -124,10 +129,10 @@ namespace scene
virtual bool overrideLODDistance(s32 LOD, f64 newDistance) = 0;
//! Scales the base texture, similar to makePlanarTextureMapping.
/** \param scale: The scaling amount. Values above 1.0 increase the number of time the
/** \param scale: The scaling amount. Values above 1.0 increase the number of time the
texture is drawn on the terrain. Values below 0 will decrease the number of times the
texture is drawn on the terrain. Using negative values will flip the texture, as
well as still scaling it.
well as still scaling it.
\param scale2: If set to 0 (default value), this will set the second texture coordinate set
to the same values as in the first set. If this is another value than zero, it will scale
the second texture coordinate set by this value. */

View File

@ -142,7 +142,7 @@ namespace scene
//! flags the mesh as changed, reloads hardware buffers
virtual void setDirty() {ChangedID++;}
virtual void setDirty(E_BUFFER_TYPE Buffer=EBT_VERTEX_AND_INDEX) {ChangedID++;}
virtual const u32 getChangedID() const {return ChangedID;}

View File

@ -282,7 +282,7 @@ struct SSkinMeshBuffer : public IMeshBuffer
//! flags the mesh as changed, reloads hardware buffers
virtual void setDirty() {ChangedID++;}
virtual void setDirty(E_BUFFER_TYPE Buffer=EBT_VERTEX_AND_INDEX) {ChangedID++;}
virtual const u32 getChangedID() const {return ChangedID;}

View File

@ -572,6 +572,10 @@ bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
extGlGenBuffers(1, &HWBuffer->vbo_verticesID);
if (!HWBuffer->vbo_verticesID) return false;
newBuffer=true;
}
else if (HWBuffer->vbo_verticesSize < vertexCount*vertexSize)
{
newBuffer=true;
}
extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID );
@ -580,7 +584,9 @@ bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
if (!newBuffer)
extGlBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * vertexSize, buffer.const_pointer());
else
{
{
HWBuffer->vbo_verticesSize = vertexCount*vertexSize;
if (HWBuffer->Mapped==scene::EHM_STATIC)
extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_STATIC_DRAW);
else if (HWBuffer->Mapped==scene::EHM_DYNAMIC)
@ -623,7 +629,10 @@ bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
if (!HWBuffer->vbo_indicesID) return false;
newBuffer=true;
}
else if (HWBuffer->vbo_indicesSize < indexCount*indexSize)
{
newBuffer=true;
}
extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID);
@ -631,7 +640,9 @@ bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
if (!newBuffer)
extGlBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices);
else
{
{
HWBuffer->vbo_indicesSize = indexCount*indexSize;
if (HWBuffer->Mapped==scene::EHM_STATIC)
extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW);
else if (HWBuffer->Mapped==scene::EHM_DYNAMIC)
@ -688,7 +699,9 @@ COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::I
HWBuffer->Mapped=mb->getHardwareMappingHint();
HWBuffer->LastUsed=0;
HWBuffer->vbo_verticesID=0;
HWBuffer->vbo_indicesID=0;
HWBuffer->vbo_indicesID=0;
HWBuffer->vbo_verticesSize=0;
HWBuffer->vbo_indicesSize=0;
if (!updateHardwareBuffer(HWBuffer))
{

View File

@ -112,7 +112,11 @@ namespace video
SHWBufferLink_opengl(const scene::IMeshBuffer *_MeshBuffer): SHWBufferLink(_MeshBuffer), vbo_verticesID(0),vbo_indicesID(0){}
GLuint vbo_verticesID; //tmp
GLuint vbo_indicesID; //tmp
GLuint vbo_indicesID; //tmp
GLuint vbo_verticesSize; //tmp
GLuint vbo_indicesSize; //tmp
};
bool updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer);

View File

@ -251,7 +251,13 @@ void COpenGLTexture::copyTexture(bool newTexture)
{
glBindTexture(GL_TEXTURE_2D, TextureName);
if (Driver->testGLError())
os::Printer::log("Could not bind Texture", ELL_ERROR);
os::Printer::log("Could not bind Texture", ELL_ERROR);
if (!Image)
{
os::Printer::log("No image for OpenGL texture to upload", ELL_ERROR);
return;
}
switch (Image->getColorFormat())
{

View File

@ -188,6 +188,8 @@ namespace scene
// Pre-allocate memory for indices
RenderBuffer.Indices.set_used( TerrainData.PatchCount * TerrainData.PatchCount *
TerrainData.CalcPatchSize * TerrainData.CalcPatchSize * 6 );
RenderBuffer.setDirty();
const u32 endTime = os::Timer::getRealTime();
@ -393,7 +395,10 @@ namespace scene
}
calculateDistanceThresholds( true );
calculatePatchData();
calculatePatchData();
RenderBuffer.setDirty(EBT_VERTEX);
}
//! Updates the scene nodes indices if the camera has moved or rotated by a certain
@ -520,7 +525,11 @@ namespace scene
}
}
}
}
}
RenderBuffer.Indices.set_used(IndicesToRender);
RenderBuffer.setDirty(EBT_INDEX);
if ( DynamicSelectorUpdate && TriangleSelector )
{
@ -544,13 +553,10 @@ namespace scene
core::matrix4 identity;
driver->setTransform (video::ETS_WORLD, identity);
driver->setMaterial(Mesh.getMeshBuffer(0)->getMaterial());
driver->setMaterial(Mesh.getMeshBuffer(0)->getMaterial());
// For use with geomorphing
driver->drawVertexPrimitiveList(
RenderBuffer.getVertices(), RenderBuffer.getVertexCount(),
RenderBuffer.getIndices(), IndicesToRender / 3,
video::EVT_2TCOORDS, EPT_TRIANGLES);
// For use with geomorphing
driver->drawMeshBuffer(&RenderBuffer);
// for debug purposes only:
if (DebugDataVisible)
@ -817,7 +823,9 @@ namespace scene
}
xval += resBySize;
x2val += res2BySize;
}
}
RenderBuffer.setDirty(EBT_VERTEX);
}
//! used to get the indices when generating index data for patches at varying levels of detail.
@ -1206,7 +1214,7 @@ namespace scene
{
loadHeightMap(file, video::SColor(255,255,255,255), 0);
file->drop();
}
}
else
os::Printer::log("could not open heightmap", newHeightmap.c_str());
}
@ -1242,7 +1250,7 @@ namespace scene
4, ETPS_17, getPosition(), getRotation(), getScale());
nb->cloneMembers(this, newManager);
// instead of cloning the data structures, recreate the terrain.
// (temporary solution)
@ -1253,7 +1261,7 @@ namespace scene
{
nb->loadHeightMap(file, video::SColor(255,255,255,255), 0);
file->drop();
}
}
// scale textures

View File

@ -3,8 +3,8 @@
// 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.
// 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__
@ -39,7 +39,7 @@ namespace scene
//! \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,
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),
@ -48,7 +48,7 @@ namespace scene
virtual ~CTerrainSceneNode();
//! Initializes the terrain data. Loads the vertices from the heightMapFile.
virtual bool loadHeightMap(io::IReadFile* file,
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.
@ -59,8 +59,8 @@ namespace scene
//! 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 )
{
virtual video::SMaterial& getMaterial ( u32 i )
{
return Mesh.getMeshBuffer(i)->getMaterial();
}
@ -68,19 +68,19 @@ namespace scene
//! \return Returns current count of materials used by this scene node ( always 1 )
virtual u32 getMaterialCount() const
{
return Mesh.getMeshBufferCount();
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
//! 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;
return TerrainData.Scale;
}
//! Scales the scene nodes vertices by the vector specified.
@ -89,7 +89,7 @@ namespace scene
//! 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
virtual const core::vector3df& getRotation() const
{
return TerrainData.Rotation;
}
@ -102,7 +102,7 @@ namespace scene
//! 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.
//! 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
{
@ -114,7 +114,7 @@ namespace scene
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
//! 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.
@ -133,18 +133,22 @@ namespace scene
virtual u32 getIndexCount() const { return IndicesToRender; }
//! Returns the mesh
virtual IMesh* getMesh() { return &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.
//! 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
//! \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.
@ -173,7 +177,7 @@ namespace scene
//! 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)
virtual void setCameraMovementDelta(f32 delta)
{
CameraMovementDelta = delta;
}
@ -280,7 +284,7 @@ namespace scene
//! smooth the terrain
void smoothTerrain(SMeshBufferLightMap* mb, s32 smoothFactor);
//! calculate smooth normals
//! calculate smooth normals
void calculateNormals(SMeshBufferLightMap* mb);
//! create patches, stuff that needs to only be done once for patches goes here.