mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-11 22:54:34 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
409
Engine/source/environment/basicClouds.cpp
Normal file
409
Engine/source/environment/basicClouds.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
122
Engine/source/environment/basicClouds.h
Normal file
122
Engine/source/environment/basicClouds.h
Normal 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_
|
||||
489
Engine/source/environment/cloudLayer.cpp
Normal file
489
Engine/source/environment/cloudLayer.cpp
Normal 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();
|
||||
}
|
||||
135
Engine/source/environment/cloudLayer.h
Normal file
135
Engine/source/environment/cloudLayer.h
Normal 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_
|
||||
1728
Engine/source/environment/decalRoad.cpp
Normal file
1728
Engine/source/environment/decalRoad.cpp
Normal file
File diff suppressed because it is too large
Load diff
278
Engine/source/environment/decalRoad.h
Normal file
278
Engine/source/environment/decalRoad.h
Normal 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_
|
||||
1307
Engine/source/environment/editors/guiMeshRoadEditorCtrl.cpp
Normal file
1307
Engine/source/environment/editors/guiMeshRoadEditorCtrl.cpp
Normal file
File diff suppressed because it is too large
Load diff
178
Engine/source/environment/editors/guiMeshRoadEditorCtrl.h
Normal file
178
Engine/source/environment/editors/guiMeshRoadEditorCtrl.h
Normal 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_
|
||||
|
||||
|
||||
|
||||
1506
Engine/source/environment/editors/guiRiverEditorCtrl.cpp
Normal file
1506
Engine/source/environment/editors/guiRiverEditorCtrl.cpp
Normal file
File diff suppressed because it is too large
Load diff
200
Engine/source/environment/editors/guiRiverEditorCtrl.h
Normal file
200
Engine/source/environment/editors/guiRiverEditorCtrl.h
Normal 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
|
||||
|
||||
|
||||
|
||||
1120
Engine/source/environment/editors/guiRoadEditorCtrl.cpp
Normal file
1120
Engine/source/environment/editors/guiRoadEditorCtrl.cpp
Normal file
File diff suppressed because it is too large
Load diff
168
Engine/source/environment/editors/guiRoadEditorCtrl.h
Normal file
168
Engine/source/environment/editors/guiRoadEditorCtrl.h
Normal 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
|
||||
|
||||
|
||||
|
||||
2441
Engine/source/environment/meshRoad.cpp
Normal file
2441
Engine/source/environment/meshRoad.cpp
Normal file
File diff suppressed because it is too large
Load diff
566
Engine/source/environment/meshRoad.h
Normal file
566
Engine/source/environment/meshRoad.h
Normal 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_
|
||||
275
Engine/source/environment/nodeListManager.cpp
Normal file
275
Engine/source/environment/nodeListManager.cpp
Normal 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;
|
||||
}
|
||||
133
Engine/source/environment/nodeListManager.h
Normal file
133
Engine/source/environment/nodeListManager.h
Normal 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_
|
||||
2492
Engine/source/environment/river.cpp
Normal file
2492
Engine/source/environment/river.cpp
Normal file
File diff suppressed because it is too large
Load diff
531
Engine/source/environment/river.h
Normal file
531
Engine/source/environment/river.h
Normal 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 ¶mHandles );
|
||||
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_
|
||||
1407
Engine/source/environment/scatterSky.cpp
Normal file
1407
Engine/source/environment/scatterSky.cpp
Normal file
File diff suppressed because it is too large
Load diff
251
Engine/source/environment/scatterSky.h
Normal file
251
Engine/source/environment/scatterSky.h
Normal 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_
|
||||
637
Engine/source/environment/skyBox.cpp
Normal file
637
Engine/source/environment/skyBox.cpp
Normal 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();
|
||||
}
|
||||
130
Engine/source/environment/skyBox.h
Normal file
130
Engine/source/environment/skyBox.h
Normal 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_
|
||||
563
Engine/source/environment/sun.cpp
Normal file
563
Engine/source/environment/sun.cpp
Normal 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);
|
||||
}
|
||||
|
||||
143
Engine/source/environment/sun.h
Normal file
143
Engine/source/environment/sun.h
Normal 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_
|
||||
745
Engine/source/environment/timeOfDay.cpp
Normal file
745
Engine/source/environment/timeOfDay.cpp
Normal 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 );
|
||||
}
|
||||
212
Engine/source/environment/timeOfDay.h
Normal file
212
Engine/source/environment/timeOfDay.h
Normal 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_
|
||||
700
Engine/source/environment/waterBlock.cpp
Normal file
700
Engine/source/environment/waterBlock.cpp
Normal 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 ¶mHandles)
|
||||
{
|
||||
// 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 );
|
||||
}
|
||||
152
Engine/source/environment/waterBlock.h
Normal file
152
Engine/source/environment/waterBlock.h
Normal 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 ¶mHandles );
|
||||
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_
|
||||
1205
Engine/source/environment/waterObject.cpp
Normal file
1205
Engine/source/environment/waterObject.cpp
Normal file
File diff suppressed because it is too large
Load diff
320
Engine/source/environment/waterObject.h
Normal file
320
Engine/source/environment/waterObject.h
Normal 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 ¶mHandles );
|
||||
void drawUnderwaterFilter( SceneRenderState *state );
|
||||
|
||||
virtual void setShaderParams( SceneRenderState *state, BaseMatInstance *mat, const WaterMatParams ¶mHandles );
|
||||
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_
|
||||
973
Engine/source/environment/waterPlane.cpp
Normal file
973
Engine/source/environment/waterPlane.cpp
Normal 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) );
|
||||
}
|
||||
147
Engine/source/environment/waterPlane.h
Normal file
147
Engine/source/environment/waterPlane.h
Normal 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_
|
||||
Loading…
Add table
Add a link
Reference in a new issue