C++ API Reference
cgFx/cgfxPassStateSetter.cpp
//-
// ==========================================================================
// Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+
#include <maya/MDrawContext.h>
#include <maya/MGlobal.h>
#include "cgfxPassStateSetter.h"
#include "cgfxShaderNode.h"
#include <string>
#include <map>
#include <set>
using namespace MHWRender;
// The GL enumerants for stencil wrap are not defined on every
// platforms.
#ifndef GL_INCR_WRAP
#define GL_INCR_WRAP 0x8507
#endif
#ifndef GL_DECR_WRAP
#define GL_DECR_WRAP 0x8508
#endif
namespace
{
std::string lowerCaseString(const char* str) {
std::string lower;
lower.reserve(strlen(str));
for (const char* p=str; *p != 0; ++p) {
lower += char(tolower(*p));
}
return lower;
}
//==============================================================================
// CLASS StateAssignment
//==============================================================================
class StateAssignment
{
public:
typedef void (*HandlerFn)(
const CGstateassignment& sa,
MBlendStateDesc* blendStateDesc,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* depthStencilStateDesc);
// Returns whether the state assignement is unsupported by the
// VP2.0 viewport and therefore a glPushAttrib()/glPopAttrib()
// pair is required to ensure correct rendering.
typedef bool (*UnsupportedCheckFn)(const CGstateassignment& sa);
static void registerHandler(const char* stateName, HandlerFn handler) {
CGstate cgState = cgGetNamedState(cgfxShaderNode::sCgContext, stateName);
if (cgState) {
std::string lstateName = lowerCaseString(stateName);
const bool inserted =
map.insert(
std::make_pair(lstateName,StateAssignment(cgState, handler))
).second;
if (!inserted) {
s += "cgfxPassStateSetter is trying to register multiple "
"handlers for the same CgFX state \"";
s += stateName;
s += "\".";
}
}
else {
s += "The CgFX state assignment \"";
s += stateName;
s += "\" is unknown to the Cg library.";
}
}
static void registerUnsupportedCheck(const char* stateName, UnsupportedCheckFn check) {
CGstate cgState = cgGetNamedState(cgfxShaderNode::sCgContext, stateName);
if (cgState) {
std::string lstateName = lowerCaseString(stateName);
const bool inserted =
unsupportedChecks.insert(
std::make_pair(lstateName,check)
).second;
if (!inserted) {
s += "cgfxPassStateSetter is trying to register multiple "
"unsupported checks for the same CgFX state \"";
s += stateName;
s += "\".";
}
}
else {
s += "The CgFX state assignment \"";
s += stateName;
s += "\" is unknown to the Cg library.";
}
}
static void registerIgnoredState(const char* stateName) {
CGstate cgState = cgGetNamedState(cgfxShaderNode::sCgContext, stateName);
if (cgState) {
const bool inserted =
ignoredSet.insert(lowerCaseString(stateName)).second;
if (!inserted) {
s += "cgfxPassStateSetter is trying to register multiple "
"ignore handlers for the same CgFX state \"";
s += stateName;
s += "\".";
}
}
else {
s += "The CgFX state assignment \"";
s += stateName;
s += "\" is unknown to the Cg library.";
}
}
static void registerDefaultCallBacks()
{
// The default viewport uses immediate parameter setting.
cgSetParameterSettingMode(cgfxShaderNode::sCgContext,
CG_IMMEDIATE_PARAMETER_SETTING);
const Map::const_iterator itEnd = map.end();
for ( Map::const_iterator it = map.begin();
it != itEnd; ++it) {
it->second.setDefaultCallbacks();
}
}
static void registerVP20CallBacks()
{
// The VP2.0 viewport uses deferred parameter setting.
cgSetParameterSettingMode(cgfxShaderNode::sCgContext,
CG_DEFERRED_PARAMETER_SETTING);
const Map::const_iterator itEnd = map.end();
for ( Map::const_iterator it = map.begin();
it != itEnd; ++it) {
it->second.setVP20Callbacks();
}
}
// Invokes the proper handler for given state assignment. The
// state objects will be modified accordingly if such a
// handler exists.
//
// Returns whether a glPushAttib()/glPopAttrib() is required
// due to an unsupported state assignement.
static bool callHandler(
const CGstateassignment& sa,
MBlendStateDesc* blendStateDesc,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* depthStencilStateDesc)
{
// We modify the state objects according to the sa
CGstate state = cgGetStateAssignmentState(sa);
const char *stateName = cgGetStateName(state);
std::string lstateName = lowerCaseString(stateName);
{
const Map::const_iterator handler = map.find(lstateName);
if (handler != map.end()) {
handler->second.fHandler(sa,
blendStateDesc,
rasterizerStateDesc,
depthStencilStateDesc);
return false;
}
}
{
const UnsupportedChecks::const_iterator unsupportedCheck =
unsupportedChecks.find(lstateName);
if (unsupportedCheck != unsupportedChecks.end()) {
return unsupportedCheck->second(sa);
}
}
if (ignoredSet.find(lstateName) != ignoredSet.end()) {
// This state assignment requires no specific
// handling and is therefore ignored by the
// cgfxPassStateSetter. i.e. We let Cg perform its
// default behavior in that case.
return false;
}
#ifdef DEBUG
// Unsupported state. We must use a
// glPushAttrib()/glPopAttrib() pair to guarantee correct
// rendering.
s += "cgfxShader: The CgFX state assignment \"";
s += stateName;
s += "\" contained in the shader file is not accelerated by the "
"cgfxShader plugin in a VP2.0 viewport and will result in lower "
"performance.";
#endif
return true;
}
private:
typedef std::map<std::string, StateAssignment> Map;
typedef std::map<std::string, UnsupportedCheckFn> UnsupportedChecks;
typedef std::set<std::string> IgnoredSet;
friend class std::map<std::string, StateAssignment>;
static CGbool noopStateAssignment(CGstateassignment sa) {
return CG_TRUE;
}
StateAssignment(CGstate cgState, HandlerFn handler) {
fCgState = cgState;
fDefaultSetCB = cgGetStateSetCallback(cgState);
fDefaultResetCB = cgGetStateResetCallback(cgState);
fDefaultValidateCB = cgGetStateValidateCallback(cgState);
fHandler = handler;
}
// Need a default ctor to please std::map...
StateAssignment()
: fCgState(NULL),
fDefaultSetCB(NULL),
fDefaultResetCB(NULL),
fDefaultValidateCB(NULL),
fHandler(NULL)
{};
void setDefaultCallbacks() const
{
cgSetStateCallbacks(fCgState,
fDefaultSetCB,
fDefaultResetCB,
fDefaultValidateCB);
}
void setVP20Callbacks() const
{
cgSetStateCallbacks(fCgState,
noopStateAssignment,
noopStateAssignment,
NULL);
}
static Map map;
static UnsupportedChecks unsupportedChecks;
static IgnoredSet ignoredSet;
CGstate fCgState;
CGstatecallback fDefaultSetCB;
CGstatecallback fDefaultResetCB;
CGstatecallback fDefaultValidateCB;
HandlerFn fHandler;
};
StateAssignment::Map StateAssignment::map;
StateAssignment::UnsupportedChecks StateAssignment::unsupportedChecks;
StateAssignment::IgnoredSet StateAssignment::ignoredSet;
//==============================================================================
// OpenGL mappings
//==============================================================================
MBlendState::BlendOption mapBlendOption(int blendOption)
{
switch(blendOption) {
case GL_ZERO: return MBlendState::kZero;
case GL_ONE: return MBlendState::kOne;
case GL_SRC_COLOR: return MBlendState::kSourceColor;
case GL_ONE_MINUS_SRC_COLOR: return MBlendState::kInvSourceColor;
case GL_SRC_ALPHA: return MBlendState::kSourceAlpha;
case GL_ONE_MINUS_SRC_ALPHA: return MBlendState::kInvSourceAlpha;
case GL_SRC_ALPHA_SATURATE: return MBlendState::kSourceAlphaSat;
case GL_DST_COLOR: return MBlendState::kDestinationColor;
case GL_ONE_MINUS_DST_COLOR: return MBlendState::kInvDestinationColor;
case GL_DST_ALPHA: return MBlendState::kDestinationAlpha;
case GL_ONE_MINUS_DST_ALPHA: return MBlendState::kInvDestinationAlpha;
case GL_CONSTANT_COLOR: return MBlendState::kBlendFactor;
case GL_ONE_MINUS_CONSTANT_COLOR: return MBlendState::kInvBlendFactor;
//These two cases are duplicated in OGL
// case GL_SRC_ALPHA: return MBlendState::kBothSourceAlpha;
// case GL_ONE_MINUS_SRC_ALPHA: return MBlendState::kBothInvSourceAlpha;
// Error, unknown GL enum.
default: return MBlendState::kOne;
}
}
MBlendState::BlendOperation mapBlendOperation(int blendOperation)
{
switch(blendOperation) {
case GL_FUNC_ADD: return MBlendState::kAdd;
case GL_FUNC_SUBTRACT: return MBlendState::kSubtract;
case GL_FUNC_REVERSE_SUBTRACT: return MBlendState::kReverseSubtract;
case GL_MIN: return MBlendState::kMin;
case GL_MAX: return MBlendState::kMax;
// Error, unknown GL enum.
default: return MBlendState::kAdd;
}
}
MStateManager::CompareMode mapCompareMode(int compareMode)
{
switch(compareMode)
{
case GL_NEVER: return MStateManager::kCompareNever;
case GL_LESS: return MStateManager::kCompareLess;
case GL_EQUAL: return MStateManager::kCompareEqual;
case GL_LEQUAL: return MStateManager::kCompareLessEqual;
case GL_GREATER: return MStateManager::kCompareGreater;
case GL_NOTEQUAL: return MStateManager::kCompareNotEqual;
case GL_GEQUAL: return MStateManager::kCompareGreaterEqual;
case GL_ALWAYS: return MStateManager::kCompareAlways;
// Error, unknown GL enum.
}
}
MDepthStencilState::StencilOperation mapStencilOperation(int stencilOp)
{
switch(stencilOp)
{
case GL_KEEP: return MDepthStencilState::kKeepStencil;
case GL_ZERO: return MDepthStencilState::kZeroStencil;
case GL_REPLACE: return MDepthStencilState::kReplaceStencil;
case GL_INVERT: return MDepthStencilState::kInvertStencil;
case GL_INCR_WRAP: return MDepthStencilState::kIncrementStencil;
case GL_DECR_WRAP: return MDepthStencilState::kDecrementStencil;
// Error, unknown GL enum.
}
}
//==============================================================================
// STATE ASSIGNMENT HANDLERS
//==============================================================================
// We currently support all of the states that the OpenMaya VP2.0
// API supports. The state assignments supported by CgFX but not
// by the OpenMaya VP2.0 API are not handled by the
// cgfxPassStateSetter and will be handled the the regular
// cgSetPassState mechanism. A warning is emitted when we
// encounter such a state because it is a potential performance
// bottleneck.
MString WrongNumValues(
"cgfxPassStateSetter : Incoherent number of state assignment values");
//******************************************************************************
// Blend states
//******************************************************************************
void assignHdlr_BlendColor(
const CGstateassignment& sa,
MBlendStateDesc* blendStateDesc,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const float* values = cgGetFloatStateAssignmentValues(sa, &numValues);
if(numValues == 4) {
blendStateDesc->blendFactor[0] = values[0];
blendStateDesc->blendFactor[1] = values[1];
blendStateDesc->blendFactor[2] = values[2];
blendStateDesc->blendFactor[3] = values[3];
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_BlendEnable(
const CGstateassignment& sa,
MBlendStateDesc* blendStateDesc,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const CGbool *values = cgGetBoolStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
const bool value = (values[0] == CG_TRUE) ? true : false;
// We always use the target 0 since the CgFX plugin only
// renders to a single framebuffer.
blendStateDesc->targetBlends[0].blendEnable = value;
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_SrcBlend(
const CGstateassignment& sa,
MBlendStateDesc* blendStateDesc,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
// We always use the target 0 since the CgFX plugin only
// renders to a single framebuffer.
blendStateDesc->targetBlends[0].sourceBlend =
mapBlendOption(values[0]);
blendStateDesc->targetBlends[0].alphaSourceBlend =
mapBlendOption(values[0]);
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_DestBlend(
const CGstateassignment& sa,
MBlendStateDesc* blendStateDesc,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
// We always use the target 0 since the CgFX plugin only
// renders to a single framebuffer.
blendStateDesc->targetBlends[0].destinationBlend =
mapBlendOption(values[0]);
blendStateDesc->targetBlends[0].alphaDestinationBlend =
mapBlendOption(values[0]);
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_BlendFunc(
const CGstateassignment& sa,
MBlendStateDesc* blendStateDesc,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 2) {
// We always use the target 0 since the CgFX plugin only
// renders to a single framebuffer.
blendStateDesc->targetBlends[0].sourceBlend =
mapBlendOption(values[0]);
blendStateDesc->targetBlends[0].destinationBlend =
mapBlendOption(values[1]);
blendStateDesc->targetBlends[0].alphaSourceBlend =
mapBlendOption(values[0]);
blendStateDesc->targetBlends[0].alphaDestinationBlend =
mapBlendOption(values[1]);
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_BlendOp(
const CGstateassignment& sa,
MBlendStateDesc* blendStateDesc,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
// We always use the target 0 since the CgFX plugin only
// renders to a single framebuffer.
blendStateDesc->targetBlends[0].blendOperation =
mapBlendOperation(values[0]);
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_BlendFuncSeparate(
const CGstateassignment& sa,
MBlendStateDesc* blendStateDesc,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 4) {
// We always use the target 0 since the CgFX plugin only
// renders to a single framebuffer.
blendStateDesc->targetBlends[0].sourceBlend =
mapBlendOption(values[0]);
blendStateDesc->targetBlends[0].destinationBlend =
mapBlendOption(values[1]);
blendStateDesc->targetBlends[0].alphaSourceBlend =
mapBlendOption(values[2]);
blendStateDesc->targetBlends[0].alphaDestinationBlend =
mapBlendOption(values[3]);
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_BlendEquationSeparate(
const CGstateassignment& sa,
MBlendStateDesc* blendStateDesc,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 2) {
// We always use the target 0 since the CgFX plugin only
// renders to a single framebuffer.
blendStateDesc->targetBlends[0].blendOperation =
mapBlendOperation(values[0]);
blendStateDesc->targetBlends[1].alphaBlendOperation =
mapBlendOperation(values[1]);
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_ColorWriteEnable(
const CGstateassignment& sa,
MBlendStateDesc* blendStateDesc,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const CGbool* values = cgGetBoolStateAssignmentValues(sa, &numValues);
if (numValues == 4) {
mask |= (values[0]!=0) ? MBlendState::kRedChannel : 0;
mask |= (values[1]!=0) ? MBlendState::kGreenChannel : 0;
mask |= (values[2]!=0) ? MBlendState::kBlueChannel : 0;
mask |= (values[3]!=0) ? MBlendState::kAlphaChannel : 0;
// We always use the target 0 since the CgFX plugin only
// renders to a single framebuffer.
blendStateDesc->targetBlends[0].targetWriteMask =
}
else {
MGlobal::displayError(WrongNumValues);
}
}
//******************************************************************************
// Rasterizer states
//******************************************************************************
void assignHdlr_FillMode(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues >= 1) {
switch(values[0])
{
case GL_FILL: rasterizerStateDesc->fillMode = MRasterizerState::kFillSolid; break;
case GL_LINE: rasterizerStateDesc->fillMode = MRasterizerState::kFillWireFrame; break;
case GL_POINT: //we don't have such enum in MRasteriszerState, so pass
default:; //error
}
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_CullFace(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
switch(values[0])
{
case GL_FRONT: rasterizerStateDesc->cullMode = MRasterizerState::kCullFront; break;
case GL_BACK: rasterizerStateDesc->cullMode = MRasterizerState::kCullBack; break;
case GL_FRONT_AND_BACK: //we don't have such enum in MRasteriszerState, so pass
default:; //error
}
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_CullFaceEnable(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const CGbool *values = cgGetBoolStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
if(values[0] == CG_TRUE) {
//use default cull mode if cull is enabled
rasterizerStateDesc->cullMode = MRasterizerState::kCullBack;
}
else {
rasterizerStateDesc->cullMode = MRasterizerState::kCullNone;
}
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_FrontFace(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
switch(values[0])
{
case GL_CW: rasterizerStateDesc->frontCounterClockwise = false; break;
case GL_CCW: rasterizerStateDesc->frontCounterClockwise = true; break;
default:; //error
}
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_PolygonMode(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 2) {
switch(values[0])
{
case GL_FRONT: rasterizerStateDesc->cullMode = MRasterizerState::kCullFront; break;
case GL_BACK: rasterizerStateDesc->cullMode = MRasterizerState::kCullBack; break;
case GL_FRONT_AND_BACK: //we don't have such enum in MRasteriszerState, so pass
default:; //error
}
switch(values[1])
{
case GL_FILL: rasterizerStateDesc->fillMode = MRasterizerState::kFillSolid; break;
case GL_LINE: rasterizerStateDesc->fillMode = MRasterizerState::kFillWireFrame; break;
case GL_POINT: //we don't have such enum in MRasteriszerState, so pass
default:; //error
}
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_PolygonOffset(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const float *values = cgGetFloatStateAssignmentValues(sa, &numValues);
if (numValues == 2) {
rasterizerStateDesc->slopeScaledDepthBias = values[0];
rasterizerStateDesc->depthBias = values[1];
rasterizerStateDesc->depthBiasIsFloat = true;
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_DepthBias(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const float *values = cgGetFloatStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
rasterizerStateDesc->depthBias = values[0];
rasterizerStateDesc->depthBiasIsFloat = true;
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_SlopScaleDepthBias(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const float *values = cgGetFloatStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
rasterizerStateDesc->slopeScaledDepthBias = values[0];
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_PolygonOffsetFillEnable(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const CGbool *values = cgGetBoolStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
rasterizerStateDesc->depthClipEnable = (values[0] == CG_TRUE) ? true : false;
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_ScissorTestEnable(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const CGbool *values = cgGetBoolStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
rasterizerStateDesc->scissorEnable = (values[0] == CG_TRUE) ? true : false;
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_MultisampleEnable(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const CGbool *values = cgGetBoolStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
rasterizerStateDesc->multiSampleEnable = (values[0] == CG_TRUE) ? true : false;
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_LineSmoothEnable(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* rasterizerStateDesc,
MDepthStencilStateDesc* /* depthStencilStateDesc */)
{
int numValues = 0;
const CGbool *values = cgGetBoolStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
rasterizerStateDesc->antialiasedLineEnable = (values[0] == CG_TRUE) ? true : false;
}
else {
MGlobal::displayError(WrongNumValues);
}
}
//******************************************************************************
// Depth and stencil states
//******************************************************************************
void assignHdlr_DepthTestEnable(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* depthStencilStateDesc)
{
int numValues = 0;
const CGbool *values = cgGetBoolStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
const bool value = (values[0] == CG_TRUE) ? true : false;
depthStencilStateDesc->depthEnable = value;
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_DepthMask(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* depthStencilStateDesc)
{
int numValues = 0;
const CGbool *values = cgGetBoolStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
const bool value = (values[0] == CG_TRUE) ? true : false;
depthStencilStateDesc->depthWriteEnable = value;
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_DepthFunc(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* depthStencilStateDesc)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if(numValues == 1) {
depthStencilStateDesc->depthFunc = mapCompareMode(values[0]);
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_StencilEnable(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* depthStencilStateDesc)
{
int numValues = 0;
const CGbool *values = cgGetBoolStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
const bool value = (values[0] == CG_TRUE) ? true : false;
depthStencilStateDesc->stencilEnable = value;
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_StencilWriteMask(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* depthStencilStateDesc)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 1)
{
depthStencilStateDesc->stencilWriteMask = (unsigned char)values[0];
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_StencilFunc(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* depthStencilStateDesc)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
depthStencilStateDesc->frontFace.stencilFunc =
mapCompareMode(values[0]);
depthStencilStateDesc->backFace.stencilFunc =
mapCompareMode(values[0]);
}
else if (numValues == 3)
{
depthStencilStateDesc->frontFace.stencilFunc =
mapCompareMode(values[0]);
depthStencilStateDesc->backFace.stencilFunc =
mapCompareMode(values[0]);
depthStencilStateDesc->stencilReferenceVal = values[1];
depthStencilStateDesc->stencilReadMask = (unsigned char)values[2];
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_StencilFuncSeparate(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* depthStencilStateDesc)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 4) {
switch (values[0]) {
case GL_FRONT:
depthStencilStateDesc->frontFace.stencilFunc =
mapCompareMode(values[1]);
break;
case GL_BACK:
depthStencilStateDesc->backFace.stencilFunc =
mapCompareMode(values[1]);
break;
case GL_FRONT_AND_BACK:
default:
depthStencilStateDesc->frontFace.stencilFunc =
mapCompareMode(values[1]);
depthStencilStateDesc->backFace.stencilFunc =
mapCompareMode(values[1]);
break;
}
// Note: The OpenMaya API does not support seperate
// reference and read mask for front and back faces.
depthStencilStateDesc->stencilReferenceVal = values[2];
depthStencilStateDesc->stencilReadMask = (unsigned char)values[3];
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_StencilOp(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* depthStencilStateDesc)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 3) {
depthStencilStateDesc->frontFace.stencilFailOp =
mapStencilOperation(values[0]);
depthStencilStateDesc->frontFace.stencilDepthFailOp =
mapStencilOperation(values[1]);
depthStencilStateDesc->frontFace.stencilPassOp =
mapStencilOperation(values[2]);
depthStencilStateDesc->backFace.stencilFailOp =
mapStencilOperation(values[0]);
depthStencilStateDesc->backFace.stencilDepthFailOp =
mapStencilOperation(values[1]);
depthStencilStateDesc->backFace.stencilPassOp =
mapStencilOperation(values[2]);
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_StencilOpSeparate(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* depthStencilStateDesc)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 4) {
if (values[0] == GL_FRONT || values[0] == GL_FRONT_AND_BACK) {
depthStencilStateDesc->frontFace.stencilFailOp =
mapStencilOperation(values[1]);
depthStencilStateDesc->frontFace.stencilDepthFailOp =
mapStencilOperation(values[2]);
depthStencilStateDesc->frontFace.stencilPassOp =
mapStencilOperation(values[3]);
}
if (values[0] == GL_BACK || values[0] == GL_FRONT_AND_BACK) {
depthStencilStateDesc->backFace.stencilFailOp =
mapStencilOperation(values[1]);
depthStencilStateDesc->backFace.stencilDepthFailOp =
mapStencilOperation(values[2]);
depthStencilStateDesc->backFace.stencilPassOp =
mapStencilOperation(values[3]);
}
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_StencilRef(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* depthStencilStateDesc)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
depthStencilStateDesc->stencilReferenceVal = values[0];
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_StencilFail(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* depthStencilStateDesc)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
depthStencilStateDesc->frontFace.stencilFailOp =
mapStencilOperation(values[0]);
depthStencilStateDesc->backFace.stencilFailOp =
mapStencilOperation(values[0]);
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_StencilZFail(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* depthStencilStateDesc)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
depthStencilStateDesc->frontFace.stencilDepthFailOp =
mapStencilOperation(values[0]);
depthStencilStateDesc->backFace.stencilDepthFailOp =
mapStencilOperation(values[0]);
}
else {
MGlobal::displayError(WrongNumValues);
}
}
void assignHdlr_StencilPass(
const CGstateassignment& sa,
MBlendStateDesc* /* blendStateDesc */,
MRasterizerStateDesc* /* rasterizerStateDesc */,
MDepthStencilStateDesc* depthStencilStateDesc)
{
int numValues = 0;
const int *values = cgGetIntStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
depthStencilStateDesc->frontFace.stencilPassOp =
mapStencilOperation(values[0]);
depthStencilStateDesc->backFace.stencilPassOp =
mapStencilOperation(values[0]);
}
else {
MGlobal::displayError(WrongNumValues);
}
}
//******************************************************************************
// Error handlers for unsupported states
//******************************************************************************
bool unsupportedIfTrue(const CGstateassignment& sa)
{
int numValues = 0;
const CGbool *values = cgGetBoolStateAssignmentValues(sa, &numValues);
if (numValues == 1) {
const bool value = (values[0] == CG_TRUE) ? true : false;
if (value) {
#ifdef DEBUG
CGstate state = cgGetStateAssignmentState(sa);
const char *stateName = cgGetStateName(state);
// Unsupported state. We must use a
// glPushAttrib()/glPopAttrib() pair to guarantee correct
// rendering.
s += "cgfxShader: The CgFX state assignment \"";
s += stateName;
s += " = true;\" contained in the shader file is not accelerated by the "
"cgfxShader plugin in a VP2.0 viewport and will result in lower "
"performance.";
#endif
return true;
}
else {
// The state assignment value is false. We assume that
// this state corresponds to the default Cg, VP2.0
// and OpenGL state. We can therefore safely assume
// that this state assignment is supported.
return false;
}
}
else {
MGlobal::displayError(WrongNumValues);
return true;
}
}
}
//==============================================================================
// CLASS cgfxPassStateSetter
//==============================================================================
cgfxPassStateSetter::ViewportMode cgfxPassStateSetter::sActiveViewportMode =
cgfxPassStateSetter::kUnknown;
bool cgfxPassStateSetter::registerCgStateCallBacks(
cgfxPassStateSetter::ViewportMode mode
) {
static bool initialized = false;
if(!initialized)
{
// Ignored states
StateAssignment::registerIgnoredState("VertexProgram");
StateAssignment::registerIgnoredState("VertexShader");
StateAssignment::registerIgnoredState("GeometryProgram");
StateAssignment::registerIgnoredState("GeometryShader");
StateAssignment::registerIgnoredState("FragmentProgram");
StateAssignment::registerIgnoredState("PixelShader");
// Blend states
StateAssignment::registerHandler("BlendColor", assignHdlr_BlendColor );
StateAssignment::registerHandler("BlendEnable", assignHdlr_BlendEnable );
StateAssignment::registerHandler("AlphaBlendEnable", assignHdlr_BlendEnable );
StateAssignment::registerHandler("SrcBlend", assignHdlr_SrcBlend );
StateAssignment::registerHandler("DestBlend", assignHdlr_DestBlend );
StateAssignment::registerHandler("BlendFunc", assignHdlr_BlendFunc );
StateAssignment::registerHandler("BlendOp", assignHdlr_BlendOp );
StateAssignment::registerHandler("BlendEquation", assignHdlr_BlendOp );
StateAssignment::registerHandler("BlendFuncSeparate", assignHdlr_BlendFuncSeparate );
StateAssignment::registerHandler("BlendEquationSeparate", assignHdlr_BlendEquationSeparate );
StateAssignment::registerHandler("ColorWriteEnable", assignHdlr_ColorWriteEnable);
// FXIME: I am not sure how to handle the
// MBlendStateDesc::alphaToCoverageEnable and
// MBlendStateDesc::multiSampleMask fields of the
// MBlendStateDesc. It seems to me that Maya should initialize
// them to the proper values depending on whether MSAA is
// globaly enabled. They also seems DirectX specific.
// Note: The MBlendStateDesc::independentBlendEnable field is
// always set to false since the CgFX plugin only renders to a
// single framebuffer.
// Rasterizer states
//
StateAssignment::registerHandler("FillMode", assignHdlr_FillMode );
StateAssignment::registerHandler("CullMode", assignHdlr_CullFace );
StateAssignment::registerHandler("CullFace", assignHdlr_CullFace );
StateAssignment::registerHandler("CullFaceEnable", assignHdlr_CullFaceEnable );
StateAssignment::registerHandler("FrontFace", assignHdlr_FrontFace );
StateAssignment::registerHandler("PolygonMode", assignHdlr_PolygonMode );
StateAssignment::registerHandler("PolygonOffset", assignHdlr_PolygonOffset );
StateAssignment::registerHandler("DepthBias", assignHdlr_DepthBias );
StateAssignment::registerHandler("SlopScaleDepthBias", assignHdlr_SlopScaleDepthBias );
StateAssignment::registerHandler("PolygonOffsetFillEnable", assignHdlr_PolygonOffsetFillEnable );
StateAssignment::registerHandler("ScissorTestEnable", assignHdlr_ScissorTestEnable );
StateAssignment::registerHandler("MultisampleEnable", assignHdlr_MultisampleEnable );
StateAssignment::registerHandler("MultiSampleAntialias", assignHdlr_MultisampleEnable );
// The OpenMaya API combines the Line and Point smoothing into
// a single control, mainly because there are no such separate
// controls on DX.
StateAssignment::registerHandler("LineSmoothEnable", assignHdlr_LineSmoothEnable );
StateAssignment::registerHandler("PointSmoothEnable", assignHdlr_LineSmoothEnable );
// Depth and stencil states
StateAssignment::registerHandler("DepthTestEnable", assignHdlr_DepthTestEnable );
StateAssignment::registerHandler("ZEnable", assignHdlr_DepthTestEnable );
StateAssignment::registerHandler("DepthMask", assignHdlr_DepthMask );
StateAssignment::registerHandler("ZWriteEnable", assignHdlr_DepthMask );
StateAssignment::registerHandler("DepthFunc", assignHdlr_DepthFunc );
StateAssignment::registerHandler("StencilEnable", assignHdlr_StencilEnable );
StateAssignment::registerHandler("StencilTestEnable", assignHdlr_StencilEnable );
StateAssignment::registerHandler("StencilMask", assignHdlr_StencilWriteMask );
StateAssignment::registerHandler("StencilWriteMask", assignHdlr_StencilWriteMask );
StateAssignment::registerHandler("StencilFunc", assignHdlr_StencilFunc );
StateAssignment::registerHandler("StencilFuncSeparate", assignHdlr_StencilFuncSeparate );
StateAssignment::registerHandler("StencilOp", assignHdlr_StencilOp );
StateAssignment::registerHandler("StencilOpSeparate", assignHdlr_StencilOpSeparate );
StateAssignment::registerHandler("StencilRef", assignHdlr_StencilRef );
StateAssignment::registerHandler("StencilFail", assignHdlr_StencilFail );
StateAssignment::registerHandler("StencilZFail", assignHdlr_StencilZFail );
StateAssignment::registerHandler("StencilPass", assignHdlr_StencilPass );
// Unsupported states
StateAssignment::registerUnsupportedCheck("AutoNormalEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("AlphaTestEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("ClipPlaneEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("ColorLogicOpEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("ColorVertex", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("DepthBoundsEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("DepthClampEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("DitherEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("FogEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("LightEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("LightModelLocalViewerEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("LightModelTwoSideEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("LightingEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("LineStippleEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("LocalViewer", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("LogicOpEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("NormalizeEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("PointScaleEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("PointSmoothEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("PointSpriteCoordReplace", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("PointSpriteEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("PolygonOffsetLineEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("PolygonOffsetPointEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("PolygonStippleEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("RescaleNormalEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("SampleAlphaToCoverageEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("SampleAlphaToOneEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("SampleCoverageEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("ScissorTestEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("StencilTestTwoSideEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("TexGenQEnable", unsupportedIfTrue);
StateAssignment::registerUnsupportedCheck("TexGenREnable", unsupportedIfTrue );
StateAssignment::registerUnsupportedCheck("TexGenSEnable", unsupportedIfTrue );
StateAssignment::registerUnsupportedCheck("TexGenTEnable", unsupportedIfTrue );
StateAssignment::registerUnsupportedCheck("Texture1DEnable", unsupportedIfTrue );
StateAssignment::registerUnsupportedCheck("Texture2DEnable", unsupportedIfTrue );
StateAssignment::registerUnsupportedCheck("Texture3DEnable", unsupportedIfTrue );
StateAssignment::registerUnsupportedCheck("TextureCubeMapEnable", unsupportedIfTrue );
StateAssignment::registerUnsupportedCheck("TextureRectangleEnable", unsupportedIfTrue );
StateAssignment::registerUnsupportedCheck("VertexProgramPointSizeEnable", unsupportedIfTrue );
StateAssignment::registerUnsupportedCheck("VertexProgramTwoSideEnable", unsupportedIfTrue );
initialized = true;
}
if(mode == cgfxPassStateSetter::kUnknown)
return false;
if(mode == cgfxPassStateSetter::sActiveViewportMode)
return true;
if(mode == cgfxPassStateSetter::kDefaultViewport)
{
StateAssignment::registerDefaultCallBacks();
sActiveViewportMode = cgfxPassStateSetter::kDefaultViewport;
}
else
{
StateAssignment::registerVP20CallBacks();
sActiveViewportMode = cgfxPassStateSetter::kVP20Viewport;
}
return true;
}
cgfxPassStateSetter::cgfxPassStateSetter()
: fBlendState(NULL),
fRasterizerState(NULL),
fDepthStencilState(NULL),
fIsPushPopAttribsRequired(false)
{}
void cgfxPassStateSetter::init(
MStateManager* stateMgr,
CGpass pass
)
{
// Start with the default state!
MBlendStateDesc blendStateDesc;
MRasterizerStateDesc rasterizerStateDesc;
MDepthStencilStateDesc depthStencilStateDesc;
CGstateassignment sa = cgGetFirstStateAssignment(pass);
while (sa) {
fIsPushPopAttribsRequired |=
StateAssignment::callHandler(sa,
&blendStateDesc,
&rasterizerStateDesc,
&depthStencilStateDesc);
sa = cgGetNextStateAssignment(sa);
}
fBlendState = stateMgr->acquireBlendState(blendStateDesc);
fDepthStencilState = stateMgr->acquireDepthStencilState(depthStencilStateDesc);
fRasterizerState = stateMgr->acquireRasterizerState(rasterizerStateDesc);
}
cgfxPassStateSetter::~cgfxPassStateSetter()
{
MStateManager::releaseBlendState(fBlendState);
fBlendState = NULL;
MStateManager::releaseDepthStencilState(fDepthStencilState);
fDepthStencilState = NULL;
MStateManager::releaseRasterizerState(fRasterizerState);
fRasterizerState = NULL;
}
void cgfxPassStateSetter::setPassState(MStateManager* stateMgr) const
{
stateMgr->setBlendState(fBlendState);
stateMgr->setDepthStencilState(fDepthStencilState);
stateMgr->setRasterizerState(fRasterizerState);
}