Engine directory for ticket #1

This commit is contained in:
DavidWyand-GG 2012-09-19 11:15:01 -04:00
parent 352279af7a
commit 7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions

View file

@ -0,0 +1,481 @@
//-----------------------------------------------------------------------------
// 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 "T3D/decal/decalData.h"
#include "console/consoleTypes.h"
#include "core/stream/bitStream.h"
#include "math/mathIO.h"
#include "materials/materialManager.h"
#include "materials/baseMatInstance.h"
#include "T3D/objectTypes.h"
#include "console/engineAPI.h"
GFXImplementVertexFormat( DecalVertex )
{
addElement( "POSITION", GFXDeclType_Float3 );
addElement( "NORMAL", GFXDeclType_Float3 );
addElement( "TANGENT", GFXDeclType_Float3 );
addElement( "COLOR", GFXDeclType_Color );
addElement( "TEXCOORD", GFXDeclType_Float2, 0 );
}
IMPLEMENT_CO_DATABLOCK_V1( DecalData );
ConsoleDocClass( DecalData,
"@brief A datablock describing an individual decal.\n\n"
"The textures defined by the decal Material can be divided into multiple "
"rectangular sub-textures as shown below, with a different sub-texture "
"selected by all decals using the same DecalData (via #frame) or each decal "
"instance (via #randomize).\n"
"@image html images/decal_example.png \"Example of a Decal imagemap\"\n"
"@tsexample\n"
"datablock DecalData(BulletHoleDecal)\n"
"{\n"
" material = \"DECAL_BulletHole\";\n"
" size = \"5.0\";\n"
" lifeSpan = \"50000\";\n"
" randomize = \"1\";\n"
" texRows = \"2\";\n"
" texCols = \"2\";\n"
" clippingAngle = \"60\";\n"
"};\n"
"@endtsexample\n\n"
"@see Decals\n"
"@ingroup Decals\n"
"@ingroup FX\n"
);
//-------------------------------------------------------------------------
// DecalData
//-------------------------------------------------------------------------
DecalData::DecalData()
{
size = 5;
materialName = "";
lifeSpan = 5000;
fadeTime = 1000;
frame = 0;
randomize = false;
texRows = 1;
texCols = 1;
fadeStartPixelSize = -1.0f;
fadeEndPixelSize = 200.0f;
material = NULL;
matInst = NULL;
renderPriority = 10;
clippingMasks = STATIC_COLLISION_TYPEMASK;
clippingAngle = 89.0f;
texCoordCount = 1;
// TODO: We could in theory calculate if we can skip
// normals on the decal by checking the material features.
skipVertexNormals = false;
for ( S32 i = 0; i < 16; i++ )
{
texRect[i].point.set( 0.0f, 0.0f );
texRect[i].extent.set( 1.0f, 1.0f );
}
}
DecalData::~DecalData()
{
SAFE_DELETE( matInst );
}
bool DecalData::onAdd()
{
if ( !Parent::onAdd() )
return false;
if (size < 0.0) {
Con::warnf("DecalData::onAdd: size < 0");
size = 0;
}
getSet()->addObject( this );
if( texRows > 1 || texCols > 1 )
reloadRects();
return true;
}
void DecalData::onRemove()
{
Parent::onRemove();
}
void DecalData::initPersistFields()
{
addGroup( "Decal" );
addField( "size", TypeF32, Offset( size, DecalData ),
"Width and height of the decal in meters before scale is applied." );
addField( "material", TypeMaterialName, Offset( materialName, DecalData ),
"Material to use for this decal." );
addField( "lifeSpan", TypeS32, Offset( lifeSpan, DecalData ),
"Time (in milliseconds) before this decal will be automatically deleted." );
addField( "fadeTime", TypeS32, Offset( fadeTime, DecalData ),
"@brief Time (in milliseconds) over which to fade out the decal before "
"deleting it at the end of its lifetime.\n\n"
"@see lifeSpan" );
endGroup( "Decal" );
addGroup( "Rendering" );
addField( "fadeStartPixelSize", TypeF32, Offset( fadeStartPixelSize, DecalData ),
"@brief LOD value - size in pixels at which decals of this type begin "
"to fade out.\n\n"
"This should be a larger value than #fadeEndPixelSize. However, you may "
"also set this to a negative value to disable lod-based fading." );
addField( "fadeEndPixelSize", TypeF32, Offset( fadeEndPixelSize, DecalData ),
"@brief LOD value - size in pixels at which decals of this type are "
"fully faded out.\n\n"
"This should be a smaller value than #fadeStartPixelSize." );
addField( "renderPriority", TypeS8, Offset( renderPriority, DecalData ),
"Default renderPriority for decals of this type (determines draw "
"order when decals overlap)." );
addField( "clippingAngle", TypeF32, Offset( clippingAngle, DecalData ),
"The angle in degrees used to clip geometry that faces away from the "
"decal projection direction." );
endGroup( "Rendering" );
addGroup( "Texturing" );
addField( "frame", TypeS32, Offset( frame, DecalData ),
"Index of the texture rectangle within the imagemap to use for this decal." );
addField( "randomize", TypeBool, Offset( randomize, DecalData ),
"If true, a random frame from the imagemap is selected for each "
"instance of the decal." );
addField( "textureCoordCount", TypeS32, Offset( texCoordCount, DecalData ),
"Number of individual frames in the imagemap (maximum 16)." );
addField( "texRows", TypeS32, Offset( texRows, DecalData ),
"@brief Number of rows in the supplied imagemap.\n\n"
"Use #texRows and #texCols if the imagemap frames are arranged in a "
"grid; use #textureCoords to manually specify UV coordinates for "
"irregular sized frames." );
addField( "texCols", TypeS32, Offset( texCols, DecalData ),
"@brief Number of columns in the supplied imagemap.\n\n"
"Use #texRows and #texCols if the imagemap frames are arranged in a "
"grid; use #textureCoords to manually specify UV coordinates for "
"irregular sized frames." );
addField( "textureCoords", TypeRectF, Offset( texRect, DecalData ), MAX_TEXCOORD_COUNT,
"@brief An array of RectFs (topleft.x topleft.y extent.x extent.y) "
"representing the UV coordinates for each frame in the imagemap.\n\n"
"@note This field should only be set if the imagemap frames are "
"irregular in size. Otherwise use the #texRows and #texCols fields "
"and the UV coordinates will be calculated automatically." );
endGroup( "Texturing" );
Parent::initPersistFields();
}
void DecalData::onStaticModified( const char *slotName, const char *newValue )
{
Parent::onStaticModified( slotName, newValue );
if ( !isProperlyAdded() )
return;
// To allow changing materials live.
if ( dStricmp( slotName, "material" ) == 0 )
{
materialName = newValue;
_updateMaterial();
}
// To allow changing name live.
else if ( dStricmp( slotName, "name" ) == 0 )
{
lookupName = getName();
}
else if ( dStricmp( slotName, "renderPriority" ) == 0 )
{
renderPriority = getMax( renderPriority, (U8)1 );
}
}
bool DecalData::preload( bool server, String &errorStr )
{
if (Parent::preload(server, errorStr) == false)
return false;
// Server assigns name to lookupName,
// client assigns lookupName in unpack.
if ( server )
lookupName = getName();
return true;
}
void DecalData::packData( BitStream *stream )
{
Parent::packData( stream );
stream->write( lookupName );
stream->write( size );
stream->write( materialName );
stream->write( lifeSpan );
stream->write( fadeTime );
stream->write( texCoordCount );
for (S32 i = 0; i < texCoordCount; i++)
mathWrite( *stream, texRect[i] );
stream->write( fadeStartPixelSize );
stream->write( fadeEndPixelSize );
stream->write( renderPriority );
stream->write( clippingMasks );
stream->write( clippingAngle );
stream->write( texRows );
stream->write( texCols );
stream->write( frame );
stream->write( randomize );
}
void DecalData::unpackData( BitStream *stream )
{
Parent::unpackData( stream );
stream->read( &lookupName );
stream->read( &size );
stream->read( &materialName );
_updateMaterial();
stream->read( &lifeSpan );
stream->read( &fadeTime );
stream->read( &texCoordCount );
for (S32 i = 0; i < texCoordCount; i++)
mathRead(*stream, &texRect[i]);
stream->read( &fadeStartPixelSize );
stream->read( &fadeEndPixelSize );
stream->read( &renderPriority );
stream->read( &clippingMasks );
stream->read( &clippingAngle );
stream->read( &texRows );
stream->read( &texCols );
stream->read( &frame );
stream->read( &randomize );
}
void DecalData::_initMaterial()
{
SAFE_DELETE( matInst );
if ( material )
matInst = material->createMatInstance();
else
matInst = MATMGR->createMatInstance( "WarningMaterial" );
GFXStateBlockDesc desc;
desc.setZReadWrite( true, false );
//desc.zFunc = GFXCmpLess;
matInst->addStateBlockDesc( desc );
matInst->init( MATMGR->getDefaultFeatures(), getGFXVertexFormat<DecalVertex>() );
if( !matInst->isValid() )
{
Con::errorf( "DecalData::_initMaterial - failed to create material instance for '%s'", materialName.c_str() );
SAFE_DELETE( matInst );
matInst = MATMGR->createMatInstance( "WarningMaterial" );
matInst->init( MATMGR->getDefaultFeatures(), getGFXVertexFormat< DecalVertex >() );
}
}
void DecalData::_updateMaterial()
{
if ( materialName.isEmpty() )
return;
Material *pMat = NULL;
if ( !Sim::findObject( materialName, pMat ) )
{
Con::printf( "DecalData::unpackUpdate, failed to find Material of name %s!", materialName.c_str() );
return;
}
material = pMat;
// Only update material instance if we have one allocated.
if ( matInst )
_initMaterial();
}
Material* DecalData::getMaterial()
{
if ( !material )
{
_updateMaterial();
if ( !material )
material = static_cast<Material*>( Sim::findObject("WarningMaterial") );
}
return material;
}
BaseMatInstance* DecalData::getMaterialInstance()
{
if ( !material || !matInst || matInst->getMaterial() != material )
_initMaterial();
return matInst;
}
DecalData* DecalData::findDatablock( String searchName )
{
StringTableEntry className = DecalData::getStaticClassRep()->getClassName();
DecalData *pData;
SimSet *set = getSet();
SimSetIterator iter( set );
for ( ; *iter; ++iter )
{
if ( (*iter)->getClassName() != className )
{
Con::errorf( "DecalData::findDatablock - found a class %s object in DecalDataSet!", (*iter)->getClassName() );
continue;
}
pData = static_cast<DecalData*>( *iter );
if ( pData->lookupName.equal( searchName, String::NoCase ) )
return pData;
}
return NULL;
}
void DecalData::inspectPostApply()
{
reloadRects();
}
void DecalData::reloadRects()
{
F32 rowsBase = 0;
F32 colsBase = 0;
bool canRenderRowsByFrame = false;
bool canRenderColsByFrame = false;
S32 id = 0;
texRect[id].point.x = 0.f;
texRect[id].extent.x = 1.f;
texRect[id].point.y = 0.f;
texRect[id].extent.y = 1.f;
texCoordCount = (texRows * texCols) - 1;
if( texCoordCount > 16 )
{
Con::warnf("Coordinate max must be lower than 16 to be a valid decal !");
texRows = 1;
texCols = 1;
texCoordCount = 1;
}
// use current datablock information in order to build a template to extract
// coordinates from.
if( texRows > 1 )
{
rowsBase = ( 1.f / texRows );
canRenderRowsByFrame = true;
}
if( texCols > 1 )
{
colsBase = ( 1.f / texCols );
canRenderColsByFrame = true;
}
// if were able, lets enter the loop
if( frame >= 0 && (canRenderRowsByFrame || canRenderColsByFrame) )
{
// columns first then rows
for ( S32 colId = 1; colId <= texCols; colId++ )
{
for ( S32 rowId = 1; rowId <= texRows; rowId++, id++ )
{
// if were over the coord count, lets go
if(id > texCoordCount)
return;
// keep our dimensions correct
if(rowId > texRows)
rowId = 1;
if(colId > texCols)
colId = 1;
// start setting our rect values per frame
if( canRenderRowsByFrame )
{
texRect[id].point.x = rowsBase * ( rowId - 1 );
texRect[id].extent.x = rowsBase;
}
if( canRenderColsByFrame )
{
texRect[id].point.y = colsBase * ( colId - 1 );
texRect[id].extent.y = colsBase;
}
}
}
}
}
DefineEngineMethod(DecalData, postApply, void, (),,
"Recompute the imagemap sub-texture rectangles for this DecalData.\n"
"@tsexample\n"
"// Inform the decal object to reload its imagemap and frame data.\n"
"%decalData.texRows = 4;\n"
"%decalData.postApply();\n"
"@endtsexample\n")
{
object->inspectPostApply();
}

View file

@ -0,0 +1,143 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#ifndef _DECALDATA_H_
#define _DECALDATA_H_
#ifndef _SIMDATABLOCK_H_
#include "console/simDatablock.h"
#endif
#ifndef _MATERIALDEFINITION_H_
#include "materials/materialDefinition.h"
#endif
#ifndef _MRECT_H_
#include "math/mRect.h"
#endif
#ifndef _DYNAMIC_CONSOLETYPES_H_
#include "console/dynamicTypes.h"
#endif
GFXDeclareVertexFormat( DecalVertex )
{
// .xyz = coords
Point3F point;
Point3F normal;
Point3F tangent;
GFXVertexColor color;
Point2F texCoord;
};
/// DataBlock implementation for decals.
class DecalData : public SimDataBlock
{
typedef SimDataBlock Parent;
public:
enum { MAX_TEXCOORD_COUNT = 16 };
F32 size;
/// Milliseconds for decal to expire.
U32 lifeSpan;
/// Milliseconds for decal to fade after expiration.
U32 fadeTime;
S32 texCoordCount;
RectF texRect[MAX_TEXCOORD_COUNT];
///
S32 frame;
bool randomize;
S32 texRows;
S32 texCols;
F32 fadeStartPixelSize;
F32 fadeEndPixelSize;
/// Name of material to use.
String materialName;
/// Render material for decal.
SimObjectPtr<Material> material;
/// Material instance for decal.
BaseMatInstance *matInst;
String lookupName;
U8 renderPriority;
S32 clippingMasks;
/// The angle in degress used to clip geometry
/// that faces away from the decal projection.
F32 clippingAngle;
/// Skip generating and collecting vertex normals for decals.
bool skipVertexNormals;
public:
DecalData();
~DecalData();
DECLARE_CONOBJECT(DecalData);
static void initPersistFields();
virtual void onStaticModified( const char *slotName, const char *newValue = NULL );
virtual bool onAdd();
virtual void onRemove();
virtual bool preload( bool server, String &errorStr );
virtual void packData( BitStream* );
virtual void unpackData( BitStream* );
Material* getMaterial();
BaseMatInstance* getMaterialInstance();
static SimSet* getSet();
static DecalData* findDatablock( String lookupName );
virtual void inspectPostApply();
void reloadRects();
protected:
void _initMaterial();
void _updateMaterial();
};
inline SimSet* DecalData::getSet()
{
SimSet *set = NULL;
if ( !Sim::findObject( "DecalDataSet", set ) )
{
set = new SimSet;
set->registerObject( "DecalDataSet" );
Sim::getRootGroup()->addObject( set );
}
return set;
}
#endif // _DECALDATA_H_

View file

@ -0,0 +1,407 @@
//-----------------------------------------------------------------------------
// 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 "decalDataFile.h"
#include "math/mathIO.h"
#include "core/tAlgorithm.h"
#include "core/stream/fileStream.h"
#include "T3D/decal/decalManager.h"
#include "T3D/decal/decalData.h"
template<>
void* Resource<DecalDataFile>::create( const Torque::Path &path )
{
FileStream stream;
stream.open( path.getFullPath(), Torque::FS::File::Read );
if ( stream.getStatus() != Stream::Ok )
return NULL;
DecalDataFile *file = new DecalDataFile();
if ( !file->read( stream ) )
{
delete file;
return NULL;
}
return file;
}
template<>
ResourceBase::Signature Resource<DecalDataFile>::signature()
{
return MakeFourCC('d','e','c','f');
}
//-----------------------------------------------------------------------------
DecalDataFile::DecalDataFile()
: mIsDirty( false ),
mSphereWithLastInsertion( NULL )
{
VECTOR_SET_ASSOCIATION( mSphereList );
}
//-----------------------------------------------------------------------------
DecalDataFile::~DecalDataFile()
{
clear();
}
//-----------------------------------------------------------------------------
void DecalDataFile::clear()
{
for ( U32 i=0; i < mSphereList.size(); i++ )
delete mSphereList[i];
mSphereList.clear();
mSphereWithLastInsertion = NULL;
mChunker.freeBlocks();
mIsDirty = true;
}
//-----------------------------------------------------------------------------
bool DecalDataFile::write( Stream& stream )
{
// Write our identifier... so we have a better
// idea if we're reading pure garbage.
// This identifier stands for "Torque Decal Data File".
stream.write( 4, "TDDF" );
// Now the version number.
stream.write( (U8)FILE_VERSION );
Vector<DecalInstance*> allDecals;
// Gather all DecalInstances that should be saved.
for ( U32 i = 0; i < mSphereList.size(); i++ )
{
Vector<DecalInstance*>::const_iterator item = mSphereList[i]->mItems.begin();
for ( ; item != mSphereList[i]->mItems.end(); item++ )
{
if ( (*item)->mFlags & SaveDecal )
allDecals.push_back( (*item) );
}
}
// Gather all the DecalData datablocks used.
Vector<const DecalData*> allDatablocks;
for ( U32 i = 0; i < allDecals.size(); i++ )
allDatablocks.push_back_unique( allDecals[i]->mDataBlock );
// Write out datablock lookupNames.
U32 count = allDatablocks.size();
stream.write( count );
for ( U32 i = 0; i < count; i++ )
stream.write( allDatablocks[i]->lookupName );
Vector<const DecalData*>::iterator dataIter;
// Write out the DecalInstance list.
count = allDecals.size();
stream.write( count );
for ( U32 i = 0; i < count; i++ )
{
DecalInstance *inst = allDecals[i];
dataIter = find( allDatablocks.begin(), allDatablocks.end(), inst->mDataBlock );
U8 dataIndex = dataIter - allDatablocks.begin();
stream.write( dataIndex );
mathWrite( stream, inst->mPosition );
mathWrite( stream, inst->mNormal );
mathWrite( stream, inst->mTangent );
stream.write( inst->mTextureRectIdx );
stream.write( inst->mSize );
stream.write( inst->mRenderPriority );
}
// Clear the dirty flag.
mIsDirty = false;
return true;
}
//-----------------------------------------------------------------------------
bool DecalDataFile::read( Stream &stream )
{
// NOTE: we are shortcutting by just saving out the DecalInst and
// using regular addDecal methods to add them, which will end up
// generating the DecalSphere(s) in the process.
// It would be more efficient however to just save out all the data
// and read it all in with no calculation required.
// Read our identifier... so we know we're
// not reading in pure garbage.
char id[4] = { 0 };
stream.read( 4, id );
if ( dMemcmp( id, "TDDF", 4 ) != 0 )
{
Con::errorf( "DecalDataFile::read() - This is not a Decal file!" );
return false;
}
// Empty ourselves before we really begin reading.
clear();
// Now the version number.
U8 version;
stream.read( &version );
if ( version != (U8)FILE_VERSION )
{
Con::errorf( "DecalDataFile::read() - file versions do not match!" );
Con::errorf( "You must manually delete the old .decals file before continuing!" );
return false;
}
// Read in the lookupNames of the DecalData datablocks and recover the datablock.
Vector<DecalData*> allDatablocks;
U32 count;
stream.read( &count );
allDatablocks.setSize( count );
for ( U32 i = 0; i < count; i++ )
{
String lookupName;
stream.read( &lookupName );
DecalData *data = DecalData::findDatablock( lookupName );
if ( !data )
{
char name[512];
dSprintf(name, 512, "%s_missing", lookupName.c_str());
DecalData *stubCheck = DecalData::findDatablock( name );
if( !stubCheck )
{
data = new DecalData;
data->lookupName = name;
data->registerObject(name);
Sim::getRootGroup()->addObject( data );
data->materialName = "WarningMaterial";
data->material = dynamic_cast<Material*>(Sim::findObject("WarningMaterial"));
Con::errorf( "DecalDataFile::read() - DecalData %s does not exist! Temporarily created %s_missing.", lookupName.c_str() );
}
}
allDatablocks[ i ] = data;
}
U8 dataIndex;
DecalData *data;
// Now read all the DecalInstance(s).
stream.read( &count );
for ( U32 i = 0; i < count; i++ )
{
DecalInstance *inst = _allocateInstance();
stream.read( &dataIndex );
mathRead( stream, &inst->mPosition );
mathRead( stream, &inst->mNormal );
mathRead( stream, &inst->mTangent );
stream.read( &inst->mTextureRectIdx );
stream.read( &inst->mSize );
stream.read( &inst->mRenderPriority );
inst->mVisibility = 1.0f;
inst->mFlags = PermanentDecal | SaveDecal | ClipDecal;
inst->mCreateTime = Sim::getCurrentTime();
inst->mVerts = NULL;
inst->mIndices = NULL;
inst->mVertCount = 0;
inst->mIndxCount = 0;
data = allDatablocks[ dataIndex ];
if ( data )
{
inst->mDataBlock = data;
_addDecalToSpheres( inst );
// onload set instances should get added to the appropriate vec
inst->mId = gDecalManager->mDecalInstanceVec.size();
gDecalManager->mDecalInstanceVec.push_back(inst);
}
else
{
_freeInstance( inst );
Con::errorf( "DecalDataFile::read - cannot find DecalData for DecalInstance read from disk." );
}
}
// Clear the dirty flag.
mIsDirty = false;
return true;
}
//-----------------------------------------------------------------------------
DecalInstance* DecalDataFile::addDecal( const Point3F& pos, const Point3F& normal, const Point3F& tangent,
DecalData* decalData, F32 decalScale, S32 decalTexIndex, U8 flags )
{
DecalInstance* newDecal = _allocateInstance();
newDecal->mRenderPriority = 0;
newDecal->mCustomTex = NULL;
newDecal->mId = -1;
newDecal->mPosition = pos;
newDecal->mNormal = normal;
newDecal->mTangent = tangent;
newDecal->mSize = decalData->size * decalScale;
newDecal->mDataBlock = decalData;
S32 frame = newDecal->mDataBlock->frame;
// randomize the frame if the flag is set. this number is used directly below us
// when calculating render coords
if ( decalData->randomize )
frame = gRandGen.randI();
frame %= getMax( decalData->texCoordCount, 0 ) + 1;
newDecal->mTextureRectIdx = frame;
newDecal->mVisibility = 1.0f;
newDecal->mLastAlpha = -1.0f;
newDecal->mCreateTime = Sim::getCurrentTime();
newDecal->mVerts = NULL;
newDecal->mIndices = NULL;
newDecal->mVertCount = 0;
newDecal->mIndxCount = 0;
newDecal->mFlags = flags;
newDecal->mFlags |= ClipDecal;
_addDecalToSpheres( newDecal );
return newDecal;
}
//-----------------------------------------------------------------------------
void DecalDataFile::_addDecalToSpheres( DecalInstance* inst )
{
// First try the sphere we have last inserted an item into, if there is one.
// Given a good spatial locality of insertions, this is a reasonable first
// guess as a good candidate.
if( mSphereWithLastInsertion && mSphereWithLastInsertion->tryAddItem( inst ) )
return;
// Otherwise, go through the list and try to find an existing sphere that meets
// our tolerances.
for( U32 i = 0; i < mSphereList.size(); i++ )
{
DecalSphere* sphere = mSphereList[i];
if( sphere == mSphereWithLastInsertion )
continue;
if( sphere->tryAddItem( inst ) )
{
mSphereWithLastInsertion = sphere;
return;
}
}
// Didn't find a suitable existing sphere, so create a new one.
DecalSphere* sphere = new DecalSphere( inst->mPosition, inst->mSize / 2.f );
mSphereList.push_back( sphere );
mSphereWithLastInsertion = sphere;
sphere->mItems.push_back( inst );
}
//-----------------------------------------------------------------------------
void DecalDataFile::removeDecal( DecalInstance *inst )
{
if( !_removeDecalFromSpheres( inst ) )
return;
_freeInstance( inst );
}
//-----------------------------------------------------------------------------
bool DecalDataFile::_removeDecalFromSpheres( DecalInstance *inst )
{
for( U32 i = 0; i < mSphereList.size(); i++ )
{
DecalSphere* sphere = mSphereList[ i ];
Vector< DecalInstance* > &items = sphere->mItems;
// Try to remove the instance from the list of this sphere.
// If that fails, the instance doesn't belong to this sphere
// so continue.
if( !items.remove( inst ) )
continue;
// If the sphere is now empty, remove it. Otherwise, update
// it's bounds.
if( items.empty() )
{
if( mSphereWithLastInsertion == sphere )
mSphereWithLastInsertion = NULL;
delete sphere;
mSphereList.erase( i );
}
else
sphere->updateWorldSphere();
return true;
}
return false;
}
//-----------------------------------------------------------------------------
void DecalDataFile::notifyDecalModified( DecalInstance *inst )
{
_removeDecalFromSpheres( inst );
_addDecalToSpheres( inst );
}

View file

@ -0,0 +1,133 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#ifndef _DECALDATAFILE_H_
#define _DECALDATAFILE_H_
#ifndef _DATACHUNKER_H_
#include "core/dataChunker.h"
#endif
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
#ifndef _DECALSPHERE_H_
#include "T3D/decal/decalSphere.h"
#endif
class Stream;
class DecalData;
/// This is the data file for decals.
/// Not intended to be used directly, do your work with decals
/// via the DecalManager.
class DecalDataFile
{
protected:
enum { FILE_VERSION = 5 };
/// Set to true if the file is dirty and
/// needs to be saved before being destroyed.
bool mIsDirty;
/// @name Memory Management
/// @{
/// Allocator for DecalInstances.
FreeListChunker< DecalInstance > mChunker;
/// Allocate a new, uninitialized DecalInstance.
DecalInstance* _allocateInstance() { return mChunker.alloc(); }
/// Free the memory of the given DecalInstance.
void _freeInstance( DecalInstance *decal ) { mChunker.free( decal ); }
/// @}
/// @name Instance Management
/// @{
/// The decal sphere that we have last insert an item into. This sphere
/// is most likely to be a good candidate for the next insertion so
/// test this sphere first.
DecalSphere* mSphereWithLastInsertion;
/// List of bounding sphere shapes that contain and organize
/// DecalInstances for optimized culling and lookup.
Vector< DecalSphere* > mSphereList;
/// Add the given decal to the sphere list.
void _addDecalToSpheres( DecalInstance *inst );
/// Remove the decal from the sphere list.
bool _removeDecalFromSpheres( DecalInstance *inst );
/// @}
public:
DecalDataFile();
virtual ~DecalDataFile();
Vector< DecalSphere* >& getSphereList() { return mSphereList; }
const Vector< DecalSphere* >& getSphereList() const { return mSphereList; }
/// Return true if the decal data has been modified since the last save or load.
bool isDirty() const { return mIsDirty; }
/// Deletes all the data and resets the
/// file to an empty state.
void clear();
/// @name I/O
/// @{
/// Write the decal data to the given stream.
bool write( Stream& stream );
/// Read the decal data from the given stream.
bool read( Stream& stream );
/// @}
/// @name Decal Management
/// @{
/// Create a new decal in this file using the given data.
DecalInstance* addDecal( const Point3F& pos, const Point3F& normal, const Point3F& tangent,
DecalData* decalData, F32 decalScale, S32 decalTexIndex, U8 flags );
/// Remove a decal from the file.
void removeDecal( DecalInstance *inst );
/// Let the file know that the data of the given decal has changed.
void notifyDecalModified( DecalInstance *inst );
/// @}
};
#endif // _DECALDATAFILE_H_

View file

@ -0,0 +1,73 @@
//-----------------------------------------------------------------------------
// 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 "T3D/decal/decalInstance.h"
#include "scene/sceneRenderState.h"
void DecalInstance::getWorldMatrix( MatrixF *outMat, bool flip )
{
outMat->setPosition( mPosition );
Point3F fvec;
mCross( mNormal, mTangent, &fvec );
outMat->setColumn( 0, mTangent );
outMat->setColumn( 1, fvec );
outMat->setColumn( 2, mNormal );
}
F32 DecalInstance::calcPixelSize( U32 viewportHeight, const Point3F &cameraPos, F32 worldToScreenScaleY ) const
{
// If fadeStartPixelSize is set less than zero this is interpreted to mean
// pixelSize based fading is disabled and the decal always renders.
// Returning a value of F32_MAX should be treated by the caller as
// meaning "big enough to render at normal quality, dont LOD me.".
if ( mDataBlock->fadeStartPixelSize < 0.0f )
return F32_MAX;
// This is an approximation since mSize is actually the xyz size of the
// cube we use to clip geometry for the decal. In this case we are assuming
// it is appropriate to use the radius of the sphere 'inscribed' in that
// cube as the equivalent of mShape->radius for purposes of calculating
// the pixelScale ( see TSShapeInstance::setDetailFromDistance ).
const F32 radius = mSize * 0.5f;
// Approximate distance to the decal.
const F32 distance = ( cameraPos - mPosition ).len() - radius;
// We are inside the decal's volume. There is no useful pixelSize for us
// to return, it is essentially the entire screen.
if ( distance <= 0.0f )
return F32_MAX;
// Lod is relative to a viewport with a heigh of 300. Could prescale this into decalSize...
const F32 pixelScale = viewportHeight / 300.0f;
// Inline of SceneState::projectRadius.
const F32 pixelSize = mSize / distance * worldToScreenScaleY * pixelScale;
// Optionally scale pixelSize by a detail adjust value here...
// eg. pixelSize *= TSDetailAdjust...
return pixelSize;
}

View file

@ -0,0 +1,93 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#ifndef _DECALINSTANCE_H_
#define _DECALINSTANCE_H_
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
#ifndef _DECALDATA_H_
#include "T3D/decal/decalData.h"
#endif
struct DecalVertex;
class SceneRenderState;
/// DecalInstance represents a rendering decal in the scene.
/// You should not allocate this yourself, add new decals to the scene
/// via the DecalManager.
/// All data is public, change it if you wish, but be sure to inform
/// the DecalManager.
class DecalInstance
{
public:
DecalData *mDataBlock;
Point3F mPosition;
Point3F mNormal;
Point3F mTangent;
F32 mRotAroundNormal;
F32 mSize;
U32 mCreateTime;
F32 mVisibility;
F32 mLastAlpha;
U32 mTextureRectIdx;
DecalVertex *mVerts;
U16 *mIndices;
U32 mVertCount;
U32 mIndxCount;
U8 mFlags;
U8 mRenderPriority;
S32 mId;
GFXTexHandle *mCustomTex;
void getWorldMatrix( MatrixF *outMat, bool flip = false );
Box3F getWorldBox() const
{
return Box3F( mPosition - Point3F( mSize / 2.f ), mPosition + Point3F( mSize / 2.f ) );
}
U8 getRenderPriority() const
{
return mRenderPriority == 0 ? mDataBlock->renderPriority : mRenderPriority;
}
/// Calculates the size of this decal onscreen in pixels, used for LOD.
F32 calcPixelSize( U32 viewportHeight, const Point3F &cameraPos, F32 worldToScreenScaleY ) const;
DecalInstance() : mId(-1) {}
};
#endif // _DECALINSTANCE_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,278 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#ifndef _DECALMANAGER_H_
#define _DECALMANAGER_H_
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
#ifndef _MATHUTIL_FRUSTUM_H_
#include "math/util/frustum.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#ifndef _GFXDEVICE_H_
#include "gfx/gfxDevice.h"
#endif
#ifndef _CLIPPEDPOLYLIST_H_
#include "collision/clippedPolyList.h"
#endif
#ifndef _DECALDATAFILE_H_
#include "decalDataFile.h"
#endif
#ifndef __RESOURCE_H__
#include "core/resource.h"
#endif
#ifndef _DECALINSTANCE_H_
#include "decalInstance.h"
#endif
#ifndef _TSIGNAL_H_
#include "core/util/tSignal.h"
#endif
#ifndef _DATACHUNKER_H_
#include "core/dataChunker.h"
#endif
//#define DECALMANAGER_DEBUG
struct ObjectRenderInst;
class Material;
enum DecalFlags
{
PermanentDecal = 1 << 0,
SaveDecal = 1 << 1,
ClipDecal = 1 << 2,
CustomDecal = 1 << 3 // DecalManager will not attempt to clip or remove this decal
// it is managed by someone else.
};
/// Manage decals in the scene.
class DecalManager : public SceneObject
{
public:
typedef SceneObject Parent;
// [rene, 11-Mar-11] This vector is very poorly managed; the logic is spread all over the place
Vector<DecalInstance *> mDecalInstanceVec;
protected:
/// The clipper we keep around between decal updates
/// to avoid excessive memory allocations.
ClippedPolyList mClipper;
Vector<DecalInstance*> mDecalQueue;
StringTableEntry mDataFileName;
Resource<DecalDataFile> mData;
Signal< void() > mClearDataSignal;
Vector< GFXVertexBufferHandle<DecalVertex>* > mVBs;
Vector< GFXPrimitiveBufferHandle* > mPBs;
Vector< GFXVertexBufferHandle<DecalVertex>* > mVBPool;
Vector< GFXPrimitiveBufferHandle* > mPBPool;
FreeListChunkerUntyped *mChunkers[3];
#ifdef DECALMANAGER_DEBUG
Vector<PlaneF> mDebugPlanes;
#endif
bool mDirty;
struct DecalBatch
{
U32 startDecal;
U32 decalCount;
U32 iCount;
U32 vCount;
U8 priority;
Material *mat;
BaseMatInstance *matInst;
bool dynamic;
};
/// Whether to render visualizations for debugging in the editor.
static bool smDebugRender;
static bool smDecalsOn;
static F32 smDecalLifeTimeScale;
static bool smPoolBuffers;
static const U32 smMaxVerts;
static const U32 smMaxIndices;
// Assume that a class is already given for the object:
// Point with coordinates {float x, y;}
//===================================================================
// isLeft(): tests if a point is Left|On|Right of an infinite line.
// Input: three points P0, P1, and P2
// Return: >0 for P2 left of the line through P0 and P1
// =0 for P2 on the line
// <0 for P2 right of the line
// See: the January 2001 Algorithm on Area of Triangles
inline F32 isLeft( const Point3F &P0, const Point3F &P1, const Point3F &P2 )
{
return (P1.x - P0.x)*(P2.y - P0.y) - (P2.x - P0.x)*(P1.y - P0.y);
}
U32 _generateConvexHull( const Vector<Point3F> &points, Vector<Point3F> *outPoints );
// Rendering
void prepRenderImage( SceneRenderState *state );
void _generateWindingOrder( const Point3F &cornerPoint, Vector<Point3F> *sortPoints );
// Helpers for creating and deleting the vert and index arrays
// held by DecalInstance.
void _allocBuffers( DecalInstance *inst );
void _freeBuffers( DecalInstance *inst );
void _freePools();
/// Returns index used to index into the correct sized FreeListChunker for
/// allocating vertex and index arrays.
S32 _getSizeClass( DecalInstance *inst ) const;
// Hide this from Doxygen
/// @cond
bool _handleGFXEvent(GFXDevice::GFXDeviceEventType event);
/// @endcond
void _renderDecalSpheres( ObjectRenderInst* inst, SceneRenderState* state, BaseMatInstance* overrideMat );
///
void _handleZoningChangedEvent( SceneZoneSpaceManager* zoneManager );
bool _createDataFile();
// SceneObject.
virtual bool onSceneAdd();
virtual void onSceneRemove(); public:
public:
DecalManager();
~DecalManager();
/// @name Decal Addition
/// @{
/// Adds a decal using a normal and a rotation.
///
/// @param pos The 3d position for the decal center.
/// @param normal The decal up vector.
/// @param rotAroundNormal The decal rotation around the normal.
/// @param decalData The datablock which defines this decal.
/// @param decalScale A scalar for adjusting the default size of the decal.
/// @param decalTexIndex Selects the texture coord index within the decal
/// data to use. If it is less than zero then a random
/// coord is selected.
/// @param flags The decal flags. @see DecalFlags
///
DecalInstance* addDecal( const Point3F &pos,
const Point3F &normal,
F32 rotAroundNormal,
DecalData *decalData,
F32 decalScale = 1.0f,
S32 decalTexIndex = 0,
U8 flags = 0x000 );
/// Adds a decal using a normal and a tangent.
///
/// @param pos The 3d position for the decal center.
/// @param normal The decal up vector.
/// @param tanget The decal right vector.
/// @param decalData The datablock which defines this decal.
/// @param decalScale A scalar for adjusting the default size of the decal.
/// @param decalTexIndex Selects the texture coord index within the decal
/// data to use. If it is less than zero then a random
/// coord is selected.
/// @param flags The decal flags. @see DecalFlags
///
DecalInstance* addDecal( const Point3F &pos,
const Point3F &normal,
const Point3F &tangent,
DecalData *decalData,
F32 decalScale = 1.0f,
S32 decalTexIndex = 0,
U8 flags = 0 );
/// @}
/// @name Decal Removal
/// @{
void removeDecal( DecalInstance *inst );
/// @}
DecalInstance* getDecal( S32 id );
DecalInstance* getClosestDecal( const Point3F &pos );
/// Return the closest DecalInstance hit by a ray.
DecalInstance* raycast( const Point3F &start, const Point3F &end, bool savedDecalsOnly = true );
//void dataDeleted( DecalData *data );
void saveDecals( const UTF8 *fileName );
bool loadDecals( const UTF8 *fileName );
void clearData();
/// Returns true if changes have been made since the last load/save
bool isDirty() const { return mDirty; }
bool clipDecal( DecalInstance *decal, Vector<Point3F> *edgeVerts = NULL, const Point2F *clipDepth = NULL );
void notifyDecalModified( DecalInstance *inst );
Signal< void() >& getClearDataSignal() { return mClearDataSignal; }
Resource<DecalDataFile> getDecalDataFile() { return mData; }
// SimObject.
DECLARE_CONOBJECT( DecalManager );
static void consoleInit();
};
extern DecalManager* gDecalManager;
#endif // _DECALMANAGER_H_

View file

@ -0,0 +1,109 @@
//-----------------------------------------------------------------------------
// 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 "T3D/decal/decalSphere.h"
#include "scene/zones/sceneZoneSpaceManager.h"
#include "T3D/decal/decalInstance.h"
F32 DecalSphere::smDistanceTolerance = 30.0f;
F32 DecalSphere::smRadiusTolerance = 40.0f;
//-----------------------------------------------------------------------------
bool DecalSphere::tryAddItem( DecalInstance* inst )
{
// If we are further away from the center than our tolerance
// allows, don't use this sphere.
//
// Note that we take the distance from the nearest point on the
// bounding sphere rather than the distance to the center of the
// decal. This takes decal sizes into account and generally works
// better.
const F32 distCenterToCenter = ( mWorldSphere.center - inst->mPosition ).len();
const F32 distBoundsToCenter = distCenterToCenter - inst->mSize / 2.f;
if( distBoundsToCenter > smDistanceTolerance )
return false;
// Also, if adding the current decal to the sphere would make
// it larger than our radius tolerance, don't use it.
const F32 newRadius = distCenterToCenter + inst->mSize / 2.f + 0.5f;
if( newRadius > mWorldSphere.radius && newRadius > smRadiusTolerance )
return false;
// Otherwise, go with this sphere and add the item to it.
mItems.push_back( inst );
// Update the sphere bounds, if necessary.
if( newRadius > mWorldSphere.radius )
updateWorldSphere();
return true;
}
//-----------------------------------------------------------------------------
void DecalSphere::updateWorldSphere()
{
AssertFatal( mItems.size() >= 1, "DecalSphere::updateWorldSphere - Sphere is empty!" );
Box3F aabb( mItems[ 0 ]->getWorldBox() );
const U32 numItems = mItems.size();
for( U32 i = 1; i < numItems; ++ i )
aabb.intersect( mItems[ i ]->getWorldBox() );
mWorldSphere = aabb.getBoundingSphere();
// Clear the zoning data so that it gets recomputed.
mZones.clear();
}
//-----------------------------------------------------------------------------
void DecalSphere::updateZoning( SceneZoneSpaceManager* zoneManager )
{
mZones.clear();
// If there's only a single zone in the world, it must be the
// outdoor zone, so there's no point maintaining zoning information
// on all the decalspheres.
if( zoneManager->getNumZones() == 1 )
return;
// Otherwise query the scene graph for all zones that intersect with the
// AABB around our world sphere.
Box3F aabb( mWorldSphere.radius );
aabb.setCenter( mWorldSphere.center );
zoneManager->findZones( aabb, mZones );
}

View file

@ -0,0 +1,83 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#ifndef _DECALSPHERE_H_
#define _DECALSPHERE_H_
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
#ifndef _MSPHERE_H_
#include "math/mSphere.h"
#endif
class DecalInstance;
class SceneZoneSpaceManager;
/// A bounding sphere in world space and a list of DecalInstance(s)
/// contained by it. DecalInstance(s) are organized/binned in this fashion
/// as a lookup and culling optimization.
class DecalSphere
{
public:
static F32 smDistanceTolerance;
static F32 smRadiusTolerance;
DecalSphere()
{
VECTOR_SET_ASSOCIATION( mItems );
VECTOR_SET_ASSOCIATION( mZones );
}
DecalSphere( const Point3F &position, F32 radius )
{
VECTOR_SET_ASSOCIATION( mItems );
VECTOR_SET_ASSOCIATION( mZones );
mWorldSphere.center = position;
mWorldSphere.radius = radius;
}
/// Recompute #mWorldSphere from the current instance list.
void updateWorldSphere();
/// Recompute the zoning information from the current bounds.
void updateZoning( SceneZoneSpaceManager* zoneManager );
/// Decal instances in this sphere.
Vector< DecalInstance* > mItems;
/// Zones that intersect with this sphere. If this is empty, the zoning
/// state of the sphere is uninitialized.
Vector< U32 > mZones;
/// World-space sphere corresponding to this DecalSphere.
SphereF mWorldSphere;
///
bool tryAddItem( DecalInstance* inst );
};
#endif // !_DECALSPHERE_H_