tsForestItemData.cpp
Engine/source/forest/ts/tsForestItemData.cpp
Public Functions
ConsoleDocClass(TSForestItemData , "@brief Concrete implementation of <a href="/coding/class/classforestitemdata/">ForestItemData</a> which loads and renders " "dts format <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shapeFiles.\n\n</a>" "@ingroup <a href="/coding/class/classforest/">Forest</a>" )
Detailed Description
Public Functions
ConsoleDocClass(TSForestItemData , "@brief Concrete implementation of <a href="/coding/class/classforestitemdata/">ForestItemData</a> which loads and renders " "dts format <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shapeFiles.\n\n</a>" "@ingroup <a href="/coding/class/classforest/">Forest</a>" )
IMPLEMENT_CO_DATABLOCK_V1(TSForestItemData )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "forest/ts/tsForestItemData.h" 26 27#include "forest/ts/tsForestCellBatch.h" 28#include "core/resourceManager.h" 29#include "ts/tsShapeInstance.h" 30#include "ts/tsLastDetail.h" 31#include "sim/netConnection.h" 32#include "materials/materialManager.h" 33#include "forest/windDeformation.h" 34 35using namespace Torque; 36 37IMPLEMENT_CO_DATABLOCK_V1(TSForestItemData); 38 39ConsoleDocClass( TSForestItemData, 40 "@brief Concrete implementation of ForestItemData which loads and renders " 41 "dts format shapeFiles.\n\n" 42 "@ingroup Forest" 43); 44 45TSForestItemData::TSForestItemData() 46 : mIsClientObject( false ), 47 mShapeInstance( NULL ) 48{ 49} 50 51TSForestItemData::~TSForestItemData() 52{ 53} 54 55bool TSForestItemData::preload( bool server, String &errorBuffer ) 56{ 57 mIsClientObject = !server; 58 59 if ( !SimDataBlock::preload( server, errorBuffer ) ) 60 return false; 61 62 return true; 63} 64 65void TSForestItemData::_updateCollisionDetails() 66{ 67 mCollisionDetails.clear(); 68 mLOSDetails.clear(); 69 mShape->findColDetails( false, &mCollisionDetails, &mLOSDetails ); 70} 71 72bool TSForestItemData::onAdd() 73{ 74 if ( !Parent::onAdd() ) 75 return false; 76 77 // Register for the resource change signal. 78 ResourceManager::get().getChangedSignal().notify( this, &TSForestItemData::_onResourceChanged ); 79 80 return true; 81} 82 83void TSForestItemData::onRemove() 84{ 85 // Remove the resource change signal. 86 ResourceManager::get().getChangedSignal().remove( this, &TSForestItemData::_onResourceChanged ); 87 88 SAFE_DELETE( mShapeInstance ); 89 90 Parent::onRemove(); 91} 92 93void TSForestItemData::inspectPostApply() 94{ 95 Parent::inspectPostApply(); 96 97 SAFE_DELETE( mShapeInstance ); 98 _loadShape(); 99} 100 101void TSForestItemData::_onResourceChanged( const Torque::Path &path ) 102{ 103 if ( path != Path( mShapeFile ) ) 104 return; 105 106 SAFE_DELETE( mShapeInstance ); 107 _loadShape(); 108 109 getReloadSignal().trigger(); 110} 111 112void TSForestItemData::_loadShape() 113{ 114 mShape = ResourceManager::get().load(mShapeFile); 115 if ( !(bool)mShape ) 116 return; 117 118 if ( mIsClientObject && 119 !mShape->preloadMaterialList( mShapeFile ) ) 120 return; 121 122 // Lets add an autobillboard detail if don't have one. 123 //_checkLastDetail(); 124 125 _updateCollisionDetails(); 126} 127 128TSShapeInstance* TSForestItemData::_getShapeInstance() const 129{ 130 // Create the shape instance if we haven't already. 131 if ( !mShapeInstance && mShape ) 132 { 133 // Create the instance. 134 mShapeInstance = new TSShapeInstance( mShape, true ); 135 136 // So we can make OpCode collision calls. 137 mShapeInstance->prepCollision(); 138 139 // Get the material features adding the wind effect if 140 // we have a positive wind scale and have vertex color 141 // data which is used for the weighting. 142 FeatureSet features = MATMGR->getDefaultFeatures(); 143 if ( mWindScale > 0.0f && mShape->getVertexFormat()->hasColor() ) 144 { 145 // We create our own cloned material list to 146 // enable the wind effects. 147 features.addFeature( MFT_WindEffect ); 148 mShapeInstance->cloneMaterialList( &features ); 149 } 150 } 151 152 return mShapeInstance; 153} 154 155void TSForestItemData::_checkLastDetail() 156{ 157 const S32 dl = mShape->mSmallestVisibleDL; 158 const TSDetail *detail = &mShape->details[dl]; 159 160 // TODO: Expose some real parameters to the datablock maybe? 161 if ( detail->subShapeNum != -1 ) 162 { 163 mShape->addImposter( mShapeFile, 10, 4, 0, 0, 256, 0, 0 ); 164 165 // HACK: If i don't do this it crashes! 166 while ( mShape->detailCollisionAccelerators.size() < mShape->details.size() ) 167 mShape->detailCollisionAccelerators.push_back( NULL ); 168 } 169} 170 171TSLastDetail* TSForestItemData::getLastDetail() const 172{ 173 // Gotta call this first of the last detail isn't created! 174 if (!_getShapeInstance()) 175 return NULL; 176 177 const S32 dl = mShape->mSmallestVisibleDL; 178 const TSDetail* detail = &mShape->details[dl]; 179 if ( detail->subShapeNum >= 0 || 180 mShape->billboardDetails.size() <= dl ) 181 return NULL; 182 183 return mShape->billboardDetails[dl]; 184} 185 186ForestCellBatch* TSForestItemData::allocateBatch() const 187{ 188 TSLastDetail* lastDetail = getLastDetail(); 189 if ( !lastDetail ) 190 return NULL; 191 192 return new TSForestCellBatch( lastDetail ); 193} 194 195bool TSForestItemData::canBillboard( const SceneRenderState *state, const ForestItem &item, F32 distToCamera ) const 196{ 197 PROFILE_SCOPE( TSForestItemData_canBillboard ); 198 199 if ( !mShape ) 200 return false; 201 202 // Use the shape instance to do the work it normally does. 203 TSShapeInstance *shapeInstance = _getShapeInstance(); 204 const S32 dl = shapeInstance->setDetailFromDistance( state, distToCamera / item.getScale() ); 205 206 // This item has a null LOD... lets consider 207 // that as being billboarded. 208 if ( dl < 0 ) 209 return true; 210 211 const TSDetail *detail = &mShape->details[dl]; 212 if ( detail->subShapeNum < 0 && dl < mShape->billboardDetails.size() ) 213 return true; 214 215 return false; 216} 217 218bool TSForestItemData::render( TSRenderState *rdata, const ForestItem &item ) const 219{ 220 PROFILE_SCOPE( TSForestItemData_render ); 221 222 // This shouldn't happen normally at runtime, but during 223 // development a file change notification on a bad file 224 // can cause us to get here without a shape. 225 TSShapeInstance *shapeInst = _getShapeInstance(); 226 if ( !shapeInst ) 227 return false; 228 229 const F32 scale = item.getScale(); 230 231 // Figure out the distance of this item to the camera. 232 const SceneRenderState *state = rdata->getSceneState(); 233 F32 dist = ( item.getPosition() - state->getDiffuseCameraPosition() ).len(); 234 235 // TODO: Selecting the lod seems more expensive than 236 // it should be... we should look to optimize this. 237 if ( shapeInst->setDetailFromDistance( state, dist / scale ) < 0 ) 238 return false; 239 240 // TSShapeInstance::render() uses the 241 // world matrix for the RenderInst. 242 MatrixF worldMat = item.getTransform(); 243 worldMat.scale( scale ); 244 GFX->setWorldMatrix( worldMat ); 245 rdata->setMaterialHint( (void*)&item ); 246 247 // This isn't documented well, but these calls 248 // don't really render... rather they batch the 249 // shape to be rendered by the render instance 250 // manager later on. 251 shapeInst->animate(); 252 shapeInst->render( *rdata ); 253 return true; 254} 255