diff --git a/Engine/source/T3D/tsStatic.cpp b/Engine/source/T3D/tsStatic.cpp index baf902e2e..40f10d788 100644 --- a/Engine/source/T3D/tsStatic.cpp +++ b/Engine/source/T3D/tsStatic.cpp @@ -203,6 +203,9 @@ void TSStatic::initPersistFields() addField( "originSort", TypeBool, Offset( mUseOriginSort, TSStatic ), "Enables translucent sorting of the TSStatic by its origin instead of the bounds." ); + addField("overrideColor", TypeColorF, Offset(mOverrideColor, TSStatic), + "@brief The skin applied to the shape.\n\n"); + endGroup("Rendering"); addGroup( "Reflection" ); @@ -676,6 +679,12 @@ void TSStatic::prepRenderImage( SceneRenderState* state ) // Acculumation rdata.setAccuTex(mAccuTex); + //Various arbitrary shader render bits to add + CustomShaderBindingData strudelCSB; + strudelCSB.setFloat4(StringTable->insert("overrideColor"), mOverrideColor); + + rdata.addCustomShaderBinding(strudelCSB); + // If we have submesh culling enabled then prepare // the object space frustum to pass to the shape. Frustum culler; @@ -852,6 +861,8 @@ U32 TSStatic::packUpdate(NetConnection *con, U32 mask, BitStream *stream) { stream->writeRangedU32( reflectorDesc->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast ); } + + stream->write(mOverrideColor); return retMask; } @@ -947,6 +958,8 @@ void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream) cubeDescId = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast ); } + stream->read(&mOverrideColor); + if ( isProperlyAdded() ) _updateShouldTick(); set_special_typing(); diff --git a/Engine/source/T3D/tsStatic.h b/Engine/source/T3D/tsStatic.h index 9c6918c8d..4dbcb6920 100644 --- a/Engine/source/T3D/tsStatic.h +++ b/Engine/source/T3D/tsStatic.h @@ -197,6 +197,8 @@ protected: PhysicsBody *mPhysicsRep; + LinearColorF mOverrideColor; + // Debug stuff F32 mRenderNormalScalar; S32 mForceDetail; diff --git a/Engine/source/materials/baseMatInstance.h b/Engine/source/materials/baseMatInstance.h index bca878dc2..95534cd4b 100644 --- a/Engine/source/materials/baseMatInstance.h +++ b/Engine/source/materials/baseMatInstance.h @@ -49,6 +49,13 @@ #ifndef _MATSTATEHINT_H_ #include "materials/matStateHint.h" #endif +#ifndef _GFXDEVICE_H_ +#include "gfx/gfxDevice.h" +#endif + +#ifndef CUSTOMSHADERBINDINGDATA_H +#include "materials/customShaderBindingData.h" +#endif struct RenderPassData; class GFXVertexBufferHandleBase; @@ -60,7 +67,6 @@ class GFXVertexFormat; class MatrixSet; class ProcessedMaterial; - /// class BaseMatInstance { @@ -155,6 +161,9 @@ public: /// Sets node transforms for the current stage. Used for hardware skinning. virtual void setNodeTransforms( const MatrixF *address, const U32 numTransforms ) = 0; + /// Sets custom shader data + virtual void setCustomShaderData(Vector &shaderData) = 0; + /// This initializes various material scene state settings and /// should be called after setupPass() within the pass loop. /// @see setupPass diff --git a/Engine/source/materials/customShaderBindingData.h b/Engine/source/materials/customShaderBindingData.h new file mode 100644 index 000000000..52dad2e9e --- /dev/null +++ b/Engine/source/materials/customShaderBindingData.h @@ -0,0 +1,89 @@ +#pragma once + +#ifndef CUSTOMSHADERBINDINGDATA_H +#define CUSTOMSHADERBINDINGDATA_H +#ifndef _GFXDEVICE_H_ +#include "gfx/gfxDevice.h" +#endif + +struct CustomShaderBindingData +{ +public: + enum UniformType + { + Float = 0, + Float2, + Float3, + Float4, + Texture2D, + Texture3D, + Cubemap, + Matrix2x2, + Matrix2x3, + Matrix2x4, + Matrix3x2, + Matrix3x3, + Matrix3x4, + Matrix4x2, + Matrix4x3, + Matrix4x4 + }; +private: + StringTableEntry targetedUniformName; + + //ShaderConstHandles shaderConstHandle; + + UniformType type; + + F32 mFloat; + Point2F mFloat2; + Point3F mFloat3; + Point4F mFloat4; + + //Image stuff + GFXTexHandle texture; + GFXSamplerStateDesc samplerState; + +public: + void setFloat(StringTableEntry shaderConstName, F32 f) + { + targetedUniformName = shaderConstName; + mFloat = f; + type = Float; + } + F32 getFloat() { return mFloat; } + + void setFloat2(StringTableEntry shaderConstName, Point2F f) + { + targetedUniformName = shaderConstName; + mFloat2 = f; + type = Float2; + } + Point2F getFloat2() { return mFloat2; } + + void setFloat3(StringTableEntry shaderConstName, Point3F f) + { + targetedUniformName = shaderConstName; + mFloat3 = f; + type = Float3; + } + Point3F getFloat3() { return mFloat3; } + + void setFloat4(StringTableEntry shaderConstName, Point4F f) + { + targetedUniformName = shaderConstName; + mFloat4 = f; + type = Float4; + } + Point4F getFloat4() { return mFloat4; } + + StringTableEntry getHandleName() { + return targetedUniformName; + } + + UniformType getType() { + return type; + } +}; + +#endif \ No newline at end of file diff --git a/Engine/source/materials/matInstance.cpp b/Engine/source/materials/matInstance.cpp index 88a2e0353..4473c1338 100644 --- a/Engine/source/materials/matInstance.cpp +++ b/Engine/source/materials/matInstance.cpp @@ -473,6 +473,12 @@ void MatInstance::setNodeTransforms(const MatrixF *address, const U32 numTransfo mProcessedMaterial->setNodeTransforms(address, numTransforms, getCurPass()); } +void MatInstance::setCustomShaderData(Vector &shaderData) +{ + PROFILE_SCOPE(MatInstance_setCustomShaderData); + mProcessedMaterial->setCustomShaderData(shaderData, getCurPass()); +} + void MatInstance::setSceneInfo(SceneRenderState * state, const SceneData& sgData) { PROFILE_SCOPE(MatInstance_setSceneInfo); diff --git a/Engine/source/materials/matInstance.h b/Engine/source/materials/matInstance.h index 11178a42c..a89445243 100644 --- a/Engine/source/materials/matInstance.h +++ b/Engine/source/materials/matInstance.h @@ -66,6 +66,7 @@ public: virtual bool setupPass(SceneRenderState *, const SceneData &sgData ); virtual void setTransforms(const MatrixSet &matrixSet, SceneRenderState *state); virtual void setNodeTransforms(const MatrixF *address, const U32 numTransforms); + virtual void setCustomShaderData(Vector &shaderData); virtual void setSceneInfo(SceneRenderState *, const SceneData& sgData); virtual void setTextureStages(SceneRenderState * state, const SceneData &sgData ); virtual void setBuffers(GFXVertexBufferHandleBase* vertBuffer, GFXPrimitiveBufferHandle* primBuffer); diff --git a/Engine/source/materials/materialDefinition.cpp b/Engine/source/materials/materialDefinition.cpp index bcec30202..326fdc223 100644 --- a/Engine/source/materials/materialDefinition.cpp +++ b/Engine/source/materials/materialDefinition.cpp @@ -504,6 +504,11 @@ void Material::initPersistFields() endGroup( "Behavioral" ); + addProtectedField("customShaderFeature", TypeRealString, NULL, &protectedSetCustomShaderFeature, &defaultProtectedGetFn, + "Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors); + addProtectedField("CustomShaderFeatureUniforms", TypeRealString, NULL, &protectedSetCustomShaderFeatureUniforms, &defaultProtectedGetFn, + "Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors); + Parent::initPersistFields(); } @@ -521,6 +526,42 @@ bool Material::writeField( StringTableEntry fieldname, const char *value ) return Parent::writeField( fieldname, value ); } +bool Material::protectedSetCustomShaderFeature(void *object, const char *index, const char *data) +{ + Material *material = static_cast< Material* >(object); + + CustomShaderFeatureData* customFeature; + if (!Sim::findObject(data, customFeature)) + return false; + + material->mCustomShaderFeatures.push_back(customFeature); + + return false; +} + +bool Material::protectedSetCustomShaderFeatureUniforms(void *object, const char *index, const char *data) +{ + Material *material = static_cast< Material* >(object); + + //CustomShaderFeatureData* customFeature; + //if (!Sim::findObject(data, customFeature)) + // return false; + + //material->mCustomShaderFeatures.push_back(customFeature); + if (index != NULL) + { + char featureName[256] = { 0 }; + U32 id = 0; + dSscanf(index, "%s_%i", featureName, id); + + String uniformName = data; + + bool tmp = true; + } + + return false; +} + bool Material::onAdd() { if (Parent::onAdd() == false) diff --git a/Engine/source/materials/materialDefinition.h b/Engine/source/materials/materialDefinition.h index 143f3d1c2..289627855 100644 --- a/Engine/source/materials/materialDefinition.h +++ b/Engine/source/materials/materialDefinition.h @@ -41,6 +41,9 @@ #include "console/dynamicTypes.h" #endif +#ifndef CUSTOMSHADERFEATURE_H +#include "shaderGen/customShaderFeature.h" +#endif class CubemapData; class SFXTrack; @@ -49,7 +52,7 @@ class FeatureSet; class FeatureType; class MaterialSoundProfile; class MaterialPhysicsProfile; - +class CustomShaderFeatureData; /// The basic material definition. class Material : public BaseMaterialDefinition @@ -348,6 +351,8 @@ public: F32 mDirectSoundOcclusion; ///< Amount of volume occlusion on direct sounds. F32 mReverbSoundOcclusion; ///< Amount of volume occlusion on reverb sounds. + Vector mCustomShaderFeatures; + ///@} String mMapTo; // map Material to this texture name @@ -385,6 +390,9 @@ public: virtual void inspectPostApply(); virtual bool writeField( StringTableEntry fieldname, const char *value ); + static bool protectedSetCustomShaderFeature(void *object, const char *index, const char *data); + static bool protectedSetCustomShaderFeatureUniforms(void *object, const char *index, const char *data); + // // ConsoleObject interface // diff --git a/Engine/source/materials/processedCustomMaterial.cpp b/Engine/source/materials/processedCustomMaterial.cpp index 730c2bbf2..7c3b04bd6 100644 --- a/Engine/source/materials/processedCustomMaterial.cpp +++ b/Engine/source/materials/processedCustomMaterial.cpp @@ -246,7 +246,7 @@ bool ProcessedCustomMaterial::init( const FeatureSet &features, return false; } - rpd->shaderHandles.init( rpd->shader, mCustomMaterial ); + rpd->shaderHandles.init( rpd->shader, mCustomMaterial->mCustomShaderFeatures, mCustomMaterial ); _initMaterialParameters(); mDefaultParameters = allocMaterialParameters(); setMaterialParameters( mDefaultParameters, 0 ); diff --git a/Engine/source/materials/processedFFMaterial.h b/Engine/source/materials/processedFFMaterial.h index c65175381..3ba72594c 100644 --- a/Engine/source/materials/processedFFMaterial.h +++ b/Engine/source/materials/processedFFMaterial.h @@ -54,6 +54,7 @@ public: virtual void setTransforms(const MatrixSet &matrixSet, SceneRenderState *state, const U32 pass); virtual void setNodeTransforms(const MatrixF *address, const U32 numTransforms, const U32 pass) {;} + virtual void setCustomShaderData(Vector &shaderData, const U32 pass) {;} //-JR virtual void setSceneInfo(SceneRenderState *, const SceneData& sgData, U32 pass); diff --git a/Engine/source/materials/processedMaterial.h b/Engine/source/materials/processedMaterial.h index c01059ada..40cfcc96d 100644 --- a/Engine/source/materials/processedMaterial.h +++ b/Engine/source/materials/processedMaterial.h @@ -39,6 +39,10 @@ #include "materials/matStateHint.h" #endif +#ifndef CUSTOMSHADERBINDINGDATA_H +#include "materials/customShaderBindingData.h" +#endif + class ShaderFeature; class MaterialParameters; class MaterialParameterHandle; @@ -47,7 +51,6 @@ class GFXVertexBufferHandleBase; class GFXPrimitiveBufferHandle; class MatrixSet; - /// This contains the common data needed to render a pass. struct RenderPassData { @@ -81,6 +84,8 @@ public: MaterialFeatureData mFeatureData; + Vector mCustomShaderFeatureData; + bool mGlow; Material::BlendOp mBlendOp; @@ -144,6 +149,9 @@ public: /// Sets the node transforms for HW Skinning virtual void setNodeTransforms(const MatrixF *address, const U32 numTransforms, const U32 pass) = 0; + + /// Sets any custom shader data + virtual void setCustomShaderData(Vector &shaderData, const U32 pass) = 0; /// Sets the scene info like lights for the given pass. virtual void setSceneInfo(SceneRenderState *, const SceneData& sgData, U32 pass) = 0; diff --git a/Engine/source/materials/processedShaderMaterial.cpp b/Engine/source/materials/processedShaderMaterial.cpp index 73687cdf3..ddbdc31a8 100644 --- a/Engine/source/materials/processedShaderMaterial.cpp +++ b/Engine/source/materials/processedShaderMaterial.cpp @@ -43,6 +43,8 @@ #include "renderInstance/renderProbeMgr.h" +#include "ts/tsRenderState.h" + // We need to include customMaterialDefinition for ShaderConstHandles::init #include "materials/customMaterialDefinition.h" @@ -52,7 +54,7 @@ /// /// ShaderConstHandles /// -void ShaderConstHandles::init( GFXShader *shader, CustomMaterial* mat /*=NULL*/ ) +void ShaderConstHandles::init( GFXShader *shader, Vector customFeatureData, CustomMaterial* mat /*=NULL*/) { mDiffuseColorSC = shader->getShaderConstHandle("$diffuseMaterialColor"); mTexMatSC = shader->getShaderConstHandle(ShaderGenVars::texMat); @@ -119,6 +121,19 @@ void ShaderConstHandles::init( GFXShader *shader, CustomMaterial* mat /*=NULL*/ // Deferred Shading mMatInfoFlagsSC = shader->getShaderConstHandle(ShaderGenVars::matInfoFlags); + + //custom features + for (U32 f = 0; f < customFeatureData.size(); ++f) + { + for (U32 i = 0; i < customFeatureData[f]->mAddedShaderConstants.size(); ++i) + { + customHandleData newSC; + newSC.handle = shader->getShaderConstHandle(String("$") + String(customFeatureData[f]->mAddedShaderConstants[i])); + newSC.handleName = customFeatureData[f]->mAddedShaderConstants[i]; + + mCustomHandles.push_back(newSC); +} + } } /// @@ -655,10 +670,10 @@ bool ProcessedShaderMaterial::_addPass( ShaderRenderPassData &rpd, // Generate shader GFXShader::setLogging( true, true ); - rpd.shader = SHADERGEN->getShader( rpd.mFeatureData, mVertexFormat, &mUserMacros, samplers ); + rpd.shader = SHADERGEN->getShader( rpd.mFeatureData, mMaterial->mCustomShaderFeatures, mVertexFormat, &mUserMacros, samplers ); if( !rpd.shader ) return false; - rpd.shaderHandles.init( rpd.shader ); + rpd.shaderHandles.init( rpd.shader, mMaterial->mCustomShaderFeatures); // If a pass glows, we glow if( rpd.mGlow ) @@ -1196,6 +1211,31 @@ void ProcessedShaderMaterial::_setShaderConstants(SceneRenderState * state, cons shaderConsts->set( handles->mAccuCoverageSC, mMaterial->mAccuCoverage[stageNum] ); if( handles->mAccuSpecularSC->isValid() ) shaderConsts->set( handles->mAccuSpecularSC, mMaterial->mAccuSpecular[stageNum] ); + + /*for (U32 i = 0; i < sgData.customShaderData.size(); i++) + { + //roll through and try setting our data! + for (U32 h = 0; h < handles->mCustomHandles.size(); ++h) + { + StringTableEntry handleName = sgData.customShaderData[i]->getHandleName(); + StringTableEntry rpdHandleName = handles->mCustomHandles[h].handleName; + if (handles->mCustomHandles[h].handleName == sgData.customShaderData[i]->getHandleName()) + { + if (handles->mCustomHandles[h].handle->isValid()) + { + if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat()); + else if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float2) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat2()); + else if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float3) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat3()); + else if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float4) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat4()); + break; +} + } + } + }*/ } bool ProcessedShaderMaterial::_hasCubemap(U32 pass) @@ -1262,6 +1302,46 @@ void ProcessedShaderMaterial::setNodeTransforms(const MatrixF *transforms, const } } +void ProcessedShaderMaterial::setCustomShaderData(Vector &shaderData, const U32 pass) +{ + PROFILE_SCOPE(ProcessedShaderMaterial_setCustomShaderData); + + GFXShaderConstBuffer* shaderConsts = _getShaderConstBuffer(pass); + ShaderConstHandles* handles = _getShaderConstHandles(pass); + + for (U32 i = 0; i < shaderData.size(); i++) + { + for (U32 h = 0; h < handles->mCustomHandles.size(); ++h) + { + StringTableEntry handleName = shaderData[i].getHandleName(); + bool tmp = true; + } + //roll through and try setting our data! + for (U32 h = 0; h < handles->mCustomHandles.size(); ++h) + { + StringTableEntry handleName = shaderData[i].getHandleName(); + StringTableEntry rpdHandleName = handles->mCustomHandles[h].handleName; + if (handles->mCustomHandles[h].handleName == shaderData[i].getHandleName()) + { + if (handles->mCustomHandles[h].handle->isValid()) + { + CustomShaderBindingData::UniformType type = shaderData[i].getType(); + + if (type == CustomShaderBindingData::Float) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, shaderData[i].getFloat()); + else if (type == CustomShaderBindingData::Float2) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, shaderData[i].getFloat2()); + else if (type == CustomShaderBindingData::Float3) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, shaderData[i].getFloat3()); + else if (type == CustomShaderBindingData::Float4) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, shaderData[i].getFloat4()); + break; + } + } + } + } +} + void ProcessedShaderMaterial::setSceneInfo(SceneRenderState * state, const SceneData& sgData, U32 pass) { PROFILE_SCOPE(ProcessedShaderMaterial_setSceneInfo); @@ -1303,6 +1383,31 @@ void ProcessedShaderMaterial::setSceneInfo(SceneRenderState * state, const Scene for (U32 i = 0; i < rpd->featureShaderHandles.size(); i++) rpd->featureShaderHandles[i]->setConsts(state, sgData, shaderConsts); + /*for (U32 i = 0; i < sgData.customShaderData.size(); i++) + { + //roll through and try setting our data! + for (U32 h = 0; h < handles->mCustomHandles.size(); ++h) + { + StringTableEntry handleName = sgData.customShaderData[i]->getHandleName(); + StringTableEntry rpdHandleName = handles->mCustomHandles[h].handleName; + if (handles->mCustomHandles[h].handleName == sgData.customShaderData[i]->getHandleName()) + { + if (handles->mCustomHandles[h].handle->isValid()) + { + if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat()); + else if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float2) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat2()); + else if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float3) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat3()); + else if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float4) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat4()); + break; + } + } + } + }*/ + LIGHTMGR->setLightInfo(this, mMaterial, sgData, state, pass, shaderConsts); PROBEMGR->setProbeInfo(this, mMaterial, sgData, state, pass, shaderConsts); diff --git a/Engine/source/materials/processedShaderMaterial.h b/Engine/source/materials/processedShaderMaterial.h index e95819087..a7d184b95 100644 --- a/Engine/source/materials/processedShaderMaterial.h +++ b/Engine/source/materials/processedShaderMaterial.h @@ -29,6 +29,9 @@ #ifndef _GFXSHADER_H_ #include "gfx/gfxShader.h" #endif +#ifndef CUSTOMSHADERBINDINGDATA_H +#include "materials/customShaderBindingData.h" +#endif class GenericConstBufferLayout; class ShaderData; @@ -97,7 +100,15 @@ public: GFXShaderConstHandle* mNodeTransforms; - void init( GFXShader* shader, CustomMaterial* mat = NULL ); + struct customHandleData + { + StringTableEntry handleName; + GFXShaderConstHandle* handle; + }; + Vector mCustomHandles; + + void init( GFXShader* shader, Vector customFeatureData, CustomMaterial* mat = NULL); + }; class ShaderRenderPassData : public RenderPassData @@ -133,6 +144,7 @@ public: virtual void setTextureStages(SceneRenderState *, const SceneData &sgData, U32 pass ); virtual void setTransforms(const MatrixSet &matrixSet, SceneRenderState *state, const U32 pass); virtual void setNodeTransforms(const MatrixF *address, const U32 numTransforms, const U32 pass); + virtual void setCustomShaderData(Vector &shaderData, const U32 pass); virtual void setSceneInfo(SceneRenderState *, const SceneData& sgData, U32 pass); virtual void setBuffers(GFXVertexBufferHandleBase* vertBuffer, GFXPrimitiveBufferHandle* primBuffer); virtual bool stepInstance(); diff --git a/Engine/source/materials/sceneData.h b/Engine/source/materials/sceneData.h index fd8b01633..a67c9a273 100644 --- a/Engine/source/materials/sceneData.h +++ b/Engine/source/materials/sceneData.h @@ -34,7 +34,7 @@ class GFXTexHandle; class GFXCubemap; - +class CustomShaderBindingData; struct SceneData { @@ -95,6 +95,8 @@ struct SceneData /// features. void *materialHint; + Vector customShaderData; + /// Constructor. SceneData() { diff --git a/Engine/source/renderInstance/renderBinManager.cpp b/Engine/source/renderInstance/renderBinManager.cpp index 7140f833b..6328ad0e4 100644 --- a/Engine/source/renderInstance/renderBinManager.cpp +++ b/Engine/source/renderInstance/renderBinManager.cpp @@ -151,27 +151,35 @@ S32 FN_CDECL RenderBinManager::cmpKeyFunc(const void* p1, const void* p2) return ( test1 == 0 ) ? S32(mse1->key2) - S32(mse2->key2) : test1; } -void RenderBinManager::setupSGData( MeshRenderInst *ri, SceneData &data ) +void RenderBinManager::setupSGData(MeshRenderInst *ri, SceneData &data) { - PROFILE_SCOPE( RenderBinManager_setupSGData ); + PROFILE_SCOPE(RenderBinManager_setupSGData); - // NOTE: We do not reset or clear the scene state - // here as the caller has initialized non-RI members - // himself and we must preserve them. - // - // It also saves a bunch of CPU as this is called for - // every MeshRenderInst in every pass. + // NOTE: We do not reset or clear the scene state + // here as the caller has initialized non-RI members + // himself and we must preserve them. + // + // It also saves a bunch of CPU as this is called for + // every MeshRenderInst in every pass. - dMemcpy( data.lights, ri->lights, sizeof( data.lights ) ); - data.objTrans = ri->objectToWorld; - data.backBuffTex = ri->backBuffTex; - data.cubemap = ri->cubemap; - data.miscTex = ri->miscTex; - data.reflectTex = ri->reflectTex; - data.accuTex = ri->accuTex; - data.lightmap = ri->lightmap; - data.visibility = ri->visibility; - data.materialHint = ri->materialHint; + dMemcpy(data.lights, ri->lights, sizeof(data.lights)); + data.objTrans = ri->objectToWorld; + data.backBuffTex = ri->backBuffTex; + data.cubemap = ri->cubemap; + data.miscTex = ri->miscTex; + data.reflectTex = ri->reflectTex; + data.accuTex = ri->accuTex; + data.lightmap = ri->lightmap; + data.visibility = ri->visibility; + data.materialHint = ri->materialHint; + + data.customShaderData.clear(); + for (U32 i = 0; i < ri->mCustomShaderData.size(); i++) + { + data.customShaderData.push_back(&ri->mCustomShaderData[i]); + } + + bool bl = true; } DefineEngineMethod( RenderBinManager, getBinType, const char*, (),, diff --git a/Engine/source/renderInstance/renderDeferredMgr.cpp b/Engine/source/renderInstance/renderDeferredMgr.cpp index d5035629b..c17b3a355 100644 --- a/Engine/source/renderInstance/renderDeferredMgr.cpp +++ b/Engine/source/renderInstance/renderDeferredMgr.cpp @@ -51,6 +51,8 @@ #include "materials/shaderData.h" #include "gfx/sim/cubemapData.h" +#include "materials/customShaderBindingData.h" + const MatInstanceHookType DeferredMatInstanceHook::Type( "Deferred" ); const String RenderDeferredMgr::BufferName("deferred"); const RenderInstType RenderDeferredMgr::RIT_Deferred("Deferred"); @@ -422,6 +424,13 @@ void RenderDeferredMgr::render( SceneRenderState *state ) mat->setNodeTransforms(passRI->mNodeTransforms, passRI->mNodeTransformCount); } + //-JR + //push along any overriden fields that are instance-specific as well + if (passRI->mCustomShaderData.size() > 0) + { + mat->setCustomShaderData(passRI->mCustomShaderData); + } + // If we're instanced then don't render yet. if ( mat->isInstanced() ) { diff --git a/Engine/source/renderInstance/renderGlowMgr.cpp b/Engine/source/renderInstance/renderGlowMgr.cpp index 1ce49149d..dd2d2f29d 100644 --- a/Engine/source/renderInstance/renderGlowMgr.cpp +++ b/Engine/source/renderInstance/renderGlowMgr.cpp @@ -251,6 +251,13 @@ void RenderGlowMgr::render( SceneRenderState *state ) glowMat->setNodeTransforms(passRI->mNodeTransforms, passRI->mNodeTransformCount); } + //-JR + //push along any overriden fields that are instance-specific as well + if (passRI->mCustomShaderData.size() > 0) + { + mat->setCustomShaderData(passRI->mCustomShaderData); + } + glowMat->setSceneInfo(state, sgData); glowMat->setBuffers(passRI->vertBuff, passRI->primBuff); diff --git a/Engine/source/renderInstance/renderMeshMgr.cpp b/Engine/source/renderInstance/renderMeshMgr.cpp index c9de7c229..adaee396f 100644 --- a/Engine/source/renderInstance/renderMeshMgr.cpp +++ b/Engine/source/renderInstance/renderMeshMgr.cpp @@ -182,6 +182,13 @@ void RenderMeshMgr::render(SceneRenderState * state) mat->setNodeTransforms(passRI->mNodeTransforms, passRI->mNodeTransformCount); } + //-JR + //push along any overriden fields that are instance-specific as well + if (passRI->mCustomShaderData.size() > 0) + { + mat->setCustomShaderData(passRI->mCustomShaderData); + } + setupSGData( passRI, sgData ); mat->setSceneInfo( state, sgData ); diff --git a/Engine/source/renderInstance/renderPassManager.h b/Engine/source/renderInstance/renderPassManager.h index d307c187f..8ee7d1a87 100644 --- a/Engine/source/renderInstance/renderPassManager.h +++ b/Engine/source/renderInstance/renderPassManager.h @@ -59,6 +59,8 @@ class MatrixSet; class GFXPrimitiveBufferHandle; class CubemapData; +class CustomShaderBindingData; + /// A RenderInstType hash value. typedef U32 RenderInstTypeHash; @@ -393,6 +395,9 @@ struct MeshRenderInst : public RenderInst const char *objectName; #endif + //Custom Shader data + Vector mCustomShaderData; + void clear(); }; diff --git a/Engine/source/renderInstance/renderTranslucentMgr.cpp b/Engine/source/renderInstance/renderTranslucentMgr.cpp index 9a1fba40a..3a8cded60 100644 --- a/Engine/source/renderInstance/renderTranslucentMgr.cpp +++ b/Engine/source/renderInstance/renderTranslucentMgr.cpp @@ -256,6 +256,13 @@ void RenderTranslucentMgr::render( SceneRenderState *state ) mat->setNodeTransforms(passRI->mNodeTransforms, passRI->mNodeTransformCount); } + //-JR + //push along any overriden fields that are instance-specific as well + if (passRI->mCustomShaderData.size() > 0) + { + mat->setCustomShaderData(passRI->mCustomShaderData); + } + // If we're instanced then don't render yet. if ( mat->isInstanced() ) { diff --git a/Engine/source/scene/sceneObject.h b/Engine/source/scene/sceneObject.h index be0a7b745..660d709bb 100644 --- a/Engine/source/scene/sceneObject.h +++ b/Engine/source/scene/sceneObject.h @@ -59,6 +59,9 @@ #ifndef _GFXDEVICE_H_ #include "gfx/gfxDevice.h" #endif +#ifndef _TSRENDERDATA_H_ +#include "ts/tsRenderState.h" +#endif #ifndef _COLLADA_UTILS_H_ #include "ts/collada/colladaUtils.h" diff --git a/Engine/source/shaderGen/HLSL/customFeatureHLSL.cpp b/Engine/source/shaderGen/HLSL/customFeatureHLSL.cpp new file mode 100644 index 000000000..409d280a3 --- /dev/null +++ b/Engine/source/shaderGen/HLSL/customFeatureHLSL.cpp @@ -0,0 +1,468 @@ +//----------------------------------------------------------------------------- +// 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 "customFeatureHLSL.h" +#include "shaderGen/shaderFeature.h" +#include "shaderGen/shaderOp.h" +#include "shaderGen/featureMgr.h" +//#include "materials/materialFeatureTypes.h" +//#include "gfx/gfxDevice.h" +//#include "materials/processedMaterial.h" + +//**************************************************************************** +// Accu Texture +//**************************************************************************** +void CustomFeatureHLSL::processVert(Vector &componentList, + const MaterialFeatureData &fd) +{ + /*MultiLine *meta = new MultiLine; + getOutTexCoord( "texCoord", + "float2", + false, + meta, + componentList ); + + getOutObjToTangentSpace( componentList, meta, fd ); + + output = meta;*/ + + meta = new MultiLine; + + mFeatureData = fd; + mComponentList = componentList; + + mOutputState = VertexOutput; + + if (mOwner->isMethod("processVertHLSL")) + Con::executef(mOwner, "processVertHLSL"); + + output = meta; +} + +void CustomFeatureHLSL::processPix(Vector &componentList, + const MaterialFeatureData &fd) +{ + meta = new MultiLine; + + mFeatureData = fd; + mComponentList = componentList; + + mOutputState = PixelOutput; + + /*MultiLine *meta = new MultiLine; + + output = meta; + + // OUT.col + Var *color = (Var*) LangElement::find( "col1" ); + if (!color) + { + output = new GenOp(" //NULL COLOR!"); + return; + } + + // accu map + Var *accuMap = new Var; + accuMap->setType("SamplerState"); + + accuMap->setName( "accuMap" ); + accuMap->uniform = true; + accuMap->sampler = true; + accuMap->constNum = Var::getTexUnitNum(); // used as texture unit num here + + // accuColor var + Var *accuColor = new Var; + accuColor->setType( "float4" ); + accuColor->setName( "accuColor" ); + LangElement *colorAccuDecl = new DecOp( accuColor ); + + // plc (placement) + Var *accuPlc = new Var; + accuPlc->setType( "float4" ); + accuPlc->setName( "plc" ); + LangElement *plcAccu = new DecOp( accuPlc ); + + // accu constants + Var *accuScale = (Var*)LangElement::find( "accuScale" ); + if ( !accuScale ) + { + accuScale = new Var; + accuScale->setType( "float" ); + accuScale->setName( "accuScale" ); + accuScale->uniform = true; + accuScale->sampler = false; + accuScale->constSortPos = cspPotentialPrimitive; + } + Var *accuDirection = (Var*)LangElement::find( "accuDirection" ); + if ( !accuDirection ) + { + accuDirection = new Var; + accuDirection->setType( "float" ); + accuDirection->setName( "accuDirection" ); + accuDirection->uniform = true; + accuDirection->sampler = false; + accuDirection->constSortPos = cspPotentialPrimitive; + } + Var *accuStrength = (Var*)LangElement::find( "accuStrength" ); + if ( !accuStrength ) + { + accuStrength = new Var; + accuStrength->setType( "float" ); + accuStrength->setName( "accuStrength" ); + accuStrength->uniform = true; + accuStrength->sampler = false; + accuStrength->constSortPos = cspPotentialPrimitive; + } + Var *accuCoverage = (Var*)LangElement::find( "accuCoverage" ); + if ( !accuCoverage ) + { + accuCoverage = new Var; + accuCoverage->setType( "float" ); + accuCoverage->setName( "accuCoverage" ); + accuCoverage->uniform = true; + accuCoverage->sampler = false; + accuCoverage->constSortPos = cspPotentialPrimitive; + } + Var *accuSpecular = (Var*)LangElement::find( "accuSpecular" ); + if ( !accuSpecular ) + { + accuSpecular = new Var; + accuSpecular->setType( "float" ); + accuSpecular->setName( "accuSpecular" ); + accuSpecular->uniform = true; + accuSpecular->sampler = false; + accuSpecular->constSortPos = cspPotentialPrimitive; + } + + Var *inTex = getInTexCoord( "texCoord", "float2", componentList ); + Var *accuVec = getInTexCoord( "accuVec", "float3", componentList ); + Var *bumpNorm = (Var *)LangElement::find( "bumpSample" ); + if( bumpNorm == NULL ) + { + bumpNorm = (Var *)LangElement::find( "bumpNormal" ); + if (!bumpNorm) + return; + } + + // get the accu pixel color + + Var *accuMapTex = new Var; + accuMapTex->setType("Texture2D"); + accuMapTex->setName("accuMapTex"); + accuMapTex->uniform = true; + accuMapTex->texture = true; + accuMapTex->constNum = accuMap->constNum; + meta->addStatement(new GenOp(" @ = @.Sample(@, @ * @);\r\n", colorAccuDecl, accuMapTex, accuMap, inTex, accuScale)); + + // scale up normals + meta->addStatement( new GenOp( " @.xyz = @.xyz * 2.0 - 0.5;\r\n", bumpNorm, bumpNorm ) ); + + // assign direction + meta->addStatement( new GenOp( " @.z *= @*2.0;\r\n", accuVec, accuDirection ) ); + + // saturate based on strength + meta->addStatement( new GenOp( " @ = saturate( dot( @.xyz, @.xyz * pow(@, 5) ) );\r\n", plcAccu, bumpNorm, accuVec, accuStrength ) ); + + // add coverage + meta->addStatement( new GenOp( " @.a += (2 * pow(@/2, 5)) - 0.5;\r\n", accuPlc, accuCoverage ) ); + + // clamp to a sensible value + meta->addStatement( new GenOp( " @.a = clamp(@.a, 0, 1);\r\n", accuPlc, accuPlc ) ); + + // light + Var *lightColor = (Var*) LangElement::find( "d_lightcolor" ); + if(lightColor != NULL) + meta->addStatement( new GenOp( " @ *= float4(@, 1.0);\r\n\r\n", accuColor, lightColor ) ); + + // lerp with current pixel - use the accu alpha as well + meta->addStatement( new GenOp( " @ = lerp( @, @, @.a * @.a);\r\n", color, color, accuColor, accuPlc, accuColor ) ); + + // the result should always be opaque + meta->addStatement( new GenOp( " @.a = 1.0;\r\n", color ) );*/ + if (mOwner->isMethod("processPixelHLSL")) + Con::executef(mOwner, "processPixelHLSL"); + + output = meta; +} + +void CustomFeatureHLSL::setTexData(Material::StageData &stageDat, + const MaterialFeatureData &fd, + RenderPassData &passData, + U32 &texIndex) +{ + //GFXTextureObject *tex = stageDat.getTex( MFT_AccuMap ); + //if ( tex ) + //{ + //passData.mSamplerNames[ texIndex ] = "AccuMap"; + //passData.mTexType[ texIndex++ ] = Material::AccuMap; + //} + + if (mOwner->isMethod("setTextureData")) + Con::executef(mOwner, "setTextureData"); +} + +void CustomFeatureHLSL::addUniform(String name, String type, String defaultValue, U32 arraySize) +{ + //do the var/arg fetching here + Var *newVar = (Var*)LangElement::find(name.c_str()); + if (!newVar) + { + VarHolder newVarHolder(name, type, ""); + newVarHolder.arraySize = arraySize; + newVarHolder.sampler = false; + newVarHolder.uniform = true; + newVarHolder.constSortPos = cspPotentialPrimitive; + + mVars.push_back(newVarHolder); + + mOwner->mAddedShaderConstants.push_back(StringTable->insert(name.c_str())); + } +} + +void CustomFeatureHLSL::addSampler(String name, String type, U32 arraySize) +{ + //do the var/arg fetching here + Var *newVar = (Var*)LangElement::find(name.c_str()); + if (!newVar) + { + //As far as I know, it's always SamplerState regardless of the texture's type + VarHolder newVarHolder(name, "SamplerState", ""); + newVarHolder.arraySize = arraySize; + newVarHolder.sampler = true; + newVarHolder.uniform = true; + newVarHolder.constNum = Var::getTexUnitNum(); // used as texture unit num here + + mVars.push_back(newVarHolder); + + mOwner->mAddedShaderConstants.push_back(StringTable->insert(name.c_str())); + } +} + +void CustomFeatureHLSL::addTexture(String name, String type, String samplerState, U32 arraySize) +{ + //do the var/arg fetching here + Var *newVar = (Var*)LangElement::find(name.c_str()); + if (!newVar) + { + //go find our sampler state var + U32 constNum = 0; + + Var *samplerStateVar = (Var*)LangElement::find(samplerState.c_str()); + if (!samplerStateVar) + { + //check our holder vars + bool foundHolder = false; + for (U32 v = 0; v < mVars.size(); v++) + { + if (mVars[v].varName == samplerState) + { + constNum = mVars[v].constNum; + foundHolder = true; + break; + } + } + + if (!foundHolder) + { + Con::errorf("CustomShaderFeature::addTexture: Unable to find texture's sampler state!"); + return; + } + } + else + { + constNum = samplerStateVar->constNum; + } + + VarHolder newVarHolder(name, type, ""); + newVarHolder.arraySize = arraySize; + newVarHolder.texture = true; + newVarHolder.uniform = true; + newVarHolder.constNum = constNum; // used as texture unit num here + + mVars.push_back(newVarHolder); + + mOwner->mAddedShaderConstants.push_back(StringTable->insert(name.c_str())); + } +} + +void CustomFeatureHLSL::addVariable(String name, String type, String defaultValue) +{ + //do the var/arg fetching here + Var *newVar = (Var*)LangElement::find(name.c_str()); + if (!newVar) + { + if (!defaultValue.isEmpty()) + { + char declareStatement[128]; + dSprintf(declareStatement, 128, " @ = %s;\n", defaultValue.c_str()); + + newVar = new Var(name, type); + LangElement *newVarDecl = new DecOp(newVar); + meta->addStatement(new GenOp(declareStatement, newVarDecl)); + } + else + { + VarHolder newVarHolder(name, type, defaultValue); + + mVars.push_back(newVarHolder); + } + } +} + +void CustomFeatureHLSL::addConnector(String name, String elementName, String type) +{ + // grab connector texcoord register + ShaderConnector *connectComp = dynamic_cast(mComponentList[C_CONNECTOR]); + + //Get element + S32 element = -1; + + if (elementName == String("RT_POSITION")) + element = RT_POSITION; + else if (elementName == String("RT_NORMAL")) + element = RT_NORMAL; + else if (elementName == String("RT_BINORMAL")) + element = RT_BINORMAL; + else if (elementName == String("RT_TANGENT")) + element = RT_TANGENT; + else if (elementName == String("RT_TANGENTW")) + element = RT_TANGENTW; + else if (elementName == String("RT_COLOR")) + element = RT_COLOR; + else if (elementName == String("RT_TEXCOORD")) + element = RT_TEXCOORD; + else if (elementName == String("RT_VPOS")) + element = RT_VPOS; + else if (elementName == String("RT_SVPOSITION")) + element = RT_SVPOSITION; + else if (elementName == String("RT_BLENDINDICES")) + element = RT_BLENDINDICES; + else if (elementName == String("RT_BLENDWEIGHT")) + element = RT_BLENDWEIGHT; + + if (element == -1) + { + Con::errorf("CustomShaderFeatureHLSL::addConnector - Invalid element type %s", elementName.c_str()); + return; + } + + Var *connector = connectComp->getElement((RegisterType)element); + connector->setName(name); + + if (mOutputState == VertexOutput) + connector->setStructName("OUT"); + else if(mOutputState == PixelOutput) + connector->setStructName("IN"); + + connector->setType(type); +} + +void CustomFeatureHLSL::writeLine(String format, S32 argc, ConsoleValueRef *argv) +{ + //do the var/arg fetching here + Vector varList; + bool declarationStatement = false; + + for (U32 i = 0; i < argc; i++) + { + String varName = argv[i].getStringValue(); + Var *newVar = (Var*)LangElement::find(varName.c_str()); + if (!newVar) + { + //ok, check our existing var holders, see if we just haven't utilized it yet + for (U32 v = 0; v < mVars.size(); v++) + { + if (mVars[v].varName == varName) + { + Var* newDeclVar = new Var(mVars[v].varName, mVars[v].type); + + newDeclVar->arraySize = mVars[v].arraySize; + newDeclVar->uniform = mVars[v].uniform; + newDeclVar->sampler = mVars[v].sampler; + newDeclVar->texture = mVars[v].texture; + newDeclVar->constNum = mVars[v].constNum; + newDeclVar->constSortPos = mVars[v].constSortPos; + + if (!newDeclVar->uniform) + { + LangElement *newVarDecl = new DecOp(newDeclVar); + newVar = (Var*)newVarDecl; + + declarationStatement = true; + } + else + { + newVar = newDeclVar; + } + + mVars.erase(v); + break; + } + } + + if (!newVar) + { + //couldn't find that variable, bail out + Con::errorf("CustomShaderFeature::writeLine: unable to find variable %s, meaning it was not declared before being used!", argv[i].getStringValue()); + return; + } + } + + varList.push_back(newVar); + } + + //not happy about it, but do a trampoline here to pass along the args + + switch (varList.size()) + { + case 0: + meta->addStatement(new GenOp(format + "\n")); + break; + case 1: + meta->addStatement(new GenOp(format + "\n", varList[0])); + break; + case 2: + meta->addStatement(new GenOp(format + "\n", varList[0], varList[1])); + break; + case 3: + meta->addStatement(new GenOp(format + "\n", varList[0], varList[1], varList[2])); + break; + case 4: + meta->addStatement(new GenOp(format + "\n", varList[0], varList[1], varList[2], varList[3])); + break; + case 5: + meta->addStatement(new GenOp(format + "\n", varList[0], varList[1], varList[2], varList[3], varList[4])); + break; + } +} + +bool CustomFeatureHLSL::hasFeature(String name) +{ + for (U32 i = 0; i < mFeatureData.materialFeatures.getCount(); i++) + { + String featureName = mFeatureData.materialFeatures.getAt(i).getName(); + if (name == featureName) + return true; + } + + return false; +} \ No newline at end of file diff --git a/Engine/source/shaderGen/HLSL/customFeatureHLSL.h b/Engine/source/shaderGen/HLSL/customFeatureHLSL.h new file mode 100644 index 000000000..e36e682bd --- /dev/null +++ b/Engine/source/shaderGen/HLSL/customFeatureHLSL.h @@ -0,0 +1,123 @@ +#ifndef _SHADERGEN_HLSL_SHADERFEATUREHLSL_H_ +#include "shaderGen/HLSL/shaderFeatureHLSL.h" +#endif +#ifndef _LANG_ELEMENT_H_ +#include "shaderGen/langElement.h" +#endif +#ifndef _GFXDEVICE_H_ +#include "gfx/gfxDevice.h" +#endif +#ifndef _FEATUREMGR_H_ +#include "shaderGen/featureMgr.h" +#endif +#ifndef _MATERIALFEATURETYPES_H_ +#include "materials/materialFeatureTypes.h" +#endif +#ifndef _MATERIALFEATUREDATA_H_ +#include "materials/materialFeatureData.h" +#endif + +#ifndef CUSTOMSHADERFEATURE_H +#include "shaderGen/customShaderFeature.h" +#endif + +class CustomShaderFeatureData; + +class CustomFeatureHLSL : public ShaderFeatureHLSL +{ + friend class CustomShaderFeatureData; + + struct VarHolder + { + String varName; + String defaultValue; + String type; + bool uniform; + bool sampler; + bool texture; + U32 constNum; + ConstantSortPosition constSortPos; + U32 arraySize; + + VarHolder() : + varName(""), + type(""), + defaultValue(""), + uniform(false), + sampler(false), + texture(false), + constNum(0), + arraySize(0), + constSortPos(cspUninit) + { + } + + VarHolder(String _varName,String _type, String _defaultValue) : + uniform(false), sampler(false), texture(false), constNum(0), arraySize(0), constSortPos(cspUninit) + { + varName = _varName; + type = _type; + defaultValue = _defaultValue; + } + }; + + Vector mVars; + + enum outputState + { + NoOutput, + VertexOutput, + PixelOutput + }; + + outputState mOutputState; + +public: + CustomShaderFeatureData* mOwner; + + Vector mComponentList; + MaterialFeatureData mFeatureData; + +protected: + MultiLine *meta; + +public: + + //**************************************************************************** + // Accu Texture + //**************************************************************************** + virtual void processVert(Vector &componentList, + const MaterialFeatureData &fd); + + virtual void processPix(Vector &componentList, + const MaterialFeatureData &fd); + + virtual Material::BlendOp getBlendOp() { return Material::LerpAlpha; } + + virtual Resources getResources(const MaterialFeatureData &fd) + { + Resources res; + res.numTex = 1; + res.numTexReg = 1; + return res; + } + + virtual void setTexData(Material::StageData &stageDat, + const MaterialFeatureData &fd, + RenderPassData &passData, + U32 &texIndex); + + virtual String getName() + { + return mOwner->getName(); + } + + bool hasFeature(String name); + + void addUniform(String name, String type, String defaultValue, U32 arraySize = 0); + void addVariable(String name, String type, String defaultValue); + void addSampler(String name, String type, U32 arraySize = 0); + void addTexture(String name, String type, String samplerState, U32 arraySize); + void addConnector(String name, String elementName, String type); + void writeLine(String format, S32 argc, ConsoleValueRef *argv); +}; \ No newline at end of file diff --git a/Engine/source/shaderGen/customShaderFeature.cpp b/Engine/source/shaderGen/customShaderFeature.cpp new file mode 100644 index 000000000..51d4e805e --- /dev/null +++ b/Engine/source/shaderGen/customShaderFeature.cpp @@ -0,0 +1,190 @@ +//----------------------------------------------------------------------------- +// 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 "shadergen/CustomShaderFeature.h" +#include "shaderGen/HLSL/customFeatureHLSL.h" + +#include "math/mathIO.h" +#include "scene/sceneRenderState.h" +#include "core/stream/bitStream.h" +#include "materials/sceneData.h" +#include "gfx/gfxDebugEvent.h" +#include "gfx/gfxTransformSaver.h" +#include "renderInstance/renderPassManager.h" + + +IMPLEMENT_CONOBJECT(CustomShaderFeatureData); + +ConsoleDocClass(CustomShaderFeatureData, + "@brief An example scene object which renders using a callback.\n\n" + "This class implements a basic SceneObject that can exist in the world at a " + "3D position and render itself. Note that CustomShaderFeatureData handles its own " + "rendering by submitting itself as an ObjectRenderInst (see " + "renderInstance\renderPassmanager.h) along with a delegate for its render() " + "function. However, the preffered rendering method in the engine is to submit " + "a MeshRenderInst along with a Material, vertex buffer, primitive buffer, and " + "transform and allow the RenderMeshMgr handle the actual rendering. You can " + "see this implemented in RenderMeshExample.\n\n" + "See the C++ code for implementation details.\n\n" + "@ingroup Examples\n"); + +//----------------------------------------------------------------------------- +// Object setup and teardown +//----------------------------------------------------------------------------- +CustomShaderFeatureData::CustomShaderFeatureData() +{ +} + +CustomShaderFeatureData::~CustomShaderFeatureData() +{ +} + +//----------------------------------------------------------------------------- +// Object Editing +//----------------------------------------------------------------------------- +void CustomShaderFeatureData::initPersistFields() +{ + // SceneObject already handles exposing the transform + Parent::initPersistFields(); +} + +bool CustomShaderFeatureData::onAdd() +{ + if (!Parent::onAdd()) + return false; + + mFeatureHLSL = new CustomFeatureHLSL(); + mFeatureHLSL->mOwner = this; + + return true; +} + +void CustomShaderFeatureData::onRemove() +{ + Parent::onRemove(); +} + +//Shadergen setup functions +void CustomShaderFeatureData::addVariable(String name, String type, String defaultValue) +{ + mFeatureHLSL->addVariable(name, type, defaultValue); +} + +void CustomShaderFeatureData::addUniform(String name, String type, String defaultValue, U32 arraySize) +{ + mFeatureHLSL->addUniform(name, type, defaultValue, arraySize); +} + +void CustomShaderFeatureData::addSampler(String name, String type, U32 arraySize) +{ + mFeatureHLSL->addSampler(name, type, arraySize); +} + +void CustomShaderFeatureData::addTexture(String name, String type, String samplerState, U32 arraySize) +{ + mFeatureHLSL->addTexture(name, type, samplerState, arraySize); +} + +void CustomShaderFeatureData::addConnector(String name, String elementName, String type) +{ + mFeatureHLSL->addConnector(name, elementName, type); +} + +bool CustomShaderFeatureData::hasFeature(String name) +{ + return mFeatureHLSL->hasFeature(name); +} + +void CustomShaderFeatureData::writeLine(String format, S32 argc, ConsoleValueRef *argv) +{ + /*mOnObject = onObject; + mArgc = argc; + + mArgv = new ConsoleValueRef[argc]; + for (int i = 0; itype = ConsoleValue::TypeInternalString; + mArgv[i].value->init(); + if (argv) + { + mArgv[i].value->setStringValue((const char*)argv[i]); + } + }*/ + + mFeatureHLSL->writeLine(format, argc, argv); +} + +/*//Actual shader processing +void CustomShaderFeatureData::processVert(Vector &componentList, + const MaterialFeatureData &fd) +{ + mFeatureHLSL.processVert(componentList, fd); +} + +void CustomShaderFeatureData::processPix(Vector &componentList, + const MaterialFeatureData &fd) +{ + mFeatureHLSL.processPix(componentList, fd); + +} + +void CustomShaderFeatureData::setTexData(Material::StageData &stageDat, + const MaterialFeatureData &fd, + RenderPassData &passData, + U32 &texIndex) +{ + mFeatureHLSL.setTexData(stageDat, fd, passData, texIndex); +}*/ + +DefineEngineMethod(CustomShaderFeatureData, addVariable, void, (String name, String type, String defaultValue), ("", "", ""), "") +{ + object->addVariable(name, type, defaultValue); +} + +DefineEngineMethod(CustomShaderFeatureData, addUniform, void, (String name, String type, String defaultValue, U32 arraySize), ("", "", "", 0), "") +{ + object->addUniform(name, type, defaultValue, arraySize); +} + +DefineEngineMethod(CustomShaderFeatureData, addSampler, void, (String name, U32 arraySize), ("", 0), "") +{ + object->addSampler(name, "", arraySize); +} + +DefineEngineMethod(CustomShaderFeatureData, addTexture, void, (String name, String type, String samplerState, U32 arraySize), ("", "", 0), "") +{ + object->addTexture(name, type, samplerState, arraySize); +} + +ConsoleMethod(CustomShaderFeatureData, writeLine, void, 3, 0, "( string format, string args... ) Dynamically call a method on an object.\n" + "@param method Name of method to call.\n" + "@param args Zero or more arguments for the method.\n" + "@return The result of the method call.") +{ + object->writeLine(argv[2], argc - 3, argv + 3); +} + +DefineEngineMethod(CustomShaderFeatureData, hasFeature, bool, (String name), (""), "") +{ + return object->hasFeature(name); +} \ No newline at end of file diff --git a/Engine/source/shaderGen/customShaderFeature.h b/Engine/source/shaderGen/customShaderFeature.h new file mode 100644 index 000000000..d134fff5d --- /dev/null +++ b/Engine/source/shaderGen/customShaderFeature.h @@ -0,0 +1,84 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +#pragma once +#ifndef CUSTOMSHADERFEATURE_H +#define CUSTOMSHADERFEATURE_H + +#ifndef _SIMOBJECT_H_ +#include "console/simObject.h" +#endif + +class CustomFeatureHLSL; + +class CustomShaderFeatureData : public SimObject +{ + typedef SimObject Parent; + +public: + CustomFeatureHLSL* mFeatureHLSL; + + Vector mAddedShaderConstants; + +public: + CustomShaderFeatureData(); + virtual ~CustomShaderFeatureData(); + + // Declare this object as a ConsoleObject so that we can + // instantiate it into the world and network it + DECLARE_CONOBJECT(CustomShaderFeatureData); + + //-------------------------------------------------------------------------- + // Object Editing + // Since there is always a server and a client object in Torque and we + // actually edit the server object we need to implement some basic + // networking functions + //-------------------------------------------------------------------------- + // Set up any fields that we want to be editable (like position) + static void initPersistFields(); + + // Handle when we are added to the scene and removed from the scene + bool onAdd(); + void onRemove(); + + //shadergen setup + void addVariable(String name, String type, String defaultValue); + void addUniform(String name, String type, String defaultValue, U32 arraySize); + void addSampler(String name, String type, U32 arraySize); + void addTexture(String name, String type, String samplerState, U32 arraySize); + void addConnector(String name, String elementName, String type); + + bool hasFeature(String name); + + void writeLine(String format, S32 argc, ConsoleValueRef *argv); + + //shader generation + /*void CustomShaderFeatureData::processVert(Vector &componentList, + const MaterialFeatureData &fd); + void CustomShaderFeatureData::processPix(Vector &componentList, + const MaterialFeatureData &fd); + void CustomShaderFeatureData::setTexData(Material::StageData &stageDat, + const MaterialFeatureData &fd, + RenderPassData &passData, + U32 &texIndex);*/ +}; + +#endif \ No newline at end of file diff --git a/Engine/source/shaderGen/langElement.cpp b/Engine/source/shaderGen/langElement.cpp index e4870bb14..ec94c30ee 100644 --- a/Engine/source/shaderGen/langElement.cpp +++ b/Engine/source/shaderGen/langElement.cpp @@ -112,6 +112,7 @@ Var::Var( const char *inName, const char *inType ) sampler = false; texCoordNum = 0; constSortPos = cspUninit; + constNum = 0; arraySize = 1; texture = false; rank = 0; diff --git a/Engine/source/shaderGen/shaderGen.cpp b/Engine/source/shaderGen/shaderGen.cpp index 6b19ba0f5..e4c9ad48d 100644 --- a/Engine/source/shaderGen/shaderGen.cpp +++ b/Engine/source/shaderGen/shaderGen.cpp @@ -31,6 +31,7 @@ #include "core/memVolume.h" #include "core/module.h" +#include "shaderGen/HLSL/customFeatureHLSL.h" MODULE_BEGIN( ShaderGen ) @@ -135,13 +136,16 @@ void ShaderGen::generateShader( const MaterialFeatureData &featureData, F32 *pixVersion, const GFXVertexFormat *vertexFormat, const char* cacheName, - Vector ¯os ) + Vector ¯os, + Vector &customFeatureData) { PROFILE_SCOPE( ShaderGen_GenerateShader ); mFeatureData = featureData; mVertexFormat = vertexFormat; + mCustomFeaturesData = customFeatureData; + _uninit(); _init(); @@ -281,6 +285,31 @@ void ShaderGen::_processVertFeatures( Vector ¯os, bool macro } } + //Handle if we have any custom features + if (!mCustomFeaturesData.empty()) + { + for (U32 i = 0; i < mCustomFeaturesData.size(); ++i) + { + mCustomFeaturesData[i]->mFeatureHLSL->processVert(mComponents, mFeatureData); + + String line = String::ToString(" // %s\r\n", mCustomFeaturesData[i]->mFeatureHLSL->getName().c_str()); + mOutput->addStatement(new GenOp(line)); + + if (mCustomFeaturesData[i]->mFeatureHLSL->getOutput()) + mOutput->addStatement(mCustomFeaturesData[i]->mFeatureHLSL->getOutput()); + //ShaderFeatureHLSL feature = mCustomFeaturesData[i]->mHLSLFeature; + //feature->setProcessIndex(index); + + /*feature->processPixMacros(macros, mFeatureData); + + feature->setInstancingFormat(&mInstancingFormat); + feature->processPix(mComponents, mFeatureData);*/ + + mCustomFeaturesData[i]->mFeatureHLSL->reset(); + mOutput->addStatement(new GenOp(" \r\n")); + } + } + ShaderConnector *connect = dynamic_cast( mComponents[C_CONNECTOR] ); connect->sortVars(); } @@ -320,6 +349,31 @@ void ShaderGen::_processPixFeatures( Vector ¯os, bool macros mOutput->addStatement( new GenOp( " \r\n" ) ); } } + + //Handle if we have any custom features + if (!mCustomFeaturesData.empty()) + { + for (U32 i = 0; i < mCustomFeaturesData.size(); ++i) + { + mCustomFeaturesData[i]->mFeatureHLSL->processPix(mComponents, mFeatureData); + + String line = String::ToString(" // %s\r\n", mCustomFeaturesData[i]->mFeatureHLSL->getName().c_str()); + mOutput->addStatement(new GenOp(line)); + + if (mCustomFeaturesData[i]->mFeatureHLSL->getOutput()) + mOutput->addStatement(mCustomFeaturesData[i]->mFeatureHLSL->getOutput()); + //ShaderFeatureHLSL feature = mCustomFeaturesData[i]->mHLSLFeature; + //feature->setProcessIndex(index); + + /*feature->processPixMacros(macros, mFeatureData); + + feature->setInstancingFormat(&mInstancingFormat); + feature->processPix(mComponents, mFeatureData);*/ + + mCustomFeaturesData[i]->mFeatureHLSL->reset(); + mOutput->addStatement(new GenOp(" \r\n")); + } + } ShaderConnector *connect = dynamic_cast( mComponents[C_CONNECTOR] ); connect->sortVars(); @@ -443,7 +497,7 @@ void ShaderGen::_printPixShader( Stream &stream ) mPrinter->printPixelShaderCloser(stream); } -GFXShader* ShaderGen::getShader( const MaterialFeatureData &featureData, const GFXVertexFormat *vertexFormat, const Vector *macros, const Vector &samplers ) +GFXShader* ShaderGen::getShader( const MaterialFeatureData &featureData, Vector &customFeatureData, const GFXVertexFormat *vertexFormat, const Vector *macros, const Vector &samplers ) { PROFILE_SCOPE( ShaderGen_GetShader ); @@ -483,7 +537,7 @@ GFXShader* ShaderGen::getShader( const MaterialFeatureData &featureData, const G shaderMacros.push_back( GFXShaderMacro( "TORQUE_SHADERGEN" ) ); if ( macros ) shaderMacros.merge( *macros ); - generateShader( featureData, vertFile, pixFile, &pixVersion, vertexFormat, cacheKey, shaderMacros ); + generateShader( featureData, vertFile, pixFile, &pixVersion, vertexFormat, cacheKey, shaderMacros, customFeatureData ); GFXShader *shader = GFX->createShader(); if (!shader->init(vertFile, pixFile, pixVersion, shaderMacros, samplers, &mInstancingFormat)) diff --git a/Engine/source/shaderGen/shaderGen.h b/Engine/source/shaderGen/shaderGen.h index 2ebcda4c2..829487602 100644 --- a/Engine/source/shaderGen/shaderGen.h +++ b/Engine/source/shaderGen/shaderGen.h @@ -47,6 +47,10 @@ #include "materials/materialFeatureData.h" #endif +#ifndef CUSTOMSHADERFEATURE_H +#include "shadergen/customShaderFeature.h" +#endif + /// Base class used by shaderGen to be API agnostic. Subclasses implement the various methods /// in an API specific way. class ShaderGenPrinter @@ -151,10 +155,11 @@ public: F32 *pixVersion, const GFXVertexFormat *vertexFormat, const char* cacheName, - Vector ¯os ); + Vector ¯os, + Vector &customFeatureData); // Returns a shader that implements the features listed by dat. - GFXShader* getShader( const MaterialFeatureData &dat, const GFXVertexFormat *vertexFormat, const Vector *macros, const Vector &samplers ); + GFXShader* getShader( const MaterialFeatureData &dat, Vector &customFeatureData, const GFXVertexFormat *vertexFormat, const Vector *macros, const Vector &samplers ); // This will delete all of the procedural shaders that we have. Used to regenerate shaders when // the ShaderFeatures have changed (due to lighting system change, or new plugin) @@ -176,6 +181,8 @@ protected: Vector< ShaderComponent *> mComponents; + Vector< CustomShaderFeatureData* > mCustomFeaturesData; + AutoPtr mPrinter; AutoPtr mComponentFactory; diff --git a/Engine/source/terrain/terrCellMaterial.cpp b/Engine/source/terrain/terrCellMaterial.cpp index c23209531..7b699b22d 100644 --- a/Engine/source/terrain/terrCellMaterial.cpp +++ b/Engine/source/terrain/terrCellMaterial.cpp @@ -479,6 +479,8 @@ bool TerrainCellMaterial::_createPass( Vector *materials, featureData.features = features; featureData.materialFeatures = features; + Vector customFeatures; + // Check to see how many vertex shader output // registers we're gonna need. U32 numTex = 0; @@ -521,7 +523,7 @@ bool TerrainCellMaterial::_createPass( Vector *materials, const bool logErrors = true;// matCount == 1; GFXShader::setLogging( logErrors, true ); - pass->shader = SHADERGEN->getShader( featureData, getGFXVertexFormat(), NULL, mSamplerNames ); + pass->shader = SHADERGEN->getShader( featureData, customFeatures, getGFXVertexFormat(), NULL, mSamplerNames ); } // If we got a shader then we can continue. diff --git a/Engine/source/ts/tsMesh.cpp b/Engine/source/ts/tsMesh.cpp index 5e767bd66..ddf81bfbd 100644 --- a/Engine/source/ts/tsMesh.cpp +++ b/Engine/source/ts/tsMesh.cpp @@ -207,6 +207,8 @@ void TSMesh::innerRender( TSMaterialList *materials, const TSRenderState &rdata, coreRI->materialHint = rdata.getMaterialHint(); + coreRI->mCustomShaderData = rdata.getCustomShaderBinding(); + coreRI->visibility = meshVisibility; coreRI->cubemap = rdata.getCubemap(); diff --git a/Engine/source/ts/tsRenderState.cpp b/Engine/source/ts/tsRenderState.cpp index 0c3458af7..4c0ce6b93 100644 --- a/Engine/source/ts/tsRenderState.cpp +++ b/Engine/source/ts/tsRenderState.cpp @@ -52,6 +52,7 @@ TSRenderState::TSRenderState( const TSRenderState &state ) mLightQuery( state.mLightQuery ), mAccuTex( state.mAccuTex ), mNodeTransforms( state.mNodeTransforms ), - mNodeTransformCount( state.mNodeTransformCount ) + mNodeTransformCount( state.mNodeTransformCount ), + mCustomShaderData( state.mCustomShaderData ) { } diff --git a/Engine/source/ts/tsRenderState.h b/Engine/source/ts/tsRenderState.h index fcb765185..eda8d5b3a 100644 --- a/Engine/source/ts/tsRenderState.h +++ b/Engine/source/ts/tsRenderState.h @@ -31,6 +31,10 @@ #include "gfx/gfxDevice.h" #endif +#ifndef _BASEMATINSTANCE_H_ +#include "materials/baseMatInstance.h" +#endif + class SceneRenderState; class GFXCubemap; class Frustum; @@ -115,10 +119,10 @@ protected: /// Count of matrices in the mNodeTransforms list U32 mNodeTransformCount; + //Custom Shader data + Vector mCustomShaderData; + public: - - - TSRenderState(); TSRenderState( const TSRenderState &state ); @@ -165,6 +169,15 @@ public: void setAccuTex( GFXTextureObject* query ) { mAccuTex = query; } GFXTextureObject* getAccuTex() const { return mAccuTex; } + void addCustomShaderBinding(CustomShaderBindingData data) + { + mCustomShaderData.push_back(data); + } + Vector getCustomShaderBinding() const + { + return mCustomShaderData; + } + ///@ see mNodeTransforms, mNodeTransformCount void setNodeTransforms(MatrixF *list, U32 count) { mNodeTransforms = list; mNodeTransformCount = count; } void getNodeTransforms(MatrixF **list, U32 *count) const { *list = mNodeTransforms; *count = mNodeTransformCount; } diff --git a/Templates/BaseGame/game/core/gui/scripts/fonts/Arial 12 (ansi).uft b/Templates/BaseGame/game/core/gui/scripts/fonts/Arial 12 (ansi).uft index ebcc8a82f..d33087c85 100644 Binary files a/Templates/BaseGame/game/core/gui/scripts/fonts/Arial 12 (ansi).uft and b/Templates/BaseGame/game/core/gui/scripts/fonts/Arial 12 (ansi).uft differ diff --git a/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 16 (ansi).uft b/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 16 (ansi).uft index f1f94acb3..4cfe6d917 100644 Binary files a/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 16 (ansi).uft and b/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 16 (ansi).uft differ diff --git a/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 18 (ansi).uft b/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 18 (ansi).uft index 8d0881956..72aba583d 100644 Binary files a/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 18 (ansi).uft and b/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 18 (ansi).uft differ diff --git a/Templates/BaseGame/game/core/gui/scripts/fonts/ArialItalic 14 (ansi).uft b/Templates/BaseGame/game/core/gui/scripts/fonts/ArialItalic 14 (ansi).uft index 6babff51e..8c6586e24 100644 Binary files a/Templates/BaseGame/game/core/gui/scripts/fonts/ArialItalic 14 (ansi).uft and b/Templates/BaseGame/game/core/gui/scripts/fonts/ArialItalic 14 (ansi).uft differ diff --git a/Templates/Full/game/art/shapes/cube/materials.cs b/Templates/Full/game/art/shapes/cube/materials.cs index 56e223c1f..2c9d6dc5f 100644 --- a/Templates/Full/game/art/shapes/cube/materials.cs +++ b/Templates/Full/game/art/shapes/cube/materials.cs @@ -21,7 +21,13 @@ //----------------------------------------------------------------------------- //--- cube.dae MATERIALS BEGIN --- -singleton Material(cube_GridMaterial) +singleton CustomShaderFeatureData(FlatColorFeature) +{ + + +}; + +/*singleton Material(cube_GridMaterial) { mapTo = "GridMaterial"; @@ -41,7 +47,40 @@ singleton Material(cube_GridMaterial) specularPower0 = "0.415939"; pixelSpecular0 = "0"; specular0 = "0.9 0.9 0.9 1"; + + mapTo = "GridMaterial"; + + CustomShaderFeature[0] = FlatColorFeature; + CustomShaderFeatureUniforms[FlatColorFeature,0] = "TestFloat"; }; + //--- cube.dae MATERIALS END --- +//Voodoo! +function FlatColorFeature::processVertHLSL(%this) +{ + +} + +function FlatColorFeature::processPixelHLSL(%this) +{ + %this.addUniform("strudel", "float2"); + %this.addSampler("strudelMap"); + %this.addTexture("strudelTex", "Texture2D", "strudelMap"); + + %this.addVariable("bobsyeruncle", "float", 15.915); + %this.addVariable("chimmychanga", "float"); + + %this.writeLine(" @ = @ * 2;", "chimmychanga", "bobsyeruncle"); + %this.writeLine(" @ *= @.x;", "bobsyeruncle", "strudel"); + %this.writeLine(" @ *= @.y;", "chimmychanga", "strudel"); + + %this.addVariable("sprangle", "float4"); + %this.writeLine(" @ = @.Sample(@,@);", "sprangle", "strudelTex", "strudelMap", "strudel"); +} + +function FlatColorFeature::setTextureResources(%this) +{ + +}