TorqueGameEngineAdvanced/1 8 Beta/Porting/Gotchas
From TDN
|
[edit] IntroductionWelcome to the "Gotcha" section of TGEA's 1.8 porting guide. If you are unfamiliar with the term "Gotcha" (quotes and all), imagine writing valid code in the engine that results in a bug or crash. The code worked in a previous version of TGEA, but is busted in 1.8. What you are experiencing is an engine modification you are not aware of messing up your work.
[edit] Initializing GFX In ScriptIf you are porting an older project, or creating your own from scratch, this "Gotcha" is the first issue to address. Unlike previous versions of TGEA, in 1.8 you need to initialize the renderer from TorqueScript. This is a client side operation, so you will want to call this during your client initialization script/function: // Called from client script initRenderInstManager();
ConsoleFunction(initRenderInstManager, void, 0, 0, "Initializes the render bin system and lighting system,"
"basically a signal from script that materials/shaders are loaded and GFX is up and running.")
{
gClientSceneGraph->initRender();
}
[edit] Main Loop ChangeThis "Gotcha" is one of the first modifications you need to make if you are merging an older project. Each game project has a main.cpp file. This source file is local to your project, not the engine's source. For example, the T3D main.cpp can be found in the GameExamples/T3D/source/ directory. Within this file is the entry point for your game:
// Entry point for your game.
//
// This is build by default using the "StandardMainLoop" toolkit. Feel free
// to bring code over directly as you need to modify or extend things. You
// will need to merge against future changes to the SML code if you do this.
S32 TorqueMain(S32 argc, const char **argv)
{
...
}
// Main loop StandardMainLoop::doMainLoop();
// Main loop while(StandardMainLoop::doMainLoop());
[edit] Setting Shader Constant BuffersBefore you perform a draw call, you must remember to set your shader constant buffers (GFXShaderConstBufferRef). If you forget to do this, you can end up with odd graphical glitches that do not actually produce errors/crashes/warnings.
// Get projection matrix first proj = GFX->getProjectionMatrix(); // Here, we are asssigning our shader constant buffer properties myShaderConstBuffer->set(mModelViewProjSC, &proj); myShaderConstBuffer->set(mOpacityMapSC, (S32)0); mShaderConsts->set(mLightMapSC, (S32)1); // *** SET SHADER CONSTANT BUFFER *** GFX->setShaderConstBuffer(mShaderConsts); // Now you can safely use draw calls ...
In Precipication.h, you will find various shader constant buffer variables. Here are a few examples: GFXShaderConstBufferRef mSplashShaderConsts; GFXShaderConstHandle* mSplashShaderModelViewSC; GFXShaderConstHandle* mSplashShaderFadeStartEndSC;
if (mSplashShaderConsts.isNull())
{
mSplashShaderConsts = mSplashShader->mShader->allocConstBuffer();
if (mSplashShaderConsts)
{
mSplashShaderModelViewSC = mSplashShaderConsts->getShader()->getShaderConstHandle("$modelView");
mSplashShaderFadeStartEndSC = mSplashShaderConsts->getShader()->getShaderConstHandle("$fadeStartEnd");
mSplashShaderCameraPosSC = mSplashShaderConsts->getShader()->getShaderConstHandle("$cameraPos");
mSplashShaderAmbientSC = mSplashShaderConsts->getShader()->getShaderConstHandle("$ambient");
}
}
if (mSplashShaderModelViewSC)
mSplashShaderConsts->set(mSplashShaderModelViewSC, proj);
if (mSplashShaderFadeStartEndSC)
mSplashShaderConsts->set(mSplashShaderFadeStartEndSC, fadeStartEnd);
if (mSplashShader)
{
if (mSplashShaderConsts.isValid())
GFX->setShaderConstBuffer(mSplashShaderConsts);
mSplashShader->getShader()->process();
}
As you can see, the main point of this section is addressed. If we are using the Splash Shader, we check to see if we have a valid shader constant buffer for splash rendering. If so, GFX sets the shader constant buffer before we render.
[edit] Transpose GotchaDo not transpose transform matrices before passing a shader. Doing so will result in odd visuals, since you will be passing in the wrong matrix. You might see objects flickering and shooting off into infinity from your perspective. We've avoided doing this in the newer GFX2 code, but if you need to see an example of where this "Gotcha" was corrected, you can look at the fxFoliageReplicator class. Open fxFoliageReplicator.cpp.
// Set up our shader constants
// Projection matrix
MatrixF proj = GFX->getProjectionMatrix();
//proj.transpose();
if (mFoliageShaderProjectionSC)
mFoliageShaderConsts->set(mFoliageShaderProjectionSC, proj);
In the above code, we get the projection matrix from GFX. A few lines down, we set the shader. As you can see, we commented the transpose function. Keep this in mind when you are writing similar rendering code.
[edit] Name ConsistencyThis can be a very frustrating "Gotcha", as the likelihood of repeating the mistake is high. You must avoid inconsistent naming of shader variables. As an example, we are going to examine a water shader which has been updated to work with TGEA 1.8.
uniform float3 lightVec : register(C21),
uniform float3 inLightVec : register(C21),
const static String light1Direction; How does this relate to the naming consistency issue? Switch to shaderGenVars.cpp and browse for light1Direction again.
const String ShaderGenVars::light1Direction("$inLightVec");
Jackpot! This is where inLightVec is assigned, and this is how the shaders tie in with TGEA's custom material system. So, to reiterate, make sure the shader variable names you use in a shader file match the ones declared in the engine. Don't forget the $ symbol, either!
[edit] Shader Compile FailureThis is a simple "Gotcha" to explain, but you need to keep an eye out for it. If your shader is not being displayed, or has bad results, check for a shader compile failure listed in the console. The engine may continue to run with only a warning about the compile failure. If this happens, go to the shader and check for any syntax errors or improper logic.
[edit] Set StateBlockThe introduction of StateBlocks introduces a new "Gotcha", but only if you are coding in the engine. When you declare a GFXStateBlocKData in script, the StateBlock is automatically set. This isn't the case when you are working in the engine. If you need an example, let's take a look at the Sky class. Open Sky.cpp, then scroll down to renderSkyBox(...). GFX->setStateBlock(mSkyBoxSB); The very first operation after the variables are declared is setting the StateBlock. This must happen before any rendering calls are made. Another issue with setting a StateBlock is the overriding that can occur. If you have declared a GFXStateBlock in script, it will override any C++ counterpart. For instance, if you are making changes to the terrain StateBlocks in C++, you will most likely not see any results since the TorqueScript version has taken over.
[edit] RenderDelegateWhen reading about a Render Delegate, this "Gotcha" is stated but not in a way you might have noticed. Prior to TGEA 1.8, objects were automatically rendered using the same function signal. This function was renderObject(), which every object had to use if it wanted to be drawn on screen.
if (state->isObjectRendered(this))
{
RenderInst *ri = gRenderInstManager.allocInst();
ri->obj = this;
ri->state = state;
ri->type = RenderInstManager::RIT_Sky;
gRenderInstManager.addInst( ri );
}
if (state->isObjectRendered(this))
{
ObjectRenderInst *ri = gRenderInstManager->allocInst<ObjectRenderInst>();
ri->mRenderDelegate = mRenderDelegate;
ri->state = state;
ri->type = RenderPassManager::RIT_Sky;
gRenderInstManager->addInst( ri );
}
void renderObject(SceneState *state, RenderInst *ri);
TGEA 1.8 Version void renderObject(ObjectRenderInst *ri, BaseMatInstance* );
mRenderDelegate.bind(this, &Sky::renderObject); If you do not modify the old Sky::renderObject(...) parameters, you will receive this error: error C2660: 'fastdelegate::FastDelegate2<Param1,Param2,RetType>::bind' : function does not take 2 arguments Notice the lack of information pointing you to the renderObject(...) function.
[edit] GLSL Texture OrderBy supporting OpenGL, we have to adhere to certain rules we were not obligated to follow in past versions of TGEA. One such rule is enforced when creating ShaderData objects in TorqueScript. ShaderData must now contain DX and OGL shader file references, as well as a new element. If you open C:/torque/TGEA_1_8_Repo/GameExamples/Stronghold/game/common/clientScripts/shaders.cs, you will see a perfect example of this "Gotcha":
new ShaderData( _DebugInterior_ )
{
DXVertexShaderFile = "shaders/debugInteriorsV.hlsl";
DXPixelShaderFile = "shaders/debugInteriorsP.hlsl";
OGLVertexShaderFile = "shaders/gl/debugInteriorsV.glsl";
OGLPixelShaderFile = "shaders/gl/debugInteriorsP.glsl";
OGLSamplerNames[0] = "$diffuseMap";
pixVersion = 1.1;
};
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct ConnectData
{
float2 texCoord : TEXCOORD0;
};
struct Fragout
{
float4 col : COLOR0;
};
//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
Fragout main( ConnectData IN,
uniform sampler2D diffuseMap : register(S0),
uniform float4 shadeColor : register(C0)
)
{
Fragout OUT;
OUT.col = shadeColor;
OUT.col *= tex2D(diffuseMap, IN.texCoord);
return OUT;
}
uniform sampler2D diffuseMap;
uniform vec4 shadeColor;
varying vec2 TEX0;
void main()
{
vec4 diffuseColor = texture2D( diffuseMap, TEX0 );
gl_FragColor = diffuseColor;
gl_FragColor *= shadeColor;
}
[edit] Shared Shader Global SpaceThis is a simple "Gotcha" to remember. Pixel and vertex shaders constants share the same global space. You must name your variables differently. Let's say you are using $modelView for a pixel shader const and vertex shader const. The system will read in and use the vertex shader first.
[edit] Resource Loading ChangeThe new Resource Manager introduces a "Gotcha", which directly affects the loading of texture files, such as bitmaps and DDS. Previously, the GBitmap and DDSFile classes would return a class pointer. For example: GBitmap* bitmap = GBitmap::load( path );
// MP: Load a DDS file Resource<DDSFile> dds = DDSFile::load( path ); // MP: Load a bitmap file Resource<GBitmap> bitmap = GBitmap::load( path );
[edit] What is a CSF?Simply put, CSF stands for Compiled Shader File. CSF files are automatically created, depending on a few conditions checked by the engine internally. CSF files have a similar functionality as DSO files. When you compile a TorqueScript file to DSO, the game still reads it properly, but the script itself is converted to binary form making it more secure. When your shader file is compiled to CSF, it can no longer be modified by an end user.
bool GFXD3D9Shader::init( const Torque::Path &vertFile,
const Torque::Path &pixFile,
F32 pixVersion,
const Vector<GFXShaderMacro> ¯os )
{
...
}
if ((GFXD3DX.isLoaded) && (!Con::getBoolVariable("$shaders::forceLoadCSF", false)))
{
_compileShader( vertFile, vertTarget, d3dXMacros, mVertexConstBufferLayoutF, mVertexConstBufferLayoutI);
...
#ifdef TORQUE_ENABLE_CSF_GENERATION
// Ok, we've got a valid shader and constants, let's write them all out.
if (!_saveCompiledOutput(filePath, code, bufferLayoutF, bufferLayoutI))
Con::errorf("Unable to save shader compile output for: %s", filePath);
#endif
[edit] Material InitializationThe way materials are initialized has changed. We can look at the MatInstance class (engine/source/materials/matInstance.h) to see this modification:
void init( SceneGraphData &dat, GFXVertexFlags vertFlags );
virtual void init(const GFXMaterialFeatureData::FeatureListHandle instanceData, const GFXMaterialFeatureData::FeatureListHandle globalData, GFXVertexFlags vertFlags);
[edit] OGLSamplerNames Field Name ChangePrior to TGEA 1.8, the exposed form of the ShaderData class (ConsoleObject used in TorqueScript) used a field named "OGLSamplerNames". The internal variable used by this field was ShaderData::mOGLSamplerNames, found in engine/source/materials/shaderData.h.
void ShaderData::initPersistFields()
{
// ... previous and remaining code not shown
String mOGLSamplerNames[TEXTURE_STAGE_COUNT];
}
addField("OGLSamplerNames", TypeRealString, Offset(mOGLSamplerNames, ShaderData), TEXTURE_STAGE_COUNT);
Declaration of class variable in engine/source/shaderData.h: String mSamplerNames[TEXTURE_STAGE_COUNT];
void ShaderData::initPersistFields()
{
// ... previous and remaining code not shown
String mSamplerNames[TEXTURE_STAGE_COUNT];
}
[edit] Automated Mapping of samplerNamesA new class method has been added to ShaderData, which can be found in enginer/source/materials/shaderData.h/.cpp: void mapSamplerNames(GFXShaderConstBufferRef constBuffer);
//--------------------------------------------------------------------------
// mapSamplerNames
//--------------------------------------------------------------------------
void ShaderData::mapSamplerNames(GFXShaderConstBufferRef constBuffer)
{
if (constBuffer.isNull())
return;
// Map the stage numbers to the constants
for (U32 i = 0; i < TEXTURE_STAGE_COUNT; i++)
{
if (mTexHandlesSC[i])
constBuffer->set(mTexHandlesSC[i], (S32)i);
}
}
void GroundCover::_initShader()
{
// ... previous and remaining code not shown
mConstBuffer = mBBShader->mShader->allocConstBuffer();
if (mConstBuffer)
mBBShader->mapSamplerNames(mConstBuffer);
}
[edit] November 2008 DirectX SDK Shader BugThere was a bug in the shader compiler in the November 2008 DirectX SDK (as referenced in this GarageGames forum thread: TGEA 1.7.1 and DirectX Nov. 2008 - broken ). A workaround was added for it that is specific to the Nov 2008 DXSDK (also detailed in that thread).
[edit] Atlas module not included in project templateThe Atlas module is by default not included in the project template and thus in projects set up by SetupNewProject.exe. This is intentional as Atlas is not supported on all platforms at the moment. To include the module in your project, edit the file config/project.conf in your project folder and uncomment the line that reads //includeModule( 'atlas' ); After this, regenerate your project files by invoking generateProjects.bat (Windows) or generateProjects.command (Mac). Don't forget to build your project afterwards in the IDE you are using. |



