mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 21:26:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			169 lines
		
	
	
	
		
			5.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
	
		
			5.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "chunk.hpp"
 | |
| 
 | |
| #include <OgreSceneNode.h>
 | |
| #include <OgreHardwareBufferManager.h>
 | |
| 
 | |
| #include "quadtreenode.hpp"
 | |
| #include "world.hpp"
 | |
| #include "storage.hpp"
 | |
| 
 | |
| namespace Terrain
 | |
| {
 | |
| 
 | |
|     Chunk::Chunk(QuadTreeNode* node, short lodLevel)
 | |
|         : mNode(node)
 | |
|         , mVertexLod(lodLevel)
 | |
|         , mAdditionalLod(0)
 | |
|     {
 | |
|         mVertexData = OGRE_NEW Ogre::VertexData;
 | |
|         mVertexData->vertexStart = 0;
 | |
| 
 | |
|         // Set the total number of vertices
 | |
|         size_t numVertsOneSide = mNode->getSize() * (ESM::Land::LAND_SIZE-1);
 | |
|         numVertsOneSide /= 1 << lodLevel;
 | |
|         numVertsOneSide += 1;
 | |
|         assert((int)numVertsOneSide == ESM::Land::LAND_SIZE);
 | |
|         mVertexData->vertexCount = numVertsOneSide * numVertsOneSide;
 | |
| 
 | |
|         // Set up the vertex declaration, which specifies the info for each vertex (normals, colors, UVs, etc)
 | |
|         Ogre::VertexDeclaration* vertexDecl = mVertexData->vertexDeclaration;
 | |
| 
 | |
|         Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr();
 | |
|         size_t nextBuffer = 0;
 | |
| 
 | |
|         // Positions
 | |
|         vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
 | |
|         mVertexBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3),
 | |
|                                                 mVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC);
 | |
|         // Normals
 | |
|         vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
 | |
|         mNormalBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3),
 | |
|                                                 mVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC);
 | |
| 
 | |
|         // UV texture coordinates
 | |
|         vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_FLOAT2,
 | |
|                                Ogre::VES_TEXTURE_COORDINATES, 0);
 | |
|         Ogre::HardwareVertexBufferSharedPtr uvBuf = mNode->getTerrain()->getVertexBuffer(numVertsOneSide);
 | |
| 
 | |
|         // Colours
 | |
|         vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
 | |
|         mColourBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR),
 | |
|                                                 mVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC);
 | |
| 
 | |
|         mNode->getTerrain()->getStorage()->fillVertexBuffers(lodLevel, mNode->getSize(), mNode->getCenter(),
 | |
|                                                              mVertexBuffer, mNormalBuffer, mColourBuffer);
 | |
| 
 | |
|         mVertexData->vertexBufferBinding->setBinding(0, mVertexBuffer);
 | |
|         mVertexData->vertexBufferBinding->setBinding(1, mNormalBuffer);
 | |
|         mVertexData->vertexBufferBinding->setBinding(2, uvBuf);
 | |
|         mVertexData->vertexBufferBinding->setBinding(3, mColourBuffer);
 | |
| 
 | |
|         mIndexData = OGRE_NEW Ogre::IndexData();
 | |
|         mIndexData->indexStart = 0;
 | |
|     }
 | |
| 
 | |
| 
 | |
| 
 | |
|     void Chunk::updateIndexBuffer()
 | |
|     {
 | |
|         // Fetch a suitable index buffer (which may be shared)
 | |
|         size_t ourLod = mVertexLod + mAdditionalLod;
 | |
| 
 | |
|         int flags = 0;
 | |
| 
 | |
|         for (int i=0; i<4; ++i)
 | |
|         {
 | |
|             QuadTreeNode* neighbour = mNode->getNeighbour((Direction)i);
 | |
| 
 | |
|             // If the neighbour isn't currently rendering itself,
 | |
|             // go up until we find one. NOTE: We don't need to go down,
 | |
|             // because in that case neighbour's detail would be higher than
 | |
|             // our detail and the neighbour would handle stitching by itself.
 | |
|             while (neighbour && !neighbour->hasChunk())
 | |
|                 neighbour = neighbour->getParent();
 | |
| 
 | |
|             size_t lod = 0;
 | |
|             if (neighbour)
 | |
|                 lod = neighbour->getActualLodLevel();
 | |
| 
 | |
|             if (lod <= ourLod) // We only need to worry about neighbours less detailed than we are -
 | |
|                 lod = 0;         // neighbours with more detail will do the stitching themselves
 | |
| 
 | |
|             // Use 4 bits for each LOD delta
 | |
|             if (lod > 0)
 | |
|             {
 | |
|                 assert (lod - ourLod < (1 << 4));
 | |
|                 flags |= int(lod - ourLod) << (4*i);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         flags |= ((int)mAdditionalLod) << (4*4);
 | |
| 
 | |
|         size_t numIndices;
 | |
|         mIndexBuffer = mNode->getTerrain()->getIndexBuffer(flags, numIndices);
 | |
|         mIndexData->indexCount = numIndices;
 | |
|         mIndexData->indexBuffer = mIndexBuffer;
 | |
|     }
 | |
| 
 | |
|     Chunk::~Chunk()
 | |
|     {
 | |
|         OGRE_DELETE mVertexData;
 | |
|         OGRE_DELETE mIndexData;
 | |
|     }
 | |
| 
 | |
|     void Chunk::setMaterial(const Ogre::MaterialPtr &material)
 | |
|     {
 | |
|         mMaterial = material;
 | |
|     }
 | |
| 
 | |
|     const Ogre::AxisAlignedBox& Chunk::getBoundingBox(void) const
 | |
|     {
 | |
|         return mNode->getBoundingBox();
 | |
|     }
 | |
| 
 | |
|     Ogre::Real Chunk::getBoundingRadius(void) const
 | |
|     {
 | |
|         return mNode->getBoundingBox().getHalfSize().length();
 | |
|     }
 | |
| 
 | |
|     void Chunk::_updateRenderQueue(Ogre::RenderQueue* queue)
 | |
|     {
 | |
|         queue->addRenderable(this, mRenderQueueID);
 | |
|     }
 | |
| 
 | |
|     void Chunk::visitRenderables(Ogre::Renderable::Visitor* visitor,
 | |
|         bool debugRenderables)
 | |
|     {
 | |
|         visitor->visit(this, 0, false);
 | |
|     }
 | |
| 
 | |
|     const Ogre::MaterialPtr& Chunk::getMaterial(void) const
 | |
|     {
 | |
|         return mMaterial;
 | |
|     }
 | |
| 
 | |
|     void Chunk::getRenderOperation(Ogre::RenderOperation& op)
 | |
|     {
 | |
|         assert (!mIndexBuffer.isNull() && "Trying to render, but no index buffer set!");
 | |
|         op.useIndexes = true;
 | |
|         op.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
 | |
|         op.vertexData = mVertexData;
 | |
|         op.indexData = mIndexData;
 | |
|     }
 | |
| 
 | |
|     void Chunk::getWorldTransforms(Ogre::Matrix4* xform) const
 | |
|     {
 | |
|         *xform = getParentSceneNode()->_getFullTransform();
 | |
|     }
 | |
| 
 | |
|     Ogre::Real Chunk::getSquaredViewDepth(const Ogre::Camera* cam) const
 | |
|     {
 | |
|         return getParentSceneNode()->getSquaredViewDepth(cam);
 | |
|     }
 | |
| 
 | |
|     const Ogre::LightList& Chunk::getLights(void) const
 | |
|     {
 | |
|         return queryLights();
 | |
|     }
 | |
| 
 | |
| }
 |