| // Copyright 2016 The SwiftShader Authors. All Rights Reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "TextureStage.hpp" | |
| #include "Sampler.hpp" | |
| #include "Common/Debug.hpp" | |
| #include <string.h> | |
| namespace sw | |
| { | |
| TextureStage::State::State() | |
| { | |
| memset(this, 0, sizeof(State)); | |
| } | |
| TextureStage::TextureStage() : sampler(0), previousStage(0) | |
| { | |
| } | |
| TextureStage::~TextureStage() | |
| { | |
| } | |
| void TextureStage::init(int stage, const Sampler *sampler, const TextureStage *previousStage) | |
| { | |
| this->stage = stage; | |
| stageOperation = (stage == 0 ? STAGE_MODULATE : STAGE_DISABLE); | |
| firstArgument = SOURCE_TEXTURE; | |
| secondArgument = SOURCE_CURRENT; | |
| thirdArgument = SOURCE_CURRENT; | |
| stageOperationAlpha = (stage == 0 ? STAGE_SELECTARG1 : STAGE_DISABLE); | |
| firstArgumentAlpha = SOURCE_DIFFUSE; | |
| secondArgumentAlpha = SOURCE_CURRENT; | |
| thirdArgumentAlpha = SOURCE_CURRENT; | |
| firstModifier = MODIFIER_COLOR; | |
| secondModifier = MODIFIER_COLOR; | |
| thirdModifier = MODIFIER_COLOR; | |
| firstModifierAlpha = MODIFIER_COLOR; | |
| secondModifierAlpha = MODIFIER_COLOR; | |
| thirdModifierAlpha = MODIFIER_COLOR; | |
| destinationArgument = DESTINATION_CURRENT; | |
| texCoordIndex = stage; | |
| this->sampler = sampler; | |
| this->previousStage = previousStage; | |
| } | |
| TextureStage::State TextureStage::textureStageState() const | |
| { | |
| State state; | |
| if(!isStageDisabled()) | |
| { | |
| state.stageOperation = stageOperation; | |
| state.firstArgument = firstArgument; | |
| state.secondArgument = secondArgument; | |
| state.thirdArgument = thirdArgument; | |
| state.stageOperationAlpha = stageOperationAlpha; | |
| state.firstArgumentAlpha = firstArgumentAlpha; | |
| state.secondArgumentAlpha = secondArgumentAlpha; | |
| state.thirdArgumentAlpha = thirdArgumentAlpha; | |
| state.firstModifier = firstModifier; | |
| state.secondModifier = secondModifier; | |
| state.thirdModifier = thirdModifier; | |
| state.firstModifierAlpha = firstModifierAlpha; | |
| state.secondModifierAlpha = secondModifierAlpha; | |
| state.thirdModifierAlpha = thirdModifierAlpha; | |
| state.destinationArgument = destinationArgument; | |
| state.texCoordIndex = texCoordIndex; | |
| state.cantUnderflow = sampler->hasUnsignedTexture() || !usesTexture(); | |
| state.usesTexture = usesTexture(); | |
| } | |
| return state; | |
| } | |
| void TextureStage::setConstantColor(const Color<float> &constantColor) | |
| { | |
| // FIXME: Compact into generic function // FIXME: Clamp | |
| short r = iround(4095 * constantColor.r); | |
| short g = iround(4095 * constantColor.g); | |
| short b = iround(4095 * constantColor.b); | |
| short a = iround(4095 * constantColor.a); | |
| uniforms.constantColor4[0][0] = uniforms.constantColor4[0][1] = uniforms.constantColor4[0][2] = uniforms.constantColor4[0][3] = r; | |
| uniforms.constantColor4[1][0] = uniforms.constantColor4[1][1] = uniforms.constantColor4[1][2] = uniforms.constantColor4[1][3] = g; | |
| uniforms.constantColor4[2][0] = uniforms.constantColor4[2][1] = uniforms.constantColor4[2][2] = uniforms.constantColor4[2][3] = b; | |
| uniforms.constantColor4[3][0] = uniforms.constantColor4[3][1] = uniforms.constantColor4[3][2] = uniforms.constantColor4[3][3] = a; | |
| } | |
| void TextureStage::setBumpmapMatrix(int element, float value) | |
| { | |
| uniforms.bumpmapMatrix4F[element / 2][element % 2][0] = value; | |
| uniforms.bumpmapMatrix4F[element / 2][element % 2][1] = value; | |
| uniforms.bumpmapMatrix4F[element / 2][element % 2][2] = value; | |
| uniforms.bumpmapMatrix4F[element / 2][element % 2][3] = value; | |
| uniforms.bumpmapMatrix4W[element / 2][element % 2][0] = iround(4095 * value); | |
| uniforms.bumpmapMatrix4W[element / 2][element % 2][1] = iround(4095 * value); | |
| uniforms.bumpmapMatrix4W[element / 2][element % 2][2] = iround(4095 * value); | |
| uniforms.bumpmapMatrix4W[element / 2][element % 2][3] = iround(4095 * value); | |
| } | |
| void TextureStage::setLuminanceScale(float value) | |
| { | |
| short scale = iround(4095 * value); | |
| uniforms.luminanceScale4[0] = uniforms.luminanceScale4[1] = uniforms.luminanceScale4[2] = uniforms.luminanceScale4[3] = scale; | |
| } | |
| void TextureStage::setLuminanceOffset(float value) | |
| { | |
| short offset = iround(4095 * value); | |
| uniforms.luminanceOffset4[0] = uniforms.luminanceOffset4[1] = uniforms.luminanceOffset4[2] = uniforms.luminanceOffset4[3] = offset; | |
| } | |
| void TextureStage::setTexCoordIndex(unsigned int texCoordIndex) | |
| { | |
| ASSERT(texCoordIndex < 8); | |
| this->texCoordIndex = texCoordIndex; | |
| } | |
| void TextureStage::setStageOperation(StageOperation stageOperation) | |
| { | |
| this->stageOperation = stageOperation; | |
| } | |
| void TextureStage::setFirstArgument(SourceArgument firstArgument) | |
| { | |
| this->firstArgument = firstArgument; | |
| } | |
| void TextureStage::setSecondArgument(SourceArgument secondArgument) | |
| { | |
| this->secondArgument = secondArgument; | |
| } | |
| void TextureStage::setThirdArgument(SourceArgument thirdArgument) | |
| { | |
| this->thirdArgument = thirdArgument; | |
| } | |
| void TextureStage::setStageOperationAlpha(StageOperation stageOperationAlpha) | |
| { | |
| this->stageOperationAlpha = stageOperationAlpha; | |
| } | |
| void TextureStage::setFirstArgumentAlpha(SourceArgument firstArgumentAlpha) | |
| { | |
| this->firstArgumentAlpha = firstArgumentAlpha; | |
| } | |
| void TextureStage::setSecondArgumentAlpha(SourceArgument secondArgumentAlpha) | |
| { | |
| this->secondArgumentAlpha = secondArgumentAlpha; | |
| } | |
| void TextureStage::setThirdArgumentAlpha(SourceArgument thirdArgumentAlpha) | |
| { | |
| this->thirdArgumentAlpha= thirdArgumentAlpha; | |
| } | |
| void TextureStage::setFirstModifier(ArgumentModifier firstModifier) | |
| { | |
| this->firstModifier = firstModifier; | |
| } | |
| void TextureStage::setSecondModifier(ArgumentModifier secondModifier) | |
| { | |
| this->secondModifier = secondModifier; | |
| } | |
| void TextureStage::setThirdModifier(ArgumentModifier thirdModifier) | |
| { | |
| this->thirdModifier = thirdModifier; | |
| } | |
| void TextureStage::setFirstModifierAlpha(ArgumentModifier firstModifierAlpha) | |
| { | |
| this->firstModifierAlpha = firstModifierAlpha; | |
| } | |
| void TextureStage::setSecondModifierAlpha(ArgumentModifier secondModifierAlpha) | |
| { | |
| this->secondModifierAlpha = secondModifierAlpha; | |
| } | |
| void TextureStage::setThirdModifierAlpha(ArgumentModifier thirdModifierAlpha) | |
| { | |
| this->thirdModifierAlpha = thirdModifierAlpha; | |
| } | |
| void TextureStage::setDestinationArgument(DestinationArgument destinationArgument) | |
| { | |
| this->destinationArgument = destinationArgument; | |
| } | |
| bool TextureStage::usesColor(SourceArgument source) const | |
| { | |
| // One argument | |
| if(stageOperation == STAGE_SELECTARG1 || stageOperation == STAGE_PREMODULATE) | |
| { | |
| return firstArgument == source; | |
| } | |
| else if(stageOperation == STAGE_SELECTARG2) | |
| { | |
| return secondArgument == source; | |
| } | |
| else if(stageOperation == STAGE_SELECTARG3) | |
| { | |
| return thirdArgument == source; | |
| } | |
| else | |
| { | |
| // Two arguments or more | |
| if(firstArgument == source || secondArgument == source) | |
| { | |
| return true; | |
| } | |
| // Three arguments | |
| if(stageOperation == STAGE_MULTIPLYADD || stageOperation == STAGE_LERP) | |
| { | |
| return thirdArgument == source; | |
| } | |
| } | |
| return false; | |
| } | |
| bool TextureStage::usesAlpha(SourceArgument source) const | |
| { | |
| if(stageOperationAlpha == STAGE_DISABLE) | |
| { | |
| return false; | |
| } | |
| if(source == SOURCE_TEXTURE) | |
| { | |
| if(stageOperation == STAGE_BLENDTEXTUREALPHA || stageOperation == STAGE_BLENDTEXTUREALPHAPM) | |
| { | |
| return true; | |
| } | |
| } | |
| else if(source == SOURCE_CURRENT) | |
| { | |
| if(stageOperation == STAGE_BLENDCURRENTALPHA) | |
| { | |
| return true; | |
| } | |
| } | |
| else if(source == SOURCE_DIFFUSE) | |
| { | |
| if(stageOperation == STAGE_BLENDDIFFUSEALPHA) | |
| { | |
| return true; | |
| } | |
| } | |
| else if(source == SOURCE_TFACTOR) | |
| { | |
| if(stageOperation == STAGE_BLENDFACTORALPHA) | |
| { | |
| return true; | |
| } | |
| } | |
| // One argument | |
| if(stageOperation == STAGE_SELECTARG1 || stageOperation == STAGE_PREMODULATE) | |
| { | |
| if(firstArgument == source && (firstModifier == MODIFIER_ALPHA || firstModifier == MODIFIER_INVALPHA)) | |
| { | |
| return true; | |
| } | |
| } | |
| else if(stageOperation == STAGE_SELECTARG2) | |
| { | |
| if(secondArgument == source && (secondModifier == MODIFIER_ALPHA || secondModifier == MODIFIER_INVALPHA)) | |
| { | |
| return true; | |
| } | |
| } | |
| else if(stageOperation == STAGE_SELECTARG3) | |
| { | |
| if(thirdArgument == source && (thirdModifier == MODIFIER_ALPHA || thirdModifier == MODIFIER_INVALPHA)) | |
| { | |
| return true; | |
| } | |
| } | |
| else | |
| { | |
| // Two arguments or more | |
| if(firstArgument == source || secondArgument == source) | |
| { | |
| if(firstArgument == source && (firstModifier == MODIFIER_ALPHA || firstModifier == MODIFIER_INVALPHA)) | |
| { | |
| return true; | |
| } | |
| if(secondArgument == source && (secondModifier == MODIFIER_ALPHA || secondModifier == MODIFIER_INVALPHA)) | |
| { | |
| return true; | |
| } | |
| } | |
| // Three arguments | |
| if(stageOperation == STAGE_MULTIPLYADD || stageOperation == STAGE_LERP) | |
| { | |
| if(thirdArgument == source && (thirdModifier == MODIFIER_ALPHA || thirdModifier == MODIFIER_INVALPHA)) | |
| { | |
| return true; | |
| } | |
| } | |
| } | |
| // One argument | |
| if(stageOperationAlpha == STAGE_SELECTARG1 || stageOperationAlpha == STAGE_PREMODULATE) | |
| { | |
| return firstArgumentAlpha == source; | |
| } | |
| else if(stageOperationAlpha == STAGE_SELECTARG2) | |
| { | |
| return secondArgumentAlpha == source; | |
| } | |
| else if(stageOperationAlpha == STAGE_SELECTARG3) | |
| { | |
| return thirdArgumentAlpha == source; | |
| } | |
| else | |
| { | |
| // Two arguments or more | |
| if(firstArgumentAlpha == source || secondArgumentAlpha == source) | |
| { | |
| return true; | |
| } | |
| // Three arguments | |
| if(stageOperationAlpha == STAGE_MULTIPLYADD || stageOperationAlpha == STAGE_LERP) | |
| { | |
| return thirdArgumentAlpha == source; | |
| } | |
| } | |
| return false; | |
| } | |
| bool TextureStage::uses(SourceArgument source) const | |
| { | |
| return usesColor(source) || usesAlpha(source); | |
| } | |
| bool TextureStage::usesCurrent() const | |
| { | |
| return uses(SOURCE_CURRENT) || (stageOperation == STAGE_BLENDCURRENTALPHA || stageOperationAlpha == STAGE_BLENDCURRENTALPHA); | |
| } | |
| bool TextureStage::usesDiffuse() const | |
| { | |
| return uses(SOURCE_DIFFUSE) || (stageOperation == STAGE_BLENDDIFFUSEALPHA || stageOperationAlpha == STAGE_BLENDDIFFUSEALPHA); | |
| } | |
| bool TextureStage::usesSpecular() const | |
| { | |
| return uses(SOURCE_SPECULAR); | |
| } | |
| bool TextureStage::usesTexture() const | |
| { | |
| return uses(SOURCE_TEXTURE) || | |
| stageOperation == STAGE_BLENDTEXTUREALPHA || | |
| stageOperationAlpha == STAGE_BLENDTEXTUREALPHA || | |
| stageOperation == STAGE_BLENDTEXTUREALPHAPM || | |
| stageOperationAlpha == STAGE_BLENDTEXTUREALPHAPM || | |
| (previousStage && previousStage->stageOperation == STAGE_PREMODULATE) || | |
| (previousStage && previousStage->stageOperationAlpha == STAGE_PREMODULATE); | |
| } | |
| bool TextureStage::isStageDisabled() const | |
| { | |
| bool disabled = (stageOperation == STAGE_DISABLE) || (!sampler->hasTexture() && usesTexture()); | |
| if(!previousStage || disabled) | |
| { | |
| return disabled; | |
| } | |
| else | |
| { | |
| return previousStage->isStageDisabled(); | |
| } | |
| } | |
| bool TextureStage::writesCurrent() const | |
| { | |
| return !isStageDisabled() && destinationArgument == DESTINATION_CURRENT && stageOperation != STAGE_BUMPENVMAP && stageOperation != STAGE_BUMPENVMAPLUMINANCE; | |
| } | |
| } |