⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ogreiplrenderable.cpp

📁 使用stl技术,(还没看,是听说的)
💻 CPP
字号:
/***************************************************************************
  OgreIPLRenderable.cpp 

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

***************************************************************************/

#include "OgreIPLRenderable.h"

#include "OgreIPLPrerequisites.h"
#include "OgreIPLOptions.h"
#include "OgreIPLIndexBuffer.h"
#include "OgreIPLPage.h"
#include "OgreIPLData2D.h"

#include <OgreSceneNode.h>
#include <OgreStringConverter.h>
#include <OgreRenderOperation.h>
#include <OgreCamera.h>
#include <OgreRoot.h>
#include <OgreMath.h>
#include <OgreHardwareBufferManager.h>
#include <OgreHardwareVertexBuffer.h>
#include <OgreHardwareIndexBuffer.h>

namespace Ogre
{
//-----------------------------------------------------------------------
int IPLRenderable::mRenderedTris = 0;
String IPLRenderable::mType = "IPLRenderable";

//-----------------------------------------------------------------------
IPLRenderable::IPLRenderable( IPLTile* tile, const int x, const int z )
{
	mTile		 = tile;
	mName		 = "Patch." + StringConverter::toString( x ) + "." + StringConverter::toString( z );
	mRenderLevel = 0;
	mLOD		 = IPLOptions::getSingleton( ).mPatchLOD;
	mMaterialLODIndex = 0;
	mSize		 = 1 << mLOD;
	mOffsetX	 = x * mSize;
	mOffsetZ	 = z * mSize;
	// start ID at 0; page should start at 1 which will force an update
	mID			 = 0;

	// attach a new scene node to the tile scene node
	SceneNode* patchNode = mTile->getTileNode( )->createChildSceneNode( );

	// set the new node position relative to the tile node position
	const Vector3 scale	= IPLOptions::getSingleton( ).scale;
	patchNode->setPosition( mOffsetX * scale.x, 0, mOffsetZ * scale.z );
	patchNode->attachObject( this );

	// initialize the vertex buffer only once
	_buildVertexBuffer( );
	// force init so that the patch has a bounding box and will get triggered when visible
	_init( );
}

//-----------------------------------------------------------------------
IPLRenderable::~IPLRenderable( void )
{
	release( );
}

//-----------------------------------------------------------------------
void IPLRenderable::release( void )
{
	if ( mRend.indexData != 0 )
	{
		mRend.indexData = 0;
	}

	if ( mRend.vertexData != 0 )
	{
		delete mRend.vertexData;
		mRend.vertexData = 0;
	}
}

//-----------------------------------------------------------------------
const String& IPLRenderable::getName( void ) const
{
	return mName;
}

//-----------------------------------------------------------------------
const String& IPLRenderable::getMovableType( void ) const
{
	return mType;
}

//-----------------------------------------------------------------------
const AxisAlignedBox& IPLRenderable::getBoundingBox( void ) const
{
	return mPatchAABB;
}

//-----------------------------------------------------------------------
void IPLRenderable::_notifyCurrentCamera( Camera* cam )
{

	// Material LOD
	if ( getMaterial()->getNumLodLevels() > 1 )
	{
		mMaterialLODIndex = getMaterial()->getLodIndexSquaredDepth( getSquaredViewDepth( cam ) );
	}

	// check to see if within radius visibility
	// use distance from camera to renderable centre position < radius
	float viewRatio = getSquaredViewDepth( cam ) / IPLOptions::getSingleton( ).visibilityRadiusSquared;

	// don't let view ratio get to large or it will screw up the visibility level calculation
	if ( viewRatio > 1.1f )
	{
		viewRatio = 1.1f;
	}

	// renderable is only visible if view ratio is less than 1 meaning its in the view radius
	setVisible( viewRatio < 1.0f );
	// LOD decreases as renderable gets closer to edge of view radius which means render Level increases

	// partition the chunk data build process
	// start building hopefully just before renderable comes into view
	if ( viewRatio < 1.1f )
	{
		// check to see if the patch needs to be rebuilt because the page changed
		// only do a rebuild if the last rebuild is complete
		if ( ( mBuildStep < 1 ) && ( mID != mTile->getPage( )->getID( ) ) )
		{
			_init( );
			// adjust build step count based on distance from the camera
			// the farther away the patch is when it first comes into view the longer it takes to build
			mBuildStep = 2 + viewRatio * 2;
		};

		if ( mBuildStep > 0 )
		{
			mBuildStep--;
			// since vertex data not ready then don't make renderable visible
			setVisible( false );
			switch ( mBuildStep ) 
			{
			case 0:
				mPatchAABB.setExtents( 0, mMin, 0, ( Real )( mSize * IPLOptions::getSingleton( ).scale.x ), mMax, ( Real )( mSize * IPLOptions::getSingleton( ).scale.z ) );
				mParentNode->needUpdate( );
				mRend.indexData = IPLIndexBuffer::getSingleton( ).getIndexData( this );
				break;

			case 1:
				_buildVertexData( );
				break;
			}
		}
	}
}

//-----------------------------------------------------------------------
void IPLRenderable::_updateRenderQueue( RenderQueue* queue )
{
	queue->addRenderable( this );
}

//-----------------------------------------------------------------------
Technique* IPLRenderable::getTechnique(void) const
{
	return getMaterial( )->getBestTechnique(mMaterialLODIndex);
}

//-----------------------------------------------------------------------
Real IPLRenderable::getBoundingRadius( void ) const
{
	return 0; /* not needed */
}

//-----------------------------------------------------------------------
void IPLRenderable::getRenderOperation( RenderOperation& rend )
{
	rend = mRend;
}

//-----------------------------------------------------------------------
Material* IPLRenderable::getMaterial( void ) const
{
	return mTile->getPage( )->getTexture( )->getMaterial( );
}

//-----------------------------------------------------------------------
void IPLRenderable::getWorldTransforms( Matrix4* xform ) const
{
	*xform = mParentNode->_getFullTransform( );
}

//-----------------------------------------------------------------------
const Quaternion& IPLRenderable::getWorldOrientation( void ) const
{
	return mParentNode->_getDerivedOrientation( );
}

//-----------------------------------------------------------------------
const Vector3& IPLRenderable::getWorldPosition( void ) const
{
	return mParentNode->_getDerivedPosition( );
}

//-----------------------------------------------------------------------
Real IPLRenderable::getSquaredViewDepth( const Camera* cam ) const
{
	//	return mParentNode->getSquaredViewDepth( cam );
	Vector3 diff = cam->getDerivedPosition( ) - mParentNode->getWorldPosition( );
	return ( diff.x * diff.x + diff.z * diff.z );
}

//-----------------------------------------------------------------------
const LightList& IPLRenderable::getLights( void ) const
{
	return mParentNode->getLights( );
}

//-----------------------------------------------------------------------
SceneDetailLevel IPLRenderable::getRenderDetail( void )
{
	return SDL_SOLID;
}

//-----------------------------------------------------------------------
int IPLRenderable::getRenderLevel( void ) const
{
	return mRenderLevel;
}

//-----------------------------------------------------------------------
int IPLRenderable::getRenderSize( void ) const
{
	return mSize;
}

//-----------------------------------------------------------------------
Real IPLRenderable::getViewDepth( const Camera* cam ) const
{
	Vector3 diff = cam->getDerivedPosition( ) - mParentNode->getWorldPosition( );
	return sqrt( diff.x * diff.x + diff.z * diff.z );
}

//-----------------------------------------------------------------------
void  IPLRenderable::_init( void )
{
	// new build required
	mBuildStep = -1;

	const Vector3 scale	= IPLOptions::getSingleton( ).scale;
	mPatchAABB.setExtents( 0, 0, 0, ( Real )( mSize * scale.x ), 100 * scale.y, ( Real )( mSize * scale.z ) );
	mParentNode->needUpdate( );
}

//-----------------------------------------------------------------------
void IPLRenderable::_buildVertexBuffer( void )
{
	mRend.vertexData = new VertexData( );
	mRend.vertexData->vertexStart = 0;
	mRend.vertexData->vertexCount = ( mSize + 1 ) * ( mSize + 1 ); 

	// Vertex declaration
	VertexDeclaration* decl = mRend.vertexData->vertexDeclaration;
	VertexBufferBinding* binding = binding = mRend.vertexData->vertexBufferBinding;

	size_t offset = 0;

	decl->addElement( POSITION_BINDING, 0, VET_FLOAT3, VES_POSITION, 0 );
	offset += VertexElement::getTypeSize( VET_FLOAT3 );

	// Normal 
	decl->addElement( POSITION_BINDING, offset, VET_FLOAT3, VES_NORMAL,0 );
	offset += VertexElement::getTypeSize( VET_FLOAT3 );

	// texture coordinate sets
	decl->addElement( POSITION_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0 );
	offset += VertexElement::getTypeSize( VET_FLOAT2 );
	decl->addElement( POSITION_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 1 );

	// Vertex buffer #1: position
	HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton( ).createVertexBuffer(
			decl->getVertexSize( POSITION_BINDING ), 
			mRend.vertexData->vertexCount,
			HardwareBuffer::HBU_STATIC_WRITE_ONLY, false );

	binding->setBinding( POSITION_BINDING, vbuf );

	//No need to set the indexData since it is shared from LandScapeIndexBuffer class
	mRend.operationType = RenderOperation::OT_TRIANGLE_STRIP;
	mRend.useIndexes = true;
}

//-----------------------------------------------------------------------
void IPLRenderable::_buildVertexData( void )
{
	struct UVSplat 
	{
		float startU;
		float startV;
		float endU;
		float endV;
	};

	static UVSplat splatUVTable[ ] = 
	{
		//// bottom left
		{0, 0, 1, 1},
		//{0, 1, 1, 0},
		//{1, 0, 0, 1},
		//{1, 1, 0, 0},

		//{0, 0, 0.5, 0.5},
		//{0, 0.5, 0.5, 0},
		//{0.5, 0, 0, 0.5},
		//{0.5, 0.5, 0, 0},

		//// bottom right
		//{0.5, 0.0, 1.0, 0.5},
		//{1.0, 0.0, 0.5, 0.5},
		//{0.5, 0.5, 1.00, 0.0},
		//{1.0, 0.5, 0.5, 0.0},

		//// top left
		//{0.0, 1.0, 0.5, 0.5},
		//{0.5, 0.5, 0.0, 1.0},
		//{0.0, 0.5, 0.5, 1.0},
		//{0.5, 1.0, 0.0, 0.5},

		//// top right
		//{0.5, 0.5, 1.0, 1.0},
		//{1.0, 1.0, 0.5, 0.5},
		//{0.5, 1.0, 1.0, 0.5},
		//{1.0, 0.5, 0.5, 1.0},

	};

	VertexBufferBinding* binding = mRend.vertexData->vertexBufferBinding; 

	//calculate min and max heights;
	mMin = 256000, mMax = 0;
	// randomly pick texture coordinates for splat
	// currently disabled
	int splatIndex = 0;//rand()%16;
	float baseSplatU = splatUVTable[ splatIndex ].startU;
	float baseSplatV = splatUVTable[ splatIndex ].startV;
	float splat_dU = splatUVTable[ splatIndex ].endU - baseSplatU;
	float splat_dV = splatUVTable[ splatIndex ].endV - baseSplatV;

	const int startx = mTile->getOffsetX( ) + mOffsetX;
	const int startz = mTile->getOffsetZ( )+ mOffsetZ;
	const int endx = startx + mSize;
	const int endz = startz + mSize;
	const Real Aux1 = IPLOptions::getSingleton( ).PageSize - 1;

	// This allow to reuse the variables in the loop
	Real height, baseTex_V, splatTex_V;

	Vector3 norm;

	// Lock the Vertices
	HardwareVertexBufferSharedPtr vVertices = binding->getBuffer( POSITION_BINDING );
	Real *pVertices = static_cast<Real*>( vVertices->lock( HardwareBuffer::HBL_DISCARD ) );

	IPLData2D* heightData = mTile->getPage( )->getHeightData( );
	const Vector3 scale	= IPLOptions::getSingleton( ).scale;
	const float detailRepeat = IPLOptions::getSingleton( ).mPatchDetailRepeat;

	for ( int k = startz; k <= endz; k++ )
	{
		baseTex_V = ( ( Real )k ) / Aux1;
		splatTex_V = ( baseSplatV + splat_dV * ( ( Real )k - startz ) / mSize ) * detailRepeat;
		for ( int i = startx; i <= endx; i++ )
		{
			height = heightData->getHeight( i, k ) * scale.y;
			// vertices are relative to the scene node
			*pVertices++ = ( Real )( ( i - startx ) * scale.x );	//X
			*pVertices++ = height;									//Y
			*pVertices++ = ( Real )( ( k - startz ) * scale.z );	//Z

			// place the normal vector in the buffer
			heightData->getNormalAt( i, k, &norm );
			*pVertices++ = norm.x;
			*pVertices++ = norm.y;
			*pVertices++ = norm.z;

			// place the first texture coordinate in the buffer
			*pVertices++ = ( ( Real )i ) / Aux1;	
			*pVertices++ = baseTex_V;

			// place the splat texture coordinate in the buffer
			*pVertices++ = ( baseSplatU + splat_dU * ( ( Real )i - startx ) / mSize ) * detailRepeat;	
			*pVertices++ = splatTex_V; 

			if ( height < mMin )
			{
				mMin = ( Real )height;
			}
			if ( height > mMax )
			{
				mMax = ( Real )height;
			}
		}
	}

	// Unlock the buffers
	vVertices->unlock( );

	// buffer is up to date with page setting
	mID = mTile->getPage( )->getID( );
}

} //namespace

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -