| // 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 "Context.hpp" | |
| #include "Primitive.hpp" | |
| #include "Surface.hpp" | |
| #include "Shader/PixelShader.hpp" | |
| #include "Shader/VertexShader.hpp" | |
| #include "Common/Memory.hpp" | |
| #include "Common/Debug.hpp" | |
| #include <string.h> | |
| namespace sw | |
| { | |
| extern bool perspectiveCorrection; | |
| bool halfIntegerCoordinates = false; // Pixel centers are not at integer coordinates | |
| bool symmetricNormalizedDepth = false; // [-1, 1] instead of [0, 1] | |
| bool booleanFaceRegister = false; | |
| bool fullPixelPositionRegister = false; | |
| bool leadingVertexFirst = false; // Flat shading uses first vertex, else last | |
| bool secondaryColor = false; // Specular lighting is applied after texturing | |
| bool colorsDefaultToZero = false; | |
| bool forceWindowed = false; | |
| bool quadLayoutEnabled = false; | |
| bool veryEarlyDepthTest = true; | |
| bool complementaryDepthBuffer = false; | |
| bool postBlendSRGB = false; | |
| bool exactColorRounding = false; | |
| TransparencyAntialiasing transparencyAntialiasing = TRANSPARENCY_NONE; | |
| bool forceClearRegisters = false; | |
| Context::Context() | |
| { | |
| init(); | |
| } | |
| Context::~Context() | |
| { | |
| } | |
| void *Context::operator new(size_t bytes) | |
| { | |
| return allocate((unsigned int)bytes); | |
| } | |
| void Context::operator delete(void *pointer, size_t bytes) | |
| { | |
| deallocate(pointer); | |
| } | |
| bool Context::isDrawPoint(bool fillModeAware) const | |
| { | |
| switch(drawType) | |
| { | |
| case DRAW_POINTLIST: | |
| case DRAW_INDEXEDPOINTLIST8: | |
| case DRAW_INDEXEDPOINTLIST16: | |
| case DRAW_INDEXEDPOINTLIST32: | |
| return true; | |
| case DRAW_LINELIST: | |
| case DRAW_LINESTRIP: | |
| case DRAW_LINELOOP: | |
| case DRAW_INDEXEDLINELIST8: | |
| case DRAW_INDEXEDLINESTRIP8: | |
| case DRAW_INDEXEDLINELOOP8: | |
| case DRAW_INDEXEDLINELIST16: | |
| case DRAW_INDEXEDLINESTRIP16: | |
| case DRAW_INDEXEDLINELOOP16: | |
| case DRAW_INDEXEDLINELIST32: | |
| case DRAW_INDEXEDLINESTRIP32: | |
| case DRAW_INDEXEDLINELOOP32: | |
| return false; | |
| case DRAW_TRIANGLELIST: | |
| case DRAW_TRIANGLESTRIP: | |
| case DRAW_TRIANGLEFAN: | |
| case DRAW_INDEXEDTRIANGLELIST8: | |
| case DRAW_INDEXEDTRIANGLESTRIP8: | |
| case DRAW_INDEXEDTRIANGLEFAN8: | |
| case DRAW_INDEXEDTRIANGLELIST16: | |
| case DRAW_INDEXEDTRIANGLESTRIP16: | |
| case DRAW_INDEXEDTRIANGLEFAN16: | |
| case DRAW_INDEXEDTRIANGLELIST32: | |
| case DRAW_INDEXEDTRIANGLESTRIP32: | |
| case DRAW_INDEXEDTRIANGLEFAN32: | |
| return fillModeAware ? fillMode == FILL_VERTEX : false; | |
| case DRAW_QUADLIST: | |
| return false; | |
| default: | |
| ASSERT(false); | |
| } | |
| return false; | |
| } | |
| bool Context::isDrawLine(bool fillModeAware) const | |
| { | |
| switch(drawType) | |
| { | |
| case DRAW_POINTLIST: | |
| case DRAW_INDEXEDPOINTLIST8: | |
| case DRAW_INDEXEDPOINTLIST16: | |
| case DRAW_INDEXEDPOINTLIST32: | |
| return false; | |
| case DRAW_LINELIST: | |
| case DRAW_LINESTRIP: | |
| case DRAW_LINELOOP: | |
| case DRAW_INDEXEDLINELIST8: | |
| case DRAW_INDEXEDLINESTRIP8: | |
| case DRAW_INDEXEDLINELOOP8: | |
| case DRAW_INDEXEDLINELIST16: | |
| case DRAW_INDEXEDLINESTRIP16: | |
| case DRAW_INDEXEDLINELOOP16: | |
| case DRAW_INDEXEDLINELIST32: | |
| case DRAW_INDEXEDLINESTRIP32: | |
| case DRAW_INDEXEDLINELOOP32: | |
| return true; | |
| case DRAW_TRIANGLELIST: | |
| case DRAW_TRIANGLESTRIP: | |
| case DRAW_TRIANGLEFAN: | |
| case DRAW_INDEXEDTRIANGLELIST8: | |
| case DRAW_INDEXEDTRIANGLESTRIP8: | |
| case DRAW_INDEXEDTRIANGLEFAN8: | |
| case DRAW_INDEXEDTRIANGLELIST16: | |
| case DRAW_INDEXEDTRIANGLESTRIP16: | |
| case DRAW_INDEXEDTRIANGLEFAN16: | |
| case DRAW_INDEXEDTRIANGLELIST32: | |
| case DRAW_INDEXEDTRIANGLESTRIP32: | |
| case DRAW_INDEXEDTRIANGLEFAN32: | |
| return fillModeAware ? fillMode == FILL_WIREFRAME : false; | |
| case DRAW_QUADLIST: | |
| return false; | |
| default: | |
| ASSERT(false); | |
| } | |
| return false; | |
| } | |
| bool Context::isDrawTriangle(bool fillModeAware) const | |
| { | |
| switch(drawType) | |
| { | |
| case DRAW_POINTLIST: | |
| case DRAW_INDEXEDPOINTLIST8: | |
| case DRAW_INDEXEDPOINTLIST16: | |
| case DRAW_INDEXEDPOINTLIST32: | |
| return false; | |
| case DRAW_LINELIST: | |
| case DRAW_LINESTRIP: | |
| case DRAW_LINELOOP: | |
| case DRAW_INDEXEDLINELIST8: | |
| case DRAW_INDEXEDLINESTRIP8: | |
| case DRAW_INDEXEDLINELOOP8: | |
| case DRAW_INDEXEDLINELIST16: | |
| case DRAW_INDEXEDLINESTRIP16: | |
| case DRAW_INDEXEDLINELOOP16: | |
| case DRAW_INDEXEDLINELIST32: | |
| case DRAW_INDEXEDLINESTRIP32: | |
| case DRAW_INDEXEDLINELOOP32: | |
| return false; | |
| case DRAW_TRIANGLELIST: | |
| case DRAW_TRIANGLESTRIP: | |
| case DRAW_TRIANGLEFAN: | |
| case DRAW_INDEXEDTRIANGLELIST8: | |
| case DRAW_INDEXEDTRIANGLESTRIP8: | |
| case DRAW_INDEXEDTRIANGLEFAN8: | |
| case DRAW_INDEXEDTRIANGLELIST16: | |
| case DRAW_INDEXEDTRIANGLESTRIP16: | |
| case DRAW_INDEXEDTRIANGLEFAN16: | |
| case DRAW_INDEXEDTRIANGLELIST32: | |
| case DRAW_INDEXEDTRIANGLESTRIP32: | |
| case DRAW_INDEXEDTRIANGLEFAN32: | |
| return fillModeAware ? fillMode == FILL_SOLID : true; | |
| case DRAW_QUADLIST: | |
| // Quads are broken up into triangles | |
| return fillModeAware ? fillMode == FILL_SOLID : true; | |
| default: | |
| ASSERT(false); | |
| } | |
| return true; | |
| } | |
| void Context::init() | |
| { | |
| for(int i = 0; i < 8; i++) | |
| { | |
| textureStage[i].init(i, &sampler[i], (i >= 1) ? &textureStage[i - 1] : 0); | |
| } | |
| // Set vertex streams to null stream | |
| for(int i = 0; i < MAX_VERTEX_INPUTS; i++) | |
| { | |
| input[i].defaults(); | |
| } | |
| fogStart = 0.0f; | |
| fogEnd = 1.0f; | |
| for(int i = 0; i < TEXTURE_IMAGE_UNITS; i++) textureWrap[i] = 0; | |
| for(int i = 0; i < 8; i++) texGen[i] = TEXGEN_PASSTHRU; | |
| for(int i = 0; i < 8; i++) textureTransformCount[i] = 0; | |
| for(int i = 0; i < 8; i++) textureTransformProject[i] = false; | |
| textureWrapActive = false; | |
| localViewer = true; | |
| normalizeNormals = false; | |
| for(int i = 0; i < RENDERTARGETS; ++i) | |
| { | |
| renderTarget[i] = nullptr; | |
| } | |
| depthBuffer = nullptr; | |
| stencilBuffer = nullptr; | |
| stencilEnable = false; | |
| stencilCompareMode = STENCIL_ALWAYS; | |
| stencilReference = 0; | |
| stencilMask = 0xFFFFFFFF; | |
| stencilFailOperation = OPERATION_KEEP; | |
| stencilPassOperation = OPERATION_KEEP; | |
| stencilZFailOperation = OPERATION_KEEP; | |
| stencilWriteMask = 0xFFFFFFFF; | |
| twoSidedStencil = false; | |
| stencilCompareModeCCW = STENCIL_ALWAYS; | |
| stencilReferenceCCW = 0; | |
| stencilMaskCCW = 0xFFFFFFFF; | |
| stencilFailOperationCCW = OPERATION_KEEP; | |
| stencilPassOperationCCW = OPERATION_KEEP; | |
| stencilZFailOperationCCW = OPERATION_KEEP; | |
| stencilWriteMaskCCW = 0xFFFFFFFF; | |
| setGlobalMipmapBias(0); | |
| lightingEnable = true; | |
| specularEnable = false; | |
| for(int i = 0; i < 8; i++) lightEnable[i] = false; | |
| for(int i = 0; i < 8; i++) worldLightPosition[i] = 0; | |
| alphaCompareMode = ALPHA_ALWAYS; | |
| alphaTestEnable = false; | |
| fillMode = FILL_SOLID; | |
| shadingMode = SHADING_GOURAUD; | |
| rasterizerDiscard = false; | |
| depthCompareMode = DEPTH_LESS; | |
| depthBufferEnable = true; | |
| depthWriteEnable = true; | |
| alphaBlendEnable = false; | |
| sourceBlendFactorState = BLEND_ONE; | |
| destBlendFactorState = BLEND_ZERO; | |
| blendOperationState = BLENDOP_ADD; | |
| separateAlphaBlendEnable = false; | |
| sourceBlendFactorStateAlpha = BLEND_ONE; | |
| destBlendFactorStateAlpha = BLEND_ZERO; | |
| blendOperationStateAlpha = BLENDOP_ADD; | |
| cullMode = CULL_CLOCKWISE; | |
| frontFacingCCW = true; | |
| alphaReference = 0.0f; | |
| depthBias = 0.0f; | |
| slopeDepthBias = 0.0f; | |
| for(int i = 0; i < RENDERTARGETS; i++) | |
| { | |
| colorWriteMask[i] = 0x0000000F; | |
| } | |
| ambientMaterialSource = MATERIAL_MATERIAL; | |
| diffuseMaterialSource = MATERIAL_COLOR1; | |
| specularMaterialSource = MATERIAL_COLOR2; | |
| emissiveMaterialSource = MATERIAL_MATERIAL; | |
| colorVertexEnable = true; | |
| fogEnable = false; | |
| pixelFogMode = FOG_NONE; | |
| vertexFogMode = FOG_NONE; | |
| wBasedFog = false; | |
| rangeFogEnable = false; | |
| indexedVertexBlendEnable = false; | |
| vertexBlendMatrixCount = 0; | |
| pixelShader = 0; | |
| vertexShader = 0; | |
| instanceID = 0; | |
| occlusionEnabled = false; | |
| transformFeedbackQueryEnabled = false; | |
| transformFeedbackEnabled = 0; | |
| pointSpriteEnable = false; | |
| pointScaleEnable = false; | |
| lineWidth = 1.0f; | |
| writeSRGB = false; | |
| sampleMask = 0xFFFFFFFF; | |
| colorLogicOpEnabled = false; | |
| logicalOperation = LOGICALOP_COPY; | |
| } | |
| const float &Context::exp2Bias() | |
| { | |
| return bias; | |
| } | |
| const Point &Context::getLightPosition(int light) | |
| { | |
| return worldLightPosition[light]; | |
| } | |
| void Context::setGlobalMipmapBias(float bias) | |
| { | |
| this->bias = exp2(bias + 0.5f); | |
| } | |
| void Context::setLightingEnable(bool lightingEnable) | |
| { | |
| this->lightingEnable = lightingEnable; | |
| } | |
| void Context::setSpecularEnable(bool specularEnable) | |
| { | |
| Context::specularEnable = specularEnable; | |
| } | |
| void Context::setLightEnable(int light, bool lightEnable) | |
| { | |
| Context::lightEnable[light] = lightEnable; | |
| } | |
| void Context::setLightPosition(int light, Point worldLightPosition) | |
| { | |
| Context::worldLightPosition[light] = worldLightPosition; | |
| } | |
| void Context::setAmbientMaterialSource(MaterialSource ambientMaterialSource) | |
| { | |
| Context::ambientMaterialSource = ambientMaterialSource; | |
| } | |
| void Context::setDiffuseMaterialSource(MaterialSource diffuseMaterialSource) | |
| { | |
| Context::diffuseMaterialSource = diffuseMaterialSource; | |
| } | |
| void Context::setSpecularMaterialSource(MaterialSource specularMaterialSource) | |
| { | |
| Context::specularMaterialSource = specularMaterialSource; | |
| } | |
| void Context::setEmissiveMaterialSource(MaterialSource emissiveMaterialSource) | |
| { | |
| Context::emissiveMaterialSource = emissiveMaterialSource; | |
| } | |
| void Context::setPointSpriteEnable(bool pointSpriteEnable) | |
| { | |
| Context::pointSpriteEnable = pointSpriteEnable; | |
| } | |
| void Context::setPointScaleEnable(bool pointScaleEnable) | |
| { | |
| Context::pointScaleEnable = pointScaleEnable; | |
| } | |
| bool Context::setDepthBufferEnable(bool depthBufferEnable) | |
| { | |
| bool modified = (Context::depthBufferEnable != depthBufferEnable); | |
| Context::depthBufferEnable = depthBufferEnable; | |
| return modified; | |
| } | |
| bool Context::setAlphaBlendEnable(bool alphaBlendEnable) | |
| { | |
| bool modified = (Context::alphaBlendEnable != alphaBlendEnable); | |
| Context::alphaBlendEnable = alphaBlendEnable; | |
| return modified; | |
| } | |
| bool Context::setSourceBlendFactor(BlendFactor sourceBlendFactor) | |
| { | |
| bool modified = (Context::sourceBlendFactorState != sourceBlendFactor); | |
| Context::sourceBlendFactorState = sourceBlendFactor; | |
| return modified; | |
| } | |
| bool Context::setDestBlendFactor(BlendFactor destBlendFactor) | |
| { | |
| bool modified = (Context::destBlendFactorState != destBlendFactor); | |
| Context::destBlendFactorState = destBlendFactor; | |
| return modified; | |
| } | |
| bool Context::setBlendOperation(BlendOperation blendOperation) | |
| { | |
| bool modified = (Context::blendOperationState != blendOperation); | |
| Context::blendOperationState = blendOperation; | |
| return modified; | |
| } | |
| bool Context::setSeparateAlphaBlendEnable(bool separateAlphaBlendEnable) | |
| { | |
| bool modified = (Context::separateAlphaBlendEnable != separateAlphaBlendEnable); | |
| Context::separateAlphaBlendEnable = separateAlphaBlendEnable; | |
| return modified; | |
| } | |
| bool Context::setSourceBlendFactorAlpha(BlendFactor sourceBlendFactorAlpha) | |
| { | |
| bool modified = (Context::sourceBlendFactorStateAlpha != sourceBlendFactorAlpha); | |
| Context::sourceBlendFactorStateAlpha = sourceBlendFactorAlpha; | |
| return modified; | |
| } | |
| bool Context::setDestBlendFactorAlpha(BlendFactor destBlendFactorAlpha) | |
| { | |
| bool modified = (Context::destBlendFactorStateAlpha != destBlendFactorAlpha); | |
| Context::destBlendFactorStateAlpha = destBlendFactorAlpha; | |
| return modified; | |
| } | |
| bool Context::setBlendOperationAlpha(BlendOperation blendOperationAlpha) | |
| { | |
| bool modified = (Context::blendOperationStateAlpha != blendOperationAlpha); | |
| Context::blendOperationStateAlpha = blendOperationAlpha; | |
| return modified; | |
| } | |
| bool Context::setColorWriteMask(int index, int colorWriteMask) | |
| { | |
| bool modified = (Context::colorWriteMask[index] != colorWriteMask); | |
| Context::colorWriteMask[index] = colorWriteMask; | |
| return modified; | |
| } | |
| bool Context::setWriteSRGB(bool sRGB) | |
| { | |
| bool modified = (Context::writeSRGB != sRGB); | |
| Context::writeSRGB = sRGB; | |
| return modified; | |
| } | |
| bool Context::setColorLogicOpEnabled(bool enabled) | |
| { | |
| bool modified = (Context::colorLogicOpEnabled != enabled); | |
| Context::colorLogicOpEnabled = enabled; | |
| return modified; | |
| } | |
| bool Context::setLogicalOperation(LogicalOperation logicalOperation) | |
| { | |
| bool modified = (Context::logicalOperation != logicalOperation); | |
| Context::logicalOperation = logicalOperation; | |
| return modified; | |
| } | |
| void Context::setColorVertexEnable(bool colorVertexEnable) | |
| { | |
| Context::colorVertexEnable = colorVertexEnable; | |
| } | |
| bool Context::fogActive() | |
| { | |
| if(!colorUsed()) return false; | |
| if(pixelShaderModel() >= 0x0300) return false; | |
| return fogEnable; | |
| } | |
| bool Context::pointSizeActive() | |
| { | |
| if(vertexShader) | |
| { | |
| return false; | |
| } | |
| return isDrawPoint(true) && (input[PointSize] || (!preTransformed && pointScaleActive())); | |
| } | |
| FogMode Context::pixelFogActive() | |
| { | |
| if(fogActive()) | |
| { | |
| return pixelFogMode; | |
| } | |
| return FOG_NONE; | |
| } | |
| bool Context::depthWriteActive() | |
| { | |
| if(!depthBufferActive()) return false; | |
| return depthWriteEnable; | |
| } | |
| bool Context::alphaTestActive() | |
| { | |
| if(transparencyAntialiasing != TRANSPARENCY_NONE) return true; | |
| if(!alphaTestEnable) return false; | |
| if(alphaCompareMode == ALPHA_ALWAYS) return false; | |
| if(alphaReference == 0.0f && alphaCompareMode == ALPHA_GREATEREQUAL) return false; | |
| return true; | |
| } | |
| bool Context::depthBufferActive() | |
| { | |
| return depthBuffer && depthBufferEnable; | |
| } | |
| bool Context::stencilActive() | |
| { | |
| return stencilBuffer && stencilEnable; | |
| } | |
| bool Context::vertexLightingActive() | |
| { | |
| if(vertexShader) | |
| { | |
| return false; | |
| } | |
| return lightingEnable && !preTransformed; | |
| } | |
| bool Context::texCoordActive(int coordinate, int component) | |
| { | |
| bool hasTexture = pointSpriteActive(); | |
| if(vertexShader) | |
| { | |
| if(!preTransformed) | |
| { | |
| if(vertexShader->getOutput(T0 + coordinate, component).usage == Shader::USAGE_TEXCOORD) | |
| { | |
| hasTexture = true; | |
| } | |
| } | |
| else | |
| { | |
| hasTexture = true; // FIXME: Check vertex buffer streams | |
| } | |
| } | |
| else | |
| { | |
| switch(texGen[coordinate]) | |
| { | |
| case TEXGEN_NONE: | |
| hasTexture = true; | |
| break; | |
| case TEXGEN_PASSTHRU: | |
| hasTexture = hasTexture || (component < input[TexCoord0 + textureStage[coordinate].texCoordIndex].count); | |
| break; | |
| case TEXGEN_NORMAL: | |
| hasTexture = hasTexture || (component <= 2); | |
| break; | |
| case TEXGEN_POSITION: | |
| hasTexture = hasTexture || (component <= 2); | |
| break; | |
| case TEXGEN_REFLECTION: | |
| hasTexture = hasTexture || (component <= 2); | |
| break; | |
| case TEXGEN_SPHEREMAP: | |
| hasTexture = hasTexture || (component <= 1); | |
| break; | |
| default: | |
| ASSERT(false); | |
| } | |
| } | |
| bool project = isProjectionComponent(coordinate, component); | |
| bool usesTexture = false; | |
| if(pixelShader) | |
| { | |
| usesTexture = pixelShader->usesTexture(coordinate, component) || project; | |
| } | |
| else | |
| { | |
| usesTexture = textureStage[coordinate].usesTexture() || project; | |
| } | |
| return hasTexture && usesTexture; | |
| } | |
| bool Context::texCoordActive(int coordinate) | |
| { | |
| return texCoordActive(coordinate, 0) || | |
| texCoordActive(coordinate, 1) || | |
| texCoordActive(coordinate, 2) || | |
| texCoordActive(coordinate, 3); | |
| } | |
| bool Context::isProjectionComponent(unsigned int coordinate, int component) | |
| { | |
| if(pixelShaderModel() <= 0x0103 && coordinate < 8 && textureTransformProject[coordinate]) | |
| { | |
| if(textureTransformCount[coordinate] == 2) | |
| { | |
| if(component == 1) return true; | |
| } | |
| else if(textureTransformCount[coordinate] == 3) | |
| { | |
| if(component == 2) return true; | |
| } | |
| else if(textureTransformCount[coordinate] == 4 || textureTransformCount[coordinate] == 0) | |
| { | |
| if(component == 3) return true; | |
| } | |
| } | |
| return false; | |
| } | |
| bool Context::vertexSpecularActive() | |
| { | |
| return vertexLightingActive() && specularEnable && vertexNormalActive(); | |
| } | |
| bool Context::vertexNormalActive() | |
| { | |
| if(vertexShader) | |
| { | |
| return false; | |
| } | |
| return input[Normal]; | |
| } | |
| bool Context::vertexLightActive(int i) | |
| { | |
| if(vertexShader) | |
| { | |
| return false; | |
| } | |
| return lightingEnable && lightEnable[i]; | |
| } | |
| MaterialSource Context::vertexDiffuseMaterialSourceActive() | |
| { | |
| if(vertexShader) | |
| { | |
| return MATERIAL_MATERIAL; | |
| } | |
| if(diffuseMaterialSource == MATERIAL_MATERIAL || !colorVertexEnable || | |
| (diffuseMaterialSource == MATERIAL_COLOR1 && !input[Color0]) || | |
| (diffuseMaterialSource == MATERIAL_COLOR2 && !input[Color1])) | |
| { | |
| return MATERIAL_MATERIAL; | |
| } | |
| return diffuseMaterialSource; | |
| } | |
| MaterialSource Context::vertexSpecularMaterialSourceActive() | |
| { | |
| if(vertexShader) | |
| { | |
| return MATERIAL_MATERIAL; | |
| } | |
| if(!colorVertexEnable || | |
| (specularMaterialSource == MATERIAL_COLOR1 && !input[Color0]) || | |
| (specularMaterialSource == MATERIAL_COLOR2 && !input[Color1])) | |
| { | |
| return MATERIAL_MATERIAL; | |
| } | |
| return specularMaterialSource; | |
| } | |
| MaterialSource Context::vertexAmbientMaterialSourceActive() | |
| { | |
| if(vertexShader) | |
| { | |
| return MATERIAL_MATERIAL; | |
| } | |
| if(!colorVertexEnable || | |
| (ambientMaterialSource == MATERIAL_COLOR1 && !input[Color0]) || | |
| (ambientMaterialSource == MATERIAL_COLOR2 && !input[Color1])) | |
| { | |
| return MATERIAL_MATERIAL; | |
| } | |
| return ambientMaterialSource; | |
| } | |
| MaterialSource Context::vertexEmissiveMaterialSourceActive() | |
| { | |
| if(vertexShader) | |
| { | |
| return MATERIAL_MATERIAL; | |
| } | |
| if(!colorVertexEnable || | |
| (emissiveMaterialSource == MATERIAL_COLOR1 && !input[Color0]) || | |
| (emissiveMaterialSource == MATERIAL_COLOR2 && !input[Color1])) | |
| { | |
| return MATERIAL_MATERIAL; | |
| } | |
| return emissiveMaterialSource; | |
| } | |
| bool Context::pointSpriteActive() | |
| { | |
| return isDrawPoint(true) && pointSpriteEnable; | |
| } | |
| bool Context::pointScaleActive() | |
| { | |
| if(vertexShader) | |
| { | |
| return false; | |
| } | |
| return isDrawPoint(true) && pointScaleEnable; | |
| } | |
| bool Context::alphaBlendActive() | |
| { | |
| if(!alphaBlendEnable) | |
| { | |
| return false; | |
| } | |
| if(!colorUsed()) | |
| { | |
| return false; | |
| } | |
| bool colorBlend = !(blendOperation() == BLENDOP_SOURCE && sourceBlendFactor() == BLEND_ONE); | |
| bool alphaBlend = separateAlphaBlendEnable ? !(blendOperationAlpha() == BLENDOP_SOURCE && sourceBlendFactorAlpha() == BLEND_ONE) : colorBlend; | |
| return colorBlend || alphaBlend; | |
| } | |
| LogicalOperation Context::colorLogicOp() | |
| { | |
| return colorLogicOpEnabled ? logicalOperation : LOGICALOP_COPY; | |
| } | |
| BlendFactor Context::sourceBlendFactor() | |
| { | |
| if(!alphaBlendEnable) return BLEND_ONE; | |
| switch(blendOperationState) | |
| { | |
| case BLENDOP_ADD: | |
| case BLENDOP_SUB: | |
| case BLENDOP_INVSUB: | |
| return sourceBlendFactorState; | |
| case BLENDOP_MIN: | |
| return BLEND_ONE; | |
| case BLENDOP_MAX: | |
| return BLEND_ONE; | |
| default: | |
| ASSERT(false); | |
| } | |
| return sourceBlendFactorState; | |
| } | |
| BlendFactor Context::destBlendFactor() | |
| { | |
| if(!alphaBlendEnable) return BLEND_ZERO; | |
| switch(blendOperationState) | |
| { | |
| case BLENDOP_ADD: | |
| case BLENDOP_SUB: | |
| case BLENDOP_INVSUB: | |
| return destBlendFactorState; | |
| case BLENDOP_MIN: | |
| return BLEND_ONE; | |
| case BLENDOP_MAX: | |
| return BLEND_ONE; | |
| default: | |
| ASSERT(false); | |
| } | |
| return destBlendFactorState; | |
| } | |
| BlendOperation Context::blendOperation() | |
| { | |
| if(!alphaBlendEnable) return BLENDOP_SOURCE; | |
| switch(blendOperationState) | |
| { | |
| case BLENDOP_ADD: | |
| if(sourceBlendFactor() == BLEND_ZERO) | |
| { | |
| if(destBlendFactor() == BLEND_ZERO) | |
| { | |
| return BLENDOP_NULL; | |
| } | |
| else | |
| { | |
| return BLENDOP_DEST; | |
| } | |
| } | |
| else if(sourceBlendFactor() == BLEND_ONE) | |
| { | |
| if(destBlendFactor() == BLEND_ZERO) | |
| { | |
| return BLENDOP_SOURCE; | |
| } | |
| else | |
| { | |
| return BLENDOP_ADD; | |
| } | |
| } | |
| else | |
| { | |
| if(destBlendFactor() == BLEND_ZERO) | |
| { | |
| return BLENDOP_SOURCE; | |
| } | |
| else | |
| { | |
| return BLENDOP_ADD; | |
| } | |
| } | |
| case BLENDOP_SUB: | |
| if(sourceBlendFactor() == BLEND_ZERO) | |
| { | |
| return BLENDOP_NULL; // Negative, clamped to zero | |
| } | |
| else if(sourceBlendFactor() == BLEND_ONE) | |
| { | |
| if(destBlendFactor() == BLEND_ZERO) | |
| { | |
| return BLENDOP_SOURCE; | |
| } | |
| else | |
| { | |
| return BLENDOP_SUB; | |
| } | |
| } | |
| else | |
| { | |
| if(destBlendFactor() == BLEND_ZERO) | |
| { | |
| return BLENDOP_SOURCE; | |
| } | |
| else | |
| { | |
| return BLENDOP_SUB; | |
| } | |
| } | |
| case BLENDOP_INVSUB: | |
| if(sourceBlendFactor() == BLEND_ZERO) | |
| { | |
| if(destBlendFactor() == BLEND_ZERO) | |
| { | |
| return BLENDOP_NULL; | |
| } | |
| else | |
| { | |
| return BLENDOP_DEST; | |
| } | |
| } | |
| else if(sourceBlendFactor() == BLEND_ONE) | |
| { | |
| if(destBlendFactor() == BLEND_ZERO) | |
| { | |
| return BLENDOP_NULL; // Negative, clamped to zero | |
| } | |
| else | |
| { | |
| return BLENDOP_INVSUB; | |
| } | |
| } | |
| else | |
| { | |
| if(destBlendFactor() == BLEND_ZERO) | |
| { | |
| return BLENDOP_NULL; // Negative, clamped to zero | |
| } | |
| else | |
| { | |
| return BLENDOP_INVSUB; | |
| } | |
| } | |
| case BLENDOP_MIN: | |
| return BLENDOP_MIN; | |
| case BLENDOP_MAX: | |
| return BLENDOP_MAX; | |
| default: | |
| ASSERT(false); | |
| } | |
| return blendOperationState; | |
| } | |
| BlendFactor Context::sourceBlendFactorAlpha() | |
| { | |
| if(!separateAlphaBlendEnable) | |
| { | |
| return sourceBlendFactor(); | |
| } | |
| else | |
| { | |
| switch(blendOperationStateAlpha) | |
| { | |
| case BLENDOP_ADD: | |
| case BLENDOP_SUB: | |
| case BLENDOP_INVSUB: | |
| return sourceBlendFactorStateAlpha; | |
| case BLENDOP_MIN: | |
| return BLEND_ONE; | |
| case BLENDOP_MAX: | |
| return BLEND_ONE; | |
| default: | |
| ASSERT(false); | |
| } | |
| return sourceBlendFactorStateAlpha; | |
| } | |
| } | |
| BlendFactor Context::destBlendFactorAlpha() | |
| { | |
| if(!separateAlphaBlendEnable) | |
| { | |
| return destBlendFactor(); | |
| } | |
| else | |
| { | |
| switch(blendOperationStateAlpha) | |
| { | |
| case BLENDOP_ADD: | |
| case BLENDOP_SUB: | |
| case BLENDOP_INVSUB: | |
| return destBlendFactorStateAlpha; | |
| case BLENDOP_MIN: | |
| return BLEND_ONE; | |
| case BLENDOP_MAX: | |
| return BLEND_ONE; | |
| default: | |
| ASSERT(false); | |
| } | |
| return destBlendFactorStateAlpha; | |
| } | |
| } | |
| BlendOperation Context::blendOperationAlpha() | |
| { | |
| if(!separateAlphaBlendEnable) | |
| { | |
| return blendOperation(); | |
| } | |
| else | |
| { | |
| switch(blendOperationStateAlpha) | |
| { | |
| case BLENDOP_ADD: | |
| if(sourceBlendFactorAlpha() == BLEND_ZERO) | |
| { | |
| if(destBlendFactorAlpha() == BLEND_ZERO) | |
| { | |
| return BLENDOP_NULL; | |
| } | |
| else | |
| { | |
| return BLENDOP_DEST; | |
| } | |
| } | |
| else if(sourceBlendFactorAlpha() == BLEND_ONE) | |
| { | |
| if(destBlendFactorAlpha() == BLEND_ZERO) | |
| { | |
| return BLENDOP_SOURCE; | |
| } | |
| else | |
| { | |
| return BLENDOP_ADD; | |
| } | |
| } | |
| else | |
| { | |
| if(destBlendFactorAlpha() == BLEND_ZERO) | |
| { | |
| return BLENDOP_SOURCE; | |
| } | |
| else | |
| { | |
| return BLENDOP_ADD; | |
| } | |
| } | |
| case BLENDOP_SUB: | |
| if(sourceBlendFactorAlpha() == BLEND_ZERO) | |
| { | |
| return BLENDOP_NULL; // Negative, clamped to zero | |
| } | |
| else if(sourceBlendFactorAlpha() == BLEND_ONE) | |
| { | |
| if(destBlendFactorAlpha() == BLEND_ZERO) | |
| { | |
| return BLENDOP_SOURCE; | |
| } | |
| else | |
| { | |
| return BLENDOP_SUB; | |
| } | |
| } | |
| else | |
| { | |
| if(destBlendFactorAlpha() == BLEND_ZERO) | |
| { | |
| return BLENDOP_SOURCE; | |
| } | |
| else | |
| { | |
| return BLENDOP_SUB; | |
| } | |
| } | |
| case BLENDOP_INVSUB: | |
| if(sourceBlendFactorAlpha() == BLEND_ZERO) | |
| { | |
| if(destBlendFactorAlpha() == BLEND_ZERO) | |
| { | |
| return BLENDOP_NULL; | |
| } | |
| else | |
| { | |
| return BLENDOP_DEST; | |
| } | |
| } | |
| else if(sourceBlendFactorAlpha() == BLEND_ONE) | |
| { | |
| if(destBlendFactorAlpha() == BLEND_ZERO) | |
| { | |
| return BLENDOP_NULL; // Negative, clamped to zero | |
| } | |
| else | |
| { | |
| return BLENDOP_INVSUB; | |
| } | |
| } | |
| else | |
| { | |
| if(destBlendFactorAlpha() == BLEND_ZERO) | |
| { | |
| return BLENDOP_NULL; // Negative, clamped to zero | |
| } | |
| else | |
| { | |
| return BLENDOP_INVSUB; | |
| } | |
| } | |
| case BLENDOP_MIN: | |
| return BLENDOP_MIN; | |
| case BLENDOP_MAX: | |
| return BLENDOP_MAX; | |
| default: | |
| ASSERT(false); | |
| } | |
| return blendOperationStateAlpha; | |
| } | |
| } | |
| bool Context::indexedVertexBlendActive() | |
| { | |
| if(vertexShader) | |
| { | |
| return false; | |
| } | |
| return indexedVertexBlendEnable; | |
| } | |
| int Context::vertexBlendMatrixCountActive() | |
| { | |
| if(vertexShader) | |
| { | |
| return 0; | |
| } | |
| return vertexBlendMatrixCount; | |
| } | |
| bool Context::localViewerActive() | |
| { | |
| if(vertexShader) | |
| { | |
| return false; | |
| } | |
| return localViewer; | |
| } | |
| bool Context::normalizeNormalsActive() | |
| { | |
| if(vertexShader) | |
| { | |
| return false; | |
| } | |
| return normalizeNormals; | |
| } | |
| FogMode Context::vertexFogModeActive() | |
| { | |
| if(vertexShader || !fogActive()) | |
| { | |
| return FOG_NONE; | |
| } | |
| return vertexFogMode; | |
| } | |
| bool Context::rangeFogActive() | |
| { | |
| if(vertexShader || !fogActive()) | |
| { | |
| return false; | |
| } | |
| return rangeFogEnable; | |
| } | |
| TexGen Context::texGenActive(int stage) | |
| { | |
| if(vertexShader || !texCoordActive(stage)) | |
| { | |
| return TEXGEN_PASSTHRU; | |
| } | |
| return texGen[stage]; | |
| } | |
| int Context::textureTransformCountActive(int stage) | |
| { | |
| if(vertexShader || !texCoordActive(stage)) | |
| { | |
| return 0; | |
| } | |
| return textureTransformCount[stage]; | |
| } | |
| int Context::texCoordIndexActive(int stage) | |
| { | |
| if(vertexShader || !texCoordActive(stage)) | |
| { | |
| return stage; | |
| } | |
| return textureStage[stage].texCoordIndex; | |
| } | |
| bool Context::perspectiveActive() | |
| { | |
| if(!colorUsed()) | |
| { | |
| return false; | |
| } | |
| if(!perspectiveCorrection) | |
| { | |
| return false; | |
| } | |
| if(isDrawPoint(true)) | |
| { | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool Context::diffuseUsed() | |
| { | |
| return diffuseUsed(0) || diffuseUsed(1) || diffuseUsed(2) || diffuseUsed(3); | |
| } | |
| bool Context::diffuseUsed(int component) | |
| { | |
| if(!colorUsed()) | |
| { | |
| return false; | |
| } | |
| if(pixelShader) | |
| { | |
| return pixelShader->usesDiffuse(component); | |
| } | |
| // Directly using the diffuse input color | |
| for(int i = 0; i < 8; i++) | |
| { | |
| if(textureStage[i].isStageDisabled()) | |
| { | |
| break; | |
| } | |
| if(textureStage[i].usesDiffuse()) | |
| { | |
| return true; | |
| } | |
| } | |
| // Using the current color (initialized to diffuse) before it's overwritten | |
| for(int i = 0; i < 8; i++) | |
| { | |
| if(textureStage[i].usesCurrent() || textureStage[i].isStageDisabled()) // Current color contains diffuse before being overwritten | |
| { | |
| return true; | |
| } | |
| if(textureStage[i].writesCurrent()) | |
| { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| bool Context::diffuseActive() | |
| { | |
| return diffuseActive(0) || diffuseActive(1) || diffuseActive(2) || diffuseActive(3); | |
| } | |
| bool Context::diffuseActive(int component) | |
| { | |
| if(!colorUsed()) | |
| { | |
| return false; | |
| } | |
| // Vertex processor provides diffuse component | |
| bool vertexDiffuse; | |
| if(vertexShader) | |
| { | |
| vertexDiffuse = vertexShader->getOutput(C0, component).active(); | |
| } | |
| else if(!preTransformed) | |
| { | |
| vertexDiffuse = input[Color0] || lightingEnable; | |
| } | |
| else | |
| { | |
| vertexDiffuse = input[Color0]; | |
| } | |
| // Pixel processor requires diffuse component | |
| bool pixelDiffuse = diffuseUsed(component); | |
| return vertexDiffuse && pixelDiffuse; | |
| } | |
| bool Context::specularUsed() | |
| { | |
| return Context::specularUsed(0) || Context::specularUsed(1) || Context::specularUsed(2) || Context::specularUsed(3); | |
| } | |
| bool Context::specularUsed(int component) | |
| { | |
| if(!colorUsed()) | |
| { | |
| return false; | |
| } | |
| if(pixelShader) | |
| { | |
| return pixelShader->usesSpecular(component); | |
| } | |
| bool pixelSpecular = specularEnable; | |
| for(int i = 0; i < 8; i++) | |
| { | |
| if(textureStage[i].isStageDisabled()) break; | |
| pixelSpecular = pixelSpecular || textureStage[i].usesSpecular(); | |
| } | |
| return pixelSpecular; | |
| } | |
| bool Context::specularActive() | |
| { | |
| return specularActive(0) || specularActive(1) || specularActive(2) || specularActive(3); | |
| } | |
| bool Context::specularActive(int component) | |
| { | |
| if(!colorUsed()) | |
| { | |
| return false; | |
| } | |
| // Vertex processor provides specular component | |
| bool vertexSpecular; | |
| if(!vertexShader) | |
| { | |
| vertexSpecular = input[Color1] || (lightingEnable && specularEnable); | |
| } | |
| else | |
| { | |
| vertexSpecular = vertexShader->getOutput(C1, component).active(); | |
| } | |
| // Pixel processor requires specular component | |
| bool pixelSpecular = specularUsed(component); | |
| return vertexSpecular && pixelSpecular; | |
| } | |
| bool Context::colorActive(int color, int component) | |
| { | |
| if(color == 0) | |
| { | |
| return diffuseActive(component); | |
| } | |
| else | |
| { | |
| return specularActive(component); | |
| } | |
| } | |
| bool Context::textureActive() | |
| { | |
| for(int i = 0; i < 8; i++) | |
| { | |
| if(textureActive(i)) | |
| { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| bool Context::textureActive(int coordinate) | |
| { | |
| return textureActive(coordinate, 0) || textureActive(coordinate, 1) || textureActive(coordinate, 2) || textureActive(coordinate, 3); | |
| } | |
| bool Context::textureActive(int coordinate, int component) | |
| { | |
| if(!colorUsed()) | |
| { | |
| return false; | |
| } | |
| if(!texCoordActive(coordinate, component)) | |
| { | |
| return false; | |
| } | |
| if(textureTransformProject[coordinate] && pixelShaderModel() <= 0x0103) | |
| { | |
| if(textureTransformCount[coordinate] == 2) | |
| { | |
| if(component == 1) return true; | |
| } | |
| else if(textureTransformCount[coordinate] == 3) | |
| { | |
| if(component == 2) return true; | |
| } | |
| else if(textureTransformCount[coordinate] == 4 || textureTransformCount[coordinate] == 0) | |
| { | |
| if(component == 3) return true; | |
| } | |
| } | |
| if(!pixelShader) | |
| { | |
| bool texture = textureStage[coordinate].usesTexture(); | |
| bool cube = sampler[coordinate].hasCubeTexture(); | |
| bool volume = sampler[coordinate].hasVolumeTexture(); | |
| if(texture) | |
| { | |
| for(int i = coordinate; i >= 0; i--) | |
| { | |
| if(textureStage[i].stageOperation == TextureStage::STAGE_DISABLE) | |
| { | |
| return false; | |
| } | |
| } | |
| } | |
| switch(component) | |
| { | |
| case 0: | |
| return texture; | |
| case 1: | |
| return texture; | |
| case 2: | |
| return (texture && (cube || volume)); | |
| case 3: | |
| return false; | |
| } | |
| } | |
| else | |
| { | |
| return pixelShader->usesTexture(coordinate, component); | |
| } | |
| return false; | |
| } | |
| unsigned short Context::pixelShaderModel() const | |
| { | |
| return pixelShader ? pixelShader->getShaderModel() : 0x0000; | |
| } | |
| unsigned short Context::vertexShaderModel() const | |
| { | |
| return vertexShader ? vertexShader->getShaderModel() : 0x0000; | |
| } | |
| int Context::getMultiSampleCount() const | |
| { | |
| return renderTarget[0] ? renderTarget[0]->getMultiSampleCount() : 1; | |
| } | |
| int Context::getSuperSampleCount() const | |
| { | |
| return renderTarget[0] ? renderTarget[0]->getSuperSampleCount() : 1; | |
| } | |
| Format Context::renderTargetInternalFormat(int index) | |
| { | |
| if(renderTarget[index]) | |
| { | |
| return renderTarget[index]->getInternalFormat(); | |
| } | |
| else | |
| { | |
| return FORMAT_NULL; | |
| } | |
| } | |
| bool Context::colorWriteActive() | |
| { | |
| for (int i = 0; i < RENDERTARGETS; i++) | |
| { | |
| if (colorWriteActive(i)) | |
| { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| int Context::colorWriteActive(int index) | |
| { | |
| if(!renderTarget[index] || renderTarget[index]->getInternalFormat() == FORMAT_NULL) | |
| { | |
| return 0; | |
| } | |
| if(blendOperation() == BLENDOP_DEST && destBlendFactor() == BLEND_ONE && | |
| (!separateAlphaBlendEnable || (blendOperationAlpha() == BLENDOP_DEST && destBlendFactorAlpha() == BLEND_ONE))) | |
| { | |
| return 0; | |
| } | |
| return colorWriteMask[index]; | |
| } | |
| bool Context::colorUsed() | |
| { | |
| return colorWriteActive() || alphaTestActive() || (pixelShader && pixelShader->containsKill()); | |
| } | |
| } |