bool LightingVariablesHelper::MergeAsArrayItem (csShaderVariableStack& dst, csShaderVariable* sv, size_t index) { CS::ShaderVarStringID name = sv->GetName(); if (name >= dst.GetSize()) return false; csShaderVariable*& dstVar = dst[name]; if (dstVar == 0) dstVar = CreateTempSV (name); if ((dstVar->GetType() != csShaderVariable::UNKNOWN) && (dstVar->GetType() != csShaderVariable::ARRAY)) return true; dstVar->SetArrayElement (index, sv); return true; }
void csVProcStandardProgram::SetupState (const csRenderMesh* mesh, csRenderMeshModes& modes, const csShaderVariableStack& stack) { bool skin_updated = false;// @@@ FIXME - time related detection if vertices are not already updated if (doVertexSkinning || doNormalSkinning || doTangentSkinning || doBiTangentSkinning) { skin_updated = UpdateSkinnedVertices (modes, stack); } if (numLights > 0) { int lightsActive = 0; CS::ShaderVarStringID id; id = shaderPlugin->lsvCache.GetDefaultSVId ( csLightShaderVarCache::varLightCount); csShaderVariable* sv; if ((stack.GetSize () > id) && ((sv = stack[id]) != 0)) sv->GetValue (lightsActive); iRenderBuffer *vbuf = doVertexSkinning && skin_updated ? modes.buffers->GetRenderBuffer (skinnedPositionOutputBuffer) : GetBuffer (positionBuffer, modes, stack); iRenderBuffer *nbuf = doNormalSkinning && skin_updated ? modes.buffers->GetRenderBuffer (skinnedNormalOutputBuffer) : GetBuffer (normalBuffer, modes, stack); iRenderBuffer *cbuf = GetBuffer (colorBuffer, modes, stack); if (vbuf == 0 || nbuf == 0) return; csReversibleTransform camtrans; if ((stack.GetSize () > shaderPlugin->string_world2camera) && ((sv = stack[shaderPlugin->string_world2camera]) != 0)) sv->GetValue (camtrans); csVector3 eyePos (camtrans.GetT2OTranslation ()); csVector3 eyePosObject (mesh->object2world.Other2This (eyePos)); bool hasAlpha = cbuf && cbuf->GetComponentCount() >= 4; //copy output size_t elementCount = vbuf->GetElementCount (); csRef<iRenderBuffer> clbuf; if (doDiffuse) { clbuf = csRenderBuffer::CreateRenderBuffer (elementCount, CS_BUF_STREAM, CS_BUFCOMP_FLOAT, hasAlpha ? 4 : 3); // @@@ FIXME: should probably get rid of the multiple locking/unlocking... csRenderBufferLock<float> tmpColor (clbuf); memset (tmpColor, 0, sizeof(float) * (hasAlpha?4:3) * elementCount); } csRef<iRenderBuffer> specBuf; if (doSpecular) { specBuf = csRenderBuffer::CreateRenderBuffer (elementCount, CS_BUF_STREAM, CS_BUFCOMP_FLOAT, 3); csRenderBufferLock<float> tmpColor (specBuf); memset (tmpColor, 0, sizeof(csColor) * elementCount); } float shininess = GetParamFloatVal (stack, shininessParam, 0.0f); if (lightsActive > 0) { if (lightMixMode == LIGHTMIXMODE_NONE) { //only calculate last, other have no effect const size_t lightNum = csMin((size_t)lightsActive, numLights)-1; if ((disableMask.GetSize() <= lightNum) || !disableMask.IsBitSet (lightNum)) { csLightProperties light (lightNum, shaderPlugin->lsvCache, stack, mesh->object2world); iVertexLightCalculator *calc = shaderPlugin->GetLightCalculator (light, useAttenuation); calc->CalculateLighting (light, eyePosObject, shininess, elementCount, vbuf, nbuf, clbuf, specBuf); } } else { LightMixmode useMixMode = LIGHTMIXMODE_ADD; for (size_t i = 0; i < (csMin((size_t)lightsActive, numLights)); i++) { if ((disableMask.GetSize() > i) && disableMask.IsBitSet (i)) { useMixMode = lightMixMode; continue; } csLightProperties light (i, shaderPlugin->lsvCache, stack, mesh->object2world); iVertexLightCalculator *calc = shaderPlugin->GetLightCalculator (light, useAttenuation); switch (useMixMode) { case LIGHTMIXMODE_ADD: { calc->CalculateLightingAdd (light, eyePosObject, shininess, elementCount, vbuf, nbuf, clbuf, specBuf); break; } case LIGHTMIXMODE_MUL: { calc->CalculateLightingMul (light, eyePosObject, shininess, elementCount, vbuf, nbuf, clbuf, specBuf); break; } case LIGHTMIXMODE_NONE: break; } useMixMode = lightMixMode; } } } if (doDiffuse && cbuf) { switch (colorMixMode) { case LIGHTMIXMODE_NONE: if (!hasAlpha) break; { csVertexListWalker<float> cbufWalker (cbuf, 4); csRenderBufferLock<csVector4, iRenderBuffer*> tmpColor (clbuf); for (size_t i = 0; i < elementCount; i++) { const float* c = cbufWalker; tmpColor[i].w = c[3]; ++cbufWalker; } } break; case LIGHTMIXMODE_ADD: { csVertexListWalker<float> cbufWalker (cbuf, 4); csRenderBufferLock<csVector4, iRenderBuffer*> tmpColor (clbuf); for (size_t i = 0; i < elementCount; i++) { csVector4& t = tmpColor[i]; const float* c = cbufWalker; for (int j = 0; j < 3; j++) t[j] += c[j]; if (hasAlpha) t[3] = c[3]; ++cbufWalker; } } break; case LIGHTMIXMODE_MUL: { csVertexListWalker<float> cbufWalker (cbuf, 4); csRenderBufferLock<csVector4, iRenderBuffer*> tmpColor (clbuf); for (size_t i = 0; i < elementCount; i++) { csVector4& t = tmpColor[i]; const float* c = cbufWalker; for (int j = 0; j < 3; j++) t[j] *= c[j]; if (hasAlpha) t[3] = c[3]; ++cbufWalker; } } break; default: CS_ASSERT (false); } if (doSpecular && specularOnDiffuse) { csRenderBufferLock<csColor> tmpColor (clbuf); csRenderBufferLock<csColor> tmpColor2 (specBuf); for (size_t i = 0; i < elementCount; i++) { tmpColor[i] += tmpColor2[i]; } } } float finalLightFactorReal = GetParamFloatVal (stack, finalLightFactor, 1.0f); if (doDiffuse) { { csRenderBufferLock<csColor> tmpColor (clbuf); for (size_t i = 0; i < elementCount; i++) { tmpColor[i] *= finalLightFactorReal; } } modes.buffers->SetAccessor (modes.buffers->GetAccessor(), modes.buffers->GetAccessorMask() & ~CS_BUFFER_COLOR_MASK); modes.buffers->SetRenderBuffer (CS_BUFFER_COLOR, clbuf); } if (doSpecular && !specularOnDiffuse) { csRenderBufferLock<csColor> tmpColor (specBuf); for (size_t i = 0; i < elementCount; i++) { tmpColor[i] *= finalLightFactorReal; } modes.buffers->SetAccessor (modes.buffers->GetAccessor(), modes.buffers->GetAccessorMask() & ~(1 << specularOutputBuffer)); modes.buffers->SetRenderBuffer (specularOutputBuffer, specBuf); } } }