123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "forest/ts/tsForestItemData.h"
- #include "forest/ts/tsForestCellBatch.h"
- #include "core/resourceManager.h"
- #include "ts/tsShapeInstance.h"
- #include "ts/tsLastDetail.h"
- #include "sim/netConnection.h"
- #include "materials/materialManager.h"
- #include "forest/windDeformation.h"
- using namespace Torque;
- IMPLEMENT_CO_DATABLOCK_V1(TSForestItemData);
- ConsoleDocClass( TSForestItemData,
- "@brief Concrete implementation of ForestItemData which loads and renders "
- "dts format shapeFiles.\n\n"
- "@ingroup Forest"
- );
- TSForestItemData::TSForestItemData()
- : mIsClientObject( false ),
- mShapeInstance( NULL )
- {
- }
- TSForestItemData::~TSForestItemData()
- {
- }
- bool TSForestItemData::preload( bool server, String &errorBuffer )
- {
- mIsClientObject = !server;
- if ( !SimDataBlock::preload( server, errorBuffer ) )
- return false;
- return true;
- }
- void TSForestItemData::_updateCollisionDetails()
- {
- mCollisionDetails.clear();
- mLOSDetails.clear();
- mShape->findColDetails( false, &mCollisionDetails, &mLOSDetails );
- }
- bool TSForestItemData::onAdd()
- {
- if ( !Parent::onAdd() )
- return false;
- // Register for the resource change signal.
- ResourceManager::get().getChangedSignal().notify( this, &TSForestItemData::_onResourceChanged );
- return true;
- }
- void TSForestItemData::onRemove()
- {
- // Remove the resource change signal.
- ResourceManager::get().getChangedSignal().remove( this, &TSForestItemData::_onResourceChanged );
- SAFE_DELETE( mShapeInstance );
- Parent::onRemove();
- }
- void TSForestItemData::inspectPostApply()
- {
- Parent::inspectPostApply();
- SAFE_DELETE( mShapeInstance );
- _loadShape();
- }
- void TSForestItemData::_onResourceChanged( const Torque::Path &path )
- {
- if (mShapeAsset.isNull()) return;
- if ( path != Path(mShapeAsset->getShapeFilePath()) )
- return;
-
- SAFE_DELETE( mShapeInstance );
- _loadShape();
- getReloadSignal().trigger();
- }
- void TSForestItemData::_loadShape()
- {
- if (mShapeAsset.isNull()) return;
- _setShape(mShapeAssetId);
- if ( !(bool)mShape )
- return;
- if ( mIsClientObject &&
- !mShape->preloadMaterialList(mShapeAsset->getShapeFilePath()) )
- return;
-
- // Lets add an autobillboard detail if don't have one.
- //_checkLastDetail();
- _updateCollisionDetails();
- }
- TSShapeInstance* TSForestItemData::_getShapeInstance() const
- {
- // Create the shape instance if we haven't already.
- if ( !mShapeInstance && mShape )
- {
- // Create the instance.
- mShapeInstance = new TSShapeInstance( mShape, true );
-
- // So we can make OpCode collision calls.
- mShapeInstance->prepCollision();
- // Get the material features adding the wind effect if
- // we have a positive wind scale and have vertex color
- // data which is used for the weighting.
- FeatureSet features = MATMGR->getDefaultFeatures();
- if ( mWindScale > 0.0f && mShape->getVertexFormat()->hasColor() )
- {
- // We create our own cloned material list to
- // enable the wind effects.
- features.addFeature( MFT_WindEffect );
- mShapeInstance->cloneMaterialList( &features );
- }
- }
- return mShapeInstance;
- }
- void TSForestItemData::_checkLastDetail()
- {
- if (mShapeAsset.isNull()) return;
- const S32 dl = mShape->mSmallestVisibleDL;
- const TSDetail *detail = &mShape->details[dl];
- // TODO: Expose some real parameters to the datablock maybe?
- if ( detail->subShapeNum != -1 )
- {
- mShape->addImposter(mShapeAsset->getShapeFilePath(), 10, 4, 0, 0, 256, 0, 0 );
- // HACK: If i don't do this it crashes!
- while ( mShape->detailCollisionAccelerators.size() < mShape->details.size() )
- mShape->detailCollisionAccelerators.push_back( NULL );
- }
- }
- TSLastDetail* TSForestItemData::getLastDetail() const
- {
- // Gotta call this first of the last detail isn't created!
- if (!_getShapeInstance())
- return NULL;
- const S32 dl = mShape->mSmallestVisibleDL;
- const TSDetail* detail = &mShape->details[dl];
- if ( detail->subShapeNum >= 0 ||
- mShape->billboardDetails.size() <= dl )
- return NULL;
- return mShape->billboardDetails[dl];
- }
- ForestCellBatch* TSForestItemData::allocateBatch() const
- {
- TSLastDetail* lastDetail = getLastDetail();
- if ( !lastDetail )
- return NULL;
- return new TSForestCellBatch( lastDetail );
- }
- bool TSForestItemData::canBillboard( const SceneRenderState *state, const ForestItem &item, F32 distToCamera ) const
- {
- PROFILE_SCOPE( TSForestItemData_canBillboard );
- if ( !mShape )
- return false;
- // Use the shape instance to do the work it normally does.
- TSShapeInstance *shapeInstance = _getShapeInstance();
- const S32 dl = shapeInstance->setDetailFromDistance( state, distToCamera / item.getScale() );
- // This item has a null LOD... lets consider
- // that as being billboarded.
- if ( dl < 0 )
- return true;
- const TSDetail *detail = &mShape->details[dl];
- if ( detail->subShapeNum < 0 && dl < mShape->billboardDetails.size() )
- return true;
- return false;
- }
- bool TSForestItemData::render( TSRenderState *rdata, const ForestItem &item ) const
- {
- PROFILE_SCOPE( TSForestItemData_render );
- // This shouldn't happen normally at runtime, but during
- // development a file change notification on a bad file
- // can cause us to get here without a shape.
- TSShapeInstance *shapeInst = _getShapeInstance();
- if ( !shapeInst )
- return false;
- const F32 scale = item.getScale();
- // Figure out the distance of this item to the camera.
- const SceneRenderState *state = rdata->getSceneState();
- F32 dist = ( item.getPosition() - state->getDiffuseCameraPosition() ).len();
- // TODO: Selecting the lod seems more expensive than
- // it should be... we should look to optimize this.
- if ( shapeInst->setDetailFromDistance( state, dist / scale ) < 0 )
- return false;
- // TSShapeInstance::render() uses the
- // world matrix for the RenderInst.
- MatrixF worldMat = item.getTransform();
- worldMat.scale( scale );
- GFX->setWorldMatrix( worldMat );
- rdata->setMaterialHint( (void*)&item );
- // This isn't documented well, but these calls
- // don't really render... rather they batch the
- // shape to be rendered by the render instance
- // manager later on.
- shapeInst->animate();
- shapeInst->render( *rdata );
- return true;
- }
|