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,409 @@
//-----------------------------------------------------------------------------
// 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 "platform/profiler.h"
#include "console/consoleTypes.h"
#include "basicClouds.h"
#include "gfx/gfxTransformSaver.h"
#include "core/stream/fileStream.h"
#include "core/stream/bitStream.h"
#include "scene/sceneRenderState.h"
#include "renderInstance/renderPassManager.h"
#include "materials/shaderData.h"
#include "math/mathIO.h"
ConsoleDocClass( BasicClouds,
"@brief Renders up to three layers of scrolling cloud-cover textures overhead.\n\n"
"%BasicClouds always renders overhead, following the camera. It is intended "
"as part of the background of your level, rendering in front of Sky/Sun "
"type objects and behind everything else.\n\n"
"The parameters controlling the rendering of each texture are refered to "
"and grouped as 'layers'. They are rendered in sequential order, so, layer 1 "
"obscures layer 0, and so on.\n\n"
"BasicClouds is not affected by scene lighting and is therefore not appropriate "
"for scenes in which lighting radically changes, such as day/night.\n\n"
"@ingroup Atmosphere"
);
U32 BasicClouds::smVertStride = 50;
U32 BasicClouds::smStrideMinusOne = 49;
U32 BasicClouds::smVertCount = 50 * 50;
U32 BasicClouds::smTriangleCount = smStrideMinusOne * smStrideMinusOne * 2;
BasicClouds::BasicClouds()
{
mTypeMask |= EnvironmentObjectType | StaticObjectType;
mNetFlags.set(Ghostable | ScopeAlways);
mLayerEnabled[0] = true;
mLayerEnabled[1] = true;
mLayerEnabled[2] = true;
// Default textures are assigned by the ObjectBuilderGui.
//mTexName[0] = "art/skies/clouds/cloud1";
//mTexName[1] = "art/skies/clouds/cloud2";
//mTexName[2] = "art/skies/clouds/cloud3";
mHeight[0] = 4.0f;
mHeight[1] = 3.0f;
mHeight[2] = 2.0f;
mTexSpeed[0] = 0.0005f;
mTexSpeed[1] = 0.001f;
mTexSpeed[2] = 0.0003f;
mTexScale[0] = 1.0;
mTexScale[1] = 1.0;
mTexScale[2] = 1.0;
mTexDirection[0].set( 1.0f, 0.0f );
mTexDirection[1].set( 1.0f, 0.0f );
mTexDirection[2].set( 1.0f, 0.0f );
mTexOffset[0].set( 0.5f, 0.5f );
mTexOffset[1].set( 0.5f, 0.5f );
mTexOffset[2].set( 0.5f, 0.5f );
}
IMPLEMENT_CO_NETOBJECT_V1( BasicClouds );
// ConsoleObject...
bool BasicClouds::onAdd()
{
if ( !Parent::onAdd() )
return false;
setGlobalBounds();
resetWorldBox();
addToScene();
if ( isClientObject() )
{
_initTexture();
_initBuffers();
// Find ShaderData
ShaderData *shaderData;
mShader = Sim::findObject( "BasicCloudsShader", shaderData ) ? shaderData->getShader() : NULL;
if ( !mShader )
{
Con::errorf( "BasicClouds::onAdd - could not find BasicCloudsShader" );
return false;
}
// Create ShaderConstBuffer and Handles
mShaderConsts = mShader->allocConstBuffer();
mModelViewProjSC = mShader->getShaderConstHandle( "$modelView" );
mTimeSC = mShader->getShaderConstHandle( "$accumTime" );
mTexScaleSC = mShader->getShaderConstHandle( "$texScale" );
mTexDirectionSC = mShader->getShaderConstHandle( "$texDirection" );
mTexOffsetSC = mShader->getShaderConstHandle( "$texOffset" );
// Create StateBlocks
GFXStateBlockDesc desc;
desc.setCullMode( GFXCullNone );
desc.setBlend( true );
desc.setZReadWrite( false, false );
desc.samplersDefined = true;
desc.samplers[0].addressModeU = GFXAddressWrap;
desc.samplers[0].addressModeV = GFXAddressWrap;
desc.samplers[0].addressModeW = GFXAddressWrap;
desc.samplers[0].magFilter = GFXTextureFilterLinear;
desc.samplers[0].minFilter = GFXTextureFilterLinear;
desc.samplers[0].mipFilter = GFXTextureFilterLinear;
desc.samplers[0].textureColorOp = GFXTOPModulate;
mStateblock = GFX->createStateBlock( desc );
}
return true;
}
void BasicClouds::onRemove()
{
removeFromScene();
Parent::onRemove();
}
void BasicClouds::initPersistFields()
{
addGroup( "BasicClouds" );
addArray( "Layers", TEX_COUNT );
addField( "layerEnabled", TypeBool, Offset( mLayerEnabled, BasicClouds ), TEX_COUNT,
"Enable or disable rendering of this layer." );
addField( "texture", TypeImageFilename, Offset( mTexName, BasicClouds ), TEX_COUNT,
"Texture for this layer." );
addField( "texScale", TypeF32, Offset( mTexScale, BasicClouds ), TEX_COUNT,
"Texture repeat for this layer." );
addField( "texDirection", TypePoint2F, Offset( mTexDirection, BasicClouds ), TEX_COUNT,
"Texture scroll direction for this layer, relative to the world axis." );
addField( "texSpeed", TypeF32, Offset( mTexSpeed, BasicClouds ), TEX_COUNT,
"Texture scroll speed for this layer." );
addField( "texOffset", TypePoint2F, Offset( mTexOffset, BasicClouds ), TEX_COUNT,
"UV offset for this layer." );
addField( "height", TypeF32, Offset( mHeight, BasicClouds ), TEX_COUNT,
"Abstract number which controls the curvature and height of the dome mesh" );
endArray( "Layers" );
endGroup( "BasicClouds" );
Parent::initPersistFields();
}
void BasicClouds::inspectPostApply()
{
Parent::inspectPostApply();
setMaskBits( BasicCloudsMask );
}
// NetObject...
U32 BasicClouds::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
{
U32 retMask = Parent::packUpdate( conn, mask, stream );
for ( U32 i = 0; i < TEX_COUNT; i++ )
{
stream->writeFlag( mLayerEnabled[i] );
stream->write( mTexName[i] );
stream->write( mTexScale[i] );
mathWrite( *stream, mTexDirection[i] );
stream->write( mTexSpeed[i] );
mathWrite( *stream, mTexOffset[i] );
stream->write( mHeight[i] );
}
return retMask;
}
void BasicClouds::unpackUpdate( NetConnection *conn, BitStream *stream )
{
Parent::unpackUpdate( conn, stream );
for ( U32 i = 0; i < TEX_COUNT; i++ )
{
mLayerEnabled[i] = stream->readFlag();
stream->read( &mTexName[i] );
stream->read( &mTexScale[i] );
mathRead( *stream, &mTexDirection[i] );
stream->read( &mTexSpeed[i] );
mathRead( *stream, &mTexOffset[i] );
stream->read( &mHeight[i] );
}
if ( isProperlyAdded() )
{
// We could check if the height or texture have actually changed.
_initBuffers();
_initTexture();
}
}
// SceneObject...
void BasicClouds::prepRenderImage( SceneRenderState *state )
{
PROFILE_SCOPE( BasicClouds_prepRenderImage );
bool isEnabled = false;
for ( U32 i = 0; i < TEX_COUNT; i++ )
{
if ( mLayerEnabled[i] )
{
isEnabled = true;
break;
}
}
if ( !isEnabled )
return;
// This should be sufficient for most objects that don't manage zones, and
// don't need to return a specialized RenderImage...
ObjectRenderInst *ri = state->getRenderPass()->allocInst< ObjectRenderInst >();
ri->renderDelegate.bind( this, &BasicClouds::renderObject );
ri->type = RenderPassManager::RIT_Sky;
ri->defaultKey = 0;
ri->defaultKey2 = 0;
state->getRenderPass()->addInst( ri );
}
void BasicClouds::renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mi )
{
GFXTransformSaver saver;
Point3F camPos = state->getCameraPosition();
MatrixF xfm(true);
xfm.setPosition(camPos);
GFX->multWorld(xfm);
if ( state->isReflectPass() )
GFX->setProjectionMatrix( state->getSceneManager()->getNonClipProjection() );
GFX->setShader( mShader );
GFX->setShaderConstBuffer( mShaderConsts );
GFX->setStateBlock( mStateblock );
MatrixF xform(GFX->getProjectionMatrix());
xform *= GFX->getViewMatrix();
xform *= GFX->getWorldMatrix();
mShaderConsts->setSafe( mModelViewProjSC, xform );
mShaderConsts->setSafe( mTimeSC, (F32)Sim::getCurrentTime() / 1000.0f );
GFX->setPrimitiveBuffer( mPB );
for ( U32 i = 0; i < TEX_COUNT; i++ )
{
if ( !mLayerEnabled[i] )
continue;
mShaderConsts->setSafe( mTexScaleSC, mTexScale[i] );
mShaderConsts->setSafe( mTexDirectionSC, mTexDirection[i] * mTexSpeed[i] );
mShaderConsts->setSafe( mTexOffsetSC, mTexOffset[i] );
GFX->setTexture( 0, mTexture[i] );
GFX->setVertexBuffer( mVB[i] );
GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, smVertCount, 0, smTriangleCount );
}
}
// BasicClouds Internal Methods....
void BasicClouds::_initTexture()
{
for ( U32 i = 0; i < TEX_COUNT; i++ )
{
if ( !mLayerEnabled[i] )
{
mTexture[i] = NULL;
continue;
}
if ( mTexName[i].isNotEmpty() )
mTexture[i].set( mTexName[i], &GFXDefaultStaticDiffuseProfile, "BasicClouds" );
if ( mTexture[i].isNull() )
mTexture[i].set( "core/art/warnmat", &GFXDefaultStaticDiffuseProfile, "BasicClouds" );
}
}
void BasicClouds::_initBuffers()
{
// Primitive Buffer... Is shared for all Layers.
mPB.set( GFX, smTriangleCount * 3, smTriangleCount, GFXBufferTypeStatic );
U16 *pIdx = NULL;
mPB.lock(&pIdx);
U32 curIdx = 0;
for ( U32 y = 0; y < smStrideMinusOne; y++ )
{
for ( U32 x = 0; x < smStrideMinusOne; x++ )
{
U32 offset = x + y * smVertStride;
pIdx[curIdx] = offset;
curIdx++;
pIdx[curIdx] = offset + 1;
curIdx++;
pIdx[curIdx] = offset + smVertStride + 1;
curIdx++;
pIdx[curIdx] = offset;
curIdx++;
pIdx[curIdx] = offset + smVertStride + 1;
curIdx++;
pIdx[curIdx] = offset + smVertStride;
curIdx++;
}
}
mPB.unlock();
// Vertex Buffer...
// Each layer has their own so they can be at different heights.
for ( U32 i = 0; i < TEX_COUNT; i++ )
{
Point3F vertScale( 16.0f, 16.0f, mHeight[i] );
F32 zOffset = -( mCos( mSqrt( 1.0f ) ) + 0.01f );
mVB[i].set( GFX, smVertCount, GFXBufferTypeStatic );
GFXVertexPT *pVert = mVB[i].lock();
for ( U32 y = 0; y < smVertStride; y++ )
{
F32 v = ( (F32)y / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
for ( U32 x = 0; x < smVertStride; x++ )
{
F32 u = ( (F32)x / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
F32 sx = u;
F32 sy = v;
F32 sz = mCos( mSqrt( sx*sx + sy*sy ) ) + zOffset;
pVert->point.set( sx, sy, sz );
pVert->point *= vertScale;
pVert->texCoord.set( u, v );
pVert++;
}
}
mVB[i].unlock();
}
}

View file

@ -0,0 +1,122 @@
//-----------------------------------------------------------------------------
// 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 _BASICCLOUDS_H_
#define _BASICCLOUDS_H_
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
#ifndef _GFXTEXTUREHANDLE_H_
#include "gfx/gfxTextureHandle.h"
#endif
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#ifndef _GFXSTATEBLOCK_H_
#include "gfx/gfxStateBlock.h"
#endif
#ifndef _GFXSHADER_H_
#include "gfx/gfxShader.h"
#endif
class BaseMatInstance;
class BasicClouds : public SceneObject
{
typedef SceneObject Parent;
enum
{
BasicCloudsMask = Parent::NextFreeMask,
NextFreeMask = Parent::NextFreeMask << 1,
};
#define TEX_COUNT 3
public:
BasicClouds();
virtual ~BasicClouds() {}
DECLARE_CONOBJECT( BasicClouds );
// ConsoleObject
virtual bool onAdd();
virtual void onRemove();
static void initPersistFields();
virtual void inspectPostApply();
// NetObject
virtual U32 packUpdate( NetConnection *conn, U32 mask, BitStream *stream );
virtual void unpackUpdate( NetConnection *conn, BitStream *stream );
// SceneObject
virtual void prepRenderImage( SceneRenderState *state );
void renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mi );
protected:
void _initTexture();
void _initBuffers();
void _initBuffer( F32 height, GFXVertexBufferHandle<GFXVertexPT> *vb, GFXPrimitiveBufferHandle *pb );
protected:
static U32 smVertStride;
static U32 smStrideMinusOne;
static U32 smVertCount;
static U32 smTriangleCount;
GFXTexHandle mTexture[TEX_COUNT];
GFXStateBlockRef mStateblock;
GFXShaderRef mShader;
GFXShaderConstBufferRef mShaderConsts;
GFXShaderConstHandle *mTimeSC;
GFXShaderConstHandle *mModelViewProjSC;
GFXShaderConstHandle *mTexScaleSC;
GFXShaderConstHandle *mTexDirectionSC;
GFXShaderConstHandle *mTexOffsetSC;
GFXVertexBufferHandle<GFXVertexPT> mVB[TEX_COUNT];
GFXPrimitiveBufferHandle mPB;
// Fields...
bool mLayerEnabled[TEX_COUNT];
String mTexName[TEX_COUNT];
F32 mTexScale[TEX_COUNT];
Point2F mTexDirection[TEX_COUNT];
F32 mTexSpeed[TEX_COUNT];
Point2F mTexOffset[TEX_COUNT];
F32 mHeight[TEX_COUNT];
};
#endif // _BASICCLOUDS_H_

View file

@ -0,0 +1,489 @@
//-----------------------------------------------------------------------------
// 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 "platform/profiler.h"
#include "console/consoleTypes.h"
#include "cloudLayer.h"
#include "gfx/gfxTransformSaver.h"
#include "core/stream/fileStream.h"
#include "core/stream/bitStream.h"
#include "scene/sceneRenderState.h"
#include "renderInstance/renderPassManager.h"
#include "gfx/primBuilder.h"
#include "materials/materialManager.h"
#include "materials/customMaterialDefinition.h"
#include "materials/shaderData.h"
#include "lighting/lightInfo.h"
#include "math/mathIO.h"
ConsoleDocClass( CloudLayer,
"@brief A layer of clouds which change shape over time and are affected by scene lighting.\n\n"
"%CloudLayer always renders overhead, following the camera. It is intended "
"as part of the background of your level, rendering in front of Sky/Sun "
"type objects and behind everything else.\n\n"
"The illusion of clouds forming and changing over time is controlled by the "
"normal/opacity texture and the three sets of texture animation parameters. "
"The texture is sampled three times. The first sample defines overall cloud "
"density, where clouds are likely to form and their general size and shape. "
"The second two samples control how it changes over time; they are "
"combined and used as modifiers to the first sample.\n\n"
"%CloudLayer is affected by scene lighting and is designed to be used in "
"scenes with dynamic lighting or time of day changes.\n\n"
"@ingroup Atmosphere"
);
GFXImplementVertexFormat( GFXCloudVertex )
{
addElement( "POSITION", GFXDeclType_Float3 );
addElement( "NORMAL", GFXDeclType_Float3 );
addElement( "BINORMAL", GFXDeclType_Float3 );
addElement( "TANGENT", GFXDeclType_Float3 );
addElement( "TEXCOORD", GFXDeclType_Float2, 0 );
}
U32 CloudLayer::smVertStride = 50;
U32 CloudLayer::smStrideMinusOne = smVertStride - 1;
U32 CloudLayer::smVertCount = smVertStride * smVertStride;
U32 CloudLayer::smTriangleCount = smStrideMinusOne * smStrideMinusOne * 2;
CloudLayer::CloudLayer()
: mBaseColor( 0.9f, 0.9f, 0.9f, 1.0f ),
mCoverage( 0.5f ),
mExposure( 1.0f ),
mWindSpeed( 1.0f ),
mLastTime( 0 )
{
mTypeMask |= EnvironmentObjectType | StaticObjectType;
mNetFlags.set(Ghostable | ScopeAlways);
mTexScale[0] = 1.0;
mTexScale[1] = 1.0;
mTexScale[2] = 1.0;
mTexDirection[0].set( 1.0f, 0.0f );
mTexDirection[1].set( 0.0f, 1.0f );
mTexDirection[2].set( 0.5f, 0.0f );
mTexSpeed[0] = 0.005f;
mTexSpeed[1] = 0.005f;
mTexSpeed[2] = 0.005f;
mTexOffset[0] = mTexOffset[1] = mTexOffset[2] = Point2F::Zero;
mHeight = 4.0f;
}
IMPLEMENT_CO_NETOBJECT_V1( CloudLayer );
// ConsoleObject...
bool CloudLayer::onAdd()
{
if ( !Parent::onAdd() )
return false;
setGlobalBounds();
resetWorldBox();
addToScene();
if ( isClientObject() )
{
_initTexture();
_initBuffers();
// Find ShaderData
ShaderData *shaderData;
mShader = Sim::findObject( "CloudLayerShader", shaderData ) ?
shaderData->getShader() : NULL;
if ( !mShader )
{
Con::errorf( "CloudLayer::onAdd - could not find CloudLayerShader" );
return false;
}
// Create ShaderConstBuffer and Handles
mShaderConsts = mShader->allocConstBuffer();
mModelViewProjSC = mShader->getShaderConstHandle( "$modelView" );
mEyePosWorldSC = mShader->getShaderConstHandle( "$eyePosWorld" );
mSunVecSC = mShader->getShaderConstHandle( "$sunVec" );
mTexOffsetSC[0] = mShader->getShaderConstHandle( "$texOffset0" );
mTexOffsetSC[1] = mShader->getShaderConstHandle( "$texOffset1" );
mTexOffsetSC[2] = mShader->getShaderConstHandle( "$texOffset2" );
mTexScaleSC = mShader->getShaderConstHandle( "$texScale" );
mAmbientColorSC = mShader->getShaderConstHandle( "$ambientColor" );
mSunColorSC = mShader->getShaderConstHandle( "$sunColor" );
mCoverageSC = mShader->getShaderConstHandle( "$cloudCoverage" );
mExposureSC = mShader->getShaderConstHandle( "$cloudExposure" );
mBaseColorSC = mShader->getShaderConstHandle( "$cloudBaseColor" );
// Create StateBlocks
GFXStateBlockDesc desc;
desc.setCullMode( GFXCullNone );
desc.setBlend( true );
desc.setZReadWrite( false, false );
desc.samplersDefined = true;
desc.samplers[0].addressModeU = GFXAddressWrap;
desc.samplers[0].addressModeV = GFXAddressWrap;
desc.samplers[0].addressModeW = GFXAddressWrap;
desc.samplers[0].magFilter = GFXTextureFilterLinear;
desc.samplers[0].minFilter = GFXTextureFilterLinear;
desc.samplers[0].mipFilter = GFXTextureFilterLinear;
desc.samplers[0].textureColorOp = GFXTOPModulate;
mStateblock = GFX->createStateBlock( desc );
}
return true;
}
void CloudLayer::onRemove()
{
removeFromScene();
Parent::onRemove();
}
void CloudLayer::initPersistFields()
{
addGroup( "CloudLayer" );
addField( "texture", TypeImageFilename, Offset( mTextureName, CloudLayer ),
"An RGBA texture which should contain normals and opacity (density)." );
addArray( "Textures", TEX_COUNT );
addField( "texScale", TypeF32, Offset( mTexScale, CloudLayer ), TEX_COUNT,
"Controls the texture repeat of this slot." );
addField( "texDirection", TypePoint2F, Offset( mTexDirection, CloudLayer ), TEX_COUNT,
"Controls the direction this slot scrolls." );
addField( "texSpeed", TypeF32, Offset( mTexSpeed, CloudLayer ), TEX_COUNT,
"Controls the speed this slot scrolls." );
endArray( "Textures" );
addField( "baseColor", TypeColorF, Offset( mBaseColor, CloudLayer ),
"Base cloud color before lighting." );
addField( "exposure", TypeF32, Offset( mExposure, CloudLayer ),
"Brightness scale so CloudLayer can be overblown if desired." );
addField( "coverage", TypeF32, Offset( mCoverage, CloudLayer ),
"Fraction of sky covered by clouds 0-1." );
addField( "windSpeed", TypeF32, Offset( mWindSpeed, CloudLayer ),
"Overall scalar to texture scroll speed." );
addField( "height", TypeF32, Offset( mHeight, CloudLayer ),
"Abstract number which controls the curvature and height of the dome mesh." );
endGroup( "CloudLayer" );
Parent::initPersistFields();
}
void CloudLayer::inspectPostApply()
{
Parent::inspectPostApply();
setMaskBits( CloudLayerMask );
}
// NetObject...
U32 CloudLayer::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
{
U32 retMask = Parent::packUpdate( conn, mask, stream );
stream->write( mTextureName );
for ( U32 i = 0; i < TEX_COUNT; i++ )
{
stream->write( mTexScale[i] );
stream->write( mTexSpeed[i] );
mathWrite( *stream, mTexDirection[i] );
}
stream->write( mBaseColor );
stream->write( mCoverage );
stream->write( mExposure );
stream->write( mWindSpeed );
stream->write( mHeight );
return retMask;
}
void CloudLayer::unpackUpdate( NetConnection *conn, BitStream *stream )
{
Parent::unpackUpdate( conn, stream );
String oldTextureName = mTextureName;
stream->read( &mTextureName );
for ( U32 i = 0; i < TEX_COUNT; i++ )
{
stream->read( &mTexScale[i] );
stream->read( &mTexSpeed[i] );
mathRead( *stream, &mTexDirection[i] );
}
stream->read( &mBaseColor );
F32 oldCoverage = mCoverage;
stream->read( &mCoverage );
stream->read( &mExposure );
stream->read( &mWindSpeed );
F32 oldHeight = mHeight;
stream->read( &mHeight );
if ( isProperlyAdded() )
{
if ( ( oldTextureName != mTextureName ) || ( ( oldCoverage == 0.0f ) != ( mCoverage == 0.0f ) ) )
_initTexture();
if ( oldHeight != mHeight )
_initBuffers();
}
}
// SceneObject...
void CloudLayer::prepRenderImage( SceneRenderState *state )
{
PROFILE_SCOPE( CloudLayer_prepRenderImage );
if ( mCoverage <= 0.0f )
return;
if ( state->isDiffusePass() )
{
// Scroll textures...
U32 time = Sim::getCurrentTime();
F32 delta = (F32)( time - mLastTime ) / 1000.0f;
mLastTime = time;
for ( U32 i = 0; i < 3; i++ )
{
mTexOffset[i] += mTexDirection[i] * mTexSpeed[i] * delta * mWindSpeed;
}
}
// This should be sufficient for most objects that don't manage zones, and
// don't need to return a specialized RenderImage...
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
ri->renderDelegate.bind( this, &CloudLayer::renderObject );
ri->type = RenderPassManager::RIT_Sky;
ri->defaultKey = 0;
ri->defaultKey2 = 0;
state->getRenderPass()->addInst( ri );
}
void CloudLayer::renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mi )
{
GFXTransformSaver saver;
const Point3F &camPos = state->getCameraPosition();
MatrixF xfm(true);
xfm.setPosition(camPos);
GFX->multWorld(xfm);
if ( state->isReflectPass() )
GFX->setProjectionMatrix( state->getSceneManager()->getNonClipProjection() );
GFX->setShader( mShader );
GFX->setShaderConstBuffer( mShaderConsts );
GFX->setStateBlock( mStateblock );
// Set all the shader consts...
MatrixF xform(GFX->getProjectionMatrix());
xform *= GFX->getViewMatrix();
xform *= GFX->getWorldMatrix();
mShaderConsts->setSafe( mModelViewProjSC, xform );
mShaderConsts->setSafe( mEyePosWorldSC, camPos );
LightInfo *lightinfo = LIGHTMGR->getSpecialLight(LightManager::slSunLightType);
const ColorF &sunlight = state->getAmbientLightColor();
Point3F ambientColor( sunlight.red, sunlight.green, sunlight.blue );
mShaderConsts->setSafe( mAmbientColorSC, ambientColor );
const ColorF &sunColor = lightinfo->getColor();
Point3F data( sunColor.red, sunColor.green, sunColor.blue );
mShaderConsts->setSafe( mSunColorSC, data );
mShaderConsts->setSafe( mSunVecSC, lightinfo->getDirection() );
for ( U32 i = 0; i < TEX_COUNT; i++ )
mShaderConsts->setSafe( mTexOffsetSC[i], mTexOffset[i] );
Point3F scale( mTexScale[0], mTexScale[1], mTexScale[2] );
mShaderConsts->setSafe( mTexScaleSC, scale );
Point3F color;
color.set( mBaseColor.red, mBaseColor.green, mBaseColor.blue );
mShaderConsts->setSafe( mBaseColorSC, color );
mShaderConsts->setSafe( mCoverageSC, mCoverage );
mShaderConsts->setSafe( mExposureSC, mExposure );
GFX->setTexture( 0, mTexture );
GFX->setVertexBuffer( mVB );
GFX->setPrimitiveBuffer( mPB );
GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, smVertCount, 0, smTriangleCount );
}
// CloudLayer Internal Methods....
void CloudLayer::_initTexture()
{
if ( mCoverage <= 0.0f )
{
mTexture = NULL;
return;
}
if ( mTextureName.isNotEmpty() )
mTexture.set( mTextureName, &GFXDefaultStaticDiffuseProfile, "CloudLayer" );
if ( mTexture.isNull() )
mTexture.set( "core/art/warnmat", &GFXDefaultStaticDiffuseProfile, "CloudLayer" );
}
void CloudLayer::_initBuffers()
{
// Vertex Buffer...
Point3F vertScale( 16.0f, 16.0f, mHeight );
F32 zOffset = -( mCos( mSqrt( 1.0f ) ) + 0.01f );
mVB.set( GFX, smVertCount, GFXBufferTypeStatic );
GFXCloudVertex *pVert = mVB.lock();
for ( U32 y = 0; y < smVertStride; y++ )
{
F32 v = ( (F32)y / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
for ( U32 x = 0; x < smVertStride; x++ )
{
F32 u = ( (F32)x / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
F32 sx = u;
F32 sy = v;
F32 sz = mCos( mSqrt( sx*sx + sy*sy ) ) + zOffset;
//F32 sz = 1.0f;
pVert->point.set( sx, sy, sz );
pVert->point *= vertScale;
// The vert to our right.
Point3F rpnt;
F32 ru = ( (F32)( x + 1 ) / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
F32 rv = v;
rpnt.x = ru;
rpnt.y = rv;
rpnt.z = mCos( mSqrt( rpnt.x*rpnt.x + rpnt.y*rpnt.y ) ) + zOffset;
rpnt *= vertScale;
// The vert to our front.
Point3F fpnt;
F32 fu = u;
F32 fv = ( (F32)( y + 1 ) / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
fpnt.x = fu;
fpnt.y = fv;
fpnt.z = mCos( mSqrt( fpnt.x*fpnt.x + fpnt.y*fpnt.y ) ) + zOffset;
fpnt *= vertScale;
Point3F fvec = fpnt - pVert->point;
fvec.normalize();
Point3F rvec = rpnt - pVert->point;
rvec.normalize();
pVert->normal = mCross( fvec, rvec );
pVert->normal.normalize();
pVert->binormal = fvec;
pVert->tangent = rvec;
pVert->texCoord.set( u, v );
pVert++;
}
}
mVB.unlock();
// Primitive Buffer...
mPB.set( GFX, smTriangleCount * 3, smTriangleCount, GFXBufferTypeStatic );
U16 *pIdx = NULL;
mPB.lock(&pIdx);
U32 curIdx = 0;
for ( U32 y = 0; y < smStrideMinusOne; y++ )
{
for ( U32 x = 0; x < smStrideMinusOne; x++ )
{
U32 offset = x + y * smVertStride;
pIdx[curIdx] = offset;
curIdx++;
pIdx[curIdx] = offset + 1;
curIdx++;
pIdx[curIdx] = offset + smVertStride + 1;
curIdx++;
pIdx[curIdx] = offset;
curIdx++;
pIdx[curIdx] = offset + smVertStride + 1;
curIdx++;
pIdx[curIdx] = offset + smVertStride;
curIdx++;
}
}
mPB.unlock();
}

View file

@ -0,0 +1,135 @@
//-----------------------------------------------------------------------------
// 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 _CLOUDLAYER_H_
#define _CLOUDLAYER_H_
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
#ifndef _GFXTEXTUREHANDLE_H_
#include "gfx/gfxTextureHandle.h"
#endif
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#ifndef _MATINSTANCE_H_
#include "materials/matInstance.h"
#endif
GFXDeclareVertexFormat( GFXCloudVertex )
{
Point3F point;
Point3F normal;
Point3F binormal;
Point3F tangent;
Point2F texCoord;
};
class CloudLayer : public SceneObject
{
typedef SceneObject Parent;
enum
{
CloudLayerMask = Parent::NextFreeMask,
NextFreeMask = Parent::NextFreeMask << 1,
};
#define TEX_COUNT 3
public:
CloudLayer();
virtual ~CloudLayer() {}
DECLARE_CONOBJECT( CloudLayer );
// ConsoleObject
virtual bool onAdd();
virtual void onRemove();
static void initPersistFields();
virtual void inspectPostApply();
// NetObject
virtual U32 packUpdate( NetConnection *conn, U32 mask, BitStream *stream );
virtual void unpackUpdate( NetConnection *conn, BitStream *stream );
// SceneObject
void prepRenderImage( SceneRenderState *state );
void renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mi );
protected:
void _initTexture();
void _initBuffers();
protected:
static U32 smVertStride;
static U32 smStrideMinusOne;
static U32 smVertCount;
static U32 smTriangleCount;
GFXTexHandle mTexture;
GFXShaderRef mShader;
GFXStateBlockRef mStateblock;
GFXShaderConstBufferRef mShaderConsts;
GFXShaderConstHandle *mModelViewProjSC;
GFXShaderConstHandle *mAmbientColorSC;
GFXShaderConstHandle *mSunColorSC;
GFXShaderConstHandle *mSunVecSC;
GFXShaderConstHandle *mTexOffsetSC[3];
GFXShaderConstHandle *mTexScaleSC;
GFXShaderConstHandle *mBaseColorSC;
GFXShaderConstHandle *mCoverageSC;
GFXShaderConstHandle *mExposureSC;
GFXShaderConstHandle *mEyePosWorldSC;
GFXVertexBufferHandle<GFXCloudVertex> mVB;
GFXPrimitiveBufferHandle mPB;
Point2F mTexOffset[3];
U32 mLastTime;
// Fields...
String mTextureName;
F32 mTexScale[TEX_COUNT];
Point2F mTexDirection[TEX_COUNT];
F32 mTexSpeed[TEX_COUNT];
ColorF mBaseColor;
F32 mExposure;
F32 mCoverage;
F32 mWindSpeed;
F32 mHeight;
};
#endif // _CLOUDLAYER_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 _DECALROAD_H_
#define _DECALROAD_H_
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#ifndef _CLIPPEDPOLYLIST_H_
#include "collision/clippedPolyList.h"
#endif
class Path;
class TerrainBlock;
struct ObjectRenderInst;
class Material;
struct DecalRoadNodeList;
class DecalRoadUpdateEvent : public SimEvent
{
typedef SimEvent Parent;
public:
DecalRoadUpdateEvent( U32 mask, U32 ms ) { mMask = mask; mMs = ms; }
virtual void process( SimObject *object );
U32 mMask;
U32 mMs;
};
struct RoadNode
{
/// The 3D position of the node.
Point3F point;
/// The width of the road at this node.
F32 width;
/// Alpha of the road at this node.
//F32 alpha;
};
typedef Vector<RoadNode> RoadNodeVector;
struct RoadEdge
{
RoadEdge()
{
p0.zero();
p1.zero();
p2.zero();
uvec.zero();
fvec.zero();
rvec.zero();
width = 0.0f;
parentNodeIdx = -1;
};
Point3F p0;
Point3F p1;
Point3F p2;
VectorF uvec;
VectorF fvec;
VectorF rvec;
F32 width;
U32 parentNodeIdx;
};
typedef Vector<RoadEdge> RoadEdgeVector;
struct RoadBatch
{
U32 startVert;
U32 endVert;
U32 startIndex;
U32 endIndex;
Box3F bounds;
};
typedef Vector<RoadBatch> RoadBatchVector;
//------------------------------------------------------------------------------
// DecalRoad Class
//------------------------------------------------------------------------------
class DecalRoad : public SceneObject
{
private:
friend class DecalRoadUpdateEvent;
friend class GuiRoadEditorCtrl;
friend class GuiRoadEditorUndoAction;
typedef SceneObject Parent;
protected:
// Internal defines, enums, structs, classes
struct Triangle
{
GFXVertexPT v0, v1, v2;
};
enum
{
DecalRoadMask = Parent::NextFreeMask,
NodeMask = Parent::NextFreeMask << 1,
GenEdgesMask = Parent::NextFreeMask << 2,
ReClipMask = Parent::NextFreeMask << 3,
TerrainChangedMask = Parent::NextFreeMask << 4,
NextFreeMask = Parent::NextFreeMask << 5,
};
#define StepSize_Normal 10.0f
#define MIN_METERS_PER_SEGMENT 1.0f
public:
DecalRoad();
~DecalRoad();
DECLARE_CONOBJECT(DecalRoad);
// ConsoleObject
static void initPersistFields();
static void consoleInit();
// SimObject
bool onAdd();
void onRemove();
void onEditorEnable();
void onEditorDisable();
void inspectPostApply();
void onStaticModified(const char* slotName, const char*newValue = NULL);
void writeFields(Stream &stream, U32 tabStop);
bool writeField( StringTableEntry fieldname, const char *value );
// NetObject
U32 packUpdate(NetConnection *, U32, BitStream *);
void unpackUpdate(NetConnection *, BitStream *);
// SceneObject
virtual void prepRenderImage( SceneRenderState* state );
virtual void setTransform( const MatrixF &mat );
virtual void setScale( const VectorF &scale );
virtual bool containsPoint( const Point3F& point ) const { return containsPoint( point, NULL ); }
// fxRoad Public Methods
void scheduleUpdate( U32 updateMask );
void scheduleUpdate( U32 updateMask, U32 delayMs, bool restartTimer );
void regenerate();
void setTextureLength( F32 meters );
void setBreakAngle( F32 degrees );
/// Insert a node anywhere in the road.
/// Pass idx zero to add to the front and idx U32_MAX to add to the end
U32 insertNode( const Point3F &pos, const F32 &width, const U32 &idx );
U32 addNode( const Point3F &pos, F32 width = 10.0f );
void deleteNode( U32 idx );
void buildNodesFromList( DecalRoadNodeList* list );
bool getClosestNode( const Point3F &pos, U32 &idx );
bool containsPoint( const Point3F &worldPos, U32 *nodeIdx ) const;
bool castray( const Point3F &start, const Point3F &end ) const;
Point3F getNodePosition( U32 idx );
void setNodePosition( U32 idx, const Point3F &pos );
F32 getNodeWidth( U32 idx );
void setNodeWidth( U32 idx, F32 width );
/// Protected 'Node' Field setter that will add a node to the list.
static bool addNodeFromField( void *object, const char *index, const char *data );
static SimSet* getServerSet();
protected:
// Internal Helper Methods
void _initMaterial();
void _debugRender( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *matInst );
U32 _insertNode( const Point3F &pos, const F32 &width, const U32 &idx );
U32 _addNode( const Point3F &pos, F32 width );
void _generateEdges();
void _captureVerts();
bool _getTerrainHeight( Point3F &pos );
bool _getTerrainHeight( const Point2F &pos, F32 &height );
bool _getTerrainHeight( const F32 &x, const F32 &y, F32 &height );
void _onTerrainChanged( U32 type, TerrainBlock* tblock, const Point2I &min, const Point2I &max );
// static protected field set methods
static bool ptSetBreakAngle( void *object, const char *index, const char *data );
static bool ptSetTextureLength( void *object, const char *index, const char *data );
protected:
// Field Vars
F32 mBreakAngle;
U32 mSegmentsPerBatch;
F32 mTextureLength;
String mMaterialName;
U32 mRenderPriority;
// Static ConsoleVars for editor
static bool smEditorOpen;
static bool smWireframe;
static bool smShowBatches;
static bool smDiscardAll;
static bool smShowSpline;
static bool smShowRoad;
static S32 smUpdateDelay;
static SimObjectPtr<SimSet> smServerDecalRoadSet;
// Other Internal Vars
RoadEdgeVector mEdges;
RoadNodeVector mNodes;
RoadBatchVector mBatches;
bool mLoadRenderData;
SimObjectPtr<Material> mMaterial;
BaseMatInstance *mMatInst;
GFXVertexBufferHandle<GFXVertexPNTBT> mVB;
GFXPrimitiveBufferHandle mPB;
U32 mTriangleCount;
U32 mVertCount;
S32 mUpdateEventId;
DecalRoadUpdateEvent *mLastEvent;
Box3F mTerrainUpdateRect;
};
#endif // _DECALROAD_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,178 @@
//-----------------------------------------------------------------------------
// 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 _GUIMESHROADEDITORCTRL_H_
#define _GUIMESHROADEDITORCTRL_H_
#ifndef _EDITTSCTRL_H_
#include "gui/worldEditor/editTSCtrl.h"
#endif
#ifndef _UNDO_H_
#include "util/undo.h"
#endif
#ifndef _GIZMO_H_
#include "gui/worldEditor/gizmo.h"
#endif
#ifndef _MESHROAD_H_
#include "environment/meshRoad.h"
#endif
class GameBase;
class GuiMeshRoadEditorCtrl : public EditTSCtrl
{
typedef EditTSCtrl Parent;
public:
friend class GuiMeshRoadEditorUndoAction;
String mSelectMeshRoadMode;
String mAddMeshRoadMode;
String mAddNodeMode;
String mInsertPointMode;
String mRemovePointMode;
String mMovePointMode;
String mScalePointMode;
String mRotatePointMode;
GuiMeshRoadEditorCtrl();
~GuiMeshRoadEditorCtrl();
DECLARE_CONOBJECT(GuiMeshRoadEditorCtrl);
// SimObject
bool onAdd();
static void initPersistFields();
// GuiControl
virtual void onSleep();
// EditTSCtrl
bool onKeyDown(const GuiEvent& event);
void get3DCursor( GuiCursor *&cursor, bool &visible, const Gui3DMouseEvent &event_ );
void on3DMouseDown(const Gui3DMouseEvent & event);
void on3DMouseUp(const Gui3DMouseEvent & event);
void on3DMouseMove(const Gui3DMouseEvent & event);
void on3DMouseDragged(const Gui3DMouseEvent & event);
void on3DMouseEnter(const Gui3DMouseEvent & event);
void on3DMouseLeave(const Gui3DMouseEvent & event);
void on3DRightMouseDown(const Gui3DMouseEvent & event);
void on3DRightMouseUp(const Gui3DMouseEvent & event);
void updateGuiInfo();
void renderScene(const RectI & updateRect);
// GuiRiverEditorCtrl
bool getStaticPos( const Gui3DMouseEvent & event, Point3F &tpos );
void deleteSelectedNode();
void deleteSelectedRoad( bool undoAble = true );
void setMode( String mode, bool sourceShortcut );
String getMode() { return mMode; }
void setSelectedRoad( MeshRoad *road );
MeshRoad* getSelectedRoad() { return mSelRoad; };
void setSelectedNode( S32 node );
F32 getNodeWidth();
void setNodeWidth( F32 width );
F32 getNodeDepth();
void setNodeDepth( F32 depth );
Point3F getNodePosition();
void setNodePosition( Point3F pos );
VectorF getNodeNormal();
void setNodeNormal( const VectorF &normal );
void matchTerrainToRoad();
protected:
enum {
Top = 0,
Bottom = 1,
Side = 2,
SurfaceCount = 3
};
S32 _getNodeAtScreenPos( const MeshRoad *pRoad, const Point2I &posi );
void _drawSpline( MeshRoad *road, const ColorI &color );
void _drawControlNodes( MeshRoad *road, const ColorI &color );
void submitUndo( const UTF8 *name = "Action" );
GFXStateBlockRef mZDisableSB;
GFXStateBlockRef mZEnableSB;
bool mSavedDrag;
bool mIsDirty;
SimSet *mRoadSet;
S32 mSelNode;
S32 mHoverNode;
U32 mAddNodeIdx;
SimObjectPtr<MeshRoad> mSelRoad;
SimObjectPtr<MeshRoad> mHoverRoad;
String mMode;
F32 mDefaultWidth;
F32 mDefaultDepth;
VectorF mDefaultNormal;
Point2I mNodeHalfSize;
ColorI mHoverSplineColor;
ColorI mSelectedSplineColor;
ColorI mHoverNodeColor;
bool mHasCopied;
public:
StringTableEntry mMaterialName[SurfaceCount];
};
class GuiMeshRoadEditorUndoAction : public UndoAction
{
public:
GuiMeshRoadEditorUndoAction( const UTF8* actionName ) : UndoAction( actionName )
{
}
GuiMeshRoadEditorCtrl *mEditor;
Vector<MeshRoadNode> mNodes;
SimObjectId mObjId;
F32 mMetersPerSegment;
virtual void undo();
virtual void redo() { undo(); }
};
#endif // _GUIMESHROADEDITORCTRL_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,200 @@
//-----------------------------------------------------------------------------
// 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 _GUIRIVEREDITORCTRL_H_
#define _GUIRIVEREDITORCTRL_H_
#ifndef _EDITTSCTRL_H_
#include "gui/worldEditor/editTSCtrl.h"
#endif
#ifndef _UNDO_H_
#include "util/undo.h"
#endif
#ifndef _RIVER_H_
#include "environment/river.h"
#endif
#ifndef _GIZMO_H_
#include "gui/worldEditor/gizmo.h"
#endif
struct ObjectRenderInst;
class SceneManager;
class SceneRenderState;
class BaseMatInstance;
class GuiRiverEditorCtrl : public EditTSCtrl
{
typedef EditTSCtrl Parent;
public:
friend class GuiRiverEditorUndoAction;
//static StringTableEntry smNormalMode;
//static StringTableEntry smAddNodeMode;
String mSelectRiverMode;
String mAddRiverMode;
String mAddNodeMode;
String mInsertPointMode;
String mRemovePointMode;
String mMovePointMode;
String mScalePointMode;
String mRotatePointMode;
GuiRiverEditorCtrl();
~GuiRiverEditorCtrl();
DECLARE_CONOBJECT(GuiRiverEditorCtrl);
// SimObject
bool onAdd();
static void initPersistFields();
// GuiControl
virtual void onSleep();
virtual void onRender(Point2I offset, const RectI &updateRect);
// EditTSCtrl
bool onKeyDown(const GuiEvent& event);
void get3DCursor( GuiCursor *&cursor, bool &visible, const Gui3DMouseEvent &event_ );
void on3DMouseDown(const Gui3DMouseEvent & event);
void on3DMouseUp(const Gui3DMouseEvent & event);
void on3DMouseMove(const Gui3DMouseEvent & event);
void on3DMouseDragged(const Gui3DMouseEvent & event);
void on3DMouseEnter(const Gui3DMouseEvent & event);
void on3DMouseLeave(const Gui3DMouseEvent & event);
void on3DRightMouseDown(const Gui3DMouseEvent & event);
void on3DRightMouseUp(const Gui3DMouseEvent & event);
void updateGuiInfo();
void renderScene(const RectI & updateRect);
// GuiRiverEditorCtrl
bool getStaticPos( const Gui3DMouseEvent & event, Point3F &tpos );
void deleteSelectedNode();
void deleteSelectedRiver( bool undoAble = true );
void setMode( String mode, bool sourceShortcut );
String getMode() { return mMode; }
//void setGizmoMode( Gizmo::Mode mode ) { mGizmo->setMode( mode ); }
void setSelectedRiver( River *river );
River* getSelectedRiver() { return mSelRiver; };
void setSelectedNode( S32 node );
F32 getNodeWidth();
void setNodeWidth( F32 width );
F32 getNodeDepth();
void setNodeDepth( F32 depth );
Point3F getNodePosition();
void setNodePosition( Point3F pos );
VectorF getNodeNormal();
void setNodeNormal( const VectorF &normal );
protected:
void _renderSelectedRiver( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *matInst );
void _prepRenderImage( SceneManager* sceneGraph, const SceneRenderState* sceneState );
void _drawRiverSpline( River *river, const ColorI &color );
void _drawRiverControlNodes( River *river, const ColorI &color );
void submitUndo( const UTF8 *name = "Action" );
GFXStateBlockRef mZDisableSB;
GFXStateBlockRef mZEnableSB;
bool mSavedDrag;
bool mIsDirty;
SimSet *mRiverSet;
S32 mSelNode;
S32 mHoverNode;
U32 mAddNodeIdx;
SimObjectPtr<River> mSelRiver;
SimObjectPtr<River> mHoverRiver;
String mMode;
F32 mDefaultWidth;
F32 mDefaultDepth;
VectorF mDefaultNormal;
S32 mInsertIdx;
F32 mStartHeight;
F32 mStartWidth;
S32 mStartX;
Point3F mStartWorld;
Point2I mNodeHalfSize;
//Gizmo mGizmo;
Gui3DMouseEvent mLastMouseEvent;
F32 mNodeSphereRadius;
ColorI mNodeSphereFillColor;
ColorI mNodeSphereLineColor;
ColorI mHoverSplineColor;
ColorI mSelectedSplineColor;
ColorI mHoverNodeColor;
#define InvalidMousePoint Point2I(-100,-100)
Point2I mStartDragMousePoint;
Point3F mStartDragNodePos;
//GuiCursor *mMoveNodeCursor;
//GuiCursor *mAddNodeCursor;
//GuiCursor *mInsertNodeCursor;
//GuiCursor *mResizeNodeCursor;
};
class GuiRiverEditorUndoAction : public UndoAction
{
public:
GuiRiverEditorUndoAction( const UTF8* actionName ) : UndoAction( actionName )
{
}
GuiRiverEditorCtrl *mRiverEditor;
Vector<RiverNode> mNodes;
SimObjectId mObjId;
F32 mMetersPerSegment;
U32 mSegmentsPerBatch;
virtual void undo();
virtual void redo() { undo(); }
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,168 @@
//-----------------------------------------------------------------------------
// 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 _GUIROADEDITORCTRL_H_
#define _GUIROADEDITORCTRL_H_
#ifndef _EDITTSCTRL_H_
#include "gui/worldEditor/editTSCtrl.h"
#endif
#ifndef _UNDO_H_
#include "util/undo.h"
#endif
#ifndef _DECALROAD_H_
#include "environment/decalRoad.h"
#endif
class GameBase;
class DecalRoad;
class GuiRoadEditorCtrl : public EditTSCtrl
{
typedef EditTSCtrl Parent;
public:
friend class GuiRoadEditorUndoAction;
String mSelectRoadMode;
String mAddRoadMode;
String mAddNodeMode;
String mInsertPointMode;
String mRemovePointMode;
String mMovePointMode;
String mScalePointMode;
GuiRoadEditorCtrl();
~GuiRoadEditorCtrl();
DECLARE_CONOBJECT(GuiRoadEditorCtrl);
// SimObject
bool onAdd();
static void initPersistFields();
// GuiControl
virtual void onSleep();
virtual void onRender(Point2I offset, const RectI &updateRect);
// EditTSCtrl
bool onKeyDown(const GuiEvent& event);
void get3DCursor( GuiCursor *&cursor, bool &visible, const Gui3DMouseEvent &event_ );
void on3DMouseDown(const Gui3DMouseEvent & event);
void on3DMouseUp(const Gui3DMouseEvent & event);
void on3DMouseMove(const Gui3DMouseEvent & event);
void on3DMouseDragged(const Gui3DMouseEvent & event);
void on3DMouseEnter(const Gui3DMouseEvent & event);
void on3DMouseLeave(const Gui3DMouseEvent & event);
void on3DRightMouseDown(const Gui3DMouseEvent & event);
void on3DRightMouseUp(const Gui3DMouseEvent & event);
void updateGuiInfo();
void renderScene(const RectI & updateRect);
void renderGui(Point2I offset, const RectI &updateRect);
bool getTerrainPos( const Gui3DMouseEvent & event, Point3F &tpos );
void deleteSelectedNode();
void deleteSelectedRoad( bool undoAble = true );
void setMode( String mode, bool sourceShortcut );
String getMode() { return mMode; }
void setSelectedRoad( DecalRoad *road );
DecalRoad* getSelectedRoad() { return mSelRoad; };
void setSelectedNode( S32 node );
S32 getSelectedNode() { return mSelNode; };
F32 getNodeWidth();
void setNodeWidth( F32 width );
Point3F getNodePosition();
void setNodePosition( Point3F pos );
void setTextureFile( StringTableEntry file );
public:
StringTableEntry mMaterialName;
protected:
void _drawRoadSpline( DecalRoad *road, const ColorI &color );
void _drawRoadControlNodes( DecalRoad *road, const ColorI &color );
void submitUndo( const UTF8 *name );
bool mSavedDrag;
bool mIsDirty;
SimSet *mRoadSet;
S32 mSelNode;
S32 mHoverNode;
U32 mAddNodeIdx;
SimObjectPtr<DecalRoad> mSelRoad;
SimObjectPtr<DecalRoad> mHoverRoad;
ColorI mHoverSplineColor;
ColorI mSelectedSplineColor;
ColorI mHoverNodeColor;
String mMode;
F32 mDefaultWidth;
S32 mInsertIdx;
F32 mStartWidth;
S32 mStartX;
Point3F mStartWorld;
Point2I mNodeHalfSize;
// StateBlock for rendering road splines.
GFXStateBlockRef mZDisableSB;
};
class GuiRoadEditorUndoAction : public UndoAction
{
public:
GuiRoadEditorUndoAction( const UTF8* actionName ) : UndoAction( actionName )
{
}
GuiRoadEditorCtrl *mRoadEditor;
Vector<RoadNode> mNodes;
SimObjectId mObjId;
String mMaterialName;
F32 mBreakAngle;
U32 mSegmentsPerBatch;
F32 mTextureLength;
virtual void undo();
virtual void redo() { undo(); }
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,566 @@
//-----------------------------------------------------------------------------
// 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 _MESHROAD_H_
#define _MESHROAD_H_
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
#ifndef _GFXTEXTUREHANDLE_H_
#include "gfx/gfxTextureHandle.h"
#endif
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#ifndef _CLIPPEDPOLYLIST_H_
#include "collision/clippedPolyList.h"
#endif
#ifndef _MATINSTANCE_H_
#include "materials/matInstance.h"
#endif
#ifndef _CONVEX_H_
#include "collision/convex.h"
#endif
//extern U32 gIdxArray[6][2][3];
struct MeshRoadHitSegment
{
U32 idx;
F32 t;
};
class MeshRoad;
//-------------------------------------------------------------------------
// MeshRoadConvex Class
//-------------------------------------------------------------------------
class MeshRoadConvex : public Convex
{
typedef Convex Parent;
friend class MeshRoad;
protected:
MeshRoad *pRoad;
public:
U32 faceId;
U32 triangleId;
U32 segmentId;
Point3F verts[4];
PlaneF normal;
Box3F box;
public:
MeshRoadConvex() { mType = MeshRoadConvexType; }
MeshRoadConvex( const MeshRoadConvex& cv ) {
mType = MeshRoadConvexType;
mObject = cv.mObject;
pRoad = cv.pRoad;
faceId = cv.faceId;
triangleId = cv.triangleId;
segmentId = cv.segmentId;
verts[0] = cv.verts[0];
verts[1] = cv.verts[1];
verts[2] = cv.verts[2];
verts[3] = cv.verts[3];
normal = cv.normal;
box = cv.box;
}
const MatrixF& getTransform() const;
Box3F getBoundingBox() const;
Box3F getBoundingBox(const MatrixF& mat, const Point3F& scale) const;
Point3F support(const VectorF& vec) const;
void getFeatures(const MatrixF& mat,const VectorF& n, ConvexFeature* cf);
void getPolyList(AbstractPolyList* list);
};
//-------------------------------------------------------------------------
// MeshRoadSplineNode Class
//-------------------------------------------------------------------------
class Path;
class TerrainBlock;
struct ObjectRenderInst;
class MeshRoadSplineNode
{
public:
MeshRoadSplineNode() {}
F32 x;
F32 y;
F32 z;
F32 width;
F32 depth;
VectorF normal;
MeshRoadSplineNode& operator=(const MeshRoadSplineNode&);
MeshRoadSplineNode operator+(const MeshRoadSplineNode&) const;
MeshRoadSplineNode operator-(const MeshRoadSplineNode&) const;
MeshRoadSplineNode operator*(const F32) const;
F32 len();
Point3F getPosition() const { return Point3F(x,y,z); };
};
inline F32 MeshRoadSplineNode::len()
{
return mSqrt(F32(x*x + y*y + z*z));
}
inline MeshRoadSplineNode& MeshRoadSplineNode::operator=(const MeshRoadSplineNode &_node)
{
x = _node.x;
y = _node.y;
z = _node.z;
width = _node.width;
depth = _node.depth;
normal = _node.normal;
return *this;
}
inline MeshRoadSplineNode MeshRoadSplineNode::operator+(const MeshRoadSplineNode& _add) const
{
MeshRoadSplineNode result;
result.x = x + _add.x;
result.y = y + _add.y;
result.z = z + _add.z;
result.width = width + _add.width;
result.depth = depth + _add.depth;
result.normal = normal + _add.normal;
return result;
}
inline MeshRoadSplineNode MeshRoadSplineNode::operator-(const MeshRoadSplineNode& _rSub) const
{
MeshRoadSplineNode result;
result.x = x - _rSub.x;
result.y = y - _rSub.y;
result.z = z - _rSub.z;
result.width = width - _rSub.width;
result.depth = depth - _rSub.depth;
result.normal = normal - _rSub.normal;
return result;
}
inline MeshRoadSplineNode operator*(const F32 mul, const MeshRoadSplineNode& multiplicand)
{
return multiplicand * mul;
}
inline MeshRoadSplineNode MeshRoadSplineNode::operator*(const F32 _mul) const
{
MeshRoadSplineNode result;
result.x = x * _mul;
result.y = y * _mul;
result.z = z * _mul;
result.width = width * _mul;
result.depth = depth * _mul;
result.normal = normal * _mul;
return result;
}
//-------------------------------------------------------------------------
// Structures
//-------------------------------------------------------------------------
struct MeshRoadRenderBatch
{
U32 startSegmentIdx;
U32 endSegmentIdx;
U32 startVert;
U32 endVert;
U32 startIndex;
U32 endIndex;
U32 totalRows;
U32 indexCount;
U32 vertCount;
U32 triangleCount;
};
typedef Vector<MeshRoadRenderBatch> MeshRoadBatchVector;
struct MeshRoadNode
{
// The 3D position of the node
Point3F point;
// The width of the River at this node (meters)
F32 width;
// The depth of the River at this node (meters)
F32 depth;
VectorF normal;
};
typedef Vector<MeshRoadNode> MeshRoadNodeVector;
struct MeshRoadSlice
{
MeshRoadSlice()
{
p0.zero();
p1.zero();
p2.zero();
pb0.zero();
pb2.zero();
uvec.zero();
fvec.zero();
rvec.zero();
width = 0.0f;
depth = 0.0f;
normal.set(0,0,1);
texCoordV = 0.0f;
parentNodeIdx = -1;
};
Point3F p0; // upper left
Point3F p1; // upper center
Point3F p2; // upper right
Point3F pb0; // bottom left
Point3F pb2; // bottom right
VectorF uvec;
VectorF fvec;
VectorF rvec;
F32 width;
F32 depth;
Point3F normal;
F32 t;
F32 texCoordV;
U32 parentNodeIdx;
};
typedef Vector<MeshRoadSlice> MeshRoadSliceVector;
//-------------------------------------------------------------------------
// MeshRoadSegment Class
//-------------------------------------------------------------------------
class MeshRoadSegment
{
public:
MeshRoadSegment();
MeshRoadSegment( MeshRoadSlice *rs0, MeshRoadSlice *rs1, const MatrixF &roadMat );
void set( MeshRoadSlice *rs0, MeshRoadSlice *rs1 );
F32 TexCoordStart() const { return slice0->texCoordV; }
F32 TexCoordEnd() const { return slice1->texCoordV; }
const Point3F& getP00() const { return slice0->p0; }
const Point3F& getP01() const { return slice1->p0; }
const Point3F& getP11() const { return slice1->p2; }
const Point3F& getP10() const { return slice0->p2; }
Point3F getSurfaceCenter() const { return ( slice0->p1 + slice1->p1 ) / 2.0f; }
Point3F getSurfaceNormal() const { return -mPlanes[4].getNormal(); }
bool intersectBox( const Box3F &bounds ) const;
bool containsPoint( const Point3F &pnt ) const;
F32 distanceToSurface( const Point3F &pnt ) const;
F32 length() const { return ( slice1->p1 - slice0->p1 ).len(); }
// Quick access to the segment's points
Point3F& operator[](U32);
const Point3F& operator[](U32) const;
Point3F& operator[](S32 i) { return operator[](U32(i)); }
const Point3F& operator[](S32 i ) const { return operator[](U32(i)); }
const Box3F& getWorldBounds() const { return worldbounds; }
MeshRoadSlice *slice0;
MeshRoadSlice *slice1;
protected:
PlaneF mPlanes[6];
U32 mPlaneCount;
U32 columns;
U32 rows;
U32 startVert;
U32 endVert;
U32 startIndex;
U32 endIndex;
U32 numVerts;
U32 numTriangles;
Box3F objectbounds;
Box3F worldbounds;
};
typedef Vector<MeshRoadSegment> MeshRoadSegmentVector;
inline Point3F& MeshRoadSegment::operator[](U32 index)
{
AssertFatal(index < 8, "MeshRoadSegment::operator[] - out of bounds array access!");
MeshRoadSlice *slice = NULL;
if ( index > 3 )
{
slice = slice1;
index -= 4;
}
else
{
slice = slice0;
}
if ( index == 0 )
return slice->p0;
if ( index == 1 )
return slice->p2;
if ( index == 2 )
return slice->pb0;
else //( index == 3 )
return slice->pb2;
}
inline const Point3F& MeshRoadSegment::operator[](U32 index) const
{
AssertFatal(index < 8, "MeshRoadSegment::operator[] - out of bounds array access!");
MeshRoadSlice *slice = NULL;
if ( index > 3 )
{
slice = slice1;
index -= 4;
}
else
{
slice = slice0;
}
if ( index == 0 )
return slice->p0;
if ( index == 1 )
return slice->p2;
if ( index == 2 )
return slice->pb0;
else// ( index == 3 )
return slice->pb2;
}
//------------------------------------------------------------------------------
// MeshRoad Class
//------------------------------------------------------------------------------
class PhysicsBody;
struct MeshRoadNodeList;
class MeshRoad : public SceneObject
{
private:
friend class GuiMeshRoadEditorCtrl;
friend class GuiMeshRoadEditorUndoAction;
friend class MeshRoadConvex;
typedef SceneObject Parent;
enum
{
MeshRoadMask = Parent::NextFreeMask,
NodeMask = Parent::NextFreeMask << 1,
RegenMask = Parent::NextFreeMask << 2,
InitialUpdateMask = Parent::NextFreeMask << 3,
SelectedMask = Parent::NextFreeMask << 4,
MaterialMask = Parent::NextFreeMask << 5,
NextFreeMask = Parent::NextFreeMask << 6,
};
public:
MeshRoad();
~MeshRoad();
DECLARE_CONOBJECT(MeshRoad);
// ConObject.
static void initPersistFields();
static void consoleInit();
// SimObject
bool onAdd();
void onRemove();
void onEditorEnable();
void onEditorDisable();
void inspectPostApply();
void onStaticModified(const char* slotName, const char*newValue = NULL);
void writeFields(Stream &stream, U32 tabStop);
bool writeField( StringTableEntry fieldname, const char *value );
// NetObject
U32 packUpdate(NetConnection *, U32, BitStream *);
void unpackUpdate(NetConnection *, BitStream *);
// SceneObject
virtual void prepRenderImage( SceneRenderState* sceneState );
virtual void setTransform( const MatrixF &mat );
virtual void setScale( const VectorF &scale );
// SceneObject - Collision
virtual void buildConvex(const Box3F& box,Convex* convex);
virtual bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere);
virtual bool castRay(const Point3F &start, const Point3F &end, RayInfo* info);
virtual bool collideBox(const Point3F &start, const Point3F &end, RayInfo* info);
// MeshRoad
void regenerate();
void setBatchSize( U32 level );
void setTextureFile( StringTableEntry file );
void setTextureRepeat( F32 meters );
bool collideRay( const Point3F &origin, const Point3F &direction, U32 *nodeIdx = NULL, Point3F *collisionPnt = NULL );
bool buildSegmentPolyList( AbstractPolyList* polyList, U32 startSegIdx, U32 endSegIdx, bool capFront, bool capEnd );
void buildNodesFromList( MeshRoadNodeList* list );
U32 insertNode( const Point3F &pos, const F32 &width, const F32 &depth, const Point3F &normal, const U32 &idx );
U32 addNode( const Point3F &pos, const F32 &width, const F32 &depth, const Point3F &normal );
void deleteNode( U32 idx );
void setNode( const Point3F &pos, const F32 &width, const F32 &depth, const Point3F &normal, const U32 &idx );
const MeshRoadNode& getNode( U32 idx );
VectorF getNodeNormal( U32 idx );
void setNodeNormal( U32 idx, const VectorF &normal );
Point3F getNodePosition( U32 idx );
void setNodePosition( U32 idx, const Point3F &pos );
F32 getNodeWidth( U32 idx );
void setNodeWidth( U32 idx, F32 width );
F32 getNodeDepth( U32 idx );
void setNodeDepth( U32 idx, F32 depth );
MatrixF getNodeTransform( U32 idx );
void calcSliceTransform( U32 idx, MatrixF &mat );
bool isEndNode( U32 idx ) { return ( mNodes.size() > 0 && ( idx == 0 || idx == mNodes.size() - 1 ) ); }
U32 getSegmentCount() { return mSegments.size(); }
const MeshRoadSegment& getSegment( U32 idx ) { return mSegments[idx]; }
F32 getRoadLength() const;
static SimSet* getServerSet();
/// Protected 'Component' Field setter that will add a component to the list.
static bool addNodeFromField( void *object, const char *index, const char *data );
static bool smEditorOpen;
static bool smWireframe;
static bool smShowBatches;
static bool smShowSpline;
static bool smShowRoad;
static SimObjectPtr<SimSet> smServerMeshRoadSet;
protected:
void _initMaterial();
void _debugRender( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance* );
U32 _insertNode( const Point3F &pos, const F32 &width, const F32 &depth, const Point3F &normal, const U32 &idx );
U32 _addNode( const Point3F &pos, const F32 &width, const F32 &depth, const Point3F &normal );
void _regenerate();
void _generateSlices();
void _generateSegments();
void _generateVerts();
protected:
MeshRoadSliceVector mSlices;
MeshRoadNodeVector mNodes;
MeshRoadSegmentVector mSegments;
MeshRoadBatchVector mBatches;
static GFXStateBlockRef smWireframeSB;
enum {
Top = 0,
Bottom = 1,
Side = 2,
SurfaceCount = 3
};
GFXVertexBufferHandle<GFXVertexPNTT> mVB[SurfaceCount];
GFXPrimitiveBufferHandle mPB[SurfaceCount];
String mMaterialName[SurfaceCount];
SimObjectPtr<Material> mMaterial[SurfaceCount];
BaseMatInstance *mMatInst[SurfaceCount];
U32 mVertCount[SurfaceCount];
U32 mTriangleCount[SurfaceCount];
// Fields.
F32 mTextureLength;
F32 mBreakAngle;
S32 mWidthSubdivisions;
// Collision and Physics.
Convex* mConvexList;
Vector<MeshRoadConvex*> mDebugConvex;
PhysicsBody *mPhysicsRep;
};
#endif // _MESHROAD_H_

View file

@ -0,0 +1,275 @@
//-----------------------------------------------------------------------------
// 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 "environment/nodeListManager.h"
#include "core/module.h"
#include "core/stream/bitStream.h"
MODULE_BEGIN( NodeListManager )
MODULE_INIT
{
AssertFatal(gClientNodeListManager == NULL && gServerNodeListManager == NULL, "Error, already initialized the node list manager!");
gClientNodeListManager = new NodeListManager(false);
gServerNodeListManager = new NodeListManager(true);
}
MODULE_SHUTDOWN
{
AssertFatal(gClientNodeListManager != NULL && gServerNodeListManager != NULL, "Error, node list manager not initialized!");
delete gClientNodeListManager;
gClientNodeListManager = NULL;
delete gServerNodeListManager;
gServerNodeListManager = NULL;
}
MODULE_END;
//-----------------------------------------------------------------------------
// NodeListEvent Class
//-----------------------------------------------------------------------------
NodeListEvent::~NodeListEvent()
{
if (mNodeList)
{
// This means the node list wasn't processed
delete mNodeList;
}
}
void NodeListEvent::pack(NetConnection* conn, BitStream* stream)
{
stream->write(mId);
stream->write(mTotalNodes);
stream->write(mLocalListStart);
// NOTE: Child class needs to transmit the nodes
}
void NodeListEvent::write(NetConnection* conn, BitStream *stream)
{
pack(conn, stream);
}
void NodeListEvent::unpack(NetConnection* conn, BitStream* stream)
{
stream->read(&mId);
stream->read(&mTotalNodes);
stream->read(&mLocalListStart);
mNodeList->mId = mId;
// NOTE: Child class needs to populate the local node list
}
void NodeListEvent::process(NetConnection* conn)
{
if (mNodeList)
{
NodeListManager::NodeList* oldList = NULL;
gClientNodeListManager->findListById(mNodeList->mId, &oldList, false);
mergeLists(oldList);
gClientNodeListManager->addNodeList(mNodeList);
mNodeList = NULL;
}
}
void NodeListEvent::mergeLists(NodeListManager::NodeList* oldList)
{
if (oldList)
{
if ( !mNodeList->mListComplete)
{
copyIntoList( oldList );
// Is the node list now complete?
oldList->mTotalValidNodes += mNodeList->mTotalValidNodes;
if (oldList->mTotalValidNodes >= mTotalNodes)
{
oldList->mListComplete = true;
}
delete mNodeList;
mNodeList = oldList;
}
}
else
{
padListToSize();
}
}
IMPLEMENT_CO_NETEVENT_V1(NodeListEvent);
ConsoleDocClass( NodeListEvent,
"@brief Base class for events used by node editors, like River\n\n"
"Editor use only.\n\n"
"@internal"
);
//-----------------------------------------------------------------------------
// NodeListManager Class
//-----------------------------------------------------------------------------
NodeListManager* gClientNodeListManager = NULL;
NodeListManager* gServerNodeListManager = NULL;
U32 NodeListManager::smMaximumNodesPerEvent = 20;
//-----------------------------------------------------------------------------
NodeListManager::NodeListManager(const bool isServer)
{
mIsServer = isServer;
mNextListId = 0;
}
NodeListManager::~NodeListManager()
{
clearAllNotifications();
clearNodeLists();
}
void NodeListManager::clearNodeLists()
{
for ( U32 i=0; i<mNodeLists.size(); ++i )
{
delete mNodeLists[i];
}
mNodeLists.clear();
}
U32 NodeListManager::nextListId()
{
U32 id = mNextListId;
++mNextListId;
return id;
}
void NodeListManager::addNodeList( NodeList* list )
{
// Before we store the node list, we should check if anyone has registered
// an interest in it, but only if the list is complete.
if (list->mListComplete)
{
if (dispatchNotification( list ))
{
delete list;
return;
}
}
// Nothing is registered or the list is not complete, so store the list for later
mNodeLists.push_back( list );
}
bool NodeListManager::findListById(U32 id, NodeList** list, bool completeOnly)
{
*list = NULL;
for (U32 i=0; i<mNodeLists.size(); ++i)
{
if (mNodeLists[i]->mId == id)
{
if (completeOnly && !mNodeLists[i]->mListComplete)
{
// Found the list, but it is not complete.
return false;
}
// Return the node list (complete or not) and remove
// it from our list of lists
*list = mNodeLists[i];
mNodeLists.erase(i);
return true;
}
}
return false;
}
void NodeListManager::clearNotification( U32 listId )
{
for (U32 i=0; i<mNotifyList.size(); ++i)
{
if (mNotifyList[i]->getListId() == listId)
{
delete mNotifyList[i];
mNotifyList.erase(i);
return;
}
}
}
void NodeListManager::clearAllNotifications()
{
for (U32 i=0; i<mNotifyList.size(); ++i)
{
delete mNotifyList[i];
}
mNotifyList.clear();
}
void NodeListManager::registerNotification( NodeListNotify* notify )
{
mNotifyList.push_back( notify );
}
bool NodeListManager::dispatchNotification( U32 listId )
{
// Find the matching list
NodeList* list = NULL;
for (U32 i=0; i<mNodeLists.size(); ++i)
{
if (mNodeLists[i]->mId == listId)
{
list = mNodeLists[i];
break;
}
}
if (list)
return dispatchNotification( list );
return false;
}
bool NodeListManager::dispatchNotification( NodeList* list )
{
for (U32 i=0; i<mNotifyList.size(); ++i)
{
if (mNotifyList[i]->getListId() == list->mId)
{
mNotifyList[i]->sendNotification( list );
delete mNotifyList[i];
mNotifyList.erase(i);
return true;
}
}
return false;
}

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 _NODELISTMANAGER_H_
#define _NODELISTMANAGER_H_
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
#ifndef _MPOINT3_H_
#include "math/mPoint3.h"
#endif
#ifndef _MQUAT_H_
#include "math/mQuat.h"
#endif
#ifndef _NETCONNECTION_H_
#include "sim/netConnection.h"
#endif
//-----------------------------------------------------------------------------
class NodeListNotify;
class NodeListManager
{
public:
struct NodeList
{
U32 mId;
U32 mTotalValidNodes;
bool mListComplete;
NodeList() { mTotalValidNodes=0; mListComplete=false; }
virtual ~NodeList() { }
};
static U32 smMaximumNodesPerEvent;
protected:
bool mIsServer;
U32 mNextListId;
Vector<NodeList*> mNodeLists;
Vector<NodeListNotify*> mNotifyList;
public:
NodeListManager( const bool isServer );
~NodeListManager();
void clearNodeLists();
U32 nextListId();
void addNodeList( NodeList* list );
bool findListById( U32 id, NodeList** list, bool completeOnly=true );
void clearNotification( U32 listId );
void clearAllNotifications();
void registerNotification( NodeListNotify* notify );
bool dispatchNotification( U32 listId );
bool dispatchNotification( NodeList* list );
};
extern NodeListManager* gClientNodeListManager;
extern NodeListManager* gServerNodeListManager;
//-----------------------------------------------------------------------------
class NodeListNotify
{
protected:
U32 mListId;
public:
NodeListNotify() { }
virtual ~NodeListNotify() { }
U32 getListId() { return mListId; }
virtual void sendNotification( NodeListManager::NodeList* list ) { }
};
//-----------------------------------------------------------------------------
class NodeListEvent : public NetEvent
{
typedef NetEvent Parent;
public:
U32 mId;
U32 mTotalNodes;
U32 mLocalListStart;
NodeListManager::NodeList* mNodeList;
public:
NodeListEvent() { mNodeList=NULL; mTotalNodes = mLocalListStart = 0; }
virtual ~NodeListEvent();
virtual void pack(NetConnection*, BitStream*);
virtual void write(NetConnection*, BitStream*);
virtual void unpack(NetConnection*, BitStream*);
virtual void process(NetConnection*);
virtual void mergeLists(NodeListManager::NodeList* oldList);
virtual void copyIntoList(NodeListManager::NodeList* copyInto) { }
virtual void padListToSize() { }
DECLARE_CONOBJECT(NodeListEvent);
};
#endif // _NODELISTMANAGER_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,531 @@
//-----------------------------------------------------------------------------
// 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 _RIVER_H_
#define _RIVER_H_
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
#ifndef _GFXTEXTUREHANDLE_H_
#include "gfx/gfxTextureHandle.h"
#endif
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#ifndef _CLIPPEDPOLYLIST_H_
#include "collision/clippedPolyList.h"
#endif
#ifndef _GFXSTATEBLOCK_H_
#include "gfx/gfxStateBlock.h"
#endif
#ifndef _WATEROBJECT_H_
#include "waterObject.h"
#endif
//-------------------------------------------------------------------------
// RiverSplineNode Class
//-------------------------------------------------------------------------
class Path;
class TerrainBlock;
struct ObjectRenderInst;
class RiverSplineNode
{
public:
RiverSplineNode() {}
F32 x;
F32 y;
F32 z;
F32 width;
F32 depth;
VectorF normal;
RiverSplineNode& operator=(const RiverSplineNode&);
RiverSplineNode operator+(const RiverSplineNode&) const;
RiverSplineNode operator-(const RiverSplineNode&) const;
RiverSplineNode operator*(const F32) const;
F32 len();
};
inline F32 RiverSplineNode::len()
{
return mSqrt(F32(x*x + y*y + z*z));
}
inline RiverSplineNode& RiverSplineNode::operator=(const RiverSplineNode &_node)
{
x = _node.x;
y = _node.y;
z = _node.z;
width = _node.width;
depth = _node.depth;
normal = _node.normal;
return *this;
}
inline RiverSplineNode RiverSplineNode::operator+(const RiverSplineNode& _add) const
{
RiverSplineNode result;
result.x = x + _add.x;
result.y = y + _add.y;
result.z = z + _add.z;
result.width = width + _add.width;
result.depth = depth + _add.depth;
result.normal = normal + _add.normal;
return result;
}
inline RiverSplineNode RiverSplineNode::operator-(const RiverSplineNode& _rSub) const
{
RiverSplineNode result;
result.x = x - _rSub.x;
result.y = y - _rSub.y;
result.z = z - _rSub.z;
result.width = width - _rSub.width;
result.depth = depth - _rSub.depth;
result.normal = normal - _rSub.normal;
return result;
}
inline RiverSplineNode operator*(const F32 mul, const RiverSplineNode& multiplicand)
{
return multiplicand * mul;
}
inline RiverSplineNode RiverSplineNode::operator*(const F32 _mul) const
{
RiverSplineNode result;
result.x = x * _mul;
result.y = y * _mul;
result.z = z * _mul;
result.width = width * _mul;
result.depth = depth * _mul;
result.normal = normal * _mul;
return result;
}
//-------------------------------------------------------------------------
// Structures
//-------------------------------------------------------------------------
struct RiverRenderBatch
{
U32 startSegmentIdx;
U32 endSegmentIdx;
U32 startVert;
U32 endVert;
U32 startIndex;
U32 endIndex;
U32 totalRows;
U32 indexCount;
U32 vertCount;
U32 triangleCount;
};
typedef Vector<RiverRenderBatch> RiverBatchVector;
struct RiverNode
{
// The 3D position of the node
Point3F point;
// The width of the River at this node (meters)
F32 width;
// The depth of the River at this node (meters)
F32 depth;
VectorF normal;
};
typedef Vector<RiverNode> RiverNodeVector;
struct RiverSlice
{
RiverSlice()
{
p0.zero();
p1.zero();
p2.zero();
pb0.zero();
pb2.zero();
uvec.zero();
fvec.zero();
rvec.zero();
normal.zero();
width = 0.0f;
depth = 0.0f;
texCoordV = 0.0f;
parentNodeIdx = -1;
};
Point3F p0; // upper left
Point3F p1; // upper center
Point3F p2; // upper right
Point3F pb0; // bottom left
Point3F pb2; // bottom right
VectorF uvec;
VectorF fvec;
VectorF rvec;
VectorF normal;
F32 width;
F32 depth;
F32 texCoordV;
U32 parentNodeIdx;
};
typedef Vector<RiverSlice> RiverSliceVector;
//-------------------------------------------------------------------------
// RiverSegment Class
//-------------------------------------------------------------------------
static Point3F sSegmentPointCompareReference;
class RiverSegment
{
public:
RiverSegment();
RiverSegment( RiverSlice *rs0, RiverSlice *rs1 );
void set( RiverSlice *rs0, RiverSlice *rs1 );
F32 TexCoordStart() { return slice0->texCoordV; }
F32 TexCoordEnd() { return slice1->texCoordV; }
Point3F getP00() const { return slice0->p0; }
Point3F getP01() const { return slice1->p0; }
Point3F getP11() const { return slice1->p2; }
Point3F getP10() const { return slice0->p2; }
// NOTE:
// For purposes of collision testing against a RiverSegment we represent
// it as a set of 6 planes (one for each face) much like a frustum.
// This is actually a flawed representation that will be more incorrect
// the more twist/bend exists between the two RiverSlices making up
// the segment. Basically we treat the four points that make up a "face"
// as if they were coplanar.
Point3F getSurfaceCenter() const { return (slice0->p1 + slice1->p1) / 2; }
Point3F getSurfaceNormal() const { return ( -mPlanes[4].getNormal() ); }
Point3F getFaceCenter( U32 faceIdx ) const;
bool intersectBox( const Box3F &bounds ) const;
bool containsPoint( const Point3F &pnt ) const;
F32 distanceToSurface( const Point3F &pnt ) const;
// Quick access to the segment's points
Point3F& operator[](U32);
const Point3F& operator[](U32) const;
Point3F& operator[](S32 i) { return operator[](U32(i)); }
const Point3F& operator[](S32 i ) const { return operator[](U32(i)); }
RiverSlice *slice0;
RiverSlice *slice1;
PlaneF mPlanes[6];
U32 mPlaneCount;
U32 columns;
U32 rows;
U32 startVert;
U32 endVert;
U32 startIndex;
U32 endIndex;
U32 numVerts;
U32 numTriangles;
Box3F worldbounds;
protected:
PlaneF _getBestPlane( const Point3F *p0, const Point3F *p1, const Point3F *p2, const Point3F *p3 );
};
typedef Vector<RiverSegment> RiverSegmentVector;
inline Point3F& RiverSegment::operator[](U32 index)
{
AssertFatal(index < 8, "RiverSegment::operator[] - out of bounds array access!");
RiverSlice *slice = NULL;
if ( index > 3 )
{
slice = slice1;
index -= 4;
}
else
{
slice = slice0;
}
if ( index == 0 )
return slice->p0;
if ( index == 1 )
return slice->p2;
if ( index == 2 )
return slice->pb0;
else //( index == 3 )
return slice->pb2;
}
inline const Point3F& RiverSegment::operator[](U32 index) const
{
AssertFatal(index < 8, "RiverSegment::operator[] - out of bounds array access!");
RiverSlice *slice = NULL;
if ( index > 3 )
{
slice = slice1;
index -= 4;
}
else
{
slice = slice0;
}
if ( index == 0 )
return slice->p0;
if ( index == 1 )
return slice->p2;
if ( index == 2 )
return slice->pb0;
else// ( index == 3 )
return slice->pb2;
}
//------------------------------------------------------------------------------
// River Class
//------------------------------------------------------------------------------
class ParticleEmitter;
class ParticleEmitterData;
struct RiverNodeList;
class River : public WaterObject
{
private:
friend class GuiRiverEditorCtrl;
friend class GuiRiverEditorUndoAction;
typedef WaterObject Parent;
protected:
enum
{
RiverMask = Parent::NextFreeMask,
NodeMask = Parent::NextFreeMask << 1,
RegenMask = Parent::NextFreeMask << 2,
InitialUpdateMask = Parent::NextFreeMask << 3,
SelectedMask = Parent::NextFreeMask << 4,
MaterialMask = Parent::NextFreeMask << 5,
NextFreeMask = Parent::NextFreeMask << 6,
};
public:
River();
~River();
DECLARE_CONOBJECT(River);
// ConObject.
static void initPersistFields();
static void consoleInit();
// SimObject
bool onAdd();
void onRemove();
void inspectPostApply();
void onStaticModified(const char* slotName, const char*newValue = NULL);
void writeFields(Stream &stream, U32 tabStop);
bool writeField( StringTableEntry fieldname, const char *value );
// NetObject
U32 packUpdate(NetConnection *, U32, BitStream *);
void unpackUpdate(NetConnection *, BitStream *);
// SceneObject
virtual void setTransform( const MatrixF &mat );
virtual void setScale( const VectorF &scale );
virtual bool castRay(const Point3F &start, const Point3F &end, RayInfo* info);
virtual bool collideBox(const Point3F &start, const Point3F &end, RayInfo* info);
virtual bool containsPoint( const Point3F& point ) const { return containsPoint( point, NULL ); }
// WaterObject
virtual F32 getWaterCoverage( const Box3F &worldBox ) const;
virtual F32 getSurfaceHeight( const Point2F &pos ) const;
virtual VectorF getFlow( const Point3F &pos ) const;
virtual void onReflectionInfoChanged();
virtual void updateUnderwaterEffect( SceneRenderState *state );
virtual bool isUnderwater( const Point3F &pnt ) const;
F32 distanceToSurface( const Point3F &pnt, U32 segmentIdx );
bool containsPoint( const Point3F &worldPos, U32 *nodeIdx ) const;
// Cast a ray against the river -- THE TOP SURFACE ONLY
bool collideRay( const Point3F &origin, const Point3F &direction, U32 *nodeIdx = NULL, Point3F *collisionPnt = NULL ) const;
void regenerate();
void setMetersPerSegment( F32 meters );
void setBatchSize( U32 level );
void setShowNodes( bool enabled );
void setMaxDivisionSize( F32 meters );
void setColumnCount( S32 count );
U32 insertNode( const Point3F &pos, const F32 &width, const F32 &depth, const VectorF &normal, const U32 &idx );
U32 addNode( const Point3F &pos, const F32 &width, const F32 &depth, const VectorF &normal );
void setNode( const Point3F &pos, const F32 &width, const F32 &depth, const VectorF &normal, const U32 &idx );
void deleteNode( U32 idx );
void buildNodesFromList( RiverNodeList* list );
bool getClosestNode( const Point3F &pos, U32 &idx ) const;
Point3F getNodePosition( U32 idx ) const;
void setNodePosition( U32 idx, const Point3F &pos );
MatrixF getNodeTransform( U32 idx ) const;
F32 getNodeWidth( U32 idx ) const;
void setNodeWidth( U32 idx, F32 width );
F32 getNodeDepth( U32 idx ) const;
void setNodeDepth( U32 idx, F32 depth );
void setNodeHeight( U32 idx, F32 height );
void setNodeNormal( U32 idx, const VectorF &normal );
VectorF getNodeNormal( U32 idx ) const;
/// Protected 'Component' Field setter that will add a component to the list.
static bool addNodeFromField( void *object, const char *index, const char *data );
static SimSet* getServerSet();
static bool smEditorOpen;
static bool smWireframe;
static bool smShowWalls;
static bool smShowNodes;
static bool smShowSpline;
static bool smShowRiver;
static SimObjectPtr<SimSet> smServerRiverSet;
protected:
void _loadRenderData();
bool _setRenderData();
void _render( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *matInst );
void _makeRenderBatches( const Point3F &cameraPos );
void _makeHighLODBuffers();
U32 _insertNode( const Point3F &pos, const F32 &width, const F32 &depth, const VectorF &normal, const U32 &idx );
U32 _addNode( const Point3F &pos, const F32 &width, const F32 &depth, const VectorF &normal );
void _regenerate();
void _generateSlices();
void _generateSegments();
void _generateVerts();
bool _getTerrainHeight( const Point2F &pos, F32 &height );
bool _getTerrainHeight( F32 x, F32 y, F32 &height );
// WaterObject
virtual void setShaderParams( SceneRenderState *state, BaseMatInstance *mat, const WaterMatParams &paramHandles );
virtual void innerRender( SceneRenderState *state );
virtual void _getWaterPlane( const Point3F &camPos, PlaneF &outPlane, Point3F &outPos );
protected:
RiverSliceVector mSlices;
RiverNodeVector mNodes;
RiverSegmentVector mSegments;
GFXVertexBufferHandle<GFXWaterVertex> mVB_high; // the high detail vertex buffer
GFXVertexBufferHandle<GFXWaterVertex> mVB_low; // the low detail vertex buffer
GFXPrimitiveBufferHandle mPB_high; // the high detail prim buffer
GFXPrimitiveBufferHandle mPB_low; // the low detail prim buffer
RiverBatchVector mHighLODBatches;
RiverBatchVector mLowLODBatches;
U32 mLowVertCount;
U32 mHighVertCount;
U32 mLowTriangleCount;
U32 mHighTriangleCount;
// Fields.
U32 mSegmentsPerBatch;
F32 mMetersPerSegment;
F32 mDepthScale;
F32 mFlowMagnitude;
F32 mLodDistance;
// Divide segments that are greater than this length
// into sections of this size, or as close as possible
// while maintaining an equal division size.
F32 mMaxDivisionSize;
F32 mMinDivisionSize;
U32 mColumnCount;
};
#endif // _RIVER_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,251 @@
//-----------------------------------------------------------------------------
// 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 _SCATTERSKY_H_
#define _SCATTERSKY_H_
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
#ifndef _GFXSTATEBLOCK_H_
#include "gfx/gfxStateBlock.h"
#endif
#ifndef _RENDERPASSMANAGER_H_
#include "renderInstance/renderPassManager.h"
#endif
#ifndef _PRIMBUILDER_H_
#include "gfx/primBuilder.h"
#endif
#ifndef _LIGHTINFO_H_
#include "lighting/lightInfo.h"
#endif
#ifndef _LIGHTFLAREDATA_H_
#include "T3D/lightFlareData.h"
#endif
#ifndef _TRESPONSECURVE_H_
#include "math/util/tResponseCurve.h"
#endif
class LightInfo;
class SphereMesh;
class TimeOfDay;
class CubemapData;
class MatrixSet;
GFXDeclareVertexFormat( ScatterSkyVertex )
{
// .xyz = coords
Point3F point;
VectorF normal;
ColorF color;
};
class ScatterSky : public SceneObject, public ISceneLight
{
typedef SceneObject Parent;
public:
enum MaskBits
{
UpdateMask = Parent::NextFreeMask,
TimeMask = Parent::NextFreeMask << 1,
NextFreeMask = Parent::NextFreeMask << 2
};
ScatterSky();
~ScatterSky();
// SimObject
bool onAdd();
void onRemove();
// ISceneLight
virtual void submitLights( LightManager *lm, bool staticLighting );
virtual LightInfo* getLight() { return mLight; }
// ConsoleObject
DECLARE_CONOBJECT(ScatterSky);
void inspectPostApply();
static void initPersistFields();
// Network
U32 packUpdate ( NetConnection *conn, U32 mask, BitStream *stream );
void unpackUpdate( NetConnection *conn, BitStream *stream );
void prepRenderImage( SceneRenderState* state );
///
void setAzimuth( F32 azimuth );
///
void setElevation( F32 elevation );
///
F32 getAzimuth() const { return mSunAzimuth; }
///
F32 getElevation() const { return mSunElevation; }
protected:
void _render( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
void _debugRender( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
void _renderMoon( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
void _initVBIB();
bool _initShader();
void _initMoon();
void _initCurves();
F32 _getRayleighPhase( F32 fCos2 );
F32 _getMiePhase( F32 fCos, F32 fCos2, F32 g, F32 g2 );
F32 _vernierScale( F32 fCos );
void _generateSkyPoints();
void _getColor( const Point3F &pos, ColorF *outColor );
void _getFogColor( ColorF *outColor );
void _getAmbientColor( ColorF *outColor );
void _getSunColor( ColorF *outColor );
void _interpolateColors();
void _conformLights();
void _updateTimeOfDay( TimeOfDay *timeofDay, F32 time );
// static protected field set methods
static bool ptSetElevation( void *object, const char *index, const char *data );
static bool ptSetAzimuth( void *object, const char *index, const char *data );
// SimObject.
virtual void _onSelected();
virtual void _onUnselected();
protected:
static const F32 smEarthRadius;
static const F32 smAtmosphereRadius;
static const F32 smViewerHeight;
#define CURVE_COUNT 4
FloatCurve mCurves[CURVE_COUNT];
U32 mVertCount;
U32 mPrimCount;
F32 mRayleighScattering;
F32 mRayleighScattering4PI;
F32 mMieScattering;
F32 mMieScattering4PI;
F32 mSkyBrightness;
F32 mMiePhaseAssymetry;
F32 mOuterRadius;
F32 mScale;
ColorF mWavelength;
F32 mWavelength4[3];
F32 mRayleighScaleDepth;
F32 mMieScaleDepth;
F32 mSphereInnerRadius;
F32 mSphereOuterRadius;
F32 mExposure;
F32 mNightInterpolant;
VectorF mLightDir;
VectorF mSunDir;
F32 mSunAzimuth;
F32 mSunElevation;
F32 mMoonAzimuth;
F32 mMoonElevation;
F32 mTimeOfDay;
F32 mBrightness;
ColorF mNightColor;
ColorF mNightFogColor;
ColorF mAmbientColor; ///< Not a field
ColorF mSunColor; ///< Not a field
ColorF mFogColor; ///< Not a field
ColorF mAmbientScale;
ColorF mSunScale;
ColorF mFogScale;
LightInfo *mLight;
bool mCastShadows;
bool mDirty;
LightFlareData *mFlareData;
LightFlareState mFlareState;
F32 mFlareScale;
bool mMoonEnabled;
String mMoonMatName;
BaseMatInstance *mMoonMatInst;
F32 mMoonScale;
ColorF mMoonTint;
VectorF mMoonLightDir;
CubemapData *mNightCubemap;
String mNightCubemapName;
bool mUseNightCubemap;
MatrixSet *mMatrixSet;
Vector<Point3F> mSkyPoints;
// Prim buffer, vertex buffer and shader for rendering.
GFXPrimitiveBufferHandle mPrimBuffer;
GFXVertexBufferHandle<ScatterSkyVertex> mVB;
GFXShaderRef mShader;
GFXStateBlockRef mStateBlock;
// Shared shader constant blocks
GFXShaderConstBufferRef mShaderConsts;
GFXShaderConstHandle *mModelViewProjSC;
GFXShaderConstHandle *mMiscSC; // Camera height, cam height squared, scale and scale over depth.
GFXShaderConstHandle *mSphereRadiiSC; // Inner and out radius, and inner and outer radius squared.
GFXShaderConstHandle *mScatteringCoefficientsSC; // Rayleigh sun brightness, mie sun brightness and 4 * PI * coefficients.
GFXShaderConstHandle *mCamPosSC;
GFXShaderConstHandle *mLightDirSC;
GFXShaderConstHandle *mSunDirSC;
GFXShaderConstHandle *mNightColorSC;
GFXShaderConstHandle *mInverseWavelengthSC;
GFXShaderConstHandle *mNightInterpolantAndExposureSC;
GFXShaderConstHandle *mUseCubemapSC;
};
#endif // _SCATTERSKY_H_

View file

@ -0,0 +1,637 @@
//-----------------------------------------------------------------------------
// 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 "environment/skyBox.h"
#include "console/consoleTypes.h"
#include "scene/sceneRenderState.h"
#include "renderInstance/renderPassManager.h"
#include "gfx/primBuilder.h"
#include "gfx/gfxTransformSaver.h"
#include "core/stream/fileStream.h"
#include "core/stream/bitStream.h"
#include "materials/materialManager.h"
#include "materials/materialFeatureTypes.h"
#include "materials/sceneData.h"
#include "T3D/gameFunctions.h"
#include "renderInstance/renderBinManager.h"
#include "materials/processedMaterial.h"
#include "gfx/gfxDebugEvent.h"
#include "math/util/matrixSet.h"
IMPLEMENT_CO_NETOBJECT_V1( SkyBox );
ConsoleDocClass( SkyBox,
"@brief Represents the sky with an artist-created cubemap.\n\n"
"SkyBox is not a directional light and should be used in conjunction with a Sun object.\n\n"
"@ingroup Atmosphere"
);
SkyBox::SkyBox()
{
mTypeMask |= EnvironmentObjectType | StaticObjectType;
mNetFlags.set(Ghostable | ScopeAlways);
mMatName = "";
mMatInstance = NULL;
mIsVBDirty = false;
mDrawBottom = true;
mPrimCount = 0;
mFogBandHeight = 0;
mMatrixSet = reinterpret_cast<MatrixSet *>(dMalloc_aligned(sizeof(MatrixSet), 16));
constructInPlace(mMatrixSet);
mFogBandMat = NULL;
mFogBandMatInst = NULL;
}
SkyBox::~SkyBox()
{
dFree_aligned(mMatrixSet);
if( mMatInstance )
SAFE_DELETE( mMatInstance );
SAFE_DELETE( mFogBandMatInst );
if ( mFogBandMat )
{
mFogBandMat->deleteObject();
mFogBandMat = NULL;
}
}
bool SkyBox::onAdd()
{
if ( !Parent::onAdd() )
return false;
setGlobalBounds();
resetWorldBox();
addToScene();
if ( isClientObject() )
{
_initRender();
_updateMaterial();
}
return true;
}
void SkyBox::onRemove()
{
removeFromScene();
Parent::onRemove();
}
void SkyBox::initPersistFields()
{
addGroup( "Sky Box" );
addField( "material", TypeMaterialName, Offset( mMatName, SkyBox ),
"The name of a cubemap material for the sky box." );
addField( "drawBottom", TypeBool, Offset( mDrawBottom, SkyBox ),
"If false the bottom of the skybox is not rendered." );
addField( "fogBandHeight", TypeF32, Offset( mFogBandHeight, SkyBox ),
"The height (0-1) of the fog band from the horizon to the top of the SkyBox." );
endGroup( "Sky Box" );
Parent::initPersistFields();
}
void SkyBox::inspectPostApply()
{
Parent::inspectPostApply();
_updateMaterial();
}
U32 SkyBox::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
{
U32 retMask = Parent::packUpdate( conn, mask, stream );
stream->write( mMatName );
stream->writeFlag( mDrawBottom );
stream->write( mFogBandHeight );
return retMask;
}
void SkyBox::unpackUpdate( NetConnection *conn, BitStream *stream )
{
Parent::unpackUpdate( conn, stream );
String tmpString( "" );
stream->read( &tmpString );
if ( !tmpString.equal( mMatName, String::NoCase ) )
{
mMatName = tmpString;
_updateMaterial();
}
bool drawBottom = stream->readFlag();
F32 bandHeight = 0;
stream->read( &bandHeight );
// If this flag has changed
// we need to update the vertex buffer.
if ( drawBottom != mDrawBottom ||
bandHeight != mFogBandHeight )
{
mDrawBottom = drawBottom;
mFogBandHeight = bandHeight;
mIsVBDirty = true;
_initRender();
}
}
void SkyBox::prepRenderImage( SceneRenderState *state )
{
PROFILE_SCOPE( SkyBox_prepRenderImage );
if ( state->isShadowPass() ||
mVB.isNull() ||
mFogBandVB.isNull() ||
!mMatInstance )
return;
mMatrixSet->setSceneView(GFX->getWorldMatrix());
mMatrixSet->setSceneProjection(GFX->getProjectionMatrix());
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
ri->renderDelegate.bind( this, &SkyBox::_renderObject );
ri->type = RenderPassManager::RIT_Sky;
ri->defaultKey = 10;
ri->defaultKey2 = 0;
state->getRenderPass()->addInst( ri );
}
void SkyBox::_renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mi )
{
GFXDEBUGEVENT_SCOPE( SkyBox_RenderObject, ColorF::WHITE );
GFXTransformSaver saver;
GFX->setVertexBuffer( mVB );
MatrixF worldMat = MatrixF::Identity;
worldMat.setPosition( state->getCameraPosition() );
SceneData sgData;
sgData.init( state );
sgData.objTrans = &worldMat;
mMatrixSet->restoreSceneViewProjection();
mMatrixSet->setWorld( worldMat );
if ( state->isReflectPass() )
mMatrixSet->setProjection( state->getSceneManager()->getNonClipProjection() );
while ( mMatInstance->setupPass( state, sgData ) )
{
mMatInstance->setTransforms( *mMatrixSet, state );
mMatInstance->setSceneInfo( state, sgData );
GFX->drawPrimitive( GFXTriangleList, 0, mPrimCount );
}
// Draw render band.
if ( mFogBandHeight > 0 && mFogBandMatInst )
{
const FogData &fog = state->getSceneManager()->getFogData();
if ( mLastFogColor != fog.color )
{
mLastFogColor = fog.color;
_initRender();
}
// Just need it to follow the camera... no rotation.
MatrixF camPosMat( MatrixF::Identity );
camPosMat.setPosition( worldMat.getPosition() );
sgData.objTrans = &camPosMat;
mMatrixSet->setWorld( *sgData.objTrans );
while ( mFogBandMatInst->setupPass( state, sgData ) )
{
mFogBandMatInst->setTransforms( *mMatrixSet, state );
mFogBandMatInst->setSceneInfo( state, sgData );
GFX->setVertexBuffer( mFogBandVB );
GFX->drawPrimitive( GFXTriangleList, 0, 16 );
}
}
}
void SkyBox::_initRender()
{
GFXVertexPNTT *tmpVerts = NULL;
U32 vertCount = 36;
if ( !mDrawBottom )
vertCount = 30;
mPrimCount = vertCount / 3;
// Create temp vertex pointer
// so we can read from it
// for generating the normals below.
tmpVerts = new GFXVertexPNTT[vertCount];
// We don't bother sharing
// vertices here, in order to
// avoid using a primitive buffer.
tmpVerts[0].point.set( -1, -1, 1 );
tmpVerts[1].point.set( 1, -1, 1 );
tmpVerts[2].point.set( 1, -1, -1 );
tmpVerts[0].texCoord.set( 0, 0 );
tmpVerts[1].texCoord.set( 1.0f, 0 );
tmpVerts[2].texCoord.set( 1.0f, 1.0f );
tmpVerts[3].point.set( -1, -1, 1 );
tmpVerts[4].point.set( 1, -1, -1 );
tmpVerts[5].point.set( -1, -1, -1 );
tmpVerts[3].texCoord.set( 0, 0 );
tmpVerts[4].texCoord.set( 1.0f, 1.0f );
tmpVerts[5].texCoord.set( 0, 1.0f );
tmpVerts[6].point.set( 1, -1, 1 );
tmpVerts[7].point.set( 1, 1, 1 );
tmpVerts[8].point.set( 1, 1, -1 );
tmpVerts[6].texCoord.set( 0, 0 );
tmpVerts[7].texCoord.set( 1.0f, 0 );
tmpVerts[8].texCoord.set( 1.0f, 1.0f );
tmpVerts[9].point.set( 1, -1, 1 );
tmpVerts[10].point.set( 1, 1, -1 );
tmpVerts[11].point.set( 1, -1, -1 );
tmpVerts[9].texCoord.set( 0, 0 );
tmpVerts[10].texCoord.set( 1.0f, 1.0f );
tmpVerts[11].texCoord.set( 0, 1.0f );
tmpVerts[12].point.set( -1, 1, 1 );
tmpVerts[13].point.set( -1, -1, 1 );
tmpVerts[14].point.set( -1, -1, -1 );
tmpVerts[12].texCoord.set( 0, 0 );
tmpVerts[13].texCoord.set( 1.0f, 0 );
tmpVerts[14].texCoord.set( 1.0f, 1.0f );
tmpVerts[15].point.set( -1, 1, 1 );
tmpVerts[16].point.set( -1, -1, -1 );
tmpVerts[17].point.set( -1, 1, -1 );
tmpVerts[15].texCoord.set( 0, 0 );
tmpVerts[16].texCoord.set( 1.0f, 1.0f );
tmpVerts[17].texCoord.set( 1.0f, 0 );
tmpVerts[18].point.set( 1, 1, 1 );
tmpVerts[19].point.set( -1, 1, 1 );
tmpVerts[20].point.set( -1, 1, -1 );
tmpVerts[18].texCoord.set( 0, 0 );
tmpVerts[19].texCoord.set( 1.0f, 0 );
tmpVerts[20].texCoord.set( 1.0f, 1.0f );
tmpVerts[21].point.set( 1, 1, 1 );
tmpVerts[22].point.set( -1, 1, -1 );
tmpVerts[23].point.set( 1, 1, -1 );
tmpVerts[21].texCoord.set( 0, 0 );
tmpVerts[22].texCoord.set( 1.0f, 1.0f );
tmpVerts[23].texCoord.set( 0, 1.0f );
tmpVerts[24].point.set( -1, -1, 1 );
tmpVerts[25].point.set( -1, 1, 1 );
tmpVerts[26].point.set( 1, 1, 1 );
tmpVerts[24].texCoord.set( 0, 0 );
tmpVerts[25].texCoord.set( 1.0f, 0 );
tmpVerts[26].texCoord.set( 1.0f, 1.0f );
tmpVerts[27].point.set( -1, -1, 1 );
tmpVerts[28].point.set( 1, 1, 1 );
tmpVerts[29].point.set( 1, -1, 1 );
tmpVerts[27].texCoord.set( 0, 0 );
tmpVerts[28].texCoord.set( 1.0f, 1.0f );
tmpVerts[29].texCoord.set( 0, 1.0f );
// Only set up these
// vertices if the SkyBox
// is set to render the bottom face.
if ( mDrawBottom )
{
tmpVerts[30].point.set( 1, 1, -1 );
tmpVerts[31].point.set( -1, 1, -1 );
tmpVerts[32].point.set( -1, -1, -1 );
tmpVerts[30].texCoord.set( 1.0f, 1.0f );
tmpVerts[31].texCoord.set( 1.0f, 0 );
tmpVerts[32].texCoord.set( 0, 0 );
tmpVerts[33].point.set( 1, -1, -1 );
tmpVerts[34].point.set( 1, 1, -1 );
tmpVerts[35].point.set( -1, -1, -1 );
tmpVerts[33].texCoord.set( 0, 1.0f );
tmpVerts[34].texCoord.set( 1.0f, 1.0f );
tmpVerts[35].texCoord.set( 0, 0 );
}
VectorF tmp( 0, 0, 0 );
for ( U32 i = 0; i < vertCount; i++ )
{
//tmp = tmpVerts[i].point;
//tmp.normalize();
//tmpVerts[i].normal.set( tmp );
// Note: SkyBox renders with a regular material, which uses the "Reflect Cube"
// feature.
//
// This feature is really designed a cubemap representing a reflection
// on an objects surface and therefore looks up into the cubemap with the
// cubemap-space view vector reflected by the vert normal.
//
// Since we are actually viewing the skybox from "inside" not from
// "outside" this reflection ends up making the cubemap appear upsidown.
// Therefore we set the vert-normals to "zero" so that the reflection
// operation returns the input, unreflected, vector.
tmpVerts[i].normal.set( Point3F::Zero );
}
if ( mVB.isNull() || mIsVBDirty )
{
mVB.set( GFX, vertCount, GFXBufferTypeStatic );
mIsVBDirty = false;
}
GFXVertexPNTT *vertPtr = mVB.lock();
dMemcpy( vertPtr, tmpVerts, sizeof ( GFXVertexPNTT ) * vertCount );
mVB.unlock();
// Clean up temp verts.
delete [] tmpVerts;
if ( mFogBandVB.isNull() )
mFogBandVB.set( GFX, 48, GFXBufferTypeStatic );
GFXVertexPC *bandVertPtr = mFogBandVB.lock();
// Grab the fog color.
ColorI fogColor( mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255 );
ColorI fogColorAlpha( mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255, 0 );
// Upper portion of band geometry.
{
bandVertPtr[0].point.set( -1, -1, mFogBandHeight );
bandVertPtr[1].point.set( 1, -1, mFogBandHeight );
bandVertPtr[2].point.set( 1, -1, 0 );
bandVertPtr[0].color.set( fogColorAlpha );
bandVertPtr[1].color.set( fogColorAlpha );
bandVertPtr[2].color.set( fogColor );
bandVertPtr[3].point.set( -1, -1, mFogBandHeight );
bandVertPtr[4].point.set( 1, -1, 0 );
bandVertPtr[5].point.set( -1, -1, 0 );
bandVertPtr[3].color.set( fogColorAlpha );
bandVertPtr[4].color.set( fogColor );
bandVertPtr[5].color.set( fogColor );
bandVertPtr[6].point.set( 1, -1, mFogBandHeight );
bandVertPtr[7].point.set( 1, 1, mFogBandHeight );
bandVertPtr[8].point.set( 1, 1, 0 );
bandVertPtr[6].color.set( fogColorAlpha );
bandVertPtr[7].color.set( fogColorAlpha );
bandVertPtr[8].color.set( fogColor );
bandVertPtr[9].point.set( 1, -1, mFogBandHeight );
bandVertPtr[10].point.set( 1, 1, 0 );
bandVertPtr[11].point.set( 1, -1, 0 );
bandVertPtr[9].color.set( fogColorAlpha );
bandVertPtr[10].color.set( fogColor );
bandVertPtr[11].color.set( fogColor );
bandVertPtr[12].point.set( -1, 1, mFogBandHeight );
bandVertPtr[13].point.set( -1, -1, mFogBandHeight );
bandVertPtr[14].point.set( -1, -1, 0 );
bandVertPtr[12].color.set( fogColorAlpha );
bandVertPtr[13].color.set( fogColorAlpha );
bandVertPtr[14].color.set( fogColor );
bandVertPtr[15].point.set( -1, 1, mFogBandHeight );
bandVertPtr[16].point.set( -1, -1, 0 );
bandVertPtr[17].point.set( -1, 1, 0 );
bandVertPtr[15].color.set( fogColorAlpha );
bandVertPtr[16].color.set( fogColor );
bandVertPtr[17].color.set( fogColor );
bandVertPtr[18].point.set( 1, 1, mFogBandHeight );
bandVertPtr[19].point.set( -1, 1, mFogBandHeight );
bandVertPtr[20].point.set( -1, 1, 0 );
bandVertPtr[18].color.set( fogColorAlpha );
bandVertPtr[19].color.set( fogColorAlpha );
bandVertPtr[20].color.set( fogColor );
bandVertPtr[21].point.set( 1, 1, mFogBandHeight );
bandVertPtr[22].point.set( -1, 1, 0 );
bandVertPtr[23].point.set( 1, 1, 0 );
bandVertPtr[21].color.set( fogColorAlpha );
bandVertPtr[22].color.set( fogColor );
bandVertPtr[23].color.set( fogColor );
}
// Lower portion of band geometry.
{
bandVertPtr[24].point.set( -1, -1, 0 );
bandVertPtr[25].point.set( 1, -1, 0 );
bandVertPtr[26].point.set( 1, -1, -1 );
bandVertPtr[24].color.set( fogColor );
bandVertPtr[25].color.set( fogColor );
bandVertPtr[26].color.set( fogColor );
bandVertPtr[27].point.set( -1, -1, 0 );
bandVertPtr[28].point.set( 1, -1, -1 );
bandVertPtr[29].point.set( -1, -1, -1 );
bandVertPtr[27].color.set( fogColor );
bandVertPtr[28].color.set( fogColor );
bandVertPtr[29].color.set( fogColor );
bandVertPtr[30].point.set( 1, -1, 0 );
bandVertPtr[31].point.set( 1, 1, 0 );
bandVertPtr[32].point.set( 1, 1, -1 );
bandVertPtr[30].color.set( fogColor );
bandVertPtr[31].color.set( fogColor );
bandVertPtr[32].color.set( fogColor );
bandVertPtr[33].point.set( 1, -1, 0 );
bandVertPtr[34].point.set( 1, 1, -1 );
bandVertPtr[35].point.set( 1, -1, -1 );
bandVertPtr[33].color.set( fogColor );
bandVertPtr[34].color.set( fogColor );
bandVertPtr[35].color.set( fogColor );
bandVertPtr[36].point.set( -1, 1, 0 );
bandVertPtr[37].point.set( -1, -1, 0 );
bandVertPtr[38].point.set( -1, -1, -1 );
bandVertPtr[36].color.set( fogColor );
bandVertPtr[37].color.set( fogColor );
bandVertPtr[38].color.set( fogColor );
bandVertPtr[39].point.set( -1, 1, 0 );
bandVertPtr[40].point.set( -1, -1, -1 );
bandVertPtr[41].point.set( -1, 1, -1 );
bandVertPtr[39].color.set( fogColor );
bandVertPtr[40].color.set( fogColor );
bandVertPtr[41].color.set( fogColor );
bandVertPtr[42].point.set( 1, 1, 0 );
bandVertPtr[43].point.set( -1, 1, 0 );
bandVertPtr[44].point.set( -1, 1, -1 );
bandVertPtr[42].color.set( fogColor );
bandVertPtr[43].color.set( fogColor );
bandVertPtr[44].color.set( fogColor );
bandVertPtr[45].point.set( 1, 1, 0 );
bandVertPtr[46].point.set( -1, 1, -1 );
bandVertPtr[47].point.set( 1, 1, -1 );
bandVertPtr[45].color.set( fogColor );
bandVertPtr[46].color.set( fogColor );
bandVertPtr[47].color.set( fogColor );
}
mFogBandVB.unlock();
SAFE_DELETE( mFogBandMatInst );
if ( mFogBandMat )
{
mFogBandMat->deleteObject();
mFogBandMat = NULL;
}
// Setup the material for this imposter.
mFogBandMat = MATMGR->allocateAndRegister( String::EmptyString );
mFogBandMat->mAutoGenerated = true;
mFogBandMat->mTranslucent = true;
mFogBandMat->mVertColor[0] = true;
mFogBandMat->mDoubleSided = true;
mFogBandMat->mEmissive[0] = true;
mFogBandMatInst = mFogBandMat->createMatInstance();
mFogBandMatInst->init( MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPC>() );
}
void SkyBox::onStaticModified( const char *slotName, const char *newValue )
{
Parent::onStaticModified( slotName, newValue );
if ( dStricmp( slotName, "material" ) == 0 )
setMaskBits( 0xFFFFFFFF );
}
void SkyBox::_initMaterial()
{
if ( mMatInstance )
SAFE_DELETE( mMatInstance );
if ( mMaterial )
mMatInstance = mMaterial->createMatInstance();
else
mMatInstance = MATMGR->createMatInstance( "WarningMaterial" );
// We want to disable culling and z write.
GFXStateBlockDesc desc;
desc.setCullMode( GFXCullCW );
desc.setZReadWrite( true, false );
mMatInstance->addStateBlockDesc( desc );
// Also disable lighting on the skybox material by default.
FeatureSet features = MATMGR->getDefaultFeatures();
features.removeFeature( MFT_RTLighting );
features.removeFeature( MFT_Visibility );
// Now initialize the material.
mMatInstance->init( features, getGFXVertexFormat<GFXVertexPNTT>() );
}
void SkyBox::_updateMaterial()
{
if ( mMatName.isEmpty() )
return;
Material *pMat = NULL;
if ( !Sim::findObject( mMatName, pMat ) )
Con::printf( "SkyBox::_updateMaterial, failed to find Material of name %s!", mMatName.c_str() );
else if ( isProperlyAdded() )
{
mMaterial = pMat;
_initMaterial();
}
}
BaseMatInstance* SkyBox::_getMaterialInstance()
{
if ( !mMaterial || !mMatInstance || mMatInstance->getMaterial() != mMaterial )
_initMaterial();
if ( !mMatInstance )
return NULL;
return mMatInstance;
}
ConsoleMethod( SkyBox, postApply, void, 2, 2, "")
{
object->inspectPostApply();
}

View file

@ -0,0 +1,130 @@
//-----------------------------------------------------------------------------
// 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 _SKYBOX_H_
#define _SKYBOX_H_
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
#ifndef _GFXDEVICE_H_
#include "gfx/gfxDevice.h"
#endif
#ifndef _CUBEMAPDATA_H_
#include "gfx/sim/cubemapData.h"
#endif
#ifndef _MATERIALLIST_H_
#include "materials/materialList.h"
#endif
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
GFXDeclareVertexFormat( GFXSkyVertex )
{
Point3F point;
Point3F normal;
GFXVertexColor color;
};
struct SkyMatParams
{
void init( BaseMatInstance *matInst ) {};
};
class MatrixSet;
class SkyBox : public SceneObject
{
typedef SceneObject Parent;
public:
SkyBox();
virtual ~SkyBox();
DECLARE_CONOBJECT( SkyBox );
// SimObject
void onStaticModified( const char *slotName, const char *newValue );
// ConsoleObject
virtual bool onAdd();
virtual void onRemove();
static void initPersistFields();
virtual void inspectPostApply();
// NetObject
virtual U32 packUpdate( NetConnection *conn, U32 mask, BitStream *stream );
virtual void unpackUpdate( NetConnection *conn, BitStream *stream );
// SceneObject
void prepRenderImage( SceneRenderState* state );
/// Our render delegate.
void _renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mi );
/// Prepares rendering structures and geometry.
void _initRender();
protected:
// Material
String mMatName;
BaseMatInstance *mMatInstance;
SkyMatParams mMatParamHandle;
SimObjectPtr<Material> mMaterial;
GFXVertexBufferHandle<GFXVertexPNTT> mVB;
GFXVertexBufferHandle<GFXVertexPC> mFogBandVB;
Material *mFogBandMat;
BaseMatInstance *mFogBandMatInst;
ColorF mLastFogColor;
bool mDrawBottom;
bool mIsVBDirty;
U32 mPrimCount;
MatrixSet *mMatrixSet;
F32 mFogBandHeight;
void _updateMaterial();
void _initMaterial();
BaseMatInstance* _getMaterialInstance();
};
#endif // _SKYBOX_H_

View file

@ -0,0 +1,563 @@
//-----------------------------------------------------------------------------
// 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 "environment/sun.h"
#include "gfx/bitmap/gBitmap.h"
#include "math/mathIO.h"
#include "core/stream/bitStream.h"
#include "console/consoleTypes.h"
#include "scene/sceneManager.h"
#include "math/mathUtils.h"
#include "lighting/lightInfo.h"
#include "lighting/lightManager.h"
#include "scene/sceneRenderState.h"
#include "renderInstance/renderPassManager.h"
#include "sim/netConnection.h"
#include "environment/timeOfDay.h"
#include "gfx/gfxTransformSaver.h"
#include "materials/materialManager.h"
#include "materials/baseMatInstance.h"
#include "materials/sceneData.h"
#include "math/util/matrixSet.h"
IMPLEMENT_CO_NETOBJECT_V1(Sun);
ConsoleDocClass( Sun,
"@brief A global light affecting your entire scene and optionally renders a corona effect.\n\n"
"Sun is both the directional and ambient light for your entire scene.\n\n"
"@ingroup Atmosphere"
);
//-----------------------------------------------------------------------------
Sun::Sun()
{
mNetFlags.set(Ghostable | ScopeAlways);
mTypeMask = EnvironmentObjectType | LightObjectType | StaticObjectType;
mLightColor.set(0.7f, 0.7f, 0.7f);
mLightAmbient.set(0.3f, 0.3f, 0.3f);
mBrightness = 1.0f;
mSunAzimuth = 0.0f;
mSunElevation = 35.0f;
mCastShadows = true;
mAnimateSun = false;
mTotalTime = 0.0f;
mCurrTime = 0.0f;
mStartAzimuth = 0.0f;
mEndAzimuth = 0.0f;
mStartElevation = 0.0f;
mEndElevation = 0.0f;
mLight = LightManager::createLightInfo();
mLight->setType( LightInfo::Vector );
mFlareData = NULL;
mFlareState.clear();
mFlareScale = 1.0f;
mCoronaEnabled = true;
mCoronaScale = 0.5f;
mCoronaTint.set( 1.0f, 1.0f, 1.0f, 1.0f );
mCoronaUseLightColor = true;
mCoronaMatInst = NULL;
mMatrixSet = reinterpret_cast<MatrixSet *>(dMalloc_aligned(sizeof(MatrixSet), 16));
constructInPlace(mMatrixSet);
mCoronaWorldRadius = 0.0f;
mLightWorldPos = Point3F::Zero;
}
Sun::~Sun()
{
SAFE_DELETE( mLight );
SAFE_DELETE( mCoronaMatInst );
dFree_aligned(mMatrixSet);
}
bool Sun::onAdd()
{
if ( !Parent::onAdd() )
return false;
// Register as listener to TimeOfDay update events
TimeOfDay::getTimeOfDayUpdateSignal().notify( this, &Sun::_updateTimeOfDay );
// Make this thing have a global bounds so that its
// always returned from spatial light queries.
setGlobalBounds();
resetWorldBox();
setRenderTransform( mObjToWorld );
addToScene();
_initCorona();
// Update the light parameters.
_conformLights();
setProcessTick( true );
return true;
}
void Sun::onRemove()
{
TimeOfDay::getTimeOfDayUpdateSignal().remove( this, &Sun::_updateTimeOfDay );
removeFromScene();
Parent::onRemove();
}
void Sun::initPersistFields()
{
addGroup( "Orbit" );
addField( "azimuth", TypeF32, Offset( mSunAzimuth, Sun ),
"The horizontal angle of the sun measured clockwise from the positive Y world axis." );
addField( "elevation", TypeF32, Offset( mSunElevation, Sun ),
"The elevation angle of the sun above or below the horizon." );
endGroup( "Orbit" );
// We only add the basic lighting options that all lighting
// systems would use... the specific lighting system options
// are injected at runtime by the lighting system itself.
addGroup( "Lighting" );
addField( "color", TypeColorF, Offset( mLightColor, Sun ),
"Color shading applied to surfaces in direct contact with light source.");
addField( "ambient", TypeColorF, Offset( mLightAmbient, Sun ), "Color shading applied to surfaces not "
"in direct contact with light source, such as in the shadows or interiors.");
addField( "brightness", TypeF32, Offset( mBrightness, Sun ),
"Adjust the Sun's global contrast/intensity");
addField( "castShadows", TypeBool, Offset( mCastShadows, Sun ),
"Enables/disables shadows cast by objects due to Sun light");
endGroup( "Lighting" );
addGroup( "Corona" );
addField( "coronaEnabled", TypeBool, Offset( mCoronaEnabled, Sun ),
"Enable or disable rendering of the corona sprite." );
addField( "coronaMaterial", TypeMaterialName, Offset( mCoronaMatName, Sun ),
"Texture for the corona sprite." );
addField( "coronaScale", TypeF32, Offset( mCoronaScale, Sun ),
"Controls size the corona sprite renders, specified as a fractional amount of the screen height." );
addField( "coronaTint", TypeColorF, Offset( mCoronaTint, Sun ),
"Modulates the corona sprite color ( if coronaUseLightColor is false )." );
addField( "coronaUseLightColor", TypeBool, Offset( mCoronaUseLightColor, Sun ),
"Modulate the corona sprite color by the color of the light ( overrides coronaTint )." );
endGroup( "Corona" );
addGroup( "Misc" );
addField( "flareType", TYPEID< LightFlareData >(), Offset( mFlareData, Sun ),
"Datablock for the flare produced by the Sun" );
addField( "flareScale", TypeF32, Offset( mFlareScale, Sun ),
"Changes the size and intensity of the flare." );
endGroup( "Misc" );
// Now inject any light manager specific fields.
LightManager::initLightFields();
Parent::initPersistFields();
}
void Sun::inspectPostApply()
{
_conformLights();
setMaskBits(UpdateMask);
}
U32 Sun::packUpdate(NetConnection *conn, U32 mask, BitStream *stream )
{
U32 retMask = Parent::packUpdate( conn, mask, stream );
if ( stream->writeFlag( mask & UpdateMask ) )
{
stream->write( mSunAzimuth );
stream->write( mSunElevation );
stream->write( mLightColor );
stream->write( mLightAmbient );
stream->write( mBrightness );
stream->writeFlag( mCastShadows );
stream->write( mFlareScale );
if ( stream->writeFlag( mFlareData ) )
{
stream->writeRangedU32( mFlareData->getId(),
DataBlockObjectIdFirst,
DataBlockObjectIdLast );
}
stream->writeFlag( mCoronaEnabled );
stream->write( mCoronaMatName );
stream->write( mCoronaScale );
stream->write( mCoronaTint );
stream->writeFlag( mCoronaUseLightColor );
mLight->packExtended( stream );
}
return retMask;
}
void Sun::unpackUpdate( NetConnection *conn, BitStream *stream )
{
Parent::unpackUpdate( conn, stream );
if ( stream->readFlag() ) // UpdateMask
{
stream->read( &mSunAzimuth );
stream->read( &mSunElevation );
stream->read( &mLightColor );
stream->read( &mLightAmbient );
stream->read( &mBrightness );
mCastShadows = stream->readFlag();
stream->read( &mFlareScale );
if ( stream->readFlag() )
{
SimObjectId id = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
LightFlareData *datablock = NULL;
if ( Sim::findObject( id, datablock ) )
mFlareData = datablock;
else
{
conn->setLastError( "Sun::unpackUpdate() - invalid LightFlareData!" );
mFlareData = NULL;
}
}
else
mFlareData = NULL;
mCoronaEnabled = stream->readFlag();
stream->read( &mCoronaMatName );
stream->read( &mCoronaScale );
stream->read( &mCoronaTint );
mCoronaUseLightColor = stream->readFlag();
mLight->unpackExtended( stream );
}
if ( isProperlyAdded() )
{
_initCorona();
_conformLights();
}
}
void Sun::submitLights( LightManager *lm, bool staticLighting )
{
// The sun is a special light and needs special registration.
lm->setSpecialLight( LightManager::slSunLightType, mLight );
}
void Sun::advanceTime( F32 timeDelta )
{
if (mAnimateSun)
{
if (mCurrTime >= mTotalTime)
{
mAnimateSun = false;
mCurrTime = 0.0f;
}
else
{
mCurrTime += timeDelta;
F32 fract = mCurrTime / mTotalTime;
F32 inverse = 1.0f - fract;
F32 newAzimuth = mStartAzimuth * inverse + mEndAzimuth * fract;
F32 newElevation = mStartElevation * inverse + mEndElevation * fract;
if (newAzimuth > 360.0f)
newAzimuth -= 360.0f;
if (newElevation > 360.0f)
newElevation -= 360.0f;
setAzimuth(newAzimuth);
setElevation(newElevation);
}
}
}
void Sun::prepRenderImage( SceneRenderState *state )
{
// Only render into diffuse and reflect passes.
if( !state->isDiffusePass() &&
!state->isReflectPass() )
return;
mLightWorldPos = state->getCameraPosition() - state->getFarPlane() * mLight->getDirection() * 0.9f;
F32 dist = ( mLightWorldPos - state->getCameraPosition() ).len();
F32 screenRadius = GFX->getViewport().extent.y * mCoronaScale * 0.5f;
mCoronaWorldRadius = screenRadius * dist / state->getWorldToScreenScale().y;
// Render instance for Corona effect.
if ( mCoronaEnabled && mCoronaMatInst )
{
mMatrixSet->setSceneProjection( GFX->getProjectionMatrix() );
mMatrixSet->setSceneView( GFX->getViewMatrix() );
mMatrixSet->setWorld( GFX->getWorldMatrix() );
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
ri->renderDelegate.bind( this, &Sun::_renderCorona );
ri->type = RenderPassManager::RIT_Sky;
// Render after sky objects and before CloudLayer!
ri->defaultKey = 5;
ri->defaultKey2 = 0;
state->getRenderPass()->addInst( ri );
}
// LightFlareData handles rendering flare effects.
if ( mFlareData )
{
mFlareState.fullBrightness = mBrightness;
mFlareState.scale = mFlareScale;
mFlareState.lightInfo = mLight;
mFlareState.worldRadius = mCoronaWorldRadius;
mFlareState.lightMat.identity();
mFlareState.lightMat.setPosition( mLightWorldPos );
mFlareData->prepRender( state, &mFlareState );
}
}
void Sun::setAzimuth( F32 azimuth )
{
mSunAzimuth = azimuth;
_conformLights();
setMaskBits( UpdateMask ); // TODO: Break out the masks to save bandwidth!
}
void Sun::setElevation( F32 elevation )
{
mSunElevation = elevation;
_conformLights();
setMaskBits( UpdateMask ); // TODO: Break out the masks to save some space!
}
void Sun::setColor( const ColorF &color )
{
mLightColor = color;
_conformLights();
setMaskBits( UpdateMask ); // TODO: Break out the masks to save some space!
}
void Sun::animate( F32 duration, F32 startAzimuth, F32 endAzimuth, F32 startElevation, F32 endElevation )
{
mAnimateSun = true;
mCurrTime = 0.0f;
mTotalTime = duration;
mStartAzimuth = startAzimuth;
mEndAzimuth = endAzimuth;
mStartElevation = startElevation;
mEndElevation = endElevation;
}
void Sun::_conformLights()
{
// Build the light direction from the azimuth and elevation.
F32 yaw = mDegToRad(mClampF(mSunAzimuth,0,359));
F32 pitch = mDegToRad(mClampF(mSunElevation,-360,+360));
VectorF lightDirection;
MathUtils::getVectorFromAngles(lightDirection, yaw, pitch);
lightDirection.normalize();
mLight->setDirection( -lightDirection );
mLight->setBrightness( mBrightness );
// Now make sure the colors are within range.
mLightColor.clamp();
mLight->setColor( mLightColor );
mLightAmbient.clamp();
mLight->setAmbient( mLightAmbient );
// Optimization... disable shadows if the ambient and
// directional color are the same.
bool castShadows = mLightColor != mLightAmbient && mCastShadows;
mLight->setCastShadows( castShadows );
}
void Sun::_initCorona()
{
if ( isServerObject() )
return;
SAFE_DELETE( mCoronaMatInst );
if ( mCoronaMatName.isNotEmpty() )
mCoronaMatInst = MATMGR->createMatInstance( mCoronaMatName, MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPCT>() );
}
void Sun::_renderCorona( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat )
{
// Calculate Billboard Radius (in world units) to be constant, independent of distance.
// Takes into account distance, viewport size, and specified size in editor
F32 BBRadius = mCoronaWorldRadius;
mMatrixSet->restoreSceneViewProjection();
if ( state->isReflectPass() )
mMatrixSet->setProjection( state->getSceneManager()->getNonClipProjection() );
//mMatrixSet->setWorld( MatrixF::Identity );
// Initialize points with basic info
Point3F points[4];
points[0] = Point3F(-BBRadius, 0.0, -BBRadius);
points[1] = Point3F( -BBRadius, 0.0, BBRadius);
points[2] = Point3F( BBRadius, 0.0, BBRadius);
points[3] = Point3F( BBRadius, 0.0, -BBRadius);
static const Point2F sCoords[4] =
{
Point2F( 0.0f, 0.0f ),
Point2F( 0.0f, 1.0f ),
Point2F( 1.0f, 1.0f ),
Point2F( 1.0f, 0.0f )
};
// Get info we need to adjust points
const MatrixF &camView = state->getCameraTransform();
// Finalize points
for(int i = 0; i < 4; i++)
{
// align with camera
camView.mulV(points[i]);
// offset
points[i] += mLightWorldPos;
}
ColorF vertColor;
if ( mCoronaUseLightColor )
vertColor = mLightColor;
else
vertColor = mCoronaTint;
GFXVertexBufferHandle< GFXVertexPCT > vb;
vb.set( GFX, 4, GFXBufferTypeVolatile );
GFXVertexPCT *pVert = vb.lock();
for ( S32 i = 0; i < 4; i++ )
{
pVert->color.set( vertColor );
pVert->point.set( points[i] );
pVert->texCoord.set( sCoords[i].x, sCoords[i].y );
pVert++;
}
vb.unlock();
// Setup SceneData struct.
SceneData sgData;
sgData.wireframe = GFXDevice::getWireframe();
sgData.visibility = 1.0f;
// Draw it
while ( mCoronaMatInst->setupPass( state, sgData ) )
{
mCoronaMatInst->setTransforms( *mMatrixSet, state );
mCoronaMatInst->setSceneInfo( state, sgData );
GFX->setVertexBuffer( vb );
GFX->drawPrimitive( GFXTriangleFan, 0, 2 );
}
}
void Sun::_updateTimeOfDay( TimeOfDay *timeOfDay, F32 time )
{
setElevation( timeOfDay->getElevationDegrees() );
setAzimuth( timeOfDay->getAzimuthDegrees() );
}
void Sun::_onSelected()
{
#ifdef TORQUE_DEBUG
// Enable debug rendering on the light.
if( isClientObject() )
mLight->enableDebugRendering( true );
#endif
Parent::_onSelected();
}
void Sun::_onUnselected()
{
#ifdef TORQUE_DEBUG
// Disable debug rendering on the light.
if( isClientObject() )
mLight->enableDebugRendering( false );
#endif
Parent::_onUnselected();
}
ConsoleMethod(Sun, apply, void, 2, 2, "")
{
object->inspectPostApply();
}
ConsoleMethod(Sun, animate, void, 7, 7, "animate( F32 duration, F32 startAzimuth, F32 endAzimuth, F32 startElevation, F32 endElevation )")
{
F32 duration = dAtof(argv[2]);
F32 startAzimuth = dAtof(argv[3]);
F32 endAzimuth = dAtof(argv[4]);
F32 startElevation = dAtof(argv[5]);
F32 endElevation = dAtof(argv[6]);
object->animate(duration, startAzimuth, endAzimuth, startElevation, endElevation);
}

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 _SUN_H_
#define _SUN_H_
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
#ifndef _LIGHTINFO_H_
#include "lighting/lightInfo.h"
#endif
#ifndef _LIGHTFLAREDATA_H_
#include "T3D/lightFlareData.h"
#endif
class TimeOfDay;
class MatrixSet;
///
class Sun : public SceneObject, public ISceneLight
{
typedef SceneObject Parent;
protected:
F32 mSunAzimuth;
F32 mSunElevation;
ColorF mLightColor;
ColorF mLightAmbient;
F32 mBrightness;
bool mAnimateSun;
F32 mTotalTime;
F32 mCurrTime;
F32 mStartAzimuth;
F32 mEndAzimuth;
F32 mStartElevation;
F32 mEndElevation;
bool mCastShadows;
LightInfo *mLight;
LightFlareData *mFlareData;
LightFlareState mFlareState;
F32 mFlareScale;
bool mCoronaEnabled;
String mCoronaMatName;
BaseMatInstance *mCoronaMatInst;
MatrixSet *mMatrixSet;
F32 mCoronaScale;
ColorF mCoronaTint;
bool mCoronaUseLightColor;
// These are not user specified.
// These hold data calculated once used across several methods.
F32 mCoronaWorldRadius;
Point3F mLightWorldPos;
void _conformLights();
void _initCorona();
void _renderCorona( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
void _updateTimeOfDay( TimeOfDay *timeOfDay, F32 time );
// SimObject.
virtual void _onSelected();
virtual void _onUnselected();
enum NetMaskBits
{
UpdateMask = BIT(0)
};
public:
Sun();
virtual ~Sun();
// SimObject
virtual bool onAdd();
virtual void onRemove();
// ConsoleObject
DECLARE_CONOBJECT(Sun);
static void initPersistFields();
void inspectPostApply();
// NetObject
U32 packUpdate( NetConnection *conn, U32 mask, BitStream *stream );
void unpackUpdate( NetConnection *conn, BitStream *stream );
// ISceneLight
virtual void submitLights( LightManager *lm, bool staticLighting );
virtual LightInfo* getLight() { return mLight; }
// SceneObject
virtual void prepRenderImage( SceneRenderState* state );
// ProcessObject
virtual void advanceTime( F32 dt );
///
void setAzimuth( F32 azimuth );
///
void setElevation( F32 elevation );
///
void setColor( const ColorF &color );
///
void animate( F32 duration, F32 startAzimuth, F32 endAzimuth, F32 startElevation, F32 endElevation );
};
#endif // _SUN_H_

View file

@ -0,0 +1,745 @@
//-----------------------------------------------------------------------------
// 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 "environment/timeOfDay.h"
#include "console/consoleTypes.h"
#include "core/stream/bitStream.h"
#include "T3D/gameBase/gameConnection.h"
#include "environment/sun.h"
#include "console/engineAPI.h"
TimeOfDayUpdateSignal TimeOfDay::smTimeOfDayUpdateSignal;
IMPLEMENT_CO_NETOBJECT_V1(TimeOfDay);
ConsoleDocClass( TimeOfDay,
"@brief Environmental object that triggers a day/night cycle in level.\n\n"
"@note TimeOfDay only works in Advanced Lighting with a Sub object or ScatterSky\n\n"
"@tsexample\n"
"new TimeOfDay(tod)\n"
"{\n"
" axisTilt = \"23.44\";\n"
" dayLength = \"120\";\n"
" startTime = \"0.15\";\n"
" time = \"0.15\";\n"
" play = \"0\";\n"
" azimuthOverride = \"572.958\";\n"
" dayScale = \"1\";\n"
" nightScale = \"1.5\";\n"
" position = \"598.399 550.652 196.297\";\n"
" rotation = \"1 0 0 0\";\n"
" scale = \"1 1 1\";\n"
" canSave = \"1\";\n"
" canSaveDynamicFields = \"1\";\n"
"};\n"
"@endtsexample\n\n"
"@ingroup enviroMisc"
);
TimeOfDay::TimeOfDay()
: mElevation( 0.0f ),
mAzimuth( 0.0f ),
mAxisTilt( 23.44f ), // 35 degree tilt
mDayLen( 120.0f ), // 2 minutes
mStartTimeOfDay( 0.5f ), // High noon
mTimeOfDay( 0.0f ), // initialized to StartTimeOfDay in onAdd
mPlay( true ),
mDayScale( 1.0f ),
mNightScale( 1.5f ),
mAnimateTime( 0.0f ),
mAnimateSpeed( 0.0f ),
mAnimate( false )
{
mNetFlags.set( Ghostable | ScopeAlways );
mTypeMask = EnvironmentObjectType;
// Sets the sun vector directly overhead for lightmap generation
// The value of mSunVector is grabbed by the terrain lighting stuff.
/*
F32 ele, azi;
ele = azi = TORADIANS(90);
MathUtils::getVectorFromAngles(mSunVector, azi, ele);
*/
mPrevElevation = 0;
mNextElevation = 0;
mAzimuthOverride = 1.0f;
_initColors();
}
TimeOfDay::~TimeOfDay()
{
}
bool TimeOfDay::setTimeOfDay( void *object, const char *index, const char *data )
{
TimeOfDay *tod = static_cast<TimeOfDay*>(object);
tod->setTimeOfDay( dAtof( data ) );
return false;
}
bool TimeOfDay::setPlay( void *object, const char *index, const char *data )
{
TimeOfDay *tod = static_cast<TimeOfDay*>(object);
tod->setPlay( dAtob( data ) );
return false;
}
bool TimeOfDay::setDayLength( void *object, const char *index, const char *data )
{
TimeOfDay *tod = static_cast<TimeOfDay*>(object);
F32 length = dAtof( data );
if( length != 0 )
tod->setDayLength( length );
return false;
}
void TimeOfDay::initPersistFields()
{
addGroup( "TimeOfDay" );
addField( "axisTilt", TypeF32, Offset( mAxisTilt, TimeOfDay ),
"The angle in degrees between global equator and tropic." );
addProtectedField( "dayLength", TypeF32, Offset( mDayLen, TimeOfDay ), &setDayLength, &defaultProtectedGetFn,
"The length of a virtual day in real world seconds." );
addField( "startTime", TypeF32, Offset( mStartTimeOfDay, TimeOfDay ),
"" );
addProtectedField( "time", TypeF32, Offset( mTimeOfDay, TimeOfDay ), &setTimeOfDay, &defaultProtectedGetFn, "Current time of day." );
addProtectedField( "play", TypeBool, Offset( mPlay, TimeOfDay ), &setPlay, &defaultProtectedGetFn, "True when the TimeOfDay object is operating." );
addField( "azimuthOverride", TypeF32, Offset( mAzimuthOverride, TimeOfDay ), "" );
addField( "dayScale", TypeF32, Offset( mDayScale, TimeOfDay ), "Scalar applied to time that elapses while the sun is up." );
addField( "nightScale", TypeF32, Offset( mNightScale, TimeOfDay ), "Scalar applied to time that elapses while the sun is down." );
endGroup( "TimeOfDay" );
Parent::initPersistFields();
}
void TimeOfDay::consoleInit()
{
Parent::consoleInit();
//addVariable( "$TimeOfDay::currentTime", &TimeOfDay::smCurrentTime );
//addVariable( "$TimeOfDay::timeScale", TypeF32, &TimeOfDay::smTimeScale );
}
void TimeOfDay::inspectPostApply()
{
_updatePosition();
setMaskBits( OrbitMask );
}
void TimeOfDay::_onGhostAlwaysDone()
{
_updatePosition();
}
bool TimeOfDay::onAdd()
{
if ( !Parent::onAdd() )
return false;
// The server initializes to the specified starting values.
// The client initializes itself to the server time from
// unpackUpdate.
if ( isServerObject() )
{
mTimeOfDay = mStartTimeOfDay;
_updatePosition();
}
// We don't use a bounds.
setGlobalBounds();
resetWorldBox();
addToScene();
// Lets receive ghost events so we can resolve
// the sun object.
if ( isClientObject() )
NetConnection::smGhostAlwaysDone.notify( this, &TimeOfDay::_onGhostAlwaysDone );
if ( isServerObject() )
Con::executef( this, "onAdd" );
setProcessTick( true );
return true;
}
void TimeOfDay::onRemove()
{
if ( isClientObject() )
NetConnection::smGhostAlwaysDone.remove( this, &TimeOfDay::_onGhostAlwaysDone );
removeFromScene();
Parent::onRemove();
}
U32 TimeOfDay::packUpdate(NetConnection *conn, U32 mask, BitStream *stream )
{
U32 retMask = Parent::packUpdate( conn, mask, stream );
if ( stream->writeFlag( mask & OrbitMask ) )
{
stream->write( mStartTimeOfDay );
stream->write( mDayLen );
stream->write( mTimeOfDay );
stream->write( mAxisTilt );
stream->write( mAzimuthOverride );
stream->write( mDayScale );
stream->write( mNightScale );
stream->writeFlag( mPlay );
}
if ( stream->writeFlag( mask & AnimateMask ) )
{
stream->write( mAnimateTime );
stream->write( mAnimateSpeed );
}
return retMask;
}
void TimeOfDay::unpackUpdate( NetConnection *conn, BitStream *stream )
{
Parent::unpackUpdate( conn, stream );
if ( stream->readFlag() ) // OrbitMask
{
stream->read( &mStartTimeOfDay );
stream->read( &mDayLen );
stream->read( &mTimeOfDay );
stream->read( &mAxisTilt );
stream->read( &mAzimuthOverride );
stream->read( &mDayScale );
stream->read( &mNightScale );
mPlay = stream->readFlag();
_updatePosition();
}
if ( stream->readFlag() ) // AnimateMask
{
F32 time, speed;
stream->read( &time );
stream->read( &speed );
if( isProperlyAdded() )
animate( time, speed );
}
}
void TimeOfDay::processTick( const Move *move )
{
if ( mAnimate )
{
F32 current = mTimeOfDay * 360.0f;
F32 next = current + (mAnimateSpeed * TickSec);
// Protect for wrap around.
while ( next > 360.0f )
next -= 360.0f;
// Clamp to make sure we don't pass the target time.
if ( next >= mAnimateTime )
{
next = mAnimateTime;
mAnimate = false;
}
// Set the new time of day.
mTimeOfDay = next / 360.0f;
_updatePosition();
_updateTimeEvents();
if ( !mAnimate && isServerObject() )
Con::executef( this, "onAnimateDone" );
}
else if ( mPlay )
{
F32 dt = TickSec;
F32 current = mRadToDeg( mNextElevation );
if ( current > 350.0f || ( 0.0f <= current && current < 190.0f ) )
dt *= mDayScale;
else
dt *= mNightScale;
mTimeOfDay += dt / mDayLen;
// It could be possible for more than a full day to
// pass in a single advance time, so I put this inside a loop
// but timeEvents will not actually be called for the
// skipped day.
while ( mTimeOfDay > 1.0f )
mTimeOfDay -= 1.0f;
_updatePosition();
_updateTimeEvents();
}
else
_updatePosition();
}
void TimeOfDay::_updatePosition()
{
mPrevElevation = mNextElevation;
if ( mFabs( mAzimuthOverride ) )
{
mElevation = mDegToRad( mTimeOfDay * 360.0f );
mAzimuth = mAzimuthOverride;
mNextElevation = mElevation; // already normalized
}
else
{
//// Full azimuth/elevation calculation.
//// calculate sun decline and meridian angle (in radians)
//F32 sunDecline = mSin( M_2PI * mTimeOfYear ) * mDegToRad( mAxisTilt );
//F32 meridianAngle = mTimeOfDay * M_2PI - mDegToRad( mLongitude );
//// calculate the elevation and azimuth (in radians)
//mElevation = _calcElevation( mDegToRad( mLatitude ), sunDecline, meridianAngle );
//mAzimuth = _calcAzimuth( mDegToRad( mLatitude ), sunDecline, meridianAngle );
// Simplified azimuth/elevation calculation.
// calculate sun decline and meridian angle (in radians)
F32 sunDecline = mDegToRad( mAxisTilt );
F32 meridianAngle = mTimeOfDay * M_2PI;
// calculate the elevation and azimuth (in radians)
mElevation = _calcElevation( 0.0f, sunDecline, meridianAngle );
mAzimuth = _calcAzimuth( 0.0f, sunDecline, meridianAngle );
// calculate 'normalized' elevation (0=sunrise, PI/2=zenith, PI=sunset, 3PI/4=nadir)
F32 normElevation = M_PI_F * mElevation / ( 2 * _calcElevation( 0.0f, sunDecline, 0.0f ) );
if ( mAzimuth > M_PI_F )
normElevation = M_PI_F - normElevation;
else if ( mElevation < 0 )
normElevation = M_2PI_F + normElevation;
mNextElevation = normElevation;
}
// Only the client updates the sun position!
if ( isClientObject() )
smTimeOfDayUpdateSignal.trigger( this, mTimeOfDay );
}
F32 TimeOfDay::_calcElevation( F32 lat, F32 dec, F32 mer )
{
return mAsin( mSin(lat) * mSin(dec) + mCos(lat) * mCos(dec) * mCos(mer) );
}
F32 TimeOfDay::_calcAzimuth( F32 lat, F32 dec, F32 mer )
{
// Add PI to normalize this from the range of -PI/2 to PI/2 to 0 to 2 * PI;
return mAtan2( mSin(mer), mCos(mer) * mSin(lat) - mTan(dec) * mCos(lat) ) + M_PI_F;
}
void TimeOfDay::_getSunColor( ColorF *outColor ) const
{
const COLOR_TARGET *ct = NULL;
F32 ele = mClampF( M_2PI_F - mNextElevation, 0.0f, M_PI_F );
F32 phase = -1.0f;
F32 div;
if (!mColorTargets.size())
{
outColor->set(1.0f,1.0f,1.0f);
return;
}
if (mColorTargets.size() == 1)
{
ct = &mColorTargets[0];
outColor->set(ct->color.red, ct->color.green, ct->color.blue);
return;
}
//simple check
if ( mColorTargets[0].elevation != 0.0f )
{
AssertFatal(0, "TimeOfDay::GetColor() - First elevation must be 0.0 radians")
outColor->set(1.0f, 1.0f, 1.0f);
//mBandMod = 1.0f;
//mCurrentBandColor = color;
return;
}
if ( mColorTargets[mColorTargets.size()-1].elevation != M_PI_F )
{
AssertFatal(0, "Celestails::GetColor() - Last elevation must be PI")
outColor->set(1.0f, 1.0f, 1.0f);
//mBandMod = 1.0f;
//mCurrentBandColor = color;
return;
}
//we need to find the phase and interp... also loop back around
U32 count=0;
for (;count < mColorTargets.size() - 1; count++)
{
const COLOR_TARGET *one = &mColorTargets[count];
const COLOR_TARGET *two = &mColorTargets[count+1];
if (ele >= one->elevation && ele <= two->elevation)
{
div = two->elevation - one->elevation;
//catch bad input divide by zero
if ( mFabs( div ) < 0.01f )
div = 0.01f;
phase = (ele - one->elevation) / div;
outColor->interpolate( one->color, two->color, phase );
//mCurrentBandColor.interpolate(one->bandColor, two->bandColor, phase);
//mBandMod = one->bandMod * (1.0f - phase) + two->bandMod * phase;
return;
}
}
AssertFatal(0,"This isn't supposed to happen");
}
void TimeOfDay::_initColors()
{
// NOTE: The elevation targets represent distances
// from PI/2 radians (strait up).
ColorF c;
ColorF bc;
// e is for elevation
F32 e = M_PI_F / 13.0f; // (semicircle in radians)/(number of color target entries);
// Day
c.set(1.0f,1.0f,1.0f);
_addColorTarget(0, c, 1.0f, c); // High noon at equanox
c.set(.9f,.9f,.9f);
_addColorTarget(e * 1.0f, c, 1.0f, c);
c.set(.9f,.9f,.9f);
_addColorTarget(e * 2.0f, c, 1.0f, c);
c.set(.8f,.75f,.75f);
_addColorTarget(e * 3.0f, c, 1.0f, c);
c.set(.7f,.65f,.65f);
_addColorTarget(e * 4.0f, c, 1.0f, c);
//Dawn and Dusk (3 entries)
c.set(.7f,.65f,.65f);
bc.set(.8f,.6f,.3f);
_addColorTarget(e * 5.0f, c, 3.0f, bc);
c.set(.65f,.54f,.4f);
bc.set(.75f,.5f,.4f);
_addColorTarget(e * 6.0f, c, 2.75f, bc);
c.set(.55f,.45f,.25f);
bc.set(.65f,.3f,.3f);
_addColorTarget(e * 7.0f, c, 2.5f, bc);
//NIGHT
c.set(.3f,.3f,.3f);
bc.set(.7f,.4f,.2f);
_addColorTarget(e * 8.0f, c, 1.25f, bc);
c.set(.25f,.25f,.3f);
bc.set(.8f,.3f,.2f);
_addColorTarget(e * 9.0f, c, 1.00f, bc);
c.set(.25f,.25f,.4f);
_addColorTarget(e * 10.0f, c, 1.0f, c);
c.set(.2f,.2f,.35f);
_addColorTarget(e * 11.0f, c, 1.0f, c);
c.set(.15f,.15f,.2f);
_addColorTarget(M_PI_F, c, 1.0f, c); // Midnight at equanox.
}
void TimeOfDay::_addColorTarget( F32 ele, const ColorF &color, F32 bandMod, const ColorF &bandColor )
{
COLOR_TARGET newTarget;
newTarget.elevation = ele;
newTarget.color = color;
newTarget.bandMod = bandMod;
newTarget.bandColor = bandColor;
mColorTargets.push_back(newTarget);
}
void TimeOfDay::_updateTimeEvents()
{
if ( mTimeEvents.empty() )
return;
// Get the prev, next elevation in degrees since TimeOfDayEvent is specified
// in degrees.
F32 prevElevation = mRadToDeg( mPrevElevation );
F32 nextElevation = mRadToDeg( mNextElevation );
// If prevElevation is less than nextElevation then its the next day.
// Unroll it so we can just loop forward in time and simplify our loop.
if ( nextElevation < prevElevation )
nextElevation += 360.0f;
const U32 evtCount = mTimeEvents.size();
// Find where in the event list we need to start...
// The first timeEvent with elevation greater than our previous elevation.
U32 start = 0;
for ( ; start < evtCount; start++ )
{
if ( mTimeEvents[start].triggerElevation > prevElevation )
break;
}
bool onNextDay = false;
// Nothing between prevElevation and the end of the day...
// Check between start of the day and nextElevation...
if ( start == evtCount )
{
start = 0;
for ( ; start < evtCount; start++ )
{
if ( mTimeEvents[start].triggerElevation <= nextElevation )
{
onNextDay = true;
break;
}
}
}
// No events were hit...
if ( start == evtCount )
return;
U32 itr = start;
while ( true )
{
TimeOfDayEvent &timeEvent = mTimeEvents[itr];
F32 elev = timeEvent.triggerElevation;
if ( onNextDay )
elev += 360.0f;
// Hit an event that happens later after nextElevation so we
// have checked everything within the range and are done.
if ( elev > nextElevation )
break;
// If its not greater than the nextElevation it must be less, and if
// we are here we already know its greater than prevElevation.
AssertFatal( elev >= prevElevation && elev <= nextElevation, "TimeOfDay::_updateTimeEvents - Logical error in here!" );
AssertFatal( !timeEvent.deleteMe, "TimeOfDay::_updateTimeEvents - tried to fire the same event twice!" );
_onTimeEvent( timeEvent.identifier );
if ( timeEvent.oneShot )
timeEvent.deleteMe = true;
// On to the next time event...
itr++;
// We hit the end of the day?
if ( itr == evtCount )
{
// We are already on the next day so we have checked everything.
if ( onNextDay )
break;
// Check events for the next day
else
{
itr = 0;
onNextDay = true;
}
}
}
// Cleanup one-shot events that fired...
for ( S32 i = 0; i < mTimeEvents.size(); i++ )
{
if ( mTimeEvents[i].deleteMe )
{
// Don't use erase_fast, there are ordered.
mTimeEvents.erase( i );
i--;
}
}
}
void TimeOfDay::addTimeEvent( F32 triggerElevation, const UTF8 *identifier )
{
// Insert in ascending order of elevation.
// Note that having more than one TimeEvent with the same triggerElevation
// may cause undefined behavior.
TimeOfDayEvent *pEvent = NULL;
if ( mTimeEvents.empty() || mTimeEvents.last().triggerElevation <= triggerElevation )
{
mTimeEvents.increment();
pEvent = &mTimeEvents.last();
}
else
{
for ( S32 i = 0; i < mTimeEvents.size(); i++ )
{
if ( mTimeEvents[i].triggerElevation > triggerElevation )
{
mTimeEvents.insert( i );
pEvent = &mTimeEvents[i];
break;
}
}
}
AssertFatal( pEvent, "TimeOfDay::addTimeEvent - could not find place to insert event." );
pEvent->triggerElevation = triggerElevation;
pEvent->identifier = identifier;
pEvent->oneShot = false;
pEvent->deleteMe = false;
}
void TimeOfDay::setTimeOfDay( F32 time )
{
mTimeOfDay = time;
while ( mTimeOfDay > 1.0f )
mTimeOfDay -= 1.0f;
while ( mTimeOfDay < 0.0f )
mTimeOfDay += 1.0f;
_updatePosition();
//if ( isServerObject() )
_updateTimeEvents();
setMaskBits( OrbitMask );
}
void TimeOfDay::_onTimeEvent( const String &identifier )
{
// Client doesn't do onTimeEvent callbacks.
if ( isClientObject() )
return;
String strCurrentTime = String::ToString( "%g", mTimeOfDay );
F32 elevation = mRadToDeg( mNextElevation );
while( elevation < 0 )
elevation += 360.0f;
while( elevation > 360.0f )
elevation -= 360.0f;
String strCurrentElevation = String::ToString( "%g", elevation );
Con::executef( this, "onTimeEvent", identifier.c_str(), strCurrentTime.c_str(), strCurrentElevation.c_str() );
}
void TimeOfDay::animate( F32 time, F32 speed )
{
// Stop any existing animation... this one
// becomes the new one.
mAnimate = false;
// Set the target time to hit.
mAnimateTime = mClamp(time, 0.0f, 360.0f);
F32 current = mTimeOfDay * 360.0f;
F32 target = mAnimateTime;
if ( target < current )
target += 360.0f;
// If we're already at the current time then
// we have nothing more to do... the animation is here.
F32 dif = target - current;
if ( mIsZero( dif ) )
return;
// Start playback.
mAnimateSpeed = speed;
mAnimate = true;
if ( isServerObject() )
{
Con::executef( this, "onAnimateStart" );
setMaskBits( AnimateMask );
}
}
DefineEngineMethod( TimeOfDay, addTimeOfDayEvent, void, (F32 elevation, const char *identifier ),,
"" )
{
object->addTimeEvent( elevation, identifier );
}
DefineEngineMethod( TimeOfDay, setTimeOfDay, void, ( F32 time ),,
"" )
{
object->setTimeOfDay( time );
}
DefineEngineMethod( TimeOfDay, setPlay, void, ( bool enabled ),,
"")
{
object->setPlay( enabled );
}
DefineEngineMethod( TimeOfDay, setDayLength, void, ( F32 seconds ),,
"" )
{
if ( seconds > 0.0f )
object->setDayLength( seconds );
}
DefineEngineMethod( TimeOfDay, animate, void, ( F32 elevation, F32 degreesPerSecond ),,
"")
{
object->animate( elevation, degreesPerSecond );
}

View file

@ -0,0 +1,212 @@
//-----------------------------------------------------------------------------
// 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 _TIMEOFDAY_H_
#define _TIMEOFDAY_H_
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
class Sun;
class TimeOfDay;
struct COLOR_TARGET
{
F32 elevation; // maximum target elevation
ColorF color; //normalized 0 = 1.0 ...
F32 bandMod; //6 is max
ColorF bandColor;
};
typedef Vector<COLOR_TARGET> COLOR_TARGETS;
typedef Signal<void(TimeOfDay *timeOfDay, F32 time)> TimeOfDayUpdateSignal;
struct TimeOfDayEvent
{
// The elevation at which
// this event will fire.
F32 triggerElevation;
// User identifier for the event.
String identifier;
// Remove this event when it fires.
bool oneShot;
// For internal use.
bool deleteMe;
};
class TimeOfDay : public SceneObject
{
typedef SceneObject Parent;
public:
static S32 smCurrentTime;
static F32 smTimeScale; // To pause or resume time flow from outside this object, like in the editor.
TimeOfDay();
virtual ~TimeOfDay();
// ConsoleObject
static void initPersistFields();
static void consoleInit();
DECLARE_CONOBJECT( TimeOfDay );
void inspectPostApply();
// SimObject
virtual bool onAdd();
virtual void onRemove();
// NetObject
U32 packUpdate( NetConnection *conn, U32 mask, BitStream *stream );
void unpackUpdate( NetConnection *conn, BitStream *stream );
// ProcessObject
virtual void processTick( const Move *move );
F32 getAzimuthRads() { return mAzimuth; }
F32 getElevationRads() { return mElevation; }
F32 getAzimuthDegrees() { return mRadToDeg(mAzimuth); }
F32 getElevationDegrees() { return mRadToDeg(mElevation); }
/*
// Sun position stuff
void UpdateSunPosition(void);
// void UpdateSunPosition(fxSunLight *sunLight);
// Scene lighting (Adapted from Joshua Ritter's Day/Night cycle code)
// I changed references to pointers on the basis of principle. ;-)
void EnableLighting(F32 emissiveScale = 1.0);
void DisableLighting();
F32 GetIntensity()
{ return (mCurrentColor.blue + mCurrentColor.green + mCurrentColor.red) / 3; }
*/
static TimeOfDayUpdateSignal& getTimeOfDayUpdateSignal() { return smTimeOfDayUpdateSignal; }
void getSunColor( ColorF *outColor ) const { _getSunColor( outColor ); }
void addTimeEvent( F32 triggerElevation, const UTF8 *identifier );
void setTimeOfDay( F32 time );
void setPlay( bool play ) { mPlay = play; setMaskBits( OrbitMask ); }
void setDayLength( F32 length ) { mDayLen = length; setMaskBits( OrbitMask ); }
void animate( F32 time, F32 speed );
protected:
Vector<TimeOfDayEvent> mTimeEvents;
void _updateTimeEvents();
void _onTimeEvent( const String &identifier );
static TimeOfDayUpdateSignal smTimeOfDayUpdateSignal;
enum NetMaskBits
{
OrbitMask = Parent::NextFreeMask << 0,
AnimateMask = Parent::NextFreeMask << 1
};
void _updatePosition();
void _onGhostAlwaysDone();
F32 _calcElevation( F32 lat, F32 dec, F32 mer );
F32 _calcAzimuth( F32 lat, F32 dec, F32 mer );
/// Adds all of our target colors to our COLOR_TARGETS.
void _initColors();
/// Adds a color target to our set of targets.
///
/// @param ele [in] target sun elevation.
/// @param color [in] target color.
/// @param bandMod [in]
/// @param bandColor [in]
void _addColorTarget( F32 ele, const ColorF &color, F32 bandMod, const ColorF &bandColor );
// Grab our sun and sky colors based upon sun elevation.
void _getSunColor( ColorF *outColor ) const;
static bool setTimeOfDay( void *object, const char *index, const char *data );
static bool setPlay( void *object, const char *index, const char *data );
static bool setDayLength( void *object, const char *index, const char *data );
/*
// Get a pointer to the sun's light object
Sun* GetSunObject();
// return number between 0 and 1 representing color variance
F32 getColorVariance();
*/
// Date tracking stuff
F32 mStartTimeOfDay; ///< The time of day this object begins at.
F32 mDayLen; ///< length of day in real world seconds.
F32 mPrevElevation; ///< The 0-360 normalized elevation for the previous update.
F32 mNextElevation; ///< The 0-360 normalized elevation for the next update.
F32 mTimeOfDay; ///< The zero to one time of day where zero is the start of a day and one is the end.
F32 mAzimuthOverride; ///< Used to specify an azimuth that will stay constant throughout the day cycle.
// Global positioning stuff
F32 mAxisTilt; // angle between global equator and tropic
F32 mAzimuth; // Angle from true north of celestial object in radians
F32 mElevation; // Angle from horizon of celestial object in radians
VectorF mZenithDirection; // The direction of celestial object at the zenith of its orbit.
// Scalar applied to time that elapses while the sun is up.
F32 mDayScale;
// Scalar applied to time that elapses while the sun is down.
F32 mNightScale;
// color management
COLOR_TARGETS mColorTargets;
F32 mAnimateTime;
F32 mAnimateSpeed;
bool mAnimate;
/*
ColorF mCurrentColor;
F32 mBandMod;
ColorF mCurrentBandColor;
// PersistFields preparation
bool mConvertedToRads;
*/
// Debugging stuff that probably needs to be removed eventaully
bool mPlay;
};
#endif // _TIMEOFDAY_H_

View file

@ -0,0 +1,700 @@
//-----------------------------------------------------------------------------
// 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 "environment/waterBlock.h"
#include "core/util/safeDelete.h"
#include "scene/sceneRenderState.h"
#include "scene/sceneManager.h"
#include "lighting/lightInfo.h"
#include "core/stream/bitStream.h"
#include "math/mathIO.h"
#include "console/consoleTypes.h"
#include "gui/3d/guiTSControl.h"
#include "gfx/primBuilder.h"
#include "gfx/gfxTransformSaver.h"
#include "gfx/gfxDebugEvent.h"
#include "gfx/gfxOcclusionQuery.h"
#include "renderInstance/renderPassManager.h"
#include "sim/netConnection.h"
#include "scene/reflectionManager.h"
#include "ts/tsShapeInstance.h"
#include "postFx/postEffect.h"
#include "math/util/matrixSet.h"
IMPLEMENT_CO_NETOBJECT_V1(WaterBlock);
ConsoleDocClass( WaterBlock,
"@brief A block shaped water volume defined by a 3D scale and orientation.\n\n"
"@see WaterObject for inherited functionality.\n\n"
"@ingroup Water"
);
WaterBlock::WaterBlock()
{
mGridElementSize = 5.0f;
mObjScale.set( 100.0f, 100.0f, 10.0f );
mNetFlags.set(Ghostable | ScopeAlways);
mObjBox.minExtents.set( -0.5f, -0.5f, -0.5f );
mObjBox.maxExtents.set( 0.5f, 0.5f, 0.5f );
mElapsedTime = 0.0f;
mGenerateVB = true;
}
WaterBlock::~WaterBlock()
{
}
bool WaterBlock::onAdd()
{
if ( !Parent::onAdd() )
return false;
resetWorldBox();
addToScene();
return true;
}
void WaterBlock::onRemove()
{
clearVertBuffers();
removeFromScene();
Parent::onRemove();
}
//-----------------------------------------------------------------------------
// packUpdate
//-----------------------------------------------------------------------------
U32 WaterBlock::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
{
U32 retMask = Parent::packUpdate(con, mask, stream);
stream->write( mGridElementSize );
if ( stream->writeFlag( mask & UpdateMask ) )
{
// This is set to allow the user to modify the size of the water dynamically
// in the editor
mathWrite( *stream, mObjScale );
stream->writeAffineTransform( mObjToWorld );
}
return retMask;
}
//-----------------------------------------------------------------------------
// unpackUpdate
//-----------------------------------------------------------------------------
void WaterBlock::unpackUpdate(NetConnection* con, BitStream* stream)
{
Parent::unpackUpdate(con, stream);
F32 gridSize = mGridElementSize;
stream->read( &mGridElementSize );
if ( gridSize != mGridElementSize )
mGenerateVB = true;
if( stream->readFlag() ) // UpdateMask
{
Point3F scale;
mathRead( *stream, &scale );
setScale( scale );
MatrixF objToWorld;
stream->readAffineTransform( &objToWorld );
setTransform( objToWorld );
}
}
//-----------------------------------------------------------------------------
// Setup vertex and index buffers
//-----------------------------------------------------------------------------
void WaterBlock::setupVBIB()
{
clearVertBuffers();
const U32 maxIndexedVerts = 65536; // max number of indexed verts with U16 size indices
if( mObjScale.x < mGridElementSize ||
mObjScale.y < mGridElementSize )
{
F32 oldGridSize = mGridElementSize;
mGridElementSize = getMin(mObjScale.x, mObjScale.y);
logWarning("gridElementSize %g is larger than scale (%g, %g), clamping gridElementSize to %g",
oldGridSize, mObjScale.x, mObjScale.y, mGridElementSize);
}
Point3F div = getScale() / mGridElementSize;
// Add one to width and height for the edge.
mWidth = (U32)mCeil(div.x) + 1;
mHeight = (U32)mCeil(div.y) + 1;
if( mWidth > maxIndexedVerts / 2 )
mWidth = maxIndexedVerts / 2;
// figure out how many blocks are needed and their size
U32 maxBlockRows = maxIndexedVerts / mWidth;
U32 rowOffset = 0;
while( (rowOffset+1) < mHeight )
{
U32 numRows = mHeight - rowOffset;
if( numRows == 1 ) numRows++;
if( numRows > maxBlockRows )
{
numRows = maxBlockRows;
}
setupVertexBlock( mWidth, numRows, rowOffset );
setupPrimitiveBlock( mWidth, numRows );
rowOffset += numRows - 1;
}
}
//-----------------------------------------------------------------------------
// Set up a block of vertices - the width is always the width of the entire
// waterBlock, so this is a block of full rows.
//-----------------------------------------------------------------------------
void WaterBlock::setupVertexBlock( U32 width, U32 height, U32 rowOffset )
{
Point3F pos = getPosition();
RayInfo rInfo;
VectorF sunVector(-0.61f, 0.354f, 0.707f);
if ( LIGHTMGR )
{
LightInfo* linfo = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
if ( linfo )
sunVector = linfo->getDirection();
}
sunVector.normalize();
U32 numVerts = width * height;
GFXWaterVertex *verts = new GFXWaterVertex[ numVerts ];
ColorI waterColor(31, 56, 64, 127);
GFXVertexColor vertCol(waterColor);
U32 index = 0;
for( U32 i=0; i<height; i++ )
{
for( U32 j=0; j<width; j++, index++ )
{
F32 vertX = getMin((-mObjScale.x / 2.0f) + mGridElementSize * j, mObjScale.x / 2.0f);
F32 vertY = getMin((-mObjScale.y / 2.0f) + mGridElementSize * (i + rowOffset), mObjScale.y / 2.0f);
GFXWaterVertex *vert = &verts[index];
vert->point.x = vertX;
vert->point.y = vertY;
vert->point.z = 0.0;
vert->color = vertCol;
vert->normal.set(0,0,1);
vert->undulateData.set( vertX, vertY );
vert->horizonFactor.set( 0, 0, 0, 0 );
// Calculate the water depth
/*
vert->depthData.set( 0.0f, 0.0f );
Point3F start, end;
Point3F worldPoint = vert->point + pos;
start.x = end.x = worldPoint.x;
start.y = end.y = worldPoint.y;
start.z = -2000; // Really high, might be over kill
end.z = 2000; // really low, might be overkill
// Cast a ray to see how deep the water is. We are
// currently just testing for terrain and atlas
// objects, but potentially any object that responds
// to a ray cast could detected.
if(gClientContainer.castRay(start, end,
//StaticObjectType |
InteriorObjectType |
//ShapeBaseObjectType |
//StaticShapeObjectType |
//ItemObjectType |
//StaticTSObjectType |
TerrainObjectType
, &rInfo))
{
F32 depth = -(rInfo.point.z - pos.z);
if(depth <= 0.0f)
{
depth = 1.0f;
}
else
{
depth = depth / mVisibilityDepth;
if(depth > 1.0f)
{
depth = 1.0f;
}
depth = 1.0f - depth;
}
vert->depthData.x = depth;
}
else
{
vert->depthData.x = 0.0f;
}
// Cast a ray to do some AO-style shadowing.
F32 &shadow = vert->depthData.y;
if(gClientContainer.castRay(worldPoint, worldPoint + sunVector * 9000.f,
//StaticObjectType |
InteriorObjectType |
//ShapeBaseObjectType |
//StaticShapeObjectType |
//ItemObjectType |
//StaticTSObjectType |
TerrainObjectType
, &rInfo))
{
shadow = 0.f;
}
else
{
shadow = 1.f;
}
*/
}
}
// copy to vertex buffer
GFXVertexBufferHandle <GFXWaterVertex> * vertBuff = new GFXVertexBufferHandle <GFXWaterVertex>;
vertBuff->set( GFX, numVerts, GFXBufferTypeStatic );
GFXWaterVertex *vbVerts = vertBuff->lock();
dMemcpy( vbVerts, verts, sizeof(GFXWaterVertex) * numVerts );
vertBuff->unlock();
mVertBuffList.push_back( vertBuff );
delete [] verts;
}
//-----------------------------------------------------------------------------
// Set up a block of indices to match the block of vertices. The width is
// always the width of the entire waterBlock, so this is a block of full rows.
//-----------------------------------------------------------------------------
void WaterBlock::setupPrimitiveBlock( U32 width, U32 height )
{
AssertFatal( height > 1, "WaterBlock::setupPrimitiveBlock() - invalid height" );
// setup vertex / primitive buffers
U32 numIndices = (width-1) * (height-1) * 6;
U16 *indices = new U16[ numIndices ];
U32 numVerts = width * height;
// This uses indexed triangle lists instead of strips, but it shouldn't be
// significantly slower if the indices cache well.
// Rough diagram of the index order
// 0----2----+ ...
// | / | |
// |/ | |
// 1----3----+ ...
// | | |
// | | |
// +----+----+ ...
U32 index = 0;
for( U32 i=0; i<(height-1); i++ )
{
for( U32 j=0; j<(width-1); j++, index+=6 )
{
// Process one quad at a time. Note it will re-use the same indices from
// previous quad, thus optimizing vert cache. Cache will run out at
// end of each row with this implementation however.
indices[index+0] = (i) * mWidth + j; // 0
indices[index+1] = (i+1) * mWidth + j; // 1
indices[index+2] = i * mWidth + j+1; // 2
indices[index+3] = (i+1) * mWidth + j; // 1
indices[index+4] = (i+1) * mWidth + j+1; // 3
indices[index+5] = i * mWidth + j+1; // 2
}
}
GFXPrimitiveBufferHandle *indexBuff = new GFXPrimitiveBufferHandle;
GFXPrimitive pInfo;
pInfo.type = GFXTriangleList;
pInfo.numPrimitives = numIndices / 3;
pInfo.startIndex = 0;
pInfo.minIndex = 0;
pInfo.numVertices = numVerts;
U16 *ibIndices;
GFXPrimitive *piInput;
indexBuff->set( GFX, numIndices, 1, GFXBufferTypeStatic );
indexBuff->lock( &ibIndices, &piInput );
dMemcpy( ibIndices, indices, numIndices * sizeof(U16) );
dMemcpy( piInput, &pInfo, sizeof(GFXPrimitive) );
indexBuff->unlock();
mPrimBuffList.push_back( indexBuff );
delete [] indices;
}
//------------------------------------------------------------------------------
// Setup scenegraph data structure for materials
//------------------------------------------------------------------------------
SceneData WaterBlock::setupSceneGraphInfo( SceneRenderState *state )
{
SceneData sgData;
sgData.lights[0] = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
// fill in water's transform
sgData.objTrans = &getRenderTransform();
// fog
sgData.setFogParams( state->getSceneManager()->getFogData() );
// misc
sgData.backBuffTex = REFLECTMGR->getRefractTex();
sgData.reflectTex = mPlaneReflector.reflectTex;
sgData.wireframe = GFXDevice::getWireframe() || smWireframe;
return sgData;
}
//-----------------------------------------------------------------------------
// set shader parameters
//-----------------------------------------------------------------------------
void WaterBlock::setShaderParams( SceneRenderState *state, BaseMatInstance *mat, const WaterMatParams &paramHandles)
{
// Set variables that will be assigned to shader consts within WaterCommon
// before calling Parent::setShaderParams
mUndulateMaxDist = F32_MAX;
Parent::setShaderParams( state, mat, paramHandles );
// Now set the rest of the shader consts that are either unique to this
// class or that WaterObject leaves to us to handle...
MaterialParameters* matParams = mat->getMaterialParameters();
// set vertex shader constants
//-----------------------------------
MatrixF modelMat( getRenderTransform() );
if ( paramHandles.mModelMatSC->isValid() )
matParams->set(paramHandles.mModelMatSC, modelMat, GFXSCT_Float4x4);
matParams->setSafe(paramHandles.mGridElementSizeSC, (F32)mGridElementSize);
// set pixel shader constants
//-----------------------------------
ColorF c( mWaterFogData.color );
matParams->setSafe( paramHandles.mBaseColorSC, c );
// By default we need to show a true reflection is fullReflect is enabled and
// we are above water.
F32 reflect = mPlaneReflector.isEnabled() && !isUnderwater( state->getCameraPosition() );
// If we were occluded the last frame a query was fetched ( not necessarily last frame )
// and we weren't updated last frame... we don't have a valid texture to show
// so use the cubemap / fake reflection color this frame.
if ( mPlaneReflector.lastUpdateMs != REFLECTMGR->getLastUpdateMs() && mPlaneReflector.isOccluded() )
reflect = false;
Point4F reflectParams( mWaterPos.z, 0.0f, 1000.0f, !reflect );
matParams->setSafe( paramHandles.mReflectParamsSC, reflectParams );
VectorF reflectNorm = mReflectNormalUp ? VectorF(0,0,1) : static_cast<VectorF>(mPlaneReflector.refplane);
matParams->setSafe(paramHandles.mReflectNormalSC, reflectNorm );
}
void WaterBlock::innerRender( SceneRenderState *state )
{
GFXDEBUGEVENT_SCOPE( WaterBlock_innerRender, ColorI( 255, 0, 0 ) );
if ( mGenerateVB )
{
setupVBIB();
mGenerateVB = false;
}
// Setup SceneData
SceneData sgData = setupSceneGraphInfo( state );
const Point3F &camPosition = state->getCameraPosition();
// set the material
S32 matIdx = getMaterialIndex( camPosition );
if ( !initMaterial( matIdx ) )
return;
BaseMatInstance *mat = mMatInstances[matIdx];
WaterMatParams matParams = mMatParamHandles[matIdx];
// render the geometry
if ( mat )
{
// setup proj/world transform
mMatrixSet->setWorld(getRenderTransform());
mMatrixSet->restoreSceneViewProjection();
setShaderParams( state, mat, matParams );
while ( mat->setupPass( state, sgData ) )
{
mat->setSceneInfo(state, sgData);
mat->setTransforms(*mMatrixSet, state);
setCustomTextures( matIdx, mat->getCurPass(), matParams );
for ( U32 i = 0; i < mVertBuffList.size(); i++ )
{
GFX->setVertexBuffer( *mVertBuffList[i] );
GFXPrimitiveBuffer *primBuff = *mPrimBuffList[i];
GFX->setPrimitiveBuffer( primBuff );
GFX->drawPrimitives();
}
}
}
}
bool WaterBlock::setGridSizeProperty( void *obj, const char *index, const char *data )
{
WaterBlock* object = static_cast<WaterBlock*>(obj);
F32 gridSize = dAtof(data);
Point3F scale = object->getScale();
if(gridSize < 0.001f)
{
object->logWarning("gridSize cannot be <= 0, clamping to scale");
gridSize = getMin(scale.x, scale.y);
}
if(gridSize > scale.x || gridSize > scale.y)
{
object->logWarning("gridSize cannot be > scale. Your scale is (%g, %g) and your gridsize is %g",
scale.x, scale.y, gridSize);
gridSize = getMin(scale.x, scale.y);
}
object->mGridElementSize = gridSize;
// This is a hack so the console system doesn't go in and set our variable
// again, after we've already set it (possibly with a different value...)
return false;
}
//-----------------------------------------------------------------------------
// initPersistFields
//-----------------------------------------------------------------------------
void WaterBlock::initPersistFields()
{
addGroup( "WaterBlock" );
addProtectedField( "gridElementSize", TypeF32, Offset( mGridElementSize, WaterBlock ),
&setGridSizeProperty, &defaultProtectedGetFn, "Spacing between vertices in the WaterBlock mesh" );
addProtectedField( "gridSize", TypeF32, Offset( mGridElementSize, WaterBlock ),
&setGridSizeProperty, &defaultProtectedGetFn, "Duplicate of gridElementSize for backwards compatility" );
endGroup( "WaterBlock" );
Parent::initPersistFields();
}
bool WaterBlock::isUnderwater( const Point3F &pnt ) const
{
// Transform point into object space so we can test if it is within
// the WaterBlock's object box, include rotation/scale.
Point3F objPnt = pnt;
mWorldToObj.mulP( pnt, &objPnt );
objPnt.z -= 0.1f;
Box3F testBox = mObjBox;
testBox.scale( mObjScale );
// We already tested if below the surface plane,
// so clamping the z height of the box is not really necessary.
testBox.maxExtents.z = testBox.getCenter().z;
if ( testBox.isContained( objPnt ) )
return true;
return false;
}
void WaterBlock::clearVertBuffers()
{
for( U32 i=0; i<mVertBuffList.size(); i++ )
delete mVertBuffList[i];
mVertBuffList.clear();
for( U32 i=0; i<mPrimBuffList.size(); i++ )
delete mPrimBuffList[i];
mPrimBuffList.clear();
}
void WaterBlock::inspectPostApply()
{
Parent::inspectPostApply();
VectorF scale = getScale();
if( scale.x < mGridElementSize )
scale.x = mGridElementSize;
if( scale.y < mGridElementSize )
scale.y = mGridElementSize;
if( scale != getScale() )
setScale( scale );
setMaskBits( UpdateMask );
}
void WaterBlock::setTransform( const MatrixF &mat )
{
// If our transform changes we need to recalculate the
// per vertex depth/shadow info. Would be nice if this could
// be done independently of generating the whole VBIB...
MatrixF oldMat = mObjToWorld;
Parent::setTransform( mat );
// We don't need to regen our vb anymore since we aren't calculating
// per vert depth/shadow on the cpu anymore.
//if ( oldMat != mObjToWorld )
// mGenerateVB = true;
// Keep mWaterPlane up to date.
mWaterFogData.plane.set( 0, 0, 1, -getPosition().z );
}
void WaterBlock::setScale( const Point3F &scale )
{
Point3F oldScale = mObjScale;
Parent::setScale( scale );
if ( oldScale != mObjScale )
mGenerateVB = true;
}
void WaterBlock::onStaticModified( const char* slotName, const char*newValue )
{
Parent::onStaticModified( slotName, newValue );
if ( dStricmp( slotName, "surfMaterial" ) == 0 )
setMaskBits( MaterialMask );
if ( dStricmp( slotName, "gridElementSize" ) == 0 )
{
mGenerateVB = true;
setMaskBits( UpdateMask );
}
}
bool WaterBlock::castRay( const Point3F &start, const Point3F &end, RayInfo *info )
{
// Simply look for the hit on the water plane
// and ignore any future issues with waves, etc.
const Point3F norm(0,0,1);
PlaneF plane( Point3F::Zero, norm );
F32 hit = plane.intersect( start, end );
if ( hit < 0.0f || hit > 1.0f )
return false;
info->t = hit;
info->object = this;
info->point = start + ( ( end - start ) * hit );
info->normal = norm;
info->material = mMatInstances[WaterMat];
return mObjBox.isContained(info->point);
}
F32 WaterBlock::getWaterCoverage( const Box3F &testBox ) const
{
Box3F wbox = getWorldBox();
wbox.maxExtents.z = wbox.getCenter().z;
F32 coverage = 0.0f;
if ( wbox.isOverlapped(testBox) )
{
if (wbox.maxExtents.z < testBox.maxExtents.z)
coverage = (wbox.maxExtents.z - testBox.minExtents.z) / (testBox.maxExtents.z - testBox.minExtents.z);
else
coverage = 1.0f;
}
return coverage;
}
F32 WaterBlock::getSurfaceHeight( const Point2F &pos ) const
{
if ( !mWorldBox.isContained( pos ) )
return -1.0f;
return getPosition().z;
}
void WaterBlock::_getWaterPlane( const Point3F &camPos, PlaneF &outPlane, Point3F &outPos )
{
outPos = getPosition();
if ( mReflectNormalUp )
outPlane.set( outPos, Point3F(0,0,1) );
else
{
Point3F normal;
getRenderTransform().getColumn( 2, &normal );
outPlane.set( outPos, normal );
}
}
F32 WaterBlock::distanceTo( const Point3F& point ) const
{
Box3F waterBox = getWorldBox();
waterBox.maxExtents.z = getPosition().z;
return waterBox.getDistanceToPoint( point );
}

View file

@ -0,0 +1,152 @@
//-----------------------------------------------------------------------------
// 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 _WATERBLOCK_H_
#define _WATERBLOCK_H_
#ifndef _GAMEBASE_H_
#include "T3D/gameBase/gameBase.h"
#endif
#ifndef _GFXDEVICE_H_
#include "gfx/gfxDevice.h"
#endif
#ifndef _SCENEDATA_H_
#include "materials/sceneData.h"
#endif
#ifndef _MATINSTANCE_H_
#include "materials/matInstance.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#ifndef _RENDERPASSMANAGER_H_
#include "renderInstance/renderPassManager.h"
#endif
#ifndef _WATEROBJECT_H_
#include "waterObject.h"
#endif
//*****************************************************************************
// WaterBlock
//*****************************************************************************
class WaterBlock : public WaterObject
{
typedef WaterObject Parent;
public:
// LEGACY support
enum EWaterType
{
eWater = 0,
eOceanWater = 1,
eRiverWater = 2,
eStagnantWater = 3,
eLava = 4,
eHotLava = 5,
eCrustyLava = 6,
eQuicksand = 7,
};
private:
enum MaskBits {
UpdateMask = Parent::NextFreeMask,
NextFreeMask = Parent::NextFreeMask << 1
};
// vertex / index buffers
Vector< GFXVertexBufferHandle<GFXWaterVertex>* > mVertBuffList;
Vector<GFXPrimitiveBufferHandle*> mPrimBuffList;
GFXVertexBufferHandle<GFXVertexPC> mRadialVertBuff;
GFXPrimitiveBufferHandle mRadialPrimBuff;
// misc
F32 mGridElementSize;
U32 mWidth;
U32 mHeight;
F32 mElapsedTime;
GFXTexHandle mBumpTex;
bool mGenerateVB;
// reflect plane
//ReflectPlane mReflectPlane;
//Point3F mReflectPlaneWorldPos;
GFXTexHandle mReflectTex;
// Stateblocks
GFXStateBlockRef mUnderwaterSB;
void setupVertexBlock( U32 width, U32 height, U32 rowOffset );
void setupPrimitiveBlock( U32 width, U32 height );
void setMultiPassProjection();
void clearVertBuffers();
static bool setGridSizeProperty( void *object, const char *index, const char *data );
protected:
//-------------------------------------------------------
// Standard engine functions
//-------------------------------------------------------
bool onAdd();
void onRemove();
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *conn, BitStream *stream);
bool castRay(const Point3F &start, const Point3F &end, RayInfo* info);
public:
WaterBlock();
virtual ~WaterBlock();
DECLARE_CONOBJECT(WaterBlock);
static void initPersistFields();
void onStaticModified( const char* slotName, const char*newValue = NULL );
virtual void inspectPostApply();
virtual void setTransform( const MatrixF & mat );
virtual void setScale( const Point3F &scale );
// WaterObject
virtual F32 getWaterCoverage( const Box3F &worldBox ) const;
virtual F32 getSurfaceHeight( const Point2F &pos ) const;
virtual bool isUnderwater( const Point3F &pnt ) const;
// WaterBlock
bool isPointSubmerged ( const Point3F &pos, bool worldSpace = true ) const{ return true; }
// SceneObject.
virtual F32 distanceTo( const Point3F& pos ) const;
protected:
// WaterObject
virtual void setShaderParams( SceneRenderState *state, BaseMatInstance *mat, const WaterMatParams &paramHandles );
virtual SceneData setupSceneGraphInfo( SceneRenderState *state );
virtual void setupVBIB();
virtual void innerRender( SceneRenderState *state );
virtual void _getWaterPlane( const Point3F &camPos, PlaneF &outPlane, Point3F &outPos );
};
#endif // _WATERBLOCK_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,320 @@
//-----------------------------------------------------------------------------
// 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 _WATEROBJECT_H_
#define _WATEROBJECT_H_
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
#ifndef _GFXSTRUCTS_H_
#include "gfx/gfxStructs.h"
#endif
#ifndef _FOGSTRUCTS_H_
#include "scene/fogStructs.h"
#endif
#ifndef _GFXSTATEBLOCK_H_
#include "gfx/gfxStateBlock.h"
#endif
#ifndef _REFLECTOR_H_
#include "scene/reflector.h"
#endif
#ifndef _ALIGNEDARRAY_H_
#include "core/util/tAlignedArray.h"
#endif
#ifndef _MATTEXTURETARGET_H_
#include "materials/matTextureTarget.h"
#endif
GFXDeclareVertexFormat( GFXWaterVertex )
{
Point3F point;
Point3F normal;
GFXVertexColor color;
Point2F undulateData;
Point4F horizonFactor;
};
class MaterialParameterHandle;
class BaseMatInstance;
class ShaderData;
class MatrixSet;
struct WaterMatParams
{
MaterialParameterHandle* mRippleMatSC;
MaterialParameterHandle* mRippleDirSC;
MaterialParameterHandle* mRippleTexScaleSC;
MaterialParameterHandle* mRippleSpeedSC;
MaterialParameterHandle* mRippleMagnitudeSC;
MaterialParameterHandle* mFoamDirSC;
MaterialParameterHandle* mFoamTexScaleSC;
MaterialParameterHandle* mFoamOpacitySC;
MaterialParameterHandle* mFoamSpeedSC;
MaterialParameterHandle* mWaveDirSC;
MaterialParameterHandle* mWaveDataSC;
MaterialParameterHandle* mReflectTexSizeSC;
MaterialParameterHandle* mBaseColorSC;
MaterialParameterHandle* mMiscParamsSC;
MaterialParameterHandle* mReflectParamsSC;
MaterialParameterHandle* mReflectNormalSC;
MaterialParameterHandle* mHorizonPositionSC;
MaterialParameterHandle* mFogParamsSC;
MaterialParameterHandle* mMoreFogParamsSC;
MaterialParameterHandle* mFarPlaneDistSC;
MaterialParameterHandle* mWetnessParamsSC;
MaterialParameterHandle* mDistortionParamsSC;
MaterialParameterHandle* mUndulateMaxDistSC;
MaterialParameterHandle* mAmbientColorSC;
MaterialParameterHandle* mLightDirSC;
MaterialParameterHandle* mFoamParamsSC;
MaterialParameterHandle* mGridElementSizeSC;
MaterialParameterHandle* mElapsedTimeSC;
MaterialParameterHandle* mModelMatSC;
MaterialParameterHandle* mFoamSamplerSC;
MaterialParameterHandle* mRippleSamplerSC;
MaterialParameterHandle* mCubemapSamplerSC;
MaterialParameterHandle* mSpecularParamsSC;
MaterialParameterHandle* mDepthGradMaxSC;
MaterialParameterHandle* mReflectivitySC;
void clear();
void init(BaseMatInstance* matInst);
};
class GFXOcclusionQuery;
class PostEffect;
class CubemapData;
//-------------------------------------------------------------------------
// WaterObject Class
//-------------------------------------------------------------------------
class WaterObject : public SceneObject
{
typedef SceneObject Parent;
protected:
enum MaskBits {
UpdateMask = Parent::NextFreeMask << 0,
WaveMask = Parent::NextFreeMask << 1,
MaterialMask = Parent::NextFreeMask << 2,
TextureMask = Parent::NextFreeMask << 3,
SoundMask = Parent::NextFreeMask << 4,
NextFreeMask = Parent::NextFreeMask << 5
};
enum consts {
MAX_WAVES = 3,
MAX_FOAM = 2,
NUM_ANIM_FRAMES = 32,
};
enum MaterialType
{
WaterMat = 0,
UnderWaterMat,
BasicWaterMat,
BasicUnderWaterMat,
NumMatTypes
};
public:
WaterObject();
virtual ~WaterObject();
DECLARE_CONOBJECT( WaterObject );
// ConsoleObject
static void consoleInit();
static void initPersistFields();
// SimObject
virtual bool onAdd();
virtual void onRemove();
virtual void inspectPostApply();
virtual bool processArguments(S32 argc, const char **argv);
// NetObject
virtual U32 packUpdate( NetConnection * conn, U32 mask, BitStream *stream );
virtual void unpackUpdate( NetConnection * conn, BitStream *stream );
// SceneObject
virtual void prepRenderImage( SceneRenderState *state );
virtual void renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
virtual SFXAmbience* getSoundAmbience() const { return mSoundAmbience; }
virtual bool containsPoint( const Point3F& point ) { return isUnderwater( point ); }
// WaterObject
virtual F32 getViscosity() const { return mViscosity; }
virtual F32 getDensity() const { return mDensity; }
virtual F32 getSurfaceHeight( const Point2F &pos ) const { return 0.0f; };
virtual const char* getLiquidType() const { return mLiquidType; }
virtual F32 getWaterCoverage( const Box3F &worldBox ) const { return 0.0f; }
virtual VectorF getFlow( const Point3F &pos ) const { return Point3F::Zero; }
virtual void updateUnderwaterEffect( SceneRenderState *state );
virtual bool isUnderwater( const Point3F &pnt ) const { return false; }
protected:
virtual void setShaderXForms( BaseMatInstance *mat ) {};
virtual void setupVBIB() {};
virtual void innerRender( SceneRenderState *state ) {};
virtual void setCustomTextures( S32 matIdx, U32 pass, const WaterMatParams &paramHandles );
void drawUnderwaterFilter( SceneRenderState *state );
virtual void setShaderParams( SceneRenderState *state, BaseMatInstance *mat, const WaterMatParams &paramHandles );
PostEffect* getUnderwaterEffect();
bool initMaterial( S32 idx );
void cleanupMaterials();
S32 getMaterialIndex( const Point3F &camPos );
void initTextures();
virtual void _getWaterPlane( const Point3F &camPos, PlaneF &outPlane, Point3F &outPos ) {}
/// Callback used internally when smDisableTrueReflections changes.
void _onDisableTrueRelfections();
protected:
static bool _setFullReflect( void *object, const char *index, const char *data );
static bool _checkDensity(void *object, const char *index, const char *data);
// WaterObject
F32 mViscosity;
F32 mDensity;
String mLiquidType;
F32 mFresnelBias;
F32 mFresnelPower;
F32 mSpecularPower;
ColorF mSpecularColor;
bool mEmissive;
// Reflection
bool mFullReflect;
PlaneReflector mPlaneReflector;
ReflectorDesc mReflectorDesc;
PlaneF mWaterPlane;
Point3F mWaterPos;
bool mReflectNormalUp;
F32 mReflectivity;
// Water Fogging
WaterFogData mWaterFogData;
// Distortion
F32 mDistortStartDist;
F32 mDistortEndDist;
F32 mDistortFullDepth;
// Ripples
Point2F mRippleDir[ MAX_WAVES ];
F32 mRippleSpeed[ MAX_WAVES ];
Point2F mRippleTexScale[ MAX_WAVES ];
F32 mRippleMagnitude[ MAX_WAVES ];
F32 mOverallRippleMagnitude;
// Waves
Point2F mWaveDir[ MAX_WAVES ];
F32 mWaveSpeed[ MAX_WAVES ];
F32 mWaveMagnitude[ MAX_WAVES ];
F32 mOverallWaveMagnitude;
// Foam
Point2F mFoamDir[ MAX_WAVES ];
F32 mFoamSpeed[ MAX_WAVES ];
Point2F mFoamTexScale[ MAX_WAVES ];
F32 mFoamOpacity[ MAX_WAVES ];
F32 mOverallFoamOpacity;
F32 mFoamMaxDepth;
F32 mFoamAmbientLerp;
F32 mFoamRippleInfluence;
// Basic Lighting
F32 mClarity;
ColorI mUnderwaterColor;
// Misc
F32 mDepthGradientMax;
// Other textures
String mRippleTexName;
String mFoamTexName;
String mCubemapName;
String mDepthGradientTexName;
// Sound
SFXAmbience* mSoundAmbience;
// Not fields...
/// Defined here and sent to the shader in WaterCommon::setShaderParams
/// but needs to be initialized in child classes prior to that call.
F32 mUndulateMaxDist;
/// Defined in WaterCommon but set and used by child classes.
/// If true will refuse to render a reflection even if called from
/// the ReflectionManager, is set true if occlusion query is enabled and
/// it determines it is occluded.
//bool mSkipReflectUpdate;
/// Derived classes can set this value prior to calling Parent::setShaderConst
/// to pass it into the shader miscParam.w
F32 mMiscParamW;
SimObjectPtr<PostEffect> mUnderwaterPostFx;
/// A global for enabling wireframe rendering
/// on all water objects.
static bool smWireframe;
/// Force all water objects to use static cubemap reflections
static bool smDisableTrueReflections;
// Rendering
bool mBasicLighting;
//U32 mRenderUpdateCount;
//U32 mReflectUpdateCount;
bool mGenerateVB;
String mSurfMatName[NumMatTypes];
BaseMatInstance* mMatInstances[NumMatTypes];
WaterMatParams mMatParamHandles[NumMatTypes];
bool mUnderwater;
GFXStateBlockRef mUnderwaterSB;
GFXTexHandle mRippleTex;
GFXTexHandle mDepthGradientTex;
GFXTexHandle mFoamTex;
CubemapData *mCubemap;
MatrixSet *mMatrixSet;
NamedTexTarget mNamedDepthGradTex;
};
#endif // _WATEROBJECT_H_

View file

@ -0,0 +1,973 @@
//-----------------------------------------------------------------------------
// 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 "environment/waterPlane.h"
#include "core/util/safeDelete.h"
#include "scene/sceneRenderState.h"
#include "scene/sceneManager.h"
#include "lighting/lightInfo.h"
#include "core/stream/bitStream.h"
#include "math/mathIO.h"
#include "math/mathUtils.h"
#include "console/consoleTypes.h"
#include "gui/3d/guiTSControl.h"
#include "gfx/primBuilder.h"
#include "gfx/gfxTransformSaver.h"
#include "gfx/gfxDebugEvent.h"
#include "gfx/gfxOcclusionQuery.h"
#include "renderInstance/renderPassManager.h"
#include "sim/netConnection.h"
#include "scene/reflectionManager.h"
#include "ts/tsShapeInstance.h"
#include "T3D/gameFunctions.h"
#include "postFx/postEffect.h"
#include "math/util/matrixSet.h"
extern ColorI gCanvasClearColor;
#define BLEND_TEX_SIZE 256
#define V_SHADER_PARAM_OFFSET 50
IMPLEMENT_CO_NETOBJECT_V1(WaterPlane);
ConsoleDocClass( WaterPlane,
"@brief Represents a large body of water stretching to the horizon in all directions.\n\n"
"WaterPlane's position is defined only height, the z element of position, "
"it is infinite in xy and depth. %WaterPlane is designed to represent the "
"ocean on an island scene and viewed from ground level; other uses may not "
"be appropriate and a WaterBlock may be used.\n\n"
"@see WaterObject for inherited functionality.\n\n"
"Limitations:\n\n"
"Because %WaterPlane cannot be projected exactly to the far-clip distance, "
"other objects nearing this distance can have noticible artifacts as they "
"clip through first the %WaterPlane and then the far plane.\n\n"
"To avoid this large objects should be positioned such that they will not line up with "
"the far-clip from vantage points the player is expected to be. In particular, "
"your TerrainBlock should be completely contained by the far-clip distance.\n\n"
"Viewing %WaterPlane from a high altitude with a tight far-clip distance "
"will accentuate this limitation. %WaterPlane is primarily designed to "
"be viewed from ground level.\n\n"
"@ingroup Water"
);
WaterPlane::WaterPlane()
{
mGridElementSize = 1.0f;
mGridSize = 101;
mGridSizeMinusOne = mGridSize - 1;
mNetFlags.set(Ghostable | ScopeAlways);
mVertCount = 0;
mIndxCount = 0;
mPrimCount = 0;
}
WaterPlane::~WaterPlane()
{
}
bool WaterPlane::onAdd()
{
if ( !Parent::onAdd() )
return false;
setGlobalBounds();
resetWorldBox();
addToScene();
mWaterFogData.plane.set( 0, 0, 1, -getPosition().z );
return true;
}
void WaterPlane::onRemove()
{
removeFromScene();
Parent::onRemove();
}
void WaterPlane::initPersistFields()
{
addGroup( "WaterPlane" );
addProtectedField( "gridSize", TypeS32, Offset( mGridSize, WaterPlane ), &protectedSetGridSize, &defaultProtectedGetFn,
"Spacing between vertices in the WaterBlock mesh" );
addProtectedField( "gridElementSize", TypeF32, Offset( mGridElementSize, WaterPlane ), &protectedSetGridElementSize, &defaultProtectedGetFn,
"Duplicate of gridElementSize for backwards compatility");
endGroup( "WaterPlane" );
Parent::initPersistFields();
removeField( "rotation" );
removeField( "scale" );
}
U32 WaterPlane::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
{
U32 retMask = Parent::packUpdate(con, mask, stream);
stream->write( mGridSize );
stream->write( mGridElementSize );
if ( stream->writeFlag( mask & UpdateMask ) )
{
stream->write( getPosition().z );
}
return retMask;
}
void WaterPlane::unpackUpdate(NetConnection* con, BitStream* stream)
{
Parent::unpackUpdate(con, stream);
U32 inGridSize;
stream->read( &inGridSize );
setGridSize( inGridSize );
F32 inGridElementSize;
stream->read( &inGridElementSize );
setGridElementSize( inGridElementSize );
if( stream->readFlag() ) // UpdateMask
{
float posZ;
stream->read( &posZ );
Point3F newPos = getPosition();
newPos.z = posZ;
setPosition( newPos );
}
}
void WaterPlane::setupVBIB( SceneRenderState *state )
{
const Frustum &frustum = state->getFrustum();
// Water base-color, assigned as color for all verts.
const GFXVertexColor vertCol(mWaterFogData.color);
// World-Up vector, assigned as normal for all verts.
const Point3F worldUp( 0.0f, 0.0f, 1.0f );
// World-unit size of a grid cell.
const F32 squareSize = mGridElementSize;
// Column/Row count.
// So we don't neet to access class-specific member variables
// in the code below.
const U32 gridSize = mGridSize;
// Number of verts in one column / row
const U32 gridStride = gridSize + 1;
// Grid is filled in this order...
// Ex. Grid with gridSize of 2.
//
// Letters are cells.
// Numbers are verts, enumerated in their order within the vert buffer.
//
// 6 7 8
// (c) (d)
// 3 4 5
// (a) (b)
// 0 1 2
//
// Note...
// Camera would be positioned at vert 4 ( in this particular grid not a constant ).
// Positive Y points UP the diagram ( verts 0, 3, 6 ).
// Positive X points RIGHT across the diagram ( verts 0, 1, 2 ).
// Length of a grid row/column divided by two.
F32 gridSideHalfLen = squareSize * gridSize * 0.5f;
// Position of the first vertex in the grid.
// Relative to the camera this is the "Back Left" corner vert.
const Point3F cornerPosition( -gridSideHalfLen, -gridSideHalfLen, 0.0f );
// Number of verts in the grid centered on the camera.
const U32 gridVertCount = gridStride * gridStride;
// Number of verts surrounding the grid, projected by the frustum.
const U32 borderVertCount = gridSize * 4;
// Number of verts in the front-most row which are raised to the horizon.
const U32 horizonVertCount = gridStride;
// Total number of verts. Calculation explained above.
mVertCount = gridVertCount + borderVertCount + horizonVertCount;
// Fill the vertex buffer...
mVertBuff.set( GFX, mVertCount, GFXBufferTypeStatic );
GFXWaterVertex *vertPtr = mVertBuff.lock();
// Fill verts in the camera centered grid...
// Temorary storage for calculation of vert position.
F32 xVal, yVal;
for ( U32 i = 0; i < gridStride; i++ )
{
yVal = cornerPosition.y + (F32)( i * squareSize );
for ( U32 j = 0; j < gridStride; j++ )
{
xVal = cornerPosition.x + (F32)( j * squareSize );
vertPtr->point.set( xVal, yVal, 0.0f );
vertPtr->color = vertCol;
vertPtr->normal = worldUp;
vertPtr->undulateData.set( xVal, yVal );
vertPtr->horizonFactor.set( 0, 0, 0, 0 );
vertPtr++;
}
}
// Fill in 'border' verts, surrounding the grid, projected by the frustum.
// Ex. Grid with gridSize of 2.
//
// Letters in parenthesis are cells.
// x's are grid-verts ( we have already filled ).
// Numbers are border verts, enumerated in their order within the vert buffer.
//
// Lines connecting verts explained in the code below.
//
// Front
//
// L 0------1 2 R
// e x x x | i
// f (c) (d) | g
// t 7 x x x 3 h
// | (a) (b) t
// | x x x
// 6 5------4
//
// Back
//
// As in previous diagram...
// Camera would be positioned at vert 4 ( in this particular grid not a constant ).
// Positive Y points UP the diagram ( verts 6, 7, 0 ).
// Positive X points RIGHT across the diagram ( verts 0, 1, 2 ).
// Iterator i is looping through the 4 'sides' of the grid.
// Inner loop ( using iterator j ) will fill in a number of verts
// where that count is 'gridSize'.
//
//
// Ex. Given the grid with gridSize of 2 diagramed above,
// Outer loop iterates through: Front, Right, Back, Left
// Inner loop fills 2 verts per iteration of the outer loop: { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 }
// Grid-space vectors indexed by 'side'.
// Each vector describes the direction we iterate when
// filling in verts ( mathematically the tangent ).
const Point2F sBorderTangentVec [4] = {
Point2F( 1, 0 ), // Front ( 0 )
Point2F( 0, -1 ), // Right ( 1 )
Point2F( -1, 0 ), // Back ( 2 )
Point2F( 0, 1 ) // Left ( 3 )
};
// Normalized positions indexed by 'side'
// Defines the 'start' position of each side, eg. the position of the first vert.
// See Diagram below.
const Point2F sBorderStartPos [4] = {
Point2F( -1, 1 ), // Front ( 0 )
Point2F( 1, 1 ), // Right ( 1 )
Point2F( 1, -1 ), // Back ( 2 )
Point2F( -1, -1 ) // Left ( 3 )
};
// Diagram of Start vert position per Side.
//
// Labeling convention for verts is 'As' where A is the first letter of
// that side's descriptive name and lower-case s indicates 'start'.
//
//
//
// Front
// (-1,1)
// Fs------o-----Rs(1,1)R
// | | i
// | | g
// o (0,0) o h
// | | t
// | |
// L(-1,-1)Ls------o-----Bs
// e (1,-1)
// f Back
// t
// Calculate the world-space dimension of the border-vert-ring...
// Diagram shows overall layout of the WaterPlane with a gridSize of 1,
// with all 'quads' enumerated.
// center-grid ( 1 ), border ( 2, 3, 4, 5 ), and horizon ( 6 ).
//
//
// x------------x
// \ 6 \ <- horizon quad is really 'above' the front border
// x --------- x not in front of it
// | \ 2 / |
// | x---- x |
// | | | |
// | 5| 1 |3 |
// | x --- x |
// | / 4 \|
// x------------x
// WaterPlane renders relative to the camera rotation around z and xy position.
//
// That is, it rotates around the z-up axis with the camera such that the
// camera is always facing towards the front border unless looking straight
// down or up.
//
// Also note that the horizon verts are pulled straight up from the front
// border verts.
//
// Therefore...
//
// The front border must be as close to the farclip plane as possible
// so distant objects clip through the horizon and farplane at the same time.
//
// The left and right borders must be pulled outward a distance such
// that water extends horizontally across the entire viewable area while
// looking straight forward +y or straight down -z.
//
//
const F32 farDistScale = 0.99f;
//
F32 farDist = frustum.getFarDist() * farDistScale;
//
F32 farWidth = (F32)state->getViewport().extent.x * farDist / state->getWorldToScreenScale().x;
Point2F borderExtents( farWidth * 2.0f, farDist * 2.0f );
Point2F borderHalfExtents( farWidth, farDist );
Point2F borderDir;
Point2F borderStart;
for ( U32 i = 0; i < 4; i++ )
{
borderDir = sBorderTangentVec[i];
borderStart = sBorderStartPos[i];
for ( U32 j = 0; j < gridSize; j++ )
{
F32 frac = (F32)j / (F32)gridSize;
Point2F pos( borderStart * borderHalfExtents );
pos += borderDir * borderExtents * frac;
vertPtr->point.set( pos.x, pos.y, 0.0f );
vertPtr->undulateData.set( pos.x, pos.y );
vertPtr->horizonFactor.set( 0, 0, 0, 0 );
vertPtr->color = vertCol;
vertPtr->normal = worldUp;
vertPtr++;
}
}
// Fill in row of horizion verts.
// Verts are positioned identical to the front border, but will be
// manipulated in z within the shader.
//
// Z position of 50.0f is unimportant unless you want to disable
// shader manipulation and render in wireframe for debugging.
for ( U32 i = 0; i < gridStride; i++ )
{
F32 frac = (F32)i / (F32)gridSize;
Point2F pos( sBorderStartPos[0] * borderHalfExtents );
pos += sBorderTangentVec[0] * borderExtents * frac;
vertPtr->point.set( pos.x, pos.y, 50.0f );
vertPtr->undulateData.set( pos.x, pos.y );
vertPtr->horizonFactor.set( 1, 0, 0, 0 );
vertPtr->color = vertCol;
vertPtr->normal = worldUp;
vertPtr++;
}
mVertBuff.unlock();
// Fill in the PrimitiveBuffer...
// 2 triangles per cell/quad
const U32 gridTriCount = gridSize * gridSize * 2;
// 4 sides, mGridSize quads per side, 2 triangles per quad
const U32 borderTriCount = 4 * gridSize * 2;
// 1 quad per gridSize, 2 triangles per quad
// i.e. an extra row of 'cells' leading the front side of the grid
const U32 horizonTriCount = gridSize * 2;
mPrimCount = gridTriCount + borderTriCount + horizonTriCount;
// 3 indices per triangle.
mIndxCount = mPrimCount * 3;
mPrimBuff.set( GFX, mIndxCount, mPrimCount, GFXBufferTypeStatic );
U16 *idxPtr;
mPrimBuff.lock(&idxPtr);
// Temporaries to hold indices for the corner points of a quad.
U32 p00, p01, p11, p10;
U32 offset = 0;
// Given a single cell of the grid diagramed below,
// quad indice variables are in this orientation.
//
// p01 --- p11
// | |
// | |
// p00 --- p10
//
// Positive Y points UP the diagram ( p00, p01 ).
// Positive X points RIGHT across the diagram ( p00, p10 )
//
// i iterates bottom to top "column-wise"
for ( U32 i = 0; i < mGridSize; i++ )
{
// j iterates left to right "row-wise"
for ( U32 j = 0; j < mGridSize; j++ )
{
// where (j,i) is a particular cell.
p00 = offset;
p10 = offset + 1;
p01 = offset + gridStride;
p11 = offset + 1 + gridStride;
// Top Left Triangle
*idxPtr = p00;
idxPtr++;
*idxPtr = p01;
idxPtr++;
*idxPtr = p11;
idxPtr++;
// Bottom Right Triangle
*idxPtr = p00;
idxPtr++;
*idxPtr = p11;
idxPtr++;
*idxPtr = p10;
idxPtr++;
offset += 1;
}
offset += 1;
}
// Fill border indices...
// Given a grid size of 1,
// the grid / border verts are in the vertex buffer in this order.
//
//
// 4 5
// 2 --- 3
// | |
// | |
// 0 --- 1
// 7 6
//
// Positive Y points UP the diagram ( p00, p01 ).
// Positive X points RIGHT across the diagram ( p00, p10 )
//
// Note we duplicate the first border vert ( 4 ) since it is also the last
// and this makes our loop easier.
const U32 sBorderStartVert [4] = {
gridStride * gridSize, // Index to the Top-Left grid vert.
gridStride * gridSize + gridSize, // Index to the Top-Right grid vert.
gridSize, // Index to the Bottom-Right grid vert.
0, // Index to the Bottom-Left grid vert.
};
const S32 sBorderStepSize [4] = {
// Step size to the next grid vert along the specified side....
1, // Top
-(S32)gridStride, // Right
-1, // Bottom
gridStride, // Left
};
const U32 firstBorderVert = gridStride * gridSize + gridStride;
const U32 lastBorderVert = firstBorderVert + ( borderVertCount - 1 );
U32 startBorderVert = firstBorderVert;
U32 startGridVert;
U32 curStepSize;
for ( U32 i = 0; i < 4; i++ )
{
startGridVert = sBorderStartVert[i];
curStepSize = sBorderStepSize[i];
for ( U32 j = 0; j < gridSize; j++ )
{
// Each border cell is 1 quad, 2 triangles.
p00 = startGridVert;
p10 = startGridVert + curStepSize;
p01 = startBorderVert;
p11 = startBorderVert + 1;
if ( p11 > lastBorderVert )
p11 = firstBorderVert;
// Top Left Triangle
*idxPtr = p00;
idxPtr++;
*idxPtr = p01;
idxPtr++;
*idxPtr = p11;
idxPtr++;
// Bottom Right Triangle
*idxPtr = p00;
idxPtr++;
*idxPtr = p11;
idxPtr++;
*idxPtr = p10;
idxPtr++;
startBorderVert++;
startGridVert += curStepSize;
}
}
// Fill in 'horizon' triangles.
U32 curHorizonVert = lastBorderVert + 1;
U32 curBorderVert = firstBorderVert;
for ( U32 i = 0; i < gridSize; i++ )
{
p00 = curBorderVert;
p10 = curBorderVert + 1;
p01 = curHorizonVert;
p11 = curHorizonVert + 1;
// Top Left Triangle
*idxPtr = p00;
idxPtr++;
*idxPtr = p01;
idxPtr++;
*idxPtr = p11;
idxPtr++;
// Bottom Right Triangle
*idxPtr = p00;
idxPtr++;
*idxPtr = p11;
idxPtr++;
*idxPtr = p10;
idxPtr++;
curBorderVert++;
curHorizonVert++;
}
mPrimBuff.unlock();
}
SceneData WaterPlane::setupSceneGraphInfo( SceneRenderState *state )
{
SceneData sgData;
sgData.lights[0] = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
// fill in water's transform
sgData.objTrans = &getRenderTransform();
// fog
sgData.setFogParams( state->getSceneManager()->getFogData() );
// misc
sgData.backBuffTex = REFLECTMGR->getRefractTex();
sgData.reflectTex = mPlaneReflector.reflectTex;
sgData.wireframe = GFXDevice::getWireframe() || smWireframe;
return sgData;
}
void WaterPlane::setShaderParams( SceneRenderState *state, BaseMatInstance* mat, const WaterMatParams& paramHandles)
{
// Set variables that will be assigned to shader consts within WaterCommon
// before calling Parent::setShaderParams
mUndulateMaxDist = mGridElementSize * mGridSizeMinusOne * 0.5f;
Parent::setShaderParams( state, mat, paramHandles );
// Now set the rest of the shader consts that are either unique to this
// class or that WaterObject leaves to us to handle...
MaterialParameters* matParams = mat->getMaterialParameters();
// set vertex shader constants
//-----------------------------------
matParams->setSafe(paramHandles.mGridElementSizeSC, (F32)mGridElementSize);
//matParams->setSafe( paramHandles.mReflectTexSizeSC, mReflectTexSize );
if ( paramHandles.mModelMatSC->isValid() )
matParams->set(paramHandles.mModelMatSC, getRenderTransform(), GFXSCT_Float4x4);
// set pixel shader constants
//-----------------------------------
ColorF c( mWaterFogData.color );
matParams->setSafe( paramHandles.mBaseColorSC, c );
// By default we need to show a true reflection is fullReflect is enabled and
// we are above water.
F32 reflect = mPlaneReflector.isEnabled() && !isUnderwater( state->getCameraPosition() );
// If we were occluded the last frame a query was fetched ( not necessarily last frame )
// and we weren't updated last frame... we don't have a valid texture to show
// so use the cubemap / fake reflection color this frame.
if ( mPlaneReflector.lastUpdateMs != REFLECTMGR->getLastUpdateMs() && mPlaneReflector.isOccluded() )
reflect = false;
//Point4F reflectParams( getRenderPosition().z, mReflectMinDist, mReflectMaxDist, reflect );
Point4F reflectParams( getRenderPosition().z, 0.0f, 1000.0f, !reflect );
// TODO: This is a hack... why is this broken... check after
// we merge advanced lighting with trunk!
//
reflectParams.z = 0.0f;
matParams->setSafe( paramHandles.mReflectParamsSC, reflectParams );
VectorF reflectNorm( 0, 0, 1 );
matParams->setSafe(paramHandles.mReflectNormalSC, reflectNorm );
}
void WaterPlane::prepRenderImage( SceneRenderState *state )
{
PROFILE_SCOPE(WaterPlane_prepRenderImage);
if( !state->isDiffusePass() )
return;
mBasicLighting = dStricmp( LIGHTMGR->getId(), "BLM" ) == 0;
mUnderwater = isUnderwater( state->getCameraPosition() );
mMatrixSet->setSceneView(GFX->getWorldMatrix());
const Frustum &frustum = state->getFrustum();
if ( mPrimBuff.isNull() ||
mGenerateVB ||
frustum != mFrustum )
{
mFrustum = frustum;
setupVBIB( state );
mGenerateVB = false;
MatrixF proj( true );
MathUtils::getZBiasProjectionMatrix( 0.0001f, mFrustum, &proj );
mMatrixSet->setSceneProjection(proj);
}
_getWaterPlane( state->getCameraPosition(), mWaterPlane, mWaterPos );
mWaterFogData.plane = mWaterPlane;
mPlaneReflector.refplane = mWaterPlane;
updateUnderwaterEffect( state );
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
ri->renderDelegate.bind( this, &WaterObject::renderObject );
ri->type = RenderPassManager::RIT_Water;
state->getRenderPass()->addInst( ri );
//mRenderUpdateCount++;
}
void WaterPlane::innerRender( SceneRenderState *state )
{
GFXDEBUGEVENT_SCOPE( WaterPlane_innerRender, ColorI( 255, 0, 0 ) );
const Point3F &camPosition = state->getCameraPosition();
Point3F rvec, fvec, uvec, pos;
const MatrixF &objMat = getTransform(); //getRenderTransform();
const MatrixF &camMat = state->getCameraTransform();
MatrixF renderMat( true );
camMat.getColumn( 1, &fvec );
uvec.set( 0, 0, 1 );
rvec = mCross( fvec, uvec );
rvec.normalize();
fvec = mCross( uvec, rvec );
pos = camPosition;
pos.z = objMat.getPosition().z;
renderMat.setColumn( 0, rvec );
renderMat.setColumn( 1, fvec );
renderMat.setColumn( 2, uvec );
renderMat.setColumn( 3, pos );
setRenderTransform( renderMat );
// Setup SceneData
SceneData sgData = setupSceneGraphInfo( state );
// set the material
S32 matIdx = getMaterialIndex( camPosition );
if ( !initMaterial( matIdx ) )
return;
BaseMatInstance *mat = mMatInstances[matIdx];
WaterMatParams matParams = mMatParamHandles[matIdx];
// render the geometry
if ( mat )
{
// setup proj/world transform
mMatrixSet->restoreSceneViewProjection();
mMatrixSet->setWorld(getRenderTransform());
setShaderParams( state, mat, matParams );
while( mat->setupPass( state, sgData ) )
{
mat->setSceneInfo(state, sgData);
mat->setTransforms(*mMatrixSet, state);
setCustomTextures( matIdx, mat->getCurPass(), matParams );
// set vert/prim buffer
GFX->setVertexBuffer( mVertBuff );
GFX->setPrimitiveBuffer( mPrimBuff );
GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, mVertCount, 0, mPrimCount );
}
}
}
bool WaterPlane::isUnderwater( const Point3F &pnt ) const
{
F32 height = getPosition().z;
F32 diff = pnt.z - height;
return ( diff < 0.1 );
}
F32 WaterPlane::distanceTo( const Point3F& point ) const
{
if( isUnderwater( point ) )
return 0.f;
else
return ( point.z - getPosition().z );
}
void WaterPlane::inspectPostApply()
{
Parent::inspectPostApply();
setMaskBits( UpdateMask );
}
void WaterPlane::setTransform( const MatrixF &mat )
{
// We only accept the z value from the new transform.
MatrixF newMat( true );
Point3F newPos = getPosition();
newPos.z = mat.getPosition().z;
newMat.setPosition( newPos );
Parent::setTransform( newMat );
// Parent::setTransforms ends up setting our worldBox to something other than
// global, so we have to set it back... but we can't actually call setGlobalBounds
// again because it does extra work adding and removing us from the container.
mGlobalBounds = true;
mObjBox.minExtents.set(-1e10, -1e10, -1e10);
mObjBox.maxExtents.set( 1e10, 1e10, 1e10);
// Keep mWaterPlane up to date.
mWaterFogData.plane.set( 0, 0, 1, -getPosition().z );
}
void WaterPlane::onStaticModified( const char* slotName, const char*newValue )
{
Parent::onStaticModified( slotName, newValue );
if ( dStricmp( slotName, "surfMaterial" ) == 0 )
setMaskBits( MaterialMask );
}
bool WaterPlane::castRay(const Point3F& start, const Point3F& end, RayInfo* info )
{
// Simply look for the hit on the water plane
// and ignore any future issues with waves, etc.
const Point3F norm(0,0,1);
PlaneF plane( Point3F::Zero, norm );
F32 hit = plane.intersect( start, end );
if ( hit < 0.0f || hit > 1.0f )
return false;
info->t = hit;
info->object = this;
info->point = start + ( ( end - start ) * hit );
info->normal = norm;
info->material = mMatInstances[ WaterMat ];
return true;
}
F32 WaterPlane::getWaterCoverage( const Box3F &testBox ) const
{
F32 posZ = getPosition().z;
F32 coverage = 0.0f;
if ( posZ > testBox.minExtents.z )
{
if ( posZ < testBox.maxExtents.z )
coverage = (posZ - testBox.minExtents.z) / (testBox.maxExtents.z - testBox.minExtents.z);
else
coverage = 1.0f;
}
return coverage;
}
F32 WaterPlane::getSurfaceHeight( const Point2F &pos ) const
{
return getPosition().z;
}
void WaterPlane::onReflectionInfoChanged()
{
/*
if ( isClientObject() && GFX->getPixelShaderVersion() >= 1.4 )
{
if ( mFullReflect )
REFLECTMGR->registerObject( this, ReflectDelegate( this, &WaterPlane::updateReflection ), mReflectPriority, mReflectMaxRateMs, mReflectMaxDist );
else
{
REFLECTMGR->unregisterObject( this );
mReflectTex = NULL;
}
}
*/
}
void WaterPlane::setGridSize( U32 inSize )
{
if ( inSize == mGridSize )
return;
// GridSize must be an odd number.
//if ( inSize % 2 == 0 )
// inSize++;
// GridSize must be at least 1
inSize = getMax( inSize, (U32)1 );
mGridSize = inSize;
mGridSizeMinusOne = mGridSize - 1;
mGenerateVB = true;
setMaskBits( UpdateMask );
}
void WaterPlane::setGridElementSize( F32 inSize )
{
if ( inSize == mGridElementSize )
return;
// GridElementSize must be greater than 0
inSize = getMax( inSize, 0.0001f );
mGridElementSize = inSize;
mGenerateVB = true;
setMaskBits( UpdateMask );
}
bool WaterPlane::protectedSetGridSize( void *obj, const char *index, const char *data )
{
WaterPlane *object = static_cast<WaterPlane*>(obj);
S32 size = dAtoi( data );
object->setGridSize( size );
// We already set the field.
return false;
}
bool WaterPlane::protectedSetGridElementSize( void *obj, const char *index, const char *data )
{
WaterPlane *object = static_cast<WaterPlane*>(obj);
F32 size = dAtof( data );
object->setGridElementSize( size );
// We already set the field.
return false;
}
void WaterPlane::_getWaterPlane( const Point3F &camPos, PlaneF &outPlane, Point3F &outPos )
{
outPos = getPosition();
outPlane.set( outPos, Point3F(0,0,1) );
}

View file

@ -0,0 +1,147 @@
//-----------------------------------------------------------------------------
// 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 _WATERPLANE_H_
#define _WATERPLANE_H_
#ifndef _GAMEBASE_H_
#include "T3D/gameBase/gameBase.h"
#endif
#ifndef _GFXDEVICE_H_
#include "gfx/gfxDevice.h"
#endif
#ifndef _SCENEDATA_H_
#include "materials/sceneData.h"
#endif
#ifndef _MATINSTANCE_H_
#include "materials/matInstance.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#ifndef _RENDERPASSMANAGER_H_
#include "renderInstance/renderPassManager.h"
#endif
#ifndef _MATHUTIL_FRUSTUM_H_
#include "math/util/frustum.h"
#endif
#ifndef _WATEROBJECT_H_
#include "environment/waterObject.h"
#endif
//*****************************************************************************
// WaterPlane
//*****************************************************************************
class WaterPlane : public WaterObject
{
typedef WaterObject Parent;
public:
// LEGACY support
enum EWaterType
{
eWater = 0,
eOceanWater = 1,
eRiverWater = 2,
eStagnantWater = 3,
eLava = 4,
eHotLava = 5,
eCrustyLava = 6,
eQuicksand = 7,
};
private:
enum MaskBits {
UpdateMask = Parent::NextFreeMask,
NextFreeMask = Parent::NextFreeMask << 1
};
// vertex / index buffers
GFXVertexBufferHandle<GFXWaterVertex> mVertBuff;
GFXPrimitiveBufferHandle mPrimBuff;
// misc
U32 mGridSize;
U32 mGridSizeMinusOne;
F32 mGridElementSize;
U32 mVertCount;
U32 mIndxCount;
U32 mPrimCount;
Frustum mFrustum;
SceneData setupSceneGraphInfo( SceneRenderState *state );
void setShaderParams( SceneRenderState *state, BaseMatInstance* mat, const WaterMatParams& paramHandles );
void setupVBIB( SceneRenderState *state );
virtual void prepRenderImage( SceneRenderState *state );
virtual void innerRender( SceneRenderState *state );
void setMultiPassProjection();
protected:
//-------------------------------------------------------
// Standard engine functions
//-------------------------------------------------------
bool onAdd();
void onRemove();
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *conn, BitStream *stream);
bool castRay(const Point3F &start, const Point3F &end, RayInfo* info);
public:
WaterPlane();
virtual ~WaterPlane();
DECLARE_CONOBJECT(WaterPlane);
static void initPersistFields();
void onStaticModified( const char* slotName, const char*newValue = NULL );
virtual void inspectPostApply();
virtual void setTransform( const MatrixF & mat );
virtual F32 distanceTo( const Point3F& point ) const;
// WaterObject
virtual F32 getWaterCoverage( const Box3F &worldBox ) const;
virtual F32 getSurfaceHeight( const Point2F &pos ) const;
virtual void onReflectionInfoChanged();
virtual bool isUnderwater( const Point3F &pnt ) const;
// WaterBlock
bool isPointSubmerged ( const Point3F &pos, bool worldSpace = true ) const{ return true; }
// WaterPlane
void setGridSize( U32 inSize );
void setGridElementSize( F32 inSize );
// Protected Set'ers
static bool protectedSetGridSize( void *object, const char *index, const char *data );
static bool protectedSetGridElementSize( void *object, const char *index, const char *data );
protected:
// WaterObject
virtual void _getWaterPlane( const Point3F &camPos, PlaneF &outPlane, Point3F &outPos );
};
#endif // _WATERPLANE_H_