mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 12:44:46 +00:00
Swapped the water's disableTrueReflections variable to be enableTrueReflections for simplicity and consistency(also fixed a persistent typo) Swapped disableVerticalSync to be enableVerticalSync for simplicity and consistency Swapped disableParallaxMapping to be enableParallaxMapping for simplicity and consistency Fix click detection on slider mode entries for guiGameSettingsCtrl so the click position correctly matches the percentage Fixed problem where postFX initialization would always exec default.postfxpreset.tscript, even if a level's got it's own preset, which can cause problems Fixed range field type behavior so that editing the values applies in real time, and also consistently applies between slider and text field
1330 lines
41 KiB
C++
1330 lines
41 KiB
C++
//-----------------------------------------------------------------------------
|
|
// 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 "gfx/gfxDevice.h"
|
|
|
|
#include "gfx/gfxInit.h"
|
|
#include "gfx/gfxCubemap.h"
|
|
#include "gfx/primBuilder.h"
|
|
#include "gfx/gfxDrawUtil.h"
|
|
#include "gfx/gfxFence.h"
|
|
#include "gfx/gfxFontRenderBatcher.h"
|
|
#include "gfx/gfxPrimitiveBuffer.h"
|
|
#include "gfx/gfxShader.h"
|
|
#include "gfx/gfxStateBlock.h"
|
|
#include "gfx/screenshot.h"
|
|
#include "gfx/gfxStringEnumTranslate.h"
|
|
#include "gfx/gfxTextureManager.h"
|
|
|
|
#include "core/frameAllocator.h"
|
|
#include "core/stream/fileStream.h"
|
|
#include "core/strings/unicode.h"
|
|
#include "core/util/journal/process.h"
|
|
#include "core/util/safeDelete.h"
|
|
#include "math/util/frustum.h"
|
|
#include "console/consoleTypes.h"
|
|
#include "console/engineAPI.h"
|
|
|
|
GFXDevice * GFXDevice::smGFXDevice = NULL;
|
|
bool GFXDevice::smWireframe = false;
|
|
bool GFXDevice::smEnableVSync = false;
|
|
F32 GFXDevice::smForcedPixVersion = -1.0f;
|
|
bool GFXDevice::smDisableOcclusionQuery = false;
|
|
bool gDisassembleAllShaders = false;
|
|
|
|
|
|
void GFXDevice::initConsole()
|
|
{
|
|
GFXStringEnumTranslate::init();
|
|
|
|
Con::addVariable( "$gfx::wireframe", TypeBool, &smWireframe,
|
|
"Used to toggle wireframe rendering at runtime.\n"
|
|
"@ingroup GFX\n" );
|
|
|
|
Con::addVariable( "$gfx::disassembleAllShaders", TypeBool, &gDisassembleAllShaders,
|
|
"On supported devices this will dump shader disassembly to the "
|
|
"procedural shader folder.\n"
|
|
"@ingroup GFX\n" );
|
|
|
|
Con::addVariable( "$gfx::disableOcclusionQuery", TypeBool, &smDisableOcclusionQuery,
|
|
"Debug helper that disables all hardware occlusion queries causing "
|
|
"them to return only the visibile state.\n"
|
|
"@ingroup GFX\n" );
|
|
|
|
Con::addVariable( "$pref::Video::enableVerticalSync", TypeBool, &smEnableVSync,
|
|
"Enables vertical sync on the active device.\n"
|
|
"@note The video mode must be reset for the change to take affect.\n"
|
|
"@ingroup GFX\n" );
|
|
|
|
Con::addVariable( "$pref::Video::forcedPixVersion", TypeF32, &smForcedPixVersion,
|
|
"Will force the shader model if the value is positive and less than the "
|
|
"shader model supported by the active device. Use 0 for fixed function.\n"
|
|
"@note The graphics device must be reset for the change to take affect.\n"
|
|
"@ingroup GFX\n" );
|
|
}
|
|
|
|
GFXDevice::DeviceEventSignal& GFXDevice::getDeviceEventSignal()
|
|
{
|
|
static DeviceEventSignal theSignal;
|
|
return theSignal;
|
|
}
|
|
|
|
GFXDevice::GFXDevice()
|
|
{
|
|
VECTOR_SET_ASSOCIATION( mVideoModes );
|
|
VECTOR_SET_ASSOCIATION( mRTStack );
|
|
|
|
mWorldStackSize = 0;
|
|
|
|
mViewMatrix.identity();
|
|
mProjectionMatrix.identity();
|
|
|
|
for( S32 i = 0; i < GFX_WORLD_STACK_MAX; i++ )
|
|
mWorldMatrix[i].identity();
|
|
|
|
AssertFatal(smGFXDevice == NULL, "Already a GFXDevice created! Bad!");
|
|
smGFXDevice = this;
|
|
|
|
// Vertex buffer cache
|
|
mCurrVertexDecl = NULL;
|
|
mVertexDeclDirty = false;
|
|
for ( U32 i=0; i < VERTEX_STREAM_COUNT; i++ )
|
|
{
|
|
mVertexBufferDirty[i] = false;
|
|
mVertexBufferFrequency[i] = 0;
|
|
mVertexBufferFrequencyDirty[i] = false;
|
|
}
|
|
|
|
// Primitive buffer cache
|
|
mPrimitiveBufferDirty = false;
|
|
mTexturesDirty = false;
|
|
|
|
// Use of GFX_TEXTURE_STAGE_COUNT in initialization is okay [7/2/2007 Pat]
|
|
for(U32 i = 0; i < GFX_TEXTURE_STAGE_COUNT; i++)
|
|
{
|
|
mTextureDirty[i] = false;
|
|
mCurrentTexture[i] = NULL;
|
|
mNewTexture[i] = NULL;
|
|
mCurrentCubemap[i] = NULL;
|
|
mNewCubemap[i] = NULL;
|
|
mCurrentCubemapArray[i] = NULL;
|
|
mNewTextureArray[i] = NULL;
|
|
mCurrentTextureArray[i] = NULL;
|
|
mNewCubemapArray[i] = NULL;
|
|
mTexType[i] = GFXTDT_Normal;
|
|
}
|
|
|
|
// State block
|
|
mStateBlockDirty = false;
|
|
mCurrentStateBlock = NULL;
|
|
mNewStateBlock = NULL;
|
|
|
|
mCurrentShaderConstBuffer = NULL;
|
|
|
|
// misc
|
|
mAllowRender = true;
|
|
mCurrentRenderStyle = RS_Standard;
|
|
mCurrentStereoTarget = -1;
|
|
mStereoHeadTransform = MatrixF(1);
|
|
mCanCurrentlyRender = false;
|
|
mInitialized = false;
|
|
|
|
mRTDirty = false;
|
|
mViewport = RectI::Zero;
|
|
mViewportDirty = false;
|
|
|
|
mDeviceSwizzle32 = NULL;
|
|
mDeviceSwizzle24 = NULL;
|
|
|
|
mResourceListHead = NULL;
|
|
|
|
mCardProfiler = NULL;
|
|
|
|
// Initialize our drawing utility.
|
|
mDrawer = NULL;
|
|
mFrameTime = PlatformTimer::create();
|
|
// Add a few system wide shader macros.
|
|
GFXShader::addGlobalMacro( "TORQUE", "1" );
|
|
GFXShader::addGlobalMacro( "TORQUE_VERSION", String::ToString(getVersionNumber()) );
|
|
#if defined TORQUE_OS_WIN
|
|
GFXShader::addGlobalMacro( "TORQUE_OS_WIN" );
|
|
#elif defined TORQUE_OS_MAC
|
|
GFXShader::addGlobalMacro( "TORQUE_OS_MAC" );
|
|
#elif defined TORQUE_OS_LINUX
|
|
GFXShader::addGlobalMacro( "TORQUE_OS_LINUX" );
|
|
#endif
|
|
|
|
mStereoTargets[0] = NULL;
|
|
mStereoTargets[1] = NULL;
|
|
}
|
|
|
|
GFXDrawUtil* GFXDevice::getDrawUtil()
|
|
{
|
|
if (!mDrawer)
|
|
{
|
|
mDrawer = new GFXDrawUtil(this);
|
|
}
|
|
return mDrawer;
|
|
}
|
|
|
|
void GFXDevice::deviceInited()
|
|
{
|
|
getDeviceEventSignal().trigger(deInit);
|
|
mDeviceStatistics.setPrefix("$GFXDeviceStatistics::");
|
|
|
|
// Initialize the static helper textures.
|
|
GBitmap temp( 2, 2, false, GFXFormatR8G8B8A8 );
|
|
temp.fill( ColorI::ONE );
|
|
GFXTexHandle::ONE.set( &temp, &GFXStaticTextureSRGBProfile, false, "GFXTexHandle::ONE" );
|
|
temp.fill( ColorI::ZERO );
|
|
GFXTexHandle::ZERO.set( &temp, &GFXStaticTextureSRGBProfile, false, "GFXTexHandle::ZERO" );
|
|
temp.fill( ColorI( 128, 128, 255 ) );
|
|
GFXTexHandle::ZUP.set( &temp, &GFXNormalMapProfile, false, "GFXTexHandle::ZUP" );
|
|
}
|
|
|
|
bool GFXDevice::destroy()
|
|
{
|
|
// Cleanup the static helper textures.
|
|
GFXTexHandle::ONE.free();
|
|
GFXTexHandle::ZERO.free();
|
|
GFXTexHandle::ZUP.free();
|
|
|
|
// Make this release its buffer.
|
|
PrimBuild::shutdown();
|
|
|
|
// Let people know we are shutting down
|
|
getDeviceEventSignal().trigger(deDestroy);
|
|
|
|
if(smGFXDevice)
|
|
smGFXDevice->preDestroy();
|
|
SAFE_DELETE(smGFXDevice);
|
|
|
|
return true;
|
|
}
|
|
|
|
void GFXDevice::preDestroy()
|
|
{
|
|
// Delete draw util
|
|
SAFE_DELETE( mDrawer );
|
|
}
|
|
|
|
GFXDevice::~GFXDevice()
|
|
{
|
|
smGFXDevice = NULL;
|
|
|
|
// Clean up our current buffers.
|
|
mCurrentPrimitiveBuffer = NULL;
|
|
for ( U32 i=0; i < VERTEX_STREAM_COUNT; i++ )
|
|
mCurrentVertexBuffer[i] = NULL;
|
|
|
|
// Clear out our current texture references
|
|
for (U32 i = 0; i < GFX_TEXTURE_STAGE_COUNT; i++)
|
|
{
|
|
mCurrentTexture[i] = NULL;
|
|
mNewTexture[i] = NULL;
|
|
mCurrentCubemap[i] = NULL;
|
|
mNewCubemap[i] = NULL;
|
|
mCurrentCubemapArray[i] = NULL;
|
|
mNewCubemapArray[i] = NULL;
|
|
mCurrentTextureArray[i] = NULL;
|
|
mNewTextureArray[i] = NULL;
|
|
}
|
|
|
|
mCurrentRT = NULL;
|
|
|
|
// Release all the unreferenced textures in the cache.
|
|
mTextureManager->cleanupCache();
|
|
|
|
// Check for resource leaks
|
|
#ifdef TORQUE_DEBUG
|
|
AssertFatal( GFXTextureObject::dumpActiveTOs() == 0, "There is a texture object leak, check the log for more details." );
|
|
GFXPrimitiveBuffer::dumpActivePBs();
|
|
#endif
|
|
|
|
SAFE_DELETE( mTextureManager );
|
|
SAFE_DELETE( mFrameTime );
|
|
|
|
// Clear out our state block references
|
|
mCurrentStateBlocks.clear();
|
|
mNewStateBlock = NULL;
|
|
mCurrentStateBlock = NULL;
|
|
|
|
mCurrentShaderConstBuffer = NULL;
|
|
/// End Block above BTR
|
|
|
|
// -- Clear out resource list
|
|
// Note: our derived class destructor will have already released resources.
|
|
// Clearing this list saves us from having our resources (which are not deleted
|
|
// just released) turn around and try to remove themselves from this list.
|
|
while (mResourceListHead)
|
|
{
|
|
GFXResource * head = mResourceListHead;
|
|
mResourceListHead = head->mNextResource;
|
|
|
|
head->mPrevResource = NULL;
|
|
head->mNextResource = NULL;
|
|
head->mOwningDevice = NULL;
|
|
}
|
|
}
|
|
|
|
GFXStateBlockRef GFXDevice::createStateBlock(const GFXStateBlockDesc& desc)
|
|
{
|
|
PROFILE_SCOPE( GFXDevice_CreateStateBlock );
|
|
|
|
U32 hashValue = desc.getHashValue();
|
|
if (mCurrentStateBlocks[hashValue])
|
|
return mCurrentStateBlocks[hashValue];
|
|
|
|
GFXStateBlockRef result = createStateBlockInternal(desc);
|
|
result->registerResourceWithDevice(this);
|
|
mCurrentStateBlocks[hashValue] = result;
|
|
return result;
|
|
}
|
|
|
|
void GFXDevice::setStateBlock(GFXStateBlock* block)
|
|
{
|
|
AssertFatal(block, "NULL state block!");
|
|
AssertFatal(block->getOwningDevice() == this, "This state doesn't apply to this device!");
|
|
|
|
if (block != mCurrentStateBlock)
|
|
{
|
|
mStateDirty = true;
|
|
mStateBlockDirty = true;
|
|
mNewStateBlock = block;
|
|
} else {
|
|
mStateBlockDirty = false;
|
|
mNewStateBlock = mCurrentStateBlock;
|
|
}
|
|
}
|
|
|
|
void GFXDevice::setStateBlockByDesc( const GFXStateBlockDesc &desc )
|
|
{
|
|
PROFILE_SCOPE( GFXDevice_SetStateBlockByDesc );
|
|
GFXStateBlock *block = createStateBlock( desc );
|
|
setStateBlock( block );
|
|
}
|
|
|
|
void GFXDevice::setShaderConstBuffer(GFXShaderConstBuffer* buffer)
|
|
{
|
|
mCurrentShaderConstBuffer = buffer;
|
|
}
|
|
|
|
void GFXDevice::updateStates(bool forceSetAll /*=false*/)
|
|
{
|
|
PROFILE_SCOPE(GFXDevice_updateStates);
|
|
|
|
if(forceSetAll)
|
|
{
|
|
bool rememberToEndScene = false;
|
|
if(!canCurrentlyRender())
|
|
{
|
|
if (!beginScene())
|
|
{
|
|
AssertFatal(false, "GFXDevice::updateStates: Unable to beginScene!");
|
|
}
|
|
rememberToEndScene = true;
|
|
}
|
|
|
|
setVertexDecl( mCurrVertexDecl );
|
|
|
|
for ( U32 i=0; i < VERTEX_STREAM_COUNT; i++ )
|
|
{
|
|
setVertexStream( i, mCurrentVertexBuffer[i] );
|
|
setVertexStreamFrequency( i, mVertexBufferFrequency[i] );
|
|
}
|
|
|
|
if( mCurrentPrimitiveBuffer.isValid() ) // This could be NULL when the device is initalizing
|
|
mCurrentPrimitiveBuffer->prepare();
|
|
|
|
/// Stateblocks
|
|
if ( mNewStateBlock )
|
|
setStateBlockInternal(mNewStateBlock, true);
|
|
mCurrentStateBlock = mNewStateBlock;
|
|
|
|
for(U32 i = 0; i < getNumSamplers(); i++)
|
|
{
|
|
switch (mTexType[i])
|
|
{
|
|
case GFXTDT_Normal :
|
|
{
|
|
mCurrentTexture[i] = mNewTexture[i];
|
|
setTextureInternal(i, mCurrentTexture[i]);
|
|
}
|
|
break;
|
|
case GFXTDT_Cube :
|
|
{
|
|
mCurrentCubemap[i] = mNewCubemap[i];
|
|
if (mCurrentCubemap[i])
|
|
mCurrentCubemap[i]->setToTexUnit(i);
|
|
else
|
|
setTextureInternal(i, NULL);
|
|
}
|
|
break;
|
|
case GFXTDT_CubeArray:
|
|
{
|
|
mCurrentCubemapArray[i] = mNewCubemapArray[i];
|
|
if (mCurrentCubemapArray[i])
|
|
mCurrentCubemapArray[i]->setToTexUnit(i);
|
|
else
|
|
setTextureInternal(i, NULL);
|
|
}
|
|
break;
|
|
case GFXTDT_TextureArray:
|
|
{
|
|
mCurrentTextureArray[i] = mNewTextureArray[i];
|
|
if (mCurrentTextureArray[i])
|
|
mCurrentTextureArray[i]->setToTexUnit(i);
|
|
else
|
|
setTextureInternal(i, NULL);
|
|
}
|
|
break;
|
|
default:
|
|
AssertFatal(false, "Unknown texture type!");
|
|
break;
|
|
}
|
|
}
|
|
|
|
_updateRenderTargets();
|
|
|
|
if(rememberToEndScene)
|
|
endScene();
|
|
|
|
return;
|
|
}
|
|
|
|
if (!mStateDirty)
|
|
return;
|
|
|
|
// Normal update logic begins here.
|
|
mStateDirty = false;
|
|
|
|
// Update the vertex declaration.
|
|
if ( mVertexDeclDirty )
|
|
{
|
|
setVertexDecl( mCurrVertexDecl );
|
|
mVertexDeclDirty = false;
|
|
}
|
|
|
|
// Update the vertex buffers.
|
|
for ( U32 i=0; i < VERTEX_STREAM_COUNT; i++ )
|
|
{
|
|
if ( mVertexBufferDirty[i] )
|
|
{
|
|
setVertexStream( i, mCurrentVertexBuffer[i] );
|
|
mVertexBufferDirty[i] = false;
|
|
}
|
|
|
|
if ( mVertexBufferFrequencyDirty[i] )
|
|
{
|
|
setVertexStreamFrequency( i, mVertexBufferFrequency[i] );
|
|
mVertexBufferFrequencyDirty[i] = false;
|
|
}
|
|
}
|
|
|
|
// Update primitive buffer
|
|
//
|
|
// NOTE: It is very important to set the primitive buffer AFTER the vertex buffer
|
|
// because in order to draw indexed primitives in DX8, the call to SetIndicies
|
|
// needs to include the base vertex offset, and the DX8 GFXDevice relies on
|
|
// having mCurrentVB properly assigned before the call to setIndices -patw
|
|
if( mPrimitiveBufferDirty )
|
|
{
|
|
if( mCurrentPrimitiveBuffer.isValid() ) // This could be NULL when the device is initalizing
|
|
mCurrentPrimitiveBuffer->prepare();
|
|
mPrimitiveBufferDirty = false;
|
|
}
|
|
|
|
// NOTE: With state blocks, it's now important to update state before setting textures
|
|
// some devices (e.g. OpenGL) set states on the texture and we need that information before
|
|
// the texture is activated.
|
|
if (mStateBlockDirty)
|
|
{
|
|
setStateBlockInternal(mNewStateBlock, false);
|
|
mCurrentStateBlock = mNewStateBlock;
|
|
mStateBlockDirty = false;
|
|
}
|
|
|
|
_updateRenderTargets();
|
|
|
|
if( mTexturesDirty )
|
|
{
|
|
mTexturesDirty = false;
|
|
for(U32 i = 0; i < getNumSamplers(); i++)
|
|
{
|
|
if(!mTextureDirty[i])
|
|
continue;
|
|
mTextureDirty[i] = false;
|
|
|
|
switch (mTexType[i])
|
|
{
|
|
case GFXTDT_Normal :
|
|
{
|
|
mCurrentTexture[i] = mNewTexture[i];
|
|
setTextureInternal(i, mCurrentTexture[i]);
|
|
}
|
|
break;
|
|
case GFXTDT_Cube :
|
|
{
|
|
mCurrentCubemap[i] = mNewCubemap[i];
|
|
if (mCurrentCubemap[i])
|
|
mCurrentCubemap[i]->setToTexUnit(i);
|
|
else
|
|
setTextureInternal(i, NULL);
|
|
}
|
|
break;
|
|
case GFXTDT_CubeArray:
|
|
{
|
|
mCurrentCubemapArray[i] = mNewCubemapArray[i];
|
|
if (mCurrentCubemapArray[i])
|
|
mCurrentCubemapArray[i]->setToTexUnit(i);
|
|
else
|
|
setTextureInternal(i, NULL);
|
|
}
|
|
break;
|
|
case GFXTDT_TextureArray:
|
|
{
|
|
mCurrentTextureArray[i] = mNewTextureArray[i];
|
|
if (mCurrentTextureArray[i])
|
|
mCurrentTextureArray[i]->setToTexUnit(i);
|
|
else
|
|
setTextureInternal(i, NULL);
|
|
}
|
|
break;
|
|
default:
|
|
AssertFatal(false, "Unknown texture type!");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
_updateRenderTargets();
|
|
|
|
#ifdef TORQUE_DEBUG_RENDER
|
|
doParanoidStateCheck();
|
|
#endif
|
|
}
|
|
|
|
void GFXDevice::clearTextureStateImmediate(U32 stage)
|
|
{
|
|
mCurrentTexture[stage] = NULL;
|
|
mCurrentCubemap[stage] = NULL;
|
|
setTextureInternal(stage, NULL);
|
|
}
|
|
|
|
void GFXDevice::setPrimitiveBuffer( GFXPrimitiveBuffer *buffer )
|
|
{
|
|
if( buffer == mCurrentPrimitiveBuffer )
|
|
return;
|
|
|
|
mCurrentPrimitiveBuffer = buffer;
|
|
mPrimitiveBufferDirty = true;
|
|
mStateDirty = true;
|
|
}
|
|
|
|
void GFXDevice::drawPrimitive( U32 primitiveIndex )
|
|
{
|
|
AssertFatal( mCurrentPrimitiveBuffer.isValid(), "Trying to call drawPrimitive with no current primitive buffer, call setPrimitiveBuffer()" );
|
|
AssertFatal( primitiveIndex < mCurrentPrimitiveBuffer->mPrimitiveCount, "Out of range primitive index.");
|
|
drawPrimitive( mCurrentPrimitiveBuffer->mPrimitiveArray[primitiveIndex] );
|
|
}
|
|
|
|
void GFXDevice::drawPrimitive( const GFXPrimitive &prim )
|
|
{
|
|
// Do NOT add index buffer offset to this call, it will be added by drawIndexedPrimitive
|
|
drawIndexedPrimitive( prim.type,
|
|
prim.startVertex,
|
|
prim.minIndex,
|
|
prim.numVertices,
|
|
prim.startIndex,
|
|
prim.numPrimitives );
|
|
}
|
|
|
|
void GFXDevice::drawPrimitives()
|
|
{
|
|
AssertFatal( mCurrentPrimitiveBuffer.isValid(), "Trying to call drawPrimitive with no current primitive buffer, call setPrimitiveBuffer()" );
|
|
|
|
GFXPrimitive *info = NULL;
|
|
|
|
for( U32 i = 0; i < mCurrentPrimitiveBuffer->mPrimitiveCount; i++ ) {
|
|
info = &mCurrentPrimitiveBuffer->mPrimitiveArray[i];
|
|
|
|
// Do NOT add index buffer offset to this call, it will be added by drawIndexedPrimitive
|
|
drawIndexedPrimitive( info->type,
|
|
info->startVertex,
|
|
info->minIndex,
|
|
info->numVertices,
|
|
info->startIndex,
|
|
info->numPrimitives );
|
|
}
|
|
}
|
|
|
|
DefineEngineFunction( getDisplayDeviceList, String, (),,
|
|
"Returns a tab-seperated string of the detected devices across all adapters.\n"
|
|
"@ingroup GFX\n" )
|
|
{
|
|
Vector<GFXAdapter*> adapters;
|
|
GFXInit::getAdapters(&adapters);
|
|
|
|
StringBuilder str;
|
|
for (S32 i=0; i<adapters.size(); i++)
|
|
{
|
|
if (i)
|
|
str.append( '\t' );
|
|
str.append(adapters[i]->mName);
|
|
}
|
|
|
|
return str.end();
|
|
}
|
|
|
|
void GFXDevice::setFrustum( F32 left,
|
|
F32 right,
|
|
F32 bottom,
|
|
F32 top,
|
|
F32 nearPlane,
|
|
F32 farPlane,
|
|
bool bRotate )
|
|
{
|
|
// store values
|
|
mFrustum.set(false, left, right, top, bottom, nearPlane, farPlane);
|
|
|
|
// compute matrix
|
|
MatrixF projection;
|
|
mFrustum.getProjectionMatrix(&projection, bRotate);
|
|
setProjectionMatrix( projection );
|
|
}
|
|
|
|
void GFXDevice::setFrustum( const Frustum& frust, bool bRotate )
|
|
{
|
|
// store values
|
|
mFrustum = frust;
|
|
|
|
// compute matrix
|
|
MatrixF projection;
|
|
mFrustum.getProjectionMatrix(&projection, bRotate);
|
|
setProjectionMatrix( projection );
|
|
}
|
|
|
|
|
|
void GFXDevice::getFrustum( F32 *left, F32 *right, F32 *bottom, F32 *top, F32 *nearPlane, F32 *farPlane, bool *isOrtho ) const
|
|
{
|
|
if ( left ) *left = mFrustum.getNearLeft();
|
|
if ( right ) *right = mFrustum.getNearRight();
|
|
if ( bottom ) *bottom = mFrustum.getNearBottom();
|
|
if ( top ) *top = mFrustum.getNearTop();
|
|
if ( nearPlane ) *nearPlane = mFrustum.getNearDist();
|
|
if ( farPlane ) *farPlane = mFrustum.getFarDist();
|
|
if ( isOrtho ) *isOrtho = mFrustum.isOrtho();
|
|
}
|
|
|
|
void GFXDevice::setOrtho( F32 left,
|
|
F32 right,
|
|
F32 bottom,
|
|
F32 top,
|
|
F32 nearPlane,
|
|
F32 farPlane,
|
|
bool doRotate )
|
|
{
|
|
// store values
|
|
mFrustum.set(true, left, right, top, bottom, nearPlane, farPlane);
|
|
|
|
// compute matrix
|
|
MatrixF projection;
|
|
mFrustum.getProjectionMatrix(&projection, doRotate);
|
|
|
|
setProjectionMatrix( projection );
|
|
}
|
|
|
|
Point2F GFXDevice::getWorldToScreenScale() const
|
|
{
|
|
Point2F scale;
|
|
|
|
const RectI &viewport = getViewport();
|
|
|
|
if ( mFrustum.isOrtho() )
|
|
scale.set( viewport.extent.x / mFrustum.getWidth(),
|
|
viewport.extent.y / mFrustum.getHeight() );
|
|
else
|
|
scale.set( ( mFrustum.getNearDist() * viewport.extent.x ) / mFrustum.getWidth(),
|
|
( mFrustum.getNearDist() * viewport.extent.y ) / mFrustum.getHeight() );
|
|
|
|
return scale;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Set texture
|
|
//-----------------------------------------------------------------------------
|
|
void GFXDevice::setTexture( U32 stage, GFXTextureObject *texture )
|
|
{
|
|
AssertFatal(stage < getNumSamplers(), "GFXDevice::setTexture - out of range stage!");
|
|
|
|
if ( mTexType[stage] == GFXTDT_Normal &&
|
|
( ( mTextureDirty[stage] && mNewTexture[stage].getPointer() == texture ) ||
|
|
( !mTextureDirty[stage] && mCurrentTexture[stage].getPointer() == texture ) ) )
|
|
return;
|
|
|
|
mStateDirty = true;
|
|
mTexturesDirty = true;
|
|
mTextureDirty[stage] = true;
|
|
|
|
mNewTexture[stage] = texture;
|
|
mTexType[stage] = GFXTDT_Normal;
|
|
|
|
// Clear out the cubemaps
|
|
mNewCubemap[stage] = NULL;
|
|
mCurrentCubemap[stage] = NULL;
|
|
mNewCubemapArray[stage] = NULL;
|
|
mCurrentCubemapArray[stage] = NULL;
|
|
mNewTextureArray[stage] = NULL;
|
|
mCurrentTextureArray[stage] = NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Set cube texture
|
|
//-----------------------------------------------------------------------------
|
|
void GFXDevice::setCubeTexture( U32 stage, GFXCubemap *cubemap )
|
|
{
|
|
AssertFatal(stage < getNumSamplers(), "GFXDevice::setTexture - out of range stage!");
|
|
|
|
if ( mTexType[stage] == GFXTDT_Cube &&
|
|
( ( mTextureDirty[stage] && mNewCubemap[stage].getPointer() == cubemap) ||
|
|
( !mTextureDirty[stage] && mCurrentCubemap[stage].getPointer() == cubemap) ) )
|
|
return;
|
|
|
|
mStateDirty = true;
|
|
mTexturesDirty = true;
|
|
mTextureDirty[stage] = true;
|
|
|
|
mNewCubemap[stage] = cubemap;
|
|
mTexType[stage] = GFXTDT_Cube;
|
|
|
|
// Clear out textures
|
|
mNewTexture[stage] = NULL;
|
|
mCurrentTexture[stage] = NULL;
|
|
mNewCubemapArray[stage] = NULL;
|
|
mCurrentCubemapArray[stage] = NULL;
|
|
mNewTextureArray[stage] = NULL;
|
|
mCurrentTextureArray[stage] = NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Set cube texture array
|
|
//-----------------------------------------------------------------------------
|
|
void GFXDevice::setCubeArrayTexture(U32 stage, GFXCubemapArray *cubemapArray)
|
|
{
|
|
AssertFatal(stage < getNumSamplers(), avar("GFXDevice::setTexture - out of range stage! %i>%i", stage, getNumSamplers()));
|
|
|
|
if (mTexType[stage] == GFXTDT_CubeArray &&
|
|
((mTextureDirty[stage] && mNewCubemapArray[stage].getPointer() == cubemapArray) ||
|
|
(!mTextureDirty[stage] && mCurrentCubemapArray[stage].getPointer() == cubemapArray)))
|
|
return;
|
|
|
|
mStateDirty = true;
|
|
mTexturesDirty = true;
|
|
mTextureDirty[stage] = true;
|
|
|
|
mNewCubemapArray[stage] = cubemapArray;
|
|
mTexType[stage] = GFXTDT_CubeArray;
|
|
|
|
// Clear out textures
|
|
mNewTexture[stage] = NULL;
|
|
mCurrentTexture[stage] = NULL;
|
|
mNewCubemap[stage] = NULL;
|
|
mCurrentCubemap[stage] = NULL;
|
|
mNewTextureArray[stage] = NULL;
|
|
mCurrentTextureArray[stage] = NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Set texture array
|
|
//-----------------------------------------------------------------------------
|
|
void GFXDevice::setTextureArray(U32 stage, GFXTextureArray *textureArray)
|
|
{
|
|
AssertFatal(stage < getNumSamplers(), avar("GFXDevice::setTextureArray - out of range stage! %i>%i", stage, getNumSamplers()));
|
|
|
|
if (mTexType[stage] == GFXTDT_TextureArray &&
|
|
((mTextureDirty[stage] && mNewTextureArray[stage].getPointer() == textureArray) ||
|
|
(!mTextureDirty[stage] && mCurrentTextureArray[stage].getPointer() == textureArray)))
|
|
return;
|
|
|
|
mStateDirty = true;
|
|
mTexturesDirty = true;
|
|
mTextureDirty[stage] = true;
|
|
|
|
mNewTextureArray[stage] = textureArray;
|
|
mTexType[stage] = GFXTDT_TextureArray;
|
|
|
|
// Clear out textures
|
|
mNewTexture[stage] = NULL;
|
|
mCurrentTexture[stage] = NULL;
|
|
mNewCubemap[stage] = NULL;
|
|
mCurrentCubemap[stage] = NULL;
|
|
mNewCubemapArray[stage] = NULL;
|
|
mCurrentCubemapArray[stage] = NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
inline bool GFXDevice::beginScene()
|
|
{
|
|
AssertFatal( mCanCurrentlyRender == false, "GFXDevice::beginScene() - The scene has already begun!" );
|
|
|
|
mDeviceStatistics.clear();
|
|
|
|
// Send the start of frame signal.
|
|
getDeviceEventSignal().trigger( GFXDevice::deStartOfFrame );
|
|
mFrameTime->reset();
|
|
return beginSceneInternal();
|
|
}
|
|
|
|
inline void GFXDevice::endScene()
|
|
{
|
|
AssertFatal( mCanCurrentlyRender == true, "GFXDevice::endScene() - The scene has already ended!" );
|
|
|
|
// End frame signal
|
|
getDeviceEventSignal().trigger( GFXDevice::deEndOfFrame );
|
|
|
|
endSceneInternal();
|
|
mDeviceStatistics.exportToConsole();
|
|
}
|
|
|
|
inline void GFXDevice::beginField()
|
|
{
|
|
AssertFatal( mCanCurrentlyRender == true, "GFXDevice::beginField() - The scene has not yet begun!" );
|
|
|
|
// Send the start of field signal.
|
|
getDeviceEventSignal().trigger( GFXDevice::deStartOfField );
|
|
}
|
|
|
|
inline void GFXDevice::endField()
|
|
{
|
|
AssertFatal( mCanCurrentlyRender == true, "GFXDevice::endField() - The scene has not yet begun!" );
|
|
|
|
// Send the end of field signal.
|
|
getDeviceEventSignal().trigger( GFXDevice::deEndOfField );
|
|
}
|
|
|
|
void GFXDevice::setViewport( const RectI &inRect )
|
|
{
|
|
// Clip the rect against the renderable size.
|
|
Point2I size = mCurrentRT->getSize();
|
|
RectI maxRect(Point2I(0,0), size);
|
|
RectI rect = inRect;
|
|
rect.intersect(maxRect);
|
|
|
|
if ( mViewport != rect )
|
|
{
|
|
mViewport = rect;
|
|
mViewportDirty = true;
|
|
}
|
|
}
|
|
|
|
void GFXDevice::pushActiveRenderTarget()
|
|
{
|
|
// Push the current target on to the stack.
|
|
mRTStack.push_back( mCurrentRT );
|
|
}
|
|
|
|
void GFXDevice::popActiveRenderTarget()
|
|
{
|
|
AssertFatal( mRTStack.size() > 0, "GFXDevice::popActiveRenderTarget() - stack is empty!" );
|
|
|
|
// Restore the last item on the stack and pop.
|
|
setActiveRenderTarget( mRTStack.last() );
|
|
mRTStack.pop_back();
|
|
}
|
|
|
|
void GFXDevice::setActiveRenderTarget( GFXTarget *target, bool updateViewport )
|
|
{
|
|
AssertFatal( target,
|
|
"GFXDevice::setActiveRenderTarget - must specify a render target!" );
|
|
|
|
if ( target == mCurrentRT )
|
|
return;
|
|
|
|
// If we're not dirty then store the
|
|
// current RT for deactivation later.
|
|
if ( !mRTDirty )
|
|
{
|
|
// Deactivate the target queued for deactivation
|
|
if(mRTDeactivate)
|
|
mRTDeactivate->deactivate();
|
|
|
|
mRTDeactivate = mCurrentRT;
|
|
}
|
|
|
|
mRTDirty = true;
|
|
mCurrentRT = target;
|
|
|
|
// When a target changes we also change the viewport
|
|
// to match it. This causes problems when the viewport
|
|
// has been modified for clipping to a GUI bounds.
|
|
//
|
|
// We should consider removing this and making it the
|
|
// responsibility of the caller to set a proper viewport
|
|
// when the target is changed.
|
|
if ( updateViewport )
|
|
{
|
|
setViewport( RectI( Point2I::Zero, mCurrentRT->getSize() ) );
|
|
}
|
|
}
|
|
|
|
/// Helper class for GFXDevice::describeResources.
|
|
class DescriptionOutputter
|
|
{
|
|
/// Are we writing to a file?
|
|
bool mWriteToFile;
|
|
|
|
/// File if we are writing to a file
|
|
FileStream mFile;
|
|
public:
|
|
DescriptionOutputter(const char* file)
|
|
{
|
|
mWriteToFile = false;
|
|
// If we've been given what could be a valid file path, open it.
|
|
if(file && file[0] != '\0')
|
|
{
|
|
mWriteToFile = mFile.open(file, Torque::FS::File::Write);
|
|
|
|
// Note that it is safe to retry. If this is hit, we'll just write to the console instead of to the file.
|
|
AssertFatal(mWriteToFile, avar("DescriptionOutputter::DescriptionOutputter - could not open file %s", file));
|
|
}
|
|
}
|
|
|
|
~DescriptionOutputter()
|
|
{
|
|
// Close the file
|
|
if(mWriteToFile)
|
|
mFile.close();
|
|
}
|
|
|
|
/// Writes line to the file or to the console, depending on what we want.
|
|
void write(const char* line)
|
|
{
|
|
if(mWriteToFile)
|
|
mFile.writeLine((const U8*)line);
|
|
else
|
|
Con::printf(line);
|
|
}
|
|
};
|
|
|
|
#ifndef TORQUE_SHIPPING
|
|
void GFXDevice::dumpStates( const char *fileName ) const
|
|
{
|
|
DescriptionOutputter output(fileName);
|
|
|
|
output.write("Current state");
|
|
if (!mCurrentStateBlock.isNull())
|
|
output.write(mCurrentStateBlock->getDesc().describeSelf().c_str());
|
|
else
|
|
output.write("No state!");
|
|
|
|
output.write("\nAll states:\n");
|
|
GFXResource* walk = mResourceListHead;
|
|
while(walk)
|
|
{
|
|
const GFXStateBlock* sb = dynamic_cast<const GFXStateBlock*>(walk);
|
|
if (sb)
|
|
{
|
|
output.write(sb->getDesc().describeSelf().c_str());
|
|
}
|
|
walk = walk->getNextResource();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void GFXDevice::listResources(bool unflaggedOnly)
|
|
{
|
|
U32 numTextures = 0, numShaders = 0, numRenderToTextureTargs = 0, numWindowTargs = 0;
|
|
U32 numCubemaps = 0, numVertexBuffers = 0, numPrimitiveBuffers = 0, numFences = 0;
|
|
U32 numStateBlocks = 0;
|
|
|
|
GFXResource* walk = mResourceListHead;
|
|
while(walk)
|
|
{
|
|
if(unflaggedOnly && walk->isFlagged())
|
|
{
|
|
walk = walk->getNextResource();
|
|
continue;
|
|
}
|
|
|
|
if(dynamic_cast<GFXTextureObject*>(walk))
|
|
numTextures++;
|
|
else if(dynamic_cast<GFXShader*>(walk))
|
|
numShaders++;
|
|
else if(dynamic_cast<GFXTextureTarget*>(walk))
|
|
numRenderToTextureTargs++;
|
|
else if(dynamic_cast<GFXWindowTarget*>(walk))
|
|
numWindowTargs++;
|
|
else if(dynamic_cast<GFXCubemap*>(walk))
|
|
numCubemaps++;
|
|
else if(dynamic_cast<GFXVertexBuffer*>(walk))
|
|
numVertexBuffers++;
|
|
else if(dynamic_cast<GFXPrimitiveBuffer*>(walk))
|
|
numPrimitiveBuffers++;
|
|
else if(dynamic_cast<GFXFence*>(walk))
|
|
numFences++;
|
|
else if (dynamic_cast<GFXStateBlock*>(walk))
|
|
numStateBlocks++;
|
|
else
|
|
Con::warnf("Unknown resource: %x", walk);
|
|
|
|
walk = walk->getNextResource();
|
|
}
|
|
const char* flag = unflaggedOnly ? "unflagged" : "allocated";
|
|
|
|
Con::printf("GFX currently has:");
|
|
Con::printf(" %i %s textures", numTextures, flag);
|
|
Con::printf(" %i %s shaders", numShaders, flag);
|
|
Con::printf(" %i %s texture targets", numRenderToTextureTargs, flag);
|
|
Con::printf(" %i %s window targets", numWindowTargs, flag);
|
|
Con::printf(" %i %s cubemaps", numCubemaps, flag);
|
|
Con::printf(" %i %s vertex buffers", numVertexBuffers, flag);
|
|
Con::printf(" %i %s primitive buffers", numPrimitiveBuffers, flag);
|
|
Con::printf(" %i %s fences", numFences, flag);
|
|
Con::printf(" %i %s state blocks", numStateBlocks, flag);
|
|
}
|
|
|
|
void GFXDevice::fillResourceVectors(const char* resNames, bool unflaggedOnly, Vector<GFXResource*> &textureObjects,
|
|
Vector<GFXResource*> &textureTargets, Vector<GFXResource*> &windowTargets, Vector<GFXResource*> &vertexBuffers,
|
|
Vector<GFXResource*> &primitiveBuffers, Vector<GFXResource*> &fences, Vector<GFXResource*> &cubemaps,
|
|
Vector<GFXResource*> &shaders, Vector<GFXResource*> &stateblocks)
|
|
{
|
|
bool describeTexture = true, describeTextureTarget = true, describeWindowTarget = true, describeVertexBuffer = true,
|
|
describePrimitiveBuffer = true, describeFence = true, describeCubemap = true, describeShader = true,
|
|
describeStateBlock = true;
|
|
|
|
// If we didn't specify a string of names, we'll print all of them
|
|
if(resNames && resNames[0] != '\0')
|
|
{
|
|
// If we did specify a string of names, determine which names
|
|
describeTexture = (dStrstr(resNames, "GFXTextureObject") != NULL);
|
|
describeTextureTarget = (dStrstr(resNames, "GFXTextureTarget") != NULL);
|
|
describeWindowTarget = (dStrstr(resNames, "GFXWindowTarget") != NULL);
|
|
describeVertexBuffer = (dStrstr(resNames, "GFXVertexBuffer") != NULL);
|
|
describePrimitiveBuffer = (dStrstr(resNames, "GFXPrimitiveBuffer") != NULL);
|
|
describeFence = (dStrstr(resNames, "GFXFence") != NULL);
|
|
describeCubemap = (dStrstr(resNames, "GFXCubemap") != NULL);
|
|
describeShader = (dStrstr(resNames, "GFXShader") != NULL);
|
|
describeStateBlock = (dStrstr(resNames, "GFXStateBlock") != NULL);
|
|
}
|
|
|
|
// Start going through the list
|
|
GFXResource* walk = mResourceListHead;
|
|
while(walk)
|
|
{
|
|
// If we only want unflagged resources, skip all flagged resources
|
|
if(unflaggedOnly && walk->isFlagged())
|
|
{
|
|
walk = walk->getNextResource();
|
|
continue;
|
|
}
|
|
|
|
// All of the following checks go through the same logic.
|
|
// if(describingThisResource)
|
|
// {
|
|
// ResourceType* type = dynamic_cast<ResourceType*>(walk)
|
|
// if(type)
|
|
// {
|
|
// typeVector.push_back(type);
|
|
// walk = walk->getNextResource();
|
|
// continue;
|
|
// }
|
|
// }
|
|
|
|
if(describeTexture)
|
|
{
|
|
GFXTextureObject* tex = dynamic_cast<GFXTextureObject*>(walk);
|
|
{
|
|
if(tex)
|
|
{
|
|
textureObjects.push_back(tex);
|
|
walk = walk->getNextResource();
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if(describeShader)
|
|
{
|
|
GFXShader* shd = dynamic_cast<GFXShader*>(walk);
|
|
if(shd)
|
|
{
|
|
shaders.push_back(shd);
|
|
walk = walk->getNextResource();
|
|
continue;
|
|
}
|
|
}
|
|
if(describeVertexBuffer)
|
|
{
|
|
GFXVertexBuffer* buf = dynamic_cast<GFXVertexBuffer*>(walk);
|
|
if(buf)
|
|
{
|
|
vertexBuffers.push_back(buf);
|
|
walk = walk->getNextResource();
|
|
continue;
|
|
}
|
|
}
|
|
if(describePrimitiveBuffer)
|
|
{
|
|
GFXPrimitiveBuffer* buf = dynamic_cast<GFXPrimitiveBuffer*>(walk);
|
|
if(buf)
|
|
{
|
|
primitiveBuffers.push_back(buf);
|
|
walk = walk->getNextResource();
|
|
continue;
|
|
}
|
|
}
|
|
if(describeTextureTarget)
|
|
{
|
|
GFXTextureTarget* targ = dynamic_cast<GFXTextureTarget*>(walk);
|
|
if(targ)
|
|
{
|
|
textureTargets.push_back(targ);
|
|
walk = walk->getNextResource();
|
|
continue;
|
|
}
|
|
}
|
|
if(describeWindowTarget)
|
|
{
|
|
GFXWindowTarget* targ = dynamic_cast<GFXWindowTarget*>(walk);
|
|
if(targ)
|
|
{
|
|
windowTargets.push_back(targ);
|
|
walk = walk->getNextResource();
|
|
continue;
|
|
}
|
|
}
|
|
if(describeCubemap)
|
|
{
|
|
GFXCubemap* cube = dynamic_cast<GFXCubemap*>(walk);
|
|
if(cube)
|
|
{
|
|
cubemaps.push_back(cube);
|
|
walk = walk->getNextResource();
|
|
continue;
|
|
}
|
|
}
|
|
if(describeFence)
|
|
{
|
|
GFXFence* fence = dynamic_cast<GFXFence*>(walk);
|
|
if(fence)
|
|
{
|
|
fences.push_back(fence);
|
|
walk = walk->getNextResource();
|
|
continue;
|
|
}
|
|
}
|
|
if (describeStateBlock)
|
|
{
|
|
GFXStateBlock* sb = dynamic_cast<GFXStateBlock*>(walk);
|
|
if (sb)
|
|
{
|
|
stateblocks.push_back(sb);
|
|
walk = walk->getNextResource();
|
|
continue;
|
|
}
|
|
}
|
|
// Wasn't something we were looking for
|
|
walk = walk->getNextResource();
|
|
}
|
|
}
|
|
|
|
void GFXDevice::describeResources(const char* resNames, const char* filePath, bool unflaggedOnly)
|
|
{
|
|
const U32 numResourceTypes = 9;
|
|
Vector<GFXResource*> resVectors[numResourceTypes];
|
|
const char* reslabels[numResourceTypes] = { "texture", "texture target", "window target", "vertex buffers", "primitive buffers", "fences", "cubemaps", "shaders", "stateblocks" };
|
|
|
|
// Fill the vectors with the right resources
|
|
fillResourceVectors(resNames, unflaggedOnly, resVectors[0], resVectors[1], resVectors[2], resVectors[3],
|
|
resVectors[4], resVectors[5], resVectors[6], resVectors[7], resVectors[8]);
|
|
|
|
// Helper object
|
|
DescriptionOutputter output(filePath);
|
|
|
|
// Print the info to the file
|
|
// Note that we check if we have any objects of that type.
|
|
for (U32 i = 0; i < numResourceTypes; i++)
|
|
{
|
|
if (resVectors[i].size())
|
|
{
|
|
// Header
|
|
String header = String::ToString("--------Dumping GFX %s descriptions...----------", reslabels[i]);
|
|
output.write(header);
|
|
// Data
|
|
for (U32 j = 0; j < resVectors[i].size(); j++)
|
|
{
|
|
GFXResource* resource = resVectors[i][j];
|
|
String dataline = String::ToString("Addr: %x %s", resource, resource->describeSelf().c_str());
|
|
output.write(dataline.c_str());
|
|
}
|
|
// Footer
|
|
output.write("--------------------Done---------------------");
|
|
output.write("");
|
|
}
|
|
}
|
|
}
|
|
|
|
void GFXDevice::flagCurrentResources()
|
|
{
|
|
GFXResource* walk = mResourceListHead;
|
|
while(walk)
|
|
{
|
|
walk->setFlag();
|
|
walk = walk->getNextResource();
|
|
}
|
|
}
|
|
|
|
void GFXDevice::clearResourceFlags()
|
|
{
|
|
GFXResource* walk = mResourceListHead;
|
|
while(walk)
|
|
{
|
|
walk->clearFlag();
|
|
walk = walk->getNextResource();
|
|
}
|
|
}
|
|
|
|
DefineEngineFunction( listGFXResources, void, ( bool unflaggedOnly ), ( false ),
|
|
"Returns a list of the unflagged GFX resources. See flagCurrentGFXResources for usage details.\n"
|
|
"@ingroup GFX\n"
|
|
"@see flagCurrentGFXResources, clearGFXResourceFlags, describeGFXResources" )
|
|
{
|
|
GFX->listResources(unflaggedOnly);
|
|
}
|
|
|
|
DefineEngineFunction( flagCurrentGFXResources, void, (),,
|
|
"@brief Flags all currently allocated GFX resources.\n"
|
|
"Used for resource allocation and leak tracking by flagging "
|
|
"current resources then dumping a list of unflagged resources "
|
|
"at some later point in execution.\n"
|
|
"@ingroup GFX\n"
|
|
"@see listGFXResources, clearGFXResourceFlags, describeGFXResources" )
|
|
{
|
|
GFX->flagCurrentResources();
|
|
}
|
|
|
|
DefineEngineFunction( clearGFXResourceFlags, void, (),,
|
|
"Clears the flagged state on all allocated GFX resources. "
|
|
"See flagCurrentGFXResources for usage details.\n"
|
|
"@ingroup GFX\n"
|
|
"@see flagCurrentGFXResources, listGFXResources, describeGFXResources" )
|
|
{
|
|
GFX->clearResourceFlags();
|
|
}
|
|
|
|
DefineEngineFunction( describeGFXResources, void, ( const char *resourceTypes, const char *filePath, bool unflaggedOnly ), ( false ),
|
|
"@brief Dumps a description of GFX resources to a file or the console.\n"
|
|
"@param resourceTypes A space seperated list of resource types or an empty string for all resources.\n"
|
|
"@param filePath A file to dump the list to or an empty string to write to the console.\n"
|
|
"@param unflaggedOnly If true only unflagged resources are dumped. See flagCurrentGFXResources.\n"
|
|
"@note The resource types can be one or more of the following:\n\n"
|
|
" - texture\n"
|
|
" - texture target\n"
|
|
" - window target\n"
|
|
" - vertex buffers\n"
|
|
" - primitive buffers\n"
|
|
" - fences\n"
|
|
" - cubemaps\n"
|
|
" - shaders\n"
|
|
" - stateblocks\n\n"
|
|
"@ingroup GFX\n" )
|
|
{
|
|
GFX->describeResources( resourceTypes, filePath, unflaggedOnly );
|
|
}
|
|
|
|
DefineEngineFunction( describeGFXStateBlocks, void, ( const char *filePath ),,
|
|
"Dumps a description of all state blocks.\n"
|
|
"@param filePath A file to dump the state blocks to or an empty string to write to the console.\n"
|
|
"@ingroup GFX\n" )
|
|
{
|
|
GFX->dumpStates( filePath );
|
|
}
|
|
|
|
DefineEngineFunction( getPixelShaderVersion, F32, (),,
|
|
"Returns the pixel shader version for the active device.\n"
|
|
"@ingroup GFX\n" )
|
|
{
|
|
return GFX->getPixelShaderVersion();
|
|
}
|
|
|
|
DefineEngineFunction( setPixelShaderVersion, void, ( F32 version ),,
|
|
"@brief Sets the pixel shader version for the active device.\n"
|
|
"This can be used to force a lower pixel shader version than is supported by "
|
|
"the device for testing or performance optimization.\n"
|
|
"@param version The floating point shader version number.\n"
|
|
"@note This will only affect shaders/materials created after the call "
|
|
"and should be used before the game begins.\n"
|
|
"@see $pref::Video::forcedPixVersion\n"
|
|
"@ingroup GFX\n" )
|
|
{
|
|
GFX->setPixelShaderVersion( version );
|
|
}
|
|
|
|
DefineEngineFunction( getDisplayDeviceInformation, const char*, (),,
|
|
"Get the string describing the active GFX device.\n"
|
|
"@ingroup GFX\n" )
|
|
{
|
|
if (!GFXDevice::devicePresent())
|
|
return "(no device)";
|
|
|
|
const GFXAdapter& adapter = GFX->getAdapter();
|
|
return adapter.getName();
|
|
}
|
|
|
|
DefineEngineFunction(getDisplayDeviceType, GFXAdapterType, (), ,
|
|
"Get the string describing the active GFX device type.\n"
|
|
"@ingroup GFX\n")
|
|
{
|
|
if (!GFXDevice::devicePresent())
|
|
return NullDevice;
|
|
|
|
const GFXAdapter& adapter = GFX->getAdapter();
|
|
return adapter.mType;
|
|
}
|
|
|
|
DefineEngineFunction( getBestHDRFormat, GFXFormat, (),,
|
|
"Returns the best texture format for storage of HDR data for the active device.\n"
|
|
"@ingroup GFX\n" )
|
|
{
|
|
// TODO: Maybe expose GFX::selectSupportedFormat() so that this
|
|
// specialized method can be moved to script.
|
|
|
|
// Figure out the best HDR format. This is the smallest
|
|
// format which supports blending and filtering.
|
|
Vector<GFXFormat> formats;
|
|
formats.push_back(GFXFormatR16G16B16A16F);
|
|
formats.push_back( GFXFormatR10G10B10A2 );
|
|
GFXFormat format = GFX->selectSupportedFormat( &GFXRenderTargetProfile,
|
|
formats,
|
|
true,
|
|
true,
|
|
true );
|
|
|
|
return format;
|
|
}
|
|
|
|
DefineEngineFunction(ResetGFX, void, (), , "forces the gbuffer to be reinitialized in cases of improper/lack of buffer clears.")
|
|
{
|
|
GFX->beginReset();
|
|
}
|