Var *AdvancedLightBufferConditioner::_conditionOutput( Var *unconditionedOutput, MultiLine *meta ) { Var *conditionedOutput = new Var; if(GFX->getAdapterType() == OpenGL) conditionedOutput->setType("vec4"); else conditionedOutput->setType("float4"); DecOp *outputDecl = new DecOp(conditionedOutput); if(mColorFormat == RGB) { conditionedOutput->setName("rgbLightInfoOut"); // If this is a 16 bit integer format, scale up/down the values. All other // formats just write out the full 0..1 if(getBufferFormat() == GFXFormatR16G16B16A16) meta->addStatement( new GenOp( " @ = max(4.0, (float4(lightColor, specular) * NL_att + float4(bufferSample.rgb, 0.0)) / 4.0);\r\n", outputDecl ) ); else meta->addStatement( new GenOp( " @ = float4(lightColor, 0) * NL_att + float4(bufferSample.rgb, specular);\r\n", outputDecl ) ); } else { // Input u'v' assumed to be scaled conditionedOutput->setName("luvLightInfoOut"); meta->addStatement( new GenOp( " @ = float4( lerp(bufferSample.xy, lightColor.xy, saturate(NL_att / bufferSample.z) * 0.5),\r\n", outputDecl ) ); meta->addStatement( new GenOp( " bufferSample.z + NL_att, bufferSample.w + saturate(specular * NL_att) );\r\n" ) ); } return conditionedOutput; }
void BufferAdapter::performAction(GLSourceBuffer theSourceBuffer) { GLenum myFormat = getBufferFormat(theSourceBuffer); if (theSourceBuffer == FRAME_BUFFER) { glReadBuffer(GL_BACK); } alloc(_myWidth * _myHeight * _myComponents); if (_myComponents != 4) { glPixelStorei(GL_PACK_ALIGNMENT, 1); } glReadPixels(0, 0, _myWidth, _myHeight, myFormat, GL_UNSIGNED_BYTE, _myData.begin()); }
Var *AdvancedLightBufferConditioner::_unconditionInput( Var *conditionedInput, MultiLine *meta ) { if(mColorFormat == RGB) { if(getBufferFormat() == GFXFormatR16G16B16A16) meta->addStatement( new GenOp( " lightColor = @.rgb * 4.0;\r\n", conditionedInput ) ); else meta->addStatement( new GenOp( " lightColor = @.rgb;\r\n", conditionedInput ) ); meta->addStatement( new GenOp( " NL_att = dot(@.rgb, float3(0.3576, 0.7152, 0.1192));\r\n", conditionedInput ) ); } else { meta->addStatement( new GenOp( " // TODO: This clamps HDR values.\r\n" ) ); meta->addStatement( new GenOp( " NL_att = @.b;\r\n", conditionedInput ) ); meta->addStatement( new GenOp( " lightColor = DecodeLuv(float3(saturate(NL_att), @.rg * 0.62));\r\n", conditionedInput ) ); } meta->addStatement( new GenOp( " specular = @.a;\r\n", conditionedInput ) ); return NULL; }
HDRStageDataTransitPtr HDRStage::setupStageData(Int32 iPixelWidth, Int32 iPixelHeight) { HDRStageDataTransitPtr returnValue = HDRStageData::createLocal(); if(returnValue == NULL) return returnValue; OSG::Thread::setCurrentLocalFlags(); // Scene Target FrameBufferObjectUnrecPtr pSceneFBO = FrameBufferObject::createLocal(); RenderBufferUnrecPtr pDepthBuffer = RenderBuffer ::createLocal(); pDepthBuffer->setInternalFormat(GL_DEPTH_COMPONENT24 ); TextureObjChunkUnrecPtr pSceneTex = TextureObjChunk::createLocal(); TextureEnvChunkUnrecPtr pSceneTexEnv = TextureEnvChunk::createLocal(); ImageUnrecPtr pImg = Image ::createLocal(); pImg->set(Image::OSG_RGB_PF, iPixelWidth, iPixelHeight, 1, 1, 1, 0.0, 0, Image::OSG_FLOAT32_IMAGEDATA, false); pSceneTex ->setImage (pImg ); pSceneTex ->setMinFilter (GL_LINEAR ); pSceneTex ->setMagFilter (GL_LINEAR ); pSceneTex ->setWrapS (GL_CLAMP_TO_EDGE ); pSceneTex ->setWrapT (GL_CLAMP_TO_EDGE ); pSceneTex ->setInternalFormat(getBufferFormat()); pSceneTexEnv->setEnvMode (GL_REPLACE ); TextureBufferUnrecPtr pSceneTexBuffer = TextureBuffer::createLocal(); pSceneTexBuffer->setTexture(pSceneTex); pSceneFBO->setSize(iPixelWidth, iPixelHeight); pSceneFBO->setColorAttachment(pSceneTexBuffer, 0); pSceneFBO->setDepthAttachment(pDepthBuffer ); pSceneFBO->editMFDrawBuffers()->push_back(GL_COLOR_ATTACHMENT0_EXT); setRenderTarget(pSceneFBO); // Shrink Target (w/2, h/2) FrameBufferObjectUnrecPtr pShrinkFBO = FrameBufferObject::createLocal(); TextureObjChunkUnrecPtr pShrinkTex = TextureObjChunk::createLocal(); TextureEnvChunkUnrecPtr pShrinkTexEnv = TextureEnvChunk::createLocal(); pImg = Image ::createLocal(); pImg->set(Image::OSG_RGB_PF, iPixelWidth / 2, iPixelHeight / 2, 1, 1, 1, 0.0, 0, Image::OSG_FLOAT32_IMAGEDATA, false); pShrinkTex ->setImage (pImg ); pShrinkTex ->setMinFilter (GL_LINEAR ); pShrinkTex ->setMagFilter (GL_LINEAR ); pShrinkTex ->setWrapS (GL_CLAMP_TO_EDGE ); pShrinkTex ->setWrapT (GL_CLAMP_TO_EDGE ); pShrinkTex ->setInternalFormat(getBufferFormat()); pShrinkTexEnv->setEnvMode (GL_REPLACE ); TextureBufferUnrecPtr pShrinkTexBuffer = TextureBuffer::createLocal(); pShrinkTexBuffer->setTexture(pShrinkTex); pShrinkFBO->setSize(iPixelWidth / 2, iPixelHeight / 2); pShrinkFBO->setColorAttachment(pShrinkTexBuffer, 0); pShrinkFBO->editMFDrawBuffers()->push_back(GL_COLOR_ATTACHMENT0_EXT); returnValue->setShrinkRenderTarget(pShrinkFBO); // blur (w/4, h/4) FrameBufferObjectUnrecPtr pBlurFBO = FrameBufferObject::createLocal(); TextureObjChunkUnrecPtr pBlurTex1 = TextureObjChunk ::createLocal(); TextureEnvChunkUnrecPtr pBlurTex1Env = TextureEnvChunk ::createLocal(); pImg = Image::createLocal(); pImg->set(Image::OSG_RGB_PF, iPixelWidth / 4, iPixelHeight / 4, 1, 1, 1, 0.0, 0, Image::OSG_FLOAT32_IMAGEDATA, false); pBlurTex1 ->setImage (pImg ); pBlurTex1 ->setMinFilter (GL_LINEAR ); pBlurTex1 ->setMagFilter (GL_LINEAR ); pBlurTex1 ->setWrapS (GL_CLAMP_TO_EDGE ); pBlurTex1 ->setWrapT (GL_CLAMP_TO_EDGE ); pBlurTex1 ->setInternalFormat(getBufferFormat()); pBlurTex1Env->setEnvMode (GL_REPLACE ); TextureBufferUnrecPtr pBlurTexBuffer1 = TextureBuffer::createLocal(); pBlurTexBuffer1->setTexture(pBlurTex1); TextureObjChunkUnrecPtr pBlurTex2 = TextureObjChunk::createLocal(); TextureEnvChunkUnrecPtr pBlurTex2Env = TextureEnvChunk::createLocal(); pImg = Image::createLocal(); pImg->set(Image::OSG_RGB_PF, iPixelWidth / 4, iPixelHeight / 4, 1, 1, 1, 0.0, 0, Image::OSG_FLOAT32_IMAGEDATA, false); pBlurTex2 ->setImage (pImg ); pBlurTex2 ->setMinFilter (GL_LINEAR ); pBlurTex2 ->setMagFilter (GL_LINEAR ); pBlurTex2 ->setWrapS (GL_CLAMP_TO_EDGE ); pBlurTex2 ->setWrapT (GL_CLAMP_TO_EDGE ); pBlurTex2 ->setInternalFormat(getBufferFormat()); pBlurTex2Env->setEnvMode (GL_REPLACE ); TextureBufferUnrecPtr pBlurTexBuffer2 = TextureBuffer::createLocal(); pBlurTexBuffer2->setTexture(pBlurTex2); pBlurFBO->setSize(iPixelWidth / 4, iPixelHeight / 4); pBlurFBO->setColorAttachment(pBlurTexBuffer1, 0); pBlurFBO->setColorAttachment(pBlurTexBuffer2, 1); returnValue->setBlurRenderTarget(pBlurFBO); // general mat chunk MaterialChunkUnrecPtr pMatChunk = MaterialChunk::createLocal(); pMatChunk->setLit(false); // tone map material ChunkMaterialUnrecPtr pTonemapMat = ChunkMaterial ::createLocal(); pTonemapMat->addChunk(pMatChunk ); pTonemapMat->addChunk(pSceneTex, 0); pTonemapMat->addChunk(pSceneTexEnv, 0); pTonemapMat->addChunk(pBlurTex1, 1); pTonemapMat->addChunk(pBlurTex1Env, 1); SimpleSHLChunkUnrecPtr pTonemapShader = generateHDRFragmentProgram(); pTonemapShader->addUniformVariable("sceneTex", 0); pTonemapShader->addUniformVariable("blurTex", 1); pTonemapShader->addUniformVariable("blurAmount", getBlurAmount ()); pTonemapShader->addUniformVariable("exposure", getExposure ()); pTonemapShader->addUniformVariable("effectAmount", getEffectAmount()); pTonemapShader->addUniformVariable("gamma", getGamma ()); pTonemapMat->addChunk(pTonemapShader, 0); returnValue->setToneMappingMaterial(pTonemapMat); // Shrink material ChunkMaterialUnrecPtr pShrinkMat = ChunkMaterial::createLocal(); pShrinkMat->addChunk(pMatChunk ); pShrinkMat->addChunk(pSceneTex, 0); pShrinkMat->addChunk(pSceneTexEnv, 0); SimpleSHLChunkUnrecPtr pShrinkShader = generate2DShrinkHalfFilterFP(); pShrinkShader->addUniformVariable("inputTex", 0); pShrinkMat->addChunk(pShrinkShader, 0); returnValue->setShrinkMaterial(pShrinkMat); // Blur material ChunkMaterialUnrecPtr pBlurMat = ChunkMaterial::createLocal(); pBlurMat->addChunk(pMatChunk ); pBlurMat->addChunk(pShrinkTex, 0); pBlurMat->addChunk(pShrinkTexEnv, 0); pBlurMat->addChunk(pBlurTex1, 1); pBlurMat->addChunk(pBlurTex1Env, 1); pBlurMat->addChunk(pBlurTex2, 2); pBlurMat->addChunk(pBlurTex2Env, 2); pBlurMat->addChunk(pShrinkShader, 0); returnValue->setBlurMaterial(pBlurMat); // generate blur fragment programs SimpleSHLChunkUnrecPtr pHBlurShader = generate1DConvolutionFilterFP(getBlurWidth(), false, true, iPixelWidth / 2, iPixelHeight / 2); pHBlurShader->addUniformVariable("inputTex", 0); returnValue->setHBlurShader(pHBlurShader); // VBlur Override SimpleSHLChunkUnrecPtr pVBlurShader = generate1DConvolutionFilterFP(getBlurWidth(), true, true, iPixelWidth / 2, iPixelHeight / 2); pVBlurShader->addUniformVariable("inputTex", 1); returnValue->setVBlurShader(pVBlurShader); OSG::Thread::resetCurrentLocalFlags(); Thread::getCurrentChangeList()->commitChanges(); return returnValue; }
Var* GBufferConditionerGLSL::_unconditionInput( Var *conditionedInput, MultiLine *meta ) { Var *retVar = new Var; retVar->setType("float4"); retVar->setName("_gbUnconditionedInput"); LangElement *outputDecl = new DecOp( retVar ); switch(mNormalStorageType) { case CartesianXYZ: meta->addStatement( new GenOp( " // g-buffer unconditioner: float4(normal.xyz, depth)\r\n" ) ); meta->addStatement( new GenOp( " @ = float4(@, @.a);\r\n", outputDecl, _posnegDecode(new GenOp("@.xyz", conditionedInput)), conditionedInput ) ); break; case CartesianXY: meta->addStatement( new GenOp( " // g-buffer unconditioner: float4(normal.xy, depth Hi + z-sign, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " @ = float4(@, @.a);\r\n", outputDecl, _posnegDecode(new GenOp("@.xyz", conditionedInput)), conditionedInput ) ); meta->addStatement( new GenOp( " @.z *= sqrt(1.0 - dot(@.xy, @.xy));\r\n", retVar, retVar, retVar ) ); break; case Spherical: meta->addStatement( new GenOp( " // g-buffer unconditioner: float4(normal.theta, normal.phi, depth Hi, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " float2 spGPUAngles = @;\r\n", _posnegDecode(new GenOp("@.xy", conditionedInput)) ) ); meta->addStatement( new GenOp( " float2 sincosTheta;\r\n" ) ); meta->addStatement( new GenOp( " sincos(spGPUAngles.x * 3.14159265358979323846f, sincosTheta.x, sincosTheta.y);\r\n" ) ); meta->addStatement( new GenOp( " float2 sincosPhi = float2(sqrt(1.0 - spGPUAngles.y * spGPUAngles.y), spGPUAngles.y);\r\n" ) ); meta->addStatement( new GenOp( " @ = float4(sincosTheta.y * sincosPhi.x, sincosTheta.x * sincosPhi.x, sincosPhi.y, @.a);\r\n", outputDecl, conditionedInput ) ); break; case LambertAzimuthal: // Note we're casting to half to use partial precision // sqrt which is much faster on older Geforces while // still being acceptable for normals. // meta->addStatement( new GenOp( " // g-buffer unconditioner: float4(normal.X, normal.Y, depth Hi, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " float2 _inpXY = @;\r\n", _posnegDecode(new GenOp("@.xy", conditionedInput)) ) ); meta->addStatement( new GenOp( " float _xySQ = dot(_inpXY, _inpXY);\r\n" ) ); meta->addStatement( new GenOp( " @ = float4( sqrt(half(1.0 - (_xySQ / 4.0))) * _inpXY, -1.0 + (_xySQ / 2.0), @.a).xzyw;\r\n", outputDecl, conditionedInput ) ); break; } // Recover depth from encoding if(mNormalStorageType != CartesianXYZ) { const U64 maxValPerChannel = 1 << mBitsPerChannel; meta->addStatement( new GenOp( " \r\n // Decode depth\r\n" ) ); meta->addStatement( new GenOp( avar( " @.w = dot( @.zw, float2(1.0, 1.0/%llu.0));\r\n", maxValPerChannel - 1 ), retVar, conditionedInput ) ); } AssertFatal( retVar != NULL, avar( "Cannot uncondition input from buffer format: %s", GFXStringTextureFormat[getBufferFormat()] ) ); return retVar; }
Var* GBufferConditionerGLSL::_conditionOutput( Var *unconditionedOutput, MultiLine *meta ) { Var *retVar = new Var; retVar->setType("float4"); retVar->setName("_gbConditionedOutput"); LangElement *outputDecl = new DecOp( retVar ); switch(mNormalStorageType) { case CartesianXYZ: meta->addStatement( new GenOp( " // g-buffer conditioner: float4(normal.xyz, depth)\r\n" ) ); meta->addStatement( new GenOp( " @ = float4(@, @.a);\r\n", outputDecl, _posnegEncode(new GenOp("@.xyz", unconditionedOutput)), unconditionedOutput ) ); break; case CartesianXY: meta->addStatement( new GenOp( " // g-buffer conditioner: float4(normal.xy, depth Hi + z-sign, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " @ = float4(@, @.a);", outputDecl, _posnegEncode(new GenOp("float3(@.xy, sign(@.z))", unconditionedOutput, unconditionedOutput)), unconditionedOutput ) ); break; case Spherical: meta->addStatement( new GenOp( " // g-buffer conditioner: float4(normal.theta, normal.phi, depth Hi, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " @ = float4(@, 0.0, @.a);\r\n", outputDecl, _posnegEncode(new GenOp("float2(atan2(@.y, @.x) / 3.14159265358979323846f, @.z)", unconditionedOutput, unconditionedOutput, unconditionedOutput ) ), unconditionedOutput ) ); // HACK: This fixes the noise present when using a floating point // gbuffer on Geforce cards and the "flat areas unlit" issues. // // We need work around atan2() above to fix this issue correctly // without the extra overhead of this test. // meta->addStatement( new GenOp( " if ( abs( dot( @.xyz, float3( 0.0, 0.0, 1.0 ) ) ) > 0.999f ) @ = float4( 0, 1 * sign( @.z ), 0, @.a );\r\n", unconditionedOutput, retVar, unconditionedOutput, unconditionedOutput ) ); break; case LambertAzimuthal: //http://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection // // Note we're casting to half to use partial precision // sqrt which is much faster on older Geforces while // still being acceptable for normals. // meta->addStatement( new GenOp( " // g-buffer conditioner: float4(normal.X, normal.Y, depth Hi, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " @ = float4(@, 0.0, @.a);\r\n", outputDecl, _posnegEncode(new GenOp("sqrt(half(2.0/(1.0 - @.y))) * half2(@.xz)", unconditionedOutput, unconditionedOutput)), unconditionedOutput ) ); break; } // Encode depth into two channels if(mNormalStorageType != CartesianXYZ) { const U64 maxValPerChannel = 1 << mBitsPerChannel; meta->addStatement( new GenOp( " \r\n // Encode depth into hi/lo\r\n" ) ); meta->addStatement( new GenOp( avar( " float2 _tempDepth = frac(@.a * float2(1.0, %llu.0));\r\n", maxValPerChannel - 1 ), unconditionedOutput ) ); meta->addStatement( new GenOp( avar( " @.zw = _tempDepth.xy - _tempDepth.yy * float2(1.0/%llu.0, 0.0);\r\n\r\n", maxValPerChannel - 1 ), retVar ) ); } AssertFatal( retVar != NULL, avar( "Cannot condition output to buffer format: %s", GFXStringTextureFormat[getBufferFormat()] ) ); return retVar; }
Var* GBufferConditionerGLSL::_unconditionInput( Var *conditionedInput, MultiLine *meta ) { Var *retVar = new Var; retVar->setType("vec4"); retVar->setName("_gbUnconditionedInput"); LangElement *outputDecl = new DecOp( retVar ); switch(mNormalStorageType) { case CartesianXYZ: meta->addStatement( new GenOp( " // g-buffer unconditioner: vec4(normal.xyz, depth)\r\n" ) ); meta->addStatement( new GenOp( " @ = vec4(@, @.a);\r\n", outputDecl, _posnegDecode(new GenOp("@.xyz", conditionedInput)), conditionedInput ) ); break; case CartesianXY: meta->addStatement( new GenOp( " // g-buffer unconditioner: vec4(normal.xy, depth Hi + z-sign, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " @ = vec4(@, @.a);\r\n", outputDecl, _posnegDecode(new GenOp("@.xyz", conditionedInput)), conditionedInput ) ); meta->addStatement( new GenOp( " @.z *= sqrt(1.0 - dot(@.xy, @.xy));\r\n", retVar, retVar, retVar ) ); break; case Spherical: meta->addStatement( new GenOp( " // g-buffer unconditioner: vec4(normal.theta, normal.phi, depth Hi, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " vec2 spGPUAngles = @;\r\n", _posnegDecode(new GenOp("@.xy", conditionedInput)) ) ); meta->addStatement( new GenOp( " vec2 sincosTheta;\r\n" ) ); meta->addStatement( new GenOp( " sincosTheta.x = sin(spGPUAngles.x * 3.14159265358979323846);\r\n" ) ); meta->addStatement( new GenOp( " sincosTheta.y = cos(spGPUAngles.x * 3.14159265358979323846);\r\n" ) ); meta->addStatement( new GenOp( " vec2 sincosPhi = vec2(sqrt(1.0 - spGPUAngles.y * spGPUAngles.y), spGPUAngles.y);\r\n" ) ); meta->addStatement( new GenOp( " @ = vec4(sincosTheta.y * sincosPhi.x, sincosTheta.x * sincosPhi.x, sincosPhi.y, @.a);\r\n", outputDecl, conditionedInput ) ); break; } // Recover depth from encoding if(mNormalStorageType != CartesianXYZ) { const U64 maxValPerChannel = 1 << mBitsPerChannel; meta->addStatement( new GenOp( " \r\n // Decode depth\r\n" ) ); meta->addStatement( new GenOp( avar( " @.w = dot( @.zw, vec2(1.0, 1.0/%llu.0));\r\n", maxValPerChannel - 1 ), retVar, conditionedInput ) ); } AssertFatal( retVar != NULL, avar( "Cannot uncondition input from buffer format: %s", GFXStringTextureFormat[getBufferFormat()] ) ); return retVar; }
Var* GBufferConditionerGLSL::_conditionOutput( Var *unconditionedOutput, MultiLine *meta ) { Var *retVar = new Var; retVar->setType("vec4"); retVar->setName("_gbConditionedOutput"); LangElement *outputDecl = new DecOp( retVar ); switch(mNormalStorageType) { case CartesianXYZ: meta->addStatement( new GenOp( " // g-buffer conditioner: vec4(normal.xyz, depth)\r\n" ) ); meta->addStatement( new GenOp( " @ = vec4(@, @.a);\r\n", outputDecl, _posnegEncode(new GenOp("@.xyz", unconditionedOutput)), unconditionedOutput ) ); break; case CartesianXY: meta->addStatement( new GenOp( " // g-buffer conditioner: vec4(normal.xy, depth Hi + z-sign, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " @ = vec4(@, @.a);", outputDecl, _posnegEncode(new GenOp("vec3(@.xy, sign(@.z))", unconditionedOutput, unconditionedOutput)), unconditionedOutput ) ); break; case Spherical: meta->addStatement( new GenOp( " // g-buffer conditioner: vec4(normal.theta, normal.phi, depth Hi, depth Lo)\r\n" ) ); meta->addStatement( new GenOp( " @ = vec4(@, 0.0, @.a);\r\n", outputDecl, _posnegEncode(new GenOp("vec2(atan2(@.y, @.x) / 3.14159265358979323846f, @.z)", unconditionedOutput, unconditionedOutput, unconditionedOutput ) ), unconditionedOutput ) ); break; } // Encode depth into two channels if(mNormalStorageType != CartesianXYZ) { const U64 maxValPerChannel = 1 << mBitsPerChannel; const U64 extraVal = (maxValPerChannel * maxValPerChannel - 1) - (maxValPerChannel - 1) * 2; meta->addStatement( new GenOp( " \r\n // Encode depth into hi/lo\r\n" ) ); meta->addStatement( new GenOp( avar( " vec3 _tempDepth = fract(@.a * vec3(1.0, %llu.0, %llu.0));\r\n", maxValPerChannel - 1, extraVal ), unconditionedOutput ) ); meta->addStatement( new GenOp( avar( " @.zw = _tempDepth.xy - _tempDepth.yz * vec2(1.0/%llu.0, 1.0/%llu.0);\r\n\r\n", maxValPerChannel - 1, maxValPerChannel - 1 ), retVar ) ); } AssertFatal( retVar != NULL, avar( "Cannot condition output to buffer format: %s", GFXStringTextureFormat[getBufferFormat()] ) ); return retVar; }
LangElement *ConditionerFeature::assignOutput( Var *unconditionedOutput, ShaderFeature::OutputTarget outputTarget /* = ShaderFeature::DefaultTarget*/ ) { LangElement *assign; MultiLine *meta = new MultiLine; meta->addStatement( new GenOp( avar( "\r\n\r\n // output buffer format: %s\r\n", GFXStringTextureFormat[getBufferFormat()] ) ) ); // condition the output Var *conditionedOutput = _conditionOutput( unconditionedOutput, meta ); // search for color var Var *color = (Var*) LangElement::find( getOutputTargetVarName(outputTarget) ); if ( !color ) { // create color var color = new Var; if(GFX->getAdapterType() == OpenGL) { color->setName( getOutputTargetVarName(outputTarget) ); color->setType( "vec4" ); DecOp* colDecl = new DecOp(color); assign = new GenOp( "@ = vec4(@)", colDecl, conditionedOutput ); } else { color->setType( "fragout" ); color->setName( getOutputTargetVarName(outputTarget) ); color->setStructName( "OUT" ); assign = new GenOp( "@ = @", color, conditionedOutput ); } } else { if (GFX->getAdapterType() == OpenGL) assign = new GenOp( "@ = vec4(@)", color, conditionedOutput); else assign = new GenOp( "@ = @", color, conditionedOutput ); } meta->addStatement( new GenOp( " @;\r\n", assign ) ); return meta; }