mirror of https://github.com/axmolengine/axmol.git
488 lines
13 KiB
C++
488 lines
13 KiB
C++
/****************************************************************************
|
|||
Copyright (c) 2015-2016 Chukong Technologies Inc.
|
|||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
|||
Copyright (c) 2014 GamePlay3D team
|
|||
|
|||
http://www.cocos2d-x.org
|
|||
|
|||
|
|||
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.
|
|||
|
|||
Ideas taken from:
|
|||
- GamePlay3D: http://gameplay3d.org/
|
|||
- OGRE3D: http://www.ogre3d.org/
|
|||
- Qt3D: http://qt-project.org/
|
|||
|
|||
****************************************************************************/
|
|||
|
|||
Fixes 1605 include path in 541 files
using the tools/coding-style/include-linter.py with -f options.
|
#include "renderer/CCRenderState.h"
|
||
|
|||
#include <string>
|
|||
|
#include <cassert>
|
||
|
|||
#include "renderer/CCTexture2D.h"
|
|||
#include "renderer/CCPass.h"
|
|||
|
#include "base/ccUtils.h"
|
||
#include "base/CCDirector.h"
|
|||
#include "renderer/CCRenderer.h"
|
|||
|
#include "renderer/CCMaterial.h"
|
||
|
|||
NS_CC_BEGIN
|
|||
|
|||
|
|||
std::string RenderState::getName() const
|
|||
{
|
|||
return _name;
|
|||
}
|
|||
|
|||
|
|||
|
void RenderState::bindPass(Pass* pass)
|
||
{
|
|||
CC_ASSERT(pass);
|
|||
|
assert(pass->_technique && pass->_technique->_material);
|
||
auto *technique = pass->_technique;
|
|||
auto *material = technique->_material;
|
|||
auto &pipelineDescriptor = pass->_customCommand.getPipelineDescriptor();
|
|||
|
|||
|
//need reset all state
|
||
//pipelineDescriptor.blendDescriptor.blendEnabled = true;
|
|||
|
|||
// Get the combined modified state bits for our RenderState hierarchy.
|
|||
|
long overrideBits = _state._modifiedBits;
|
||
overrideBits |= technique->getStateBlock()._modifiedBits;
|
|||
overrideBits |= material->getStateBlock()._modifiedBits;
|
|||
|
|||
// Restore renderer state to its default, except for explicitly specified states
|
|||
|
RenderState::StateBlock::restore(overrideBits, &pipelineDescriptor);
|
||
|
|||
|
material->getStateBlock().apply(&pipelineDescriptor);
|
||
technique->getStateBlock().apply(&pipelineDescriptor);
|
|||
_state.apply(&pipelineDescriptor);
|
|||
|
|||
}
|
|||
|
|||
|
void RenderState::unbindPass(Pass* pass)
|
||
|
{
|
||
|
auto &pipelineDescriptor = pass->_customCommand.getPipelineDescriptor();
|
||
RenderState::StateBlock::restore(0, &pipelineDescriptor);
|
|||
|
}
|
||
|
|||
|
RenderState::StateBlock& RenderState::getStateBlock() const
|
||
|
{
|
||
|
return _state;
|
||
|
}
|
||
|
|||
|
|||
|
void RenderState::StateBlock::bind(PipelineDescriptor *pipelineDescriptor)
|
||
{
|
|||
// When the public bind() is called with no RenderState object passed in,
|
|||
// we assume we are being called to bind the state of a single StateBlock,
|
|||
// irrespective of whether it belongs to a hierarchy of RenderStates.
|
|||
// Therefore, we call restore() here with only this StateBlock's override
|
|||
// bits to restore state before applying the new state.
|
|||
|
StateBlock::restore(_modifiedBits, pipelineDescriptor);
|
||
|
|||
|
apply(pipelineDescriptor);
|
||
}
|
|||
|
|||
|
void RenderState::StateBlock::apply(PipelineDescriptor *pipelineDescriptor)
|
||
{
|
|||
|
//CC_ASSERT(_globalState);
|
||
|
|||
auto renderer = Director::getInstance()->getRenderer();
|
|||
|
auto &blend = pipelineDescriptor->blendDescriptor;
|
||
|
|||
|
// Update any state that differs from _globalState and flip _globalState bits
|
||
if ((_modifiedBits & RS_BLEND))
|
|||
{
|
|||
|
blend.blendEnabled = _blendEnabled;
|
||
}
|
|||
|
|
||
if ((_modifiedBits & RS_BLEND_FUNC))
|
|||
{
|
|||
|
blend.sourceAlphaBlendFactor = blend.sourceRGBBlendFactor = _blendSrc;
|
||
blend.destinationAlphaBlendFactor = blend.destinationRGBBlendFactor = _blendDst;
|
|||
}
|
|||
|
|
||
if ((_modifiedBits & RS_CULL_FACE))
|
|||
{
|
|||
if (!_cullFaceEnabled)
|
|||
renderer->setCullMode(CullMode::NONE);
|
|||
}
|
|||
|
|
||
if ((_modifiedBits & RS_CULL_FACE_SIDE))
|
|||
{
|
|||
renderer->setCullMode(_cullFaceSide);
|
|||
}
|
|||
|
|
||
if ((_modifiedBits & RS_FRONT_FACE))
|
|||
{
|
|||
renderer->setWinding(_frontFace);
|
|||
}
|
|||
|
if ((_modifiedBits & RS_DEPTH_TEST))
|
||
{
|
|||
renderer->setDepthTest(_depthTestEnabled);
|
|||
}
|
|||
|
|
||
if ((_modifiedBits & RS_DEPTH_WRITE))
|
|||
{
|
|||
|
renderer->setDepthWrite(_depthWriteEnabled);
|
||
}
|
|||
|
|
||
if ((_modifiedBits & RS_DEPTH_FUNC))
|
|||
{
|
|||
renderer->setDepthCompareFunction(_depthFunction);
|
|||
}
|
|||
}
|
|||
|
|||
|
void RenderState::StateBlock::restore(long overrideBits, PipelineDescriptor *programState)
|
||
{
|
|||
auto renderer = Director::getInstance()->getRenderer();
|
|||
|
auto &blend = programState->blendDescriptor;
|
||
|
|||
|
// Update any state that differs from _globalState and flip _globalState bits
|
||
if (!(overrideBits & RS_BLEND))
|
|||
{
|
|||
|
blend.blendEnabled = true;
|
||
}
|
|||
|
|
||
if (!(overrideBits & RS_BLEND_FUNC))
|
|||
{
|
|||
|
blend.sourceAlphaBlendFactor = blend.sourceRGBBlendFactor = backend::BlendFactor::ONE;
|
||
blend.destinationAlphaBlendFactor = blend.destinationRGBBlendFactor = backend::BlendFactor::ZERO;
|
|||
}
|
|||
|
|
||
if (!(overrideBits & RS_CULL_FACE))
|
|||
{
|
|||
renderer->setCullMode(CullMode::NONE);
|
|||
}
|
|||
|
|
||
if (!(overrideBits & RS_CULL_FACE_SIDE))
|
|||
{
|
|||
renderer->setCullMode(CullMode::BACK);
|
|||
}
|
|||
|
|
||
if (!(overrideBits & RS_FRONT_FACE))
|
|||
{
|
|||
renderer->setWinding(FrontFace::COUNTER_CLOCK_WISE);
|
|||
}
|
|||
|
|
||
if (!(overrideBits & RS_DEPTH_TEST))
|
|||
{
|
|||
renderer->setDepthTest(true);
|
|||
}
|
|||
|
|
||
if (!(overrideBits & RS_DEPTH_WRITE))
|
|||
{
|
|||
renderer->setDepthWrite(false);
|
|||
}
|
|||
|
|
||
|
|||
if (!(overrideBits & RS_DEPTH_FUNC))
|
|||
{
|
|||
renderer->setDepthCompareFunction(DepthFunction::LESS);
|
|||
|
}
|
||
}
|
|||
|
|||
static bool parseBoolean(const std::string& value)
|
|||
{
|
|||
return (value.compare("true") == 0);
|
|||
}
|
|||
|
|||
|
static backend::BlendFactor parseBlend(const std::string& value)
|
||
{
|
|||
// Convert the string to uppercase for comparison.
|
|||
std::string upper(value);
|
|||
std::transform(upper.begin(), upper.end(), upper.begin(), (int(*)(int))toupper);
|
|||
if (upper == "ZERO")
|
|||
|
return backend::BlendFactor::ZERO;
|
||
else if (upper == "ONE")
|
|||
|
return backend::BlendFactor::ONE;
|
||
else if (upper == "SRC_COLOR")
|
|||
|
return backend::BlendFactor::SRC_COLOR;
|
||
else if (upper == "ONE_MINUS_SRC_COLOR")
|
|||
|
return backend::BlendFactor::ONE_MINUS_SRC_COLOR;
|
||
else if (upper == "DST_COLOR")
|
|||
|
return backend::BlendFactor::DST_COLOR;
|
||
else if (upper == "ONE_MINUS_DST_COLOR")
|
|||
|
return backend::BlendFactor::ONE_MINUS_DST_COLOR;
|
||
else if (upper == "SRC_ALPHA")
|
|||
|
return backend::BlendFactor::SRC_ALPHA;
|
||
else if (upper == "ONE_MINUS_SRC_ALPHA")
|
|||
|
return backend::BlendFactor::ONE_MINUS_SRC_ALPHA;
|
||
else if (upper == "DST_ALPHA")
|
|||
|
return backend::BlendFactor::DST_ALPHA;
|
||
else if (upper == "ONE_MINUS_DST_ALPHA")
|
|||
|
return backend::BlendFactor::ONE_MINUS_DST_ALPHA;
|
||
else if (upper == "CONSTANT_ALPHA")
|
|||
|
return backend::BlendFactor::CONSTANT_ALPHA;
|
||
else if (upper == "ONE_MINUS_CONSTANT_ALPHA")
|
|||
|
return backend::BlendFactor::ONE_MINUS_CONSTANT_ALPHA;
|
||
else if (upper == "SRC_ALPHA_SATURATE")
|
|||
|
return backend::BlendFactor::SRC_ALPHA_SATURATE;
|
||
else
|
|||
{
|
|||
CCLOG("Unsupported blend value (%s). (Will default to BLEND_ONE if errors are treated as warnings)", value.c_str());
|
|||
|
return backend::BlendFactor::ONE;
|
||
}
|
|||
}
|
|||
|
|||
static DepthFunction parseDepthFunc(const std::string& value)
|
|||
{
|
|||
// Convert string to uppercase for comparison
|
|||
std::string upper(value);
|
|||
std::transform(upper.begin(), upper.end(), upper.begin(), (int(*)(int))toupper);
|
|||
if (upper == "NEVER")
|
|||
return DepthFunction::NEVER;
|
|||
else if (upper == "LESS")
|
|||
return DepthFunction::LESS;
|
|||
else if (upper == "EQUAL")
|
|||
return DepthFunction::EQUAL;
|
|||
else if (upper == "LEQUAL")
|
|||
return DepthFunction::LESS_EQUAL;
|
|||
else if (upper == "GREATER")
|
|||
return DepthFunction::GREATER;
|
|||
else if (upper == "NOTEQUAL")
|
|||
return DepthFunction::NOT_EQUAL;
|
|||
else if (upper == "GEQUAL")
|
|||
return DepthFunction::GREATER_EQUAL;
|
|||
else if (upper == "ALWAYS")
|
|||
return DepthFunction::ALWAYS;
|
|||
else
|
|||
{
|
|||
CCLOG("Unsupported depth function value (%s). Will default to DEPTH_LESS if errors are treated as warnings)", value.c_str());
|
|||
return DepthFunction::LESS;
|
|||
}
|
|||
}
|
|||
|
|||
static CullFaceSide parseCullFaceSide(const std::string& value)
|
|||
{
|
|||
// Convert string to uppercase for comparison
|
|||
std::string upper(value);
|
|||
std::transform(upper.begin(), upper.end(), upper.begin(), (int(*)(int))toupper);
|
|||
if (upper == "BACK")
|
|||
return CullFaceSide::BACK;
|
|||
else if (upper == "FRONT")
|
|||
return CullFaceSide::FRONT;
|
|||
// XXX: metal doesn't support back&front culling. Is it needed, since it will draw nothing.
|
|||
// else if (upper == "FRONT_AND_BACK")
|
|||
// return RenderState::CULL_FACE_SIDE_FRONT_AND_BACK;
|
|||
else
|
|||
{
|
|||
CCLOG("Unsupported cull face side value (%s). Will default to BACK if errors are treated as warnings.", value.c_str());
|
|||
return CullFaceSide::BACK;
|
|||
}
|
|||
}
|
|||
|
|||
static FrontFace parseFrontFace(const std::string& value)
|
|||
{
|
|||
// Convert string to uppercase for comparison
|
|||
std::string upper(value);
|
|||
std::transform(upper.begin(), upper.end(), upper.begin(), (int(*)(int))toupper);
|
|||
if (upper == "CCW")
|
|||
return FrontFace::COUNTER_CLOCK_WISE;
|
|||
else if (upper == "CW")
|
|||
return FrontFace::CLOCK_WISE;
|
|||
else
|
|||
{
|
|||
CCLOG("Unsupported front face side value (%s). Will default to CCW if errors are treated as warnings.", value.c_str());
|
|||
return FrontFace::COUNTER_CLOCK_WISE;
|
|||
}
|
|||
}
|
|||
|
|||
void RenderState::StateBlock::setState(const std::string& name, const std::string& value)
|
|||
{
|
|||
if (name.compare("blend") == 0)
|
|||
{
|
|||
setBlend(parseBoolean(value));
|
|||
}
|
|||
else if (name.compare("blendSrc") == 0)
|
|||
{
|
|||
setBlendSrc(parseBlend(value));
|
|||
}
|
|||
else if (name.compare("blendDst") == 0)
|
|||
{
|
|||
setBlendDst(parseBlend(value));
|
|||
}
|
|||
else if (name.compare("cullFace") == 0)
|
|||
{
|
|||
setCullFace(parseBoolean(value));
|
|||
}
|
|||
else if (name.compare("cullFaceSide") == 0)
|
|||
{
|
|||
setCullFaceSide(parseCullFaceSide(value));
|
|||
}
|
|||
else if (name.compare("frontFace") == 0)
|
|||
{
|
|||
setFrontFace(parseFrontFace(value));
|
|||
}
|
|||
else if (name.compare("depthTest") == 0)
|
|||
{
|
|||
setDepthTest(parseBoolean(value));
|
|||
}
|
|||
else if (name.compare("depthWrite") == 0)
|
|||
{
|
|||
setDepthWrite(parseBoolean(value));
|
|||
}
|
|||
else if (name.compare("depthFunc") == 0)
|
|||
{
|
|||
setDepthFunction(parseDepthFunc(value));
|
|||
}
|
|||
else
|
|||
{
|
|||
CCLOG("Unsupported render state string '%s'.", name.c_str());
|
|||
}
|
|||
}
|
|||
|
|||
bool RenderState::StateBlock::isDirty() const
|
|||
{
|
|||
// XXX
|
|||
return true;
|
|||
}
|
|||
|
|||
uint32_t RenderState::StateBlock::getHash() const
|
|||
{
|
|||
// XXX
|
|||
return 0x12345678;
|
|||
}
|
|||
|
|||
void RenderState::StateBlock::setBlend(bool enabled)
|
|||
{
|
|||
_blendEnabled = enabled;
|
|||
if (enabled)
|
|||
{
|
|||
|
_modifiedBits &= ~RS_BLEND;
|
||
}
|
|||
else
|
|||
{
|
|||
|
_modifiedBits |= RS_BLEND;
|
||
}
|
|||
}
|
|||
|
|||
void RenderState::StateBlock::setBlendFunc(const BlendFunc& blendFunc)
|
|||
{
|
|||
|
setBlendSrc(blendFunc.src);
|
||
setBlendDst(blendFunc.dst);
|
|||
}
|
|||
|
|||
|
void RenderState::StateBlock::setBlendSrc(backend::BlendFactor blend)
|
||
{
|
|||
_blendSrc = blend;
|
|||
|
if (_blendSrc == backend::BlendFactor::ONE && _blendDst == backend::BlendFactor::ZERO)
|
||
{
|
|||
// Default blend func
|
|||
|
_modifiedBits &= ~RS_BLEND_FUNC;
|
||
}
|
|||
else
|
|||
{
|
|||
|
_modifiedBits |= RS_BLEND_FUNC;
|
||
}
|
|||
}
|
|||
|
|||
|
void RenderState::StateBlock::setBlendDst(backend::BlendFactor blend)
|
||
{
|
|||
_blendDst = blend;
|
|||
|
if (_blendSrc == backend::BlendFactor::ONE && _blendDst == backend::BlendFactor::ZERO)
|
||
{
|
|||
// Default blend func
|
|||
|
_modifiedBits &= ~RS_BLEND_FUNC;
|
||
}
|
|||
else
|
|||
{
|
|||
|
_modifiedBits |= RS_BLEND_FUNC;
|
||
}
|
|||
}
|
|||
|
|||
void RenderState::StateBlock::setCullFace(bool enabled)
|
|||
{
|
|||
_cullFaceEnabled = enabled;
|
|||
if (!enabled)
|
|||
{
|
|||
|
_modifiedBits &= ~RS_CULL_FACE;
|
||
}
|
|||
else
|
|||
{
|
|||
|
_modifiedBits |= RS_CULL_FACE;
|
||
}
|
|||
}
|
|||
|
|||
void RenderState::StateBlock::setCullFaceSide(CullFaceSide side)
|
|||
{
|
|||
_cullFaceSide = side;
|
|||
if (_cullFaceSide == CullFaceSide::BACK)
|
|||
{
|
|||
// Default cull side
|
|||
|
_modifiedBits &= ~RS_CULL_FACE_SIDE;
|
||
}
|
|||
else
|
|||
{
|
|||
|
_modifiedBits |= RS_CULL_FACE_SIDE;
|
||
}
|
|||
}
|
|||
|
|||
void RenderState::StateBlock::setFrontFace(FrontFace winding)
|
|||
{
|
|||
_frontFace = winding;
|
|||
if (_frontFace == FrontFace::COUNTER_CLOCK_WISE)
|
|||
{
|
|||
// Default front face
|
|||
|
_modifiedBits &= ~RS_FRONT_FACE;
|
||
}
|
|||
else
|
|||
{
|
|||
|
_modifiedBits |= RS_FRONT_FACE;
|
||
}
|
|||
}
|
|||
|
|||
void RenderState::StateBlock::setDepthTest(bool enabled)
|
|||
{
|
|||
_depthTestEnabled = enabled;
|
|||
if (enabled)
|
|||
{
|
|||
|
_modifiedBits &= ~RS_DEPTH_TEST;
|
||
}
|
|||
else
|
|||
{
|
|||
|
_modifiedBits |= RS_DEPTH_TEST;
|
||
}
|
|||
}
|
|||
|
|||
void RenderState::StateBlock::setDepthWrite(bool enabled)
|
|||
{
|
|||
_depthWriteEnabled = enabled;
|
|||
if (!enabled)
|
|||
{
|
|||
|
_modifiedBits &= ~RS_DEPTH_WRITE;
|
||
}
|
|||
else
|
|||
{
|
|||
|
_modifiedBits |= RS_DEPTH_WRITE;
|
||
}
|
|||
}
|
|||
|
|||
void RenderState::StateBlock::setDepthFunction(DepthFunction func)
|
|||
{
|
|||
_depthFunction = func;
|
|||
if (_depthFunction == DepthFunction::LESS)
|
|||
{
|
|||
// Default depth function
|
|||
|
_modifiedBits &= ~RS_DEPTH_FUNC;
|
||
}
|
|||
else
|
|||
{
|
|||
|
_modifiedBits |= RS_DEPTH_FUNC;
|
||
}
|
|||
}
|
|||
|
|||
NS_CC_END
|