#ifdef WIN32
#pragma warning( disable : 4786 ) // Disable STL warnings.
#endif
#include <maya/MIOStream.h>
#include <math.h>
#include <maya/MGlobal.h>
#include <maya/MString.h>
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFloatVector.h>
#include <maya/MFnPlugin.h>
#include <maya/MSceneMessage.h>
#include <maya/MUserData.h>
#include <maya/MHWShaderSwatchGenerator.h>
#include <maya/MHardwareRenderer.h>
#include <maya/MGeometryData.h>
#include <maya/MImage.h>
#include <maya/MMatrix.h>
#include <maya/MDrawRegistry.h>
#include <maya/MPxShaderOverride.h>
#include <maya/MDrawContext.h>
#include <maya/MStateManager.h>
#include <maya/MViewport2Renderer.h>
#include <maya/MTextureManager.h>
#include <maya/MShaderManager.h>
#include <maya/MGLdefinitions.h>
#include <maya/MGLFunctionTable.h>
#if defined(OSMac_MachO_)
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#endif
#undef ENABLE_TRACE_API_CALLS
#ifdef ENABLE_TRACE_API_CALLS
#define TRACE_API_CALLS(x) cerr << "hwPhongShader: "<<(x)<<"\n"
#else
#define TRACE_API_CALLS(x)
#endif
#ifndef GL_EXT_texture_cube_map
# define GL_NORMAL_MAP_EXT 0x8511
# define GL_REFLECTION_MAP_EXT 0x8512
# define GL_TEXTURE_CUBE_MAP_EXT 0x8513
# define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514
# define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515
# define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516
# define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517
# define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518
# define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519
# define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A
# define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B
# define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C
#endif
#include "hwPhongShader.h"
#include "hwPhongShaderBehavior.h"
MTypeId hwPhongShader::id( 0x00105449 );
MObject hwPhongShader::aColor;
MObject hwPhongShader::aTransparency;
MObject hwPhongShader::aDiffuseColor;
MObject hwPhongShader::aSpecularColor;
MObject hwPhongShader::aShininess;
MObject hwPhongShader::aGeometryShape;
void hwPhongShader::postConstructor( )
{
TRACE_API_CALLS("postConstructor");
setMPSafe(false);
}
void hwPhongShader::printGlError( const char *call )
{
GLenum error;
while( (error = glGetError()) != GL_NO_ERROR ) {
cerr << call << ":" << error << " is " << (const char *)gluErrorString( error ) << "\n";
}
}
MFloatVector hwPhongShader::Phong ( double cos_a )
{
MFloatVector p;
if ( cos_a < 0.0 ) cos_a = 0.0;
p[0] = (float)(mSpecularColor[0]*pow(cos_a,double(mShininess[0])) +
mDiffuseColor[0]*cos_a + mAmbientColor[0]);
p[1] = (float)(mSpecularColor[1]*pow(cos_a,double(mShininess[1])) +
mDiffuseColor[1]*cos_a + mAmbientColor[1]);
p[2] = (float)(mSpecularColor[2]*pow(cos_a,double(mShininess[2])) +
mDiffuseColor[2]*cos_a + mAmbientColor[2]);
if ( p[0] > 1.0f ) p[0] = 1.0f;
if ( p[1] > 1.0f ) p[1] = 1.0f;
if ( p[2] > 1.0f ) p[2] = 1.0f;
return p;
}
#define PHONG_TEXTURE_RES 256
static const GLenum faceTarget[6] =
{
GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT
};
class CubeMapTextureDrawUtility
{
public:
static void bind( unsigned int phong_map_id )
{
{
glPushAttrib ( GL_ENABLE_BIT | GL_LIGHTING_BIT | GL_TEXTURE_BIT | GL_TRANSFORM_BIT );
glDisable ( GL_LIGHTING );
glDisable ( GL_TEXTURE_1D );
glDisable ( GL_TEXTURE_2D );
glEnable ( GL_TEXTURE_CUBE_MAP_EXT );
glBindTexture ( GL_TEXTURE_CUBE_MAP_EXT, phong_map_id );
glEnable ( GL_TEXTURE_GEN_S );
glEnable ( GL_TEXTURE_GEN_T );
glEnable ( GL_TEXTURE_GEN_R );
glTexGeni ( GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT );
glTexGeni ( GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT );
glTexGeni ( GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT );
glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glMatrixMode ( GL_TEXTURE );
glPushMatrix ();
glLoadIdentity ();
glMatrixMode ( GL_MODELVIEW );
}
}
static void unbind()
{
glMatrixMode ( GL_TEXTURE );
glPopMatrix ();
glMatrixMode ( GL_MODELVIEW );
glBindTexture( GL_TEXTURE_CUBE_MAP_EXT, 0 );
glDisable ( GL_TEXTURE_CUBE_MAP_EXT );
glPopAttrib();
}
};
static void cubeToDir ( int face, double s, double t,
double &x, double &y, double &z )
{
switch ( face )
{
case 0:
x = 1;
y = -t;
z = -s;
break;
case 1:
x = -1;
y = -t;
z = s;
break;
case 2:
x = s;
y = 1;
z = t;
break;
case 3:
x = s;
y = -1;
z = -t;
break;
case 4:
x = s;
y = -t;
z = 1;
break;
case 5:
x = -s;
y = -t;
z = -1;
break;
}
double invLen = 1.0 / sqrt ( x*x + y*y + z*z );
x *= invLen;
y *= invLen;
z *= invLen;
}
void hwPhongShader::init_Phong_texture ( void )
{
if ( !mAttributesChanged && (phong_map_id != 0))
{
return;
}
GLubyte * texture_data;
if (phong_map_id != 0)
glDeleteTextures( 1, &phong_map_id );
glGenTextures ( 1, &phong_map_id );
glEnable ( GL_TEXTURE_CUBE_MAP_EXT );
glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 );
glPixelStorei ( GL_UNPACK_ROW_LENGTH, 0 );
glBindTexture ( GL_TEXTURE_CUBE_MAP_EXT, phong_map_id );
texture_data = new GLubyte[3*PHONG_TEXTURE_RES*PHONG_TEXTURE_RES];
for ( int face=0 ; face<6 ; face++ )
{
int index = 0;
for ( int j=0 ; j<PHONG_TEXTURE_RES ; j++ )
{
double t = 2*double(j)/(PHONG_TEXTURE_RES - 1) - 1;
for ( int i=0 ; i<PHONG_TEXTURE_RES ; i++ )
{
double s = 2*double(i)/(PHONG_TEXTURE_RES - 1) - 1;
double x = 0.0, y = 0.0, z = 0.0;
cubeToDir ( face, s, t, x, y, z );
MFloatVector intensity = Phong ( z );
texture_data[index++] = (GLubyte)(255*intensity[0]);
texture_data[index++] = (GLubyte)(255*intensity[1]);
texture_data[index++] = (GLubyte)(255*intensity[2]);
}
}
glTexImage2D ( faceTarget[face], 0, GL_RGB, PHONG_TEXTURE_RES, PHONG_TEXTURE_RES,
0, GL_RGB, GL_UNSIGNED_BYTE, texture_data );
}
glDisable ( GL_TEXTURE_CUBE_MAP_EXT );
delete [] texture_data;
mAttributesChanged = false;
}
hwPhongShader::hwPhongShader()
{
TRACE_API_CALLS("hwPhongShader");
attachSceneCallbacks();
mAmbientColor[0] = mAmbientColor[1] = mAmbientColor[2] = 0.1f;
mDiffuseColor[0] = mDiffuseColor[1] = mDiffuseColor[2] = 0.5f;
mSpecularColor[0] = mSpecularColor[1] = mSpecularColor[2] = 0.5f;
mShininess[0] = mShininess[1] = mShininess[2] = 100.0f;
mAttributesChanged = false;
mAttributesChangedVP2 = true;
phong_map_id = 0;
mGeometryShape = 0;
mTransparency = 0.0f;
}
hwPhongShader::~hwPhongShader()
{
TRACE_API_CALLS("~hwPhongShader");
detachSceneCallbacks();
}
void hwPhongShader::releaseEverything()
{
if (phong_map_id != 0) {
M3dView view = M3dView::active3dView();
if (view.beginGL()) {
glDeleteTextures( 1, &phong_map_id );
phong_map_id = 0;
}
view.endGL();
}
}
void hwPhongShader::attachSceneCallbacks()
{
fBeforeNewCB = MSceneMessage::addCallback(MSceneMessage::kBeforeNew, releaseCallback, this);
fBeforeOpenCB = MSceneMessage::addCallback(MSceneMessage::kBeforeOpen, releaseCallback, this);
fBeforeRemoveReferenceCB = MSceneMessage::addCallback(MSceneMessage::kBeforeRemoveReference,
releaseCallback, this);
fMayaExitingCB = MSceneMessage::addCallback(MSceneMessage::kMayaExiting, releaseCallback, this);
}
void hwPhongShader::releaseCallback(void* clientData)
{
hwPhongShader *pThis = (hwPhongShader*) clientData;
pThis->releaseEverything();
}
void hwPhongShader::detachSceneCallbacks()
{
if (fBeforeNewCB)
MMessage::removeCallback(fBeforeNewCB);
if (fBeforeOpenCB)
MMessage::removeCallback(fBeforeOpenCB);
if (fBeforeRemoveReferenceCB)
MMessage::removeCallback(fBeforeRemoveReferenceCB);
if (fMayaExitingCB)
MMessage::removeCallback(fMayaExitingCB);
fBeforeNewCB = 0;
fBeforeOpenCB = 0;
fBeforeRemoveReferenceCB = 0;
fMayaExitingCB = 0;
}
static const MString sHWPhongShaderRegistrantId("HWPhongShaderRegistrantId");
class hwPhongShaderData : public MUserData
{
public:
hwPhongShaderData() : MUserData(true) {}
virtual ~hwPhongShaderData() {}
MString fPath;
};
class hwPhongShaderOverride : public MHWRender::MPxShaderOverride
{
public:
static MHWRender::MPxShaderOverride* Creator(const MObject& obj)
{
return new hwPhongShaderOverride(obj);
}
virtual ~hwPhongShaderOverride()
{
delete[] fTextureData;
fTextureData = NULL;
fShaderNode = NULL;
MHWRender::MRenderer* theRenderer = MHWRender::MRenderer::theRenderer();
if (theRenderer)
{
MHWRender::MTextureManager *theTextureManager = theRenderer->getTextureManager();
if (theTextureManager)
{
if (fTexture)
{
theTextureManager->releaseTexture(fTexture);
}
}
const MHWRender::MShaderManager* shaderMgr = theRenderer->getShaderManager();
if (shaderMgr)
{
if (fColorShaderInstance)
{
shaderMgr->releaseShader(fColorShaderInstance);
}
if (fShadowShaderInstance)
{
shaderMgr->releaseShader(fShadowShaderInstance);
}
}
}
fTexture = NULL;
fColorShaderInstance = NULL;
fShadowShaderInstance = NULL;
}
virtual MString initialize(
const MInitContext& initContext,
MInitFeedback& initFeedback)
{
TRACE_API_CALLS("hwPhongShaderOverride::initialize");
if (fColorShaderInstance)
{
setGeometryRequirements( *fColorShaderInstance );
addShaderSignature( *fColorShaderInstance );
}
else
{
MString empty;
static bool useCustomPrimitiveGenerator = (getenv("MAYA_USE_CUSTOMPRIMITIVEGENERATOR") != NULL);
if(useCustomPrimitiveGenerator)
{
MString customPrimitiveName("customPrimitiveTest");
MHWRender::MIndexBufferDescriptor indexingRequirement(
MHWRender::MIndexBufferDescriptor::kCustom,
customPrimitiveName,
MHWRender::MGeometry::kTriangles);
addIndexingRequirement(indexingRequirement);
MHWRender::MVertexBufferDescriptor positionDesc(
empty,
MHWRender::MGeometry::kPosition,
MHWRender::MGeometry::kFloat,
3);
positionDesc.setSemanticName("customPositionStream");
MHWRender::MVertexBufferDescriptor normalDesc(
empty,
MHWRender::MGeometry::kNormal,
MHWRender::MGeometry::kFloat,
3);
normalDesc.setSemanticName("customNormalStream");
addGeometryRequirement(positionDesc);
addGeometryRequirement(normalDesc);
}
else
{
MHWRender::MVertexBufferDescriptor positionDesc(
empty,
MHWRender::MGeometry::kPosition,
MHWRender::MGeometry::kFloat,
3);
positionDesc.setSemanticName("swizzlePosition");
MHWRender::MVertexBufferDescriptor normalDesc(
empty,
MHWRender::MGeometry::kNormal,
MHWRender::MGeometry::kFloat,
3);
addGeometryRequirement(positionDesc);
addGeometryRequirement(normalDesc);
}
}
hwPhongShaderData* data = new hwPhongShaderData();
data->fPath = initContext.dagPath.fullPathName();
initFeedback.customData = data;
return MString("Autodesk Maya hwPhongShaderOverride");
}
virtual void updateDG(MObject object)
{
TRACE_API_CALLS("hwPhongShaderOverride::updateDG");
if (object != MObject::kNullObj)
{
fShaderNode = (hwPhongShader *) MPxHwShaderNode::getHwShaderNodePtr( object );
if (fShaderNode)
{
fTransparency = fShaderNode->Transparency();
}
else
{
fTransparency = 0.0f;
}
const float3 * amb = fShaderNode->Ambient();
const float3 * diff = fShaderNode->Diffuse();
const float3 * spec = fShaderNode->Specular();
const float3 * shininess = fShaderNode->Shininess();
fAmbient[0] = (*amb)[0]; fAmbient[1] = (*amb)[1]; fAmbient[2] = (*amb)[2];
fDiffuse[0] = (*diff)[0]; fDiffuse[1] = (*diff)[1]; fDiffuse[2] = (*diff)[2];
fDiffuse[3] = 1.0f - fTransparency;
fSpecular[0] = (*spec)[0]; fSpecular[1] = (*spec)[1]; fSpecular[2] = (*spec)[2];
fShininess[0] = (*shininess)[0]; fShininess[1] = (*shininess)[1]; fShininess[2] = (*shininess)[2];
}
}
virtual void updateDevice()
{
TRACE_API_CALLS("hwPhongShaderOverride::updateDevice");
if (fDrawUsingShader)
updateShaderInstance();
if (!fColorShaderInstance)
rebuildTexture();
}
virtual void endUpdate()
{
TRACE_API_CALLS("hwPhongShaderOverride::endUpdate");
}
virtual bool handlesDraw(MHWRender::MDrawContext& context)
{
const MHWRender::MPassContext & passCtx = context.getPassContext();
const MString & passId = passCtx.passIdentifier();
const MStringArray & passSem = passCtx.passSemantics();
fInShadowPass = false;
fInColorPass = false;
bool debugHandlesDraw = false;
if (debugHandlesDraw)
printf("In hwPhong shader handlesDraw(). Pass Identifier = %s\n", passId.asChar());
bool handlePass = false;
for (unsigned int i=0; i<passSem.length(); i++)
{
if (passSem[i] == MHWRender::MPassContext::kColorPassSemantic)
{
bool hasOverrideShader = passCtx.hasShaderOverride();
if (!hasOverrideShader)
{
if (debugHandlesDraw)
printf("-> handle semantic[%d][%s]\n", i, passSem[i].asChar());
handlePass = true;
fInColorPass = true;
}
}
else if (passSem[i] == MHWRender::MPassContext::kShadowPassSemantic)
{
if (fShadowShaderInstance)
handlePass = true;
if (debugHandlesDraw)
printf("-> handle semantic[%d][%s] = %d\n", i, passSem[i].asChar(), handlePass);
fInShadowPass = true;
}
else if (passSem[i] == MHWRender::MPassContext::kDepthPassSemantic)
{
if (debugHandlesDraw)
printf("-> don't handle semantic[%d][%s]\n", i, passSem[i].asChar());
handlePass = false;
}
else if (passSem[i] == MHWRender::MPassContext::kNormalDepthPassSemantic)
{
if (debugHandlesDraw)
printf("-> don't handle semantic[%d][%s]\n", i, passSem[i].asChar());
handlePass = false;
}
else
{
if (debugHandlesDraw)
printf("-> additional semantic[%d][%s]\n", i, passSem[i].asChar());
}
}
return handlePass;
}
virtual MHWRender::MShaderInstance* shaderInstance() const
{
if (fDrawUsingShader)
{
if (fInColorPass)
{
if (fColorShaderInstance)
return fColorShaderInstance;
}
else if (fInShadowPass)
{
if (fShadowShaderInstance)
return fShadowShaderInstance;
}
}
return NULL;
}
virtual void activateKey(MHWRender::MDrawContext& context, const MString& key)
{
TRACE_API_CALLS("hwPhongShaderOverride::activateKey");
fShaderBound = false;
if (fDrawUsingShader)
{
if (fInColorPass && fColorShaderInstance)
{
fColorShaderInstance->bind( context );
fShaderBound = true;
}
else if (fInShadowPass && fShadowShaderInstance)
{
MMatrix viewProj = context.getMatrix(MHWRender::MFrameContext::kViewProjMtx);
fShadowShaderInstance->setParameter("shadowViewProj", viewProj );
fShadowShaderInstance->bind( context );
fShaderBound = true;
}
}
}
virtual void terminateKey(MHWRender::MDrawContext& context, const MString& key)
{
TRACE_API_CALLS("hwPhongShaderOverride::terminateKey");
if (fShaderBound)
{
if (fInColorPass && fColorShaderInstance)
{
fColorShaderInstance->unbind( context );
}
else if (fInShadowPass && fShadowShaderInstance)
{
fShadowShaderInstance->unbind( context );
}
}
fShaderBound = false;
}
virtual bool draw(
MHWRender::MDrawContext& context,
const MHWRender::MRenderItemList& renderItemList) const
{
TRACE_API_CALLS("hwPhongShaderOverride::draw");
MHWRender::MStateManager* stateMgr = context.getStateManager();
if(sBlendState == NULL)
{
MHWRender::MBlendStateDesc blendStateDesc;
for(int i = 0; i < (blendStateDesc.independentBlendEnable ? MHWRender::MBlendState::kMaxTargets : 1); ++i)
{
blendStateDesc.targetBlends[i].blendEnable = true;
blendStateDesc.targetBlends[i].sourceBlend = MHWRender::MBlendState::kSourceAlpha;
blendStateDesc.targetBlends[i].destinationBlend = MHWRender::MBlendState::kInvSourceAlpha;
blendStateDesc.targetBlends[i].blendOperation = MHWRender::MBlendState::kAdd;
blendStateDesc.targetBlends[i].alphaSourceBlend = MHWRender::MBlendState::kOne;
blendStateDesc.targetBlends[i].alphaDestinationBlend = MHWRender::MBlendState::kInvSourceAlpha;
blendStateDesc.targetBlends[i].alphaBlendOperation = MHWRender::MBlendState::kAdd;
}
blendStateDesc.blendFactor[0] = 1.0f;
blendStateDesc.blendFactor[1] = 1.0f;
blendStateDesc.blendFactor[2] = 1.0f;
blendStateDesc.blendFactor[3] = 1.0f;
sBlendState = stateMgr->acquireBlendState(blendStateDesc);
}
int val = 0;
bool debugDrawContext = false;
if (MGlobal::getOptionVarValue("hwPhong_debugDrawContext", val))
{
debugDrawContext = (val > 0);
}
if (debugDrawContext)
printContextInformation(context);
const MHWRender::MPassContext & passCtx = context.getPassContext();
const MStringArray & passSem = passCtx.passSemantics();
bool debugPassInformation = false;
if (debugPassInformation)
{
const MString & passId = passCtx.passIdentifier();
printf("hwPhong node drawing in pass[%s], semantic[", passId.asChar());
for (unsigned int i=0; i<passSem.length(); i++)
printf(" %s", passSem[i].asChar());
printf(" ]\n");
}
const MHWRender::MBlendState* pOldBlendState = stateMgr->getBlendState();
if (fShaderBound)
{
if (fInColorPass)
{
bool needBlending = false;
if (fTransparency > 0.0f)
{
needBlending = true;
stateMgr->setBlendState(sBlendState);
}
unsigned int passCount = fColorShaderInstance->getPassCount( context );
if (passCount)
{
for (unsigned int i=0; i<passCount; i++)
{
fColorShaderInstance->activatePass( context, i );
MHWRender::MPxShaderOverride::drawGeometry(context);
}
}
if (needBlending)
{
stateMgr->setBlendState(pOldBlendState);
}
}
else if (fInShadowPass)
{
unsigned int passCount = fShadowShaderInstance->getPassCount( context );
if (passCount)
{
for (unsigned int i=0; i<passCount; i++)
{
fShadowShaderInstance->activatePass( context, i );
MHWRender::MPxShaderOverride::drawGeometry(context);
}
}
}
}
else
{
int phongTextureId = 0;
MHWRender::MRenderer *theRenderer = MHWRender::MRenderer::theRenderer();
if (theRenderer)
{
MHWRender::MTextureManager *theTextureManager = theRenderer->getTextureManager();
if(theTextureManager)
{
if(fTexture)
{
void *idPtr = fTexture->resourceHandle();
if (idPtr)
{
phongTextureId = *((int *)idPtr);
}
}
}
}
if (phongTextureId == 0)
{
return false;
}
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
MStatus status;
MMatrix transform =
context.getMatrix(MHWRender::MFrameContext::kWorldViewMtx, &status);
if (status)
{
glLoadMatrixd(transform.matrix[0]);
}
glMatrixMode(GL_PROJECTION);
glPushMatrix();
MMatrix projection =
context.getMatrix(MHWRender::MFrameContext::kProjectionMtx, &status);
if (status)
{
glLoadMatrixd(projection.matrix[0]);
}
bool needBlending = false;
if (fTransparency > 0.0f)
{
needBlending = true;
stateMgr->setBlendState(sBlendState);
glColor4f(1.0, 1.0, 1.0, 1.0f-fTransparency );
}
else
glColor4f(1.0, 1.0, 1.0, 1.0f);
CubeMapTextureDrawUtility::bind( phongTextureId );
bool debugGeometricDraw = false;
if (debugGeometricDraw)
{
customDraw(context, renderItemList);
}
else
{
MHWRender::MPxShaderOverride::drawGeometry(context);
}
CubeMapTextureDrawUtility::unbind();
if (needBlending)
{
glColor4f(1.0, 1.0, 1.0, 1.0 );
stateMgr->setBlendState(pOldBlendState);
}
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
return true;
}
void customDraw(
MHWRender::MDrawContext& context,
const MHWRender::MRenderItemList& renderItemList) const
{
static MGLFunctionTable *gGLFT = 0;
if ( 0 == gGLFT )
gGLFT = MHardwareRenderer::theRenderer()->glFunctionTable();
MGLenum currentError = 0;
glPushClientAttrib ( GL_CLIENT_ALL_ATTRIB_BITS );
{
int numRenderItems = renderItemList.length();
for (int renderItemIdx=0; renderItemIdx<numRenderItems; renderItemIdx++)
{
const MHWRender::MRenderItem* renderItem = renderItemList.itemAt(renderItemIdx);
if (!renderItem) continue;
const MHWRender::MGeometry* geometry = renderItem->geometry();
if (!geometry) continue;
hwPhongShaderData* phongData = dynamic_cast<hwPhongShaderData*>(renderItem->customData());
if (phongData)
{
fprintf(stderr, "Source object path=%s\n", phongData->fPath.asChar());
}
int bufferCount = geometry->vertexBufferCount();
#define GLOBJECT_BUFFER_OFFSET(i) ((char *)NULL + (i)) // For GLObject offsets
bool boundData = true;
for (int i=0; i<bufferCount && boundData; i++)
{
const MHWRender::MVertexBuffer* buffer = geometry->vertexBuffer(i);
if (!buffer)
{
boundData = false;
continue;
}
const MHWRender::MVertexBufferDescriptor& desc = buffer->descriptor();
GLuint * dataBufferId = NULL;
void *dataHandle = buffer->resourceHandle();
if (!dataHandle)
{
boundData = false;
continue;
}
dataBufferId = (GLuint *)(dataHandle);
unsigned int fieldOffset = desc.offset();
unsigned int fieldStride = desc.stride();
{
fprintf(stderr, "Buffer(%d), Name(%s), BufferType(%s), BufferDimension(%d), BufferSemantic(%s), Offset(%d), Stride(%d), Handle(%d)\n",
i,
desc.name().asChar(),
MHWRender::MGeometry::dataTypeString(desc.dataType()).asChar(),
desc.dimension(),
MHWRender::MGeometry::semanticString(desc.semantic()).asChar(),
fieldOffset,
fieldStride,
*dataBufferId);
}
if (*dataBufferId > 0)
{
gGLFT->glBindBufferARB(MGL_ARRAY_BUFFER_ARB, *dataBufferId);
currentError = gGLFT->glGetError();
if (currentError != MGL_NO_ERROR)
boundData = false;
}
else
boundData = false;
if (boundData)
{
if (desc.semantic() == MHWRender::MGeometry::kPosition)
{
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, fieldStride*4, GLOBJECT_BUFFER_OFFSET(fieldOffset));
currentError = gGLFT->glGetError();
if (currentError != MGL_NO_ERROR)
boundData = false;
}
else if (desc.semantic() == MHWRender::MGeometry::kNormal)
{
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, fieldStride*4, GLOBJECT_BUFFER_OFFSET(fieldOffset));
currentError = gGLFT->glGetError();
if (currentError != MGL_NO_ERROR)
boundData = false;
}
}
}
if (boundData && geometry->indexBufferCount() > 0)
{
const MHWRender::MIndexBuffer* buffer = geometry->indexBuffer(0);
void *indexHandle = buffer->resourceHandle();
unsigned int indexBufferCount = 0;
GLuint *indexBufferId = NULL;
MHWRender::MGeometry::Primitive indexPrimType = renderItem->primitive();
if (indexHandle)
{
indexBufferId = (GLuint *)(indexHandle);
indexBufferCount = buffer->size();
{
fprintf(stderr, "IndexingPrimType(%s), IndexType(%s), IndexCount(%d), Handle(%d)\n",
MHWRender::MGeometry::primitiveString(indexPrimType).asChar(),
MHWRender::MGeometry::dataTypeString(buffer->dataType()).asChar(),
indexBufferCount,
*indexBufferId);
}
}
if (indexBufferId && (*indexBufferId > 0))
{
gGLFT->glBindBufferARB(MGL_ELEMENT_ARRAY_BUFFER_ARB, *indexBufferId);
currentError = gGLFT->glGetError();
if (currentError == MGL_NO_ERROR)
{
GLenum indexPrimTypeGL = GL_TRIANGLES;
switch (indexPrimType) {
case MHWRender::MGeometry::kPoints:
indexPrimTypeGL = GL_POINTS; break;
case MHWRender::MGeometry::kLines:
indexPrimTypeGL = GL_LINES; break;
case MHWRender::MGeometry::kLineStrip:
indexPrimTypeGL = GL_LINE_STRIP; break;
case MHWRender::MGeometry::kTriangles:
indexPrimTypeGL = GL_TRIANGLES; break;
case MHWRender::MGeometry::kTriangleStrip:
indexPrimTypeGL = GL_TRIANGLE_STRIP; break;
default:
boundData = false;
break;
};
if (boundData)
{
GLenum indexType =
( buffer->dataType() == MHWRender::MGeometry::kUnsignedInt32 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT );
glDrawElements(indexPrimTypeGL, indexBufferCount, indexType, GLOBJECT_BUFFER_OFFSET(0));
}
}
}
}
}
}
glPopClientAttrib();
}
virtual MHWRender::DrawAPI supportedDrawAPIs() const
{
if (fDrawUsingShader)
return (MHWRender::kOpenGL | MHWRender::kDirectX11);
else
return MHWRender::kOpenGL;
}
virtual bool isTransparent()
{
TRACE_API_CALLS("hwPhongShaderOverride::isTransparent");
if (fShaderNode)
{
return (fTransparency > 0.0f);
}
return false;
}
virtual bool overridesDrawState()
{
return true;
}
void debugShaderParameters(const MHWRender::MShaderInstance *shaderInstance)
{
MStringArray params;
shaderInstance->parameterList(params);
unsigned int numParams = params.length();
printf("DEBUGGING SHADER, BEGIN PARAM LIST OF LENGTH %d\n", numParams);
for (unsigned int i=0; i<numParams; i++)
{
printf("ParamName='%s', ParamType=", params[i].asChar());
switch (shaderInstance->parameterType(params[i]))
{
case MHWRender::MShaderInstance::kInvalid:
printf("'Invalid', ");
break;
case MHWRender::MShaderInstance::kBoolean:
printf("'Boolean', ");
break;
case MHWRender::MShaderInstance::kInteger:
printf("'Integer', ");
break;
case MHWRender::MShaderInstance::kFloat:
printf("'Float', ");
break;
case MHWRender::MShaderInstance::kFloat2:
printf("'Float2', ");
break;
case MHWRender::MShaderInstance::kFloat3:
printf("'Float3', ");
break;
case MHWRender::MShaderInstance::kFloat4:
printf("'Float4', ");
break;
case MHWRender::MShaderInstance::kFloat4x4Row:
printf("'Float4x4Row', ");
break;
case MHWRender::MShaderInstance::kFloat4x4Col:
printf("'Float4x4Col', ");
break;
case MHWRender::MShaderInstance::kTexture1:
printf("'1D Texture', ");
break;
case MHWRender::MShaderInstance::kTexture2:
printf("'2D Texture', ");
break;
case MHWRender::MShaderInstance::kTexture3:
printf("'3D Texture', ");
break;
case MHWRender::MShaderInstance::kTextureCube:
printf("'Cube Texture', ");
break;
case MHWRender::MShaderInstance::kSampler:
printf("'Sampler', ");
break;
default:
printf("'Unknown', ");
break;
}
printf("IsArrayParameter='%s'\n", shaderInstance->isArrayParameter(params[i]) ? "YES" : "NO");
}
printf("END PARAM LIST\n");
}
void createShaderInstance()
{
TRACE_API_CALLS("hwPhongShaderOverride::createShaderInstance");
MHWRender::MRenderer *renderer = MHWRender::MRenderer::theRenderer();
if (!renderer)
return;
const MHWRender::MShaderManager* shaderMgr = renderer->getShaderManager();
if (!shaderMgr)
return;
bool debugShader = false;
if (!fShadowShaderInstance)
{
fShadowShaderInstance = shaderMgr->getStockShader( MHWRender::MShaderManager::k3dShadowerShader );
if (fShadowShaderInstance)
{
if (debugShader)
debugShaderParameters( fShadowShaderInstance );
}
else
{
fprintf(stderr, "Failed to load shadower shader for hwPhong\n");
}
}
if (!fColorShaderInstance)
{
fColorShaderInstance = shaderMgr->getStockShader( MHWRender::MShaderManager::k3dBlinnShader );
if (fColorShaderInstance && debugShader)
{
debugShaderParameters( fColorShaderInstance );
}
}
}
void updateShaderInstance()
{
TRACE_API_CALLS("hwPhongShaderOverride::updateShaderInstance");
MHWRender::MRenderer *renderer = MHWRender::MRenderer::theRenderer();
if (!renderer)
return;
if (fColorShaderInstance)
{
fColorShaderInstance->setIsTransparent( isTransparent() );
if (fShaderNode && fShaderNode->attributesChangedVP2())
{
fColorShaderInstance->setParameter("emissionColor", &fAmbient[0] );
fColorShaderInstance->setParameter("diffuseColor", &fDiffuse[0] );
fColorShaderInstance->setParameter("specularColor", &fSpecular[0] );
float specPower = fShininess[0];
fColorShaderInstance->setParameter("specularPower", specPower );
fShaderNode->resetAttributesChangedVP2();
}
}
}
void rebuildTexture()
{
TRACE_API_CALLS("hwPhongShaderOverride::rebuildTexture");
if (fShaderNode && fShaderNode->attributesChangedVP2())
{
MHWRender::MRenderer *theRenderer = MHWRender::MRenderer::theRenderer();
if (theRenderer)
{
MHWRender::MTextureManager *theTextureManager = theRenderer ? theRenderer->getTextureManager() : NULL;
MString newTextureName = MString("MyPhongCubeMap__");
const float3 * amb = fShaderNode->Ambient();
const float3 * diff = fShaderNode->Diffuse();
const float3 * spec= fShaderNode->Specular();
const float3 * shininess = fShaderNode->Shininess();
newTextureName += (*amb)[0]; newTextureName += MString("_");
newTextureName += (*amb)[1]; newTextureName += MString("_");
newTextureName += (*amb)[2]; newTextureName += MString("_");
newTextureName += (*diff)[0]; newTextureName += MString("_");
newTextureName += (*diff)[1]; newTextureName += MString("_");
newTextureName += (*diff)[2]; newTextureName += MString("_");
newTextureName += (*spec)[0]; newTextureName += MString("_");
newTextureName += (*spec)[1]; newTextureName += MString("_");
newTextureName += (*spec)[2]; newTextureName += MString("_");
newTextureName += (*shininess)[0]; newTextureName += MString("_");
newTextureName += (*shininess)[1]; newTextureName += MString("_");
newTextureName += (*shininess)[2];
if(fTexture)
{
if (theTextureManager)
{
theTextureManager->releaseTexture(fTexture);
}
fTexture = NULL;
}
if (!fTextureData)
{
fTextureData =
new unsigned char[4*PHONG_TEXTURE_RES*PHONG_TEXTURE_RES*6];
}
if (fTextureData)
{
int index = 0;
for ( int face=0 ; face<6 ; face++ )
{
for ( int j=0 ; j<PHONG_TEXTURE_RES ; j++ )
{
double t = 2*double(j)/(PHONG_TEXTURE_RES - 1) - 1;
for ( int i=0 ; i<PHONG_TEXTURE_RES ; i++ )
{
double s = 2*double(i)/(PHONG_TEXTURE_RES - 1) - 1;
double x = 0.0, y = 0.0, z = 0.0;
cubeToDir ( face, s, t, x, y, z );
MFloatVector intensity = fShaderNode->Phong ( z );
fTextureData[index++] = (unsigned char)(255*intensity[0]);
fTextureData[index++] = (unsigned char)(255*intensity[1]);
fTextureData[index++] = (unsigned char)(255*intensity[2]);
fTextureData[index++] = 255;
}
}
}
MHWRender::MTextureDescription desc;
{
desc.setToDefault2DTexture();
desc.fWidth = PHONG_TEXTURE_RES;
desc.fHeight = PHONG_TEXTURE_RES;
desc.fDepth = 1;
desc.fBytesPerRow = 4*PHONG_TEXTURE_RES;
desc.fBytesPerSlice = 4*PHONG_TEXTURE_RES*PHONG_TEXTURE_RES;
desc.fMipmaps = 1;
desc.fArraySlices = 6;
desc.fFormat = MHWRender::kR8G8B8A8_UNORM;
desc.fTextureType = MHWRender::kCubeMap;
}
if (theTextureManager)
{
fTexture = theTextureManager->acquireTexture( newTextureName, desc, fTextureData );
}
}
fShaderNode->resetAttributesChangedVP2();
}
}
}
static void printContextInformation( const MHWRender::MDrawContext & context )
{
TRACE_API_CALLS("hwPhongShaderOverride::printContextInformation");
MDoubleArray dtuple;
printf("Draw Context Diagnostics {\n");
{
dtuple = context.getTuple( MHWRender::MFrameContext::kViewPosition );
printf("\tView position: %f, %f, %f\n", dtuple[0], dtuple[1], dtuple[2]);
dtuple = context.getTuple( MHWRender::MFrameContext::kViewPosition );
printf("\tView dir : %f, %f, %f\n", dtuple[0], dtuple[1], dtuple[2]);
dtuple = context.getTuple( MHWRender::MFrameContext::kViewUp );
printf("\tView up : %f, %f, %f\n", dtuple[0], dtuple[1], dtuple[2]);
dtuple = context.getTuple( MHWRender::MFrameContext::kViewRight );
printf("\tView right : %f, %f, %f\n", dtuple[0], dtuple[1], dtuple[2]);
printf("\n");
MBoundingBox bbox = context.getSceneBox();
MPoint bmin = bbox.min();
MPoint bmax = bbox.max();
printf("\tScene bounding box = %g,%g,%g -> %g,%g,%g\n",
bmin[0],bmin[1],bmin[2],
bmax[0],bmax[1],bmax[2]);
int originX; int originY; int width; int height;
context.getRenderTargetSize( width, height );
printf("\tRender target size: %d x %d\n", width, height);
context.getViewportDimensions( originX, originY, width, height);
printf("\tViewport dimensions: %d, %d, -> %d, %d\n", originX, originY, width, height);
MStatus xStatus;
printf("\tView direction along neg z = %d\n", context.viewDirectionAlongNegZ( &xStatus ));
static MHWRender::MDrawContext::LightFilter considerAllSceneLights = MHWRender::MDrawContext::kFilteredToLightLimit;
if (considerAllSceneLights == MHWRender::MDrawContext::kFilteredToLightLimit)
considerAllSceneLights = MHWRender::MDrawContext::kFilteredIgnoreLightLimit;
else
considerAllSceneLights = MHWRender::MDrawContext::kFilteredToLightLimit;
printf("\tLight Information for %s\n",
considerAllSceneLights == MHWRender::MDrawContext::kFilteredToLightLimit
? "only lights clamped to light limit." : "lights not clamped to light limit.");
unsigned int lightCount = context.numberOfActiveLights(considerAllSceneLights);
MFloatPointArray positions;
MFloatPoint position;
MFloatVector direction;
float intensity = 1.0f;
MColor color;
bool hasDirection = false;
bool hasPosition = false;
bool visualizeLighting = false;
MMatrix identity;
if (visualizeLighting )
{
for (unsigned int i=0; i<8; i++)
{
GLenum light = GL_LIGHT0+i;
glDisable(light);
}
if (!lightCount)
glDisable(GL_LIGHTING);
else
glEnable(GL_LIGHTING);
}
for (unsigned int i=0; i<lightCount; i++)
{
bool getCommonParametersOnly = true;
if (getCommonParametersOnly)
{
context.getLightInformation( i,
positions, direction,
intensity, color, hasDirection,
hasPosition,
considerAllSceneLights);
printf("\tLight %d {\n", i);
printf("\t\tDirectional %d, Positional %d\n", hasDirection, hasPosition);
printf("\t\tDirection = %g, %g, %g\n", direction[0],direction[1],direction[2]);
unsigned int positionCount = positions.length();
if (hasPosition && positionCount)
{
for (unsigned int p=0; p<positions.length(); p++)
{
printf("\t\tPosition[%d] = %g, %g, %g\n", p, positions[p][0], positions[p][1], positions[p][2]);
position += positions[p];
}
position[0] /= (float)positionCount;
position[1] /= (float)positionCount;
position[2] /= (float)positionCount;
}
printf("\t\tColor = %g, %g, %g\n", color[0], color[1], color[2]);
printf("\t\tIntensity = %g\n", intensity);
printf("\t}\n");
}
else
{
unsigned int positionCount = 0;
position[0] = position[1] = position[2] = 0.0f;
MHWRender::MLightParameterInformation *lightParam =
context.getLightParameterInformation( i, considerAllSceneLights );
if (lightParam)
{
printf("\tLight %d {\n", i);
MStringArray params;
lightParam->parameterList(params);
for (unsigned int p=0; p<params.length(); p++)
{
MString pname = params[p];
MHWRender::MLightParameterInformation::ParameterType ptype = lightParam->parameterType( pname );
MFloatArray floatVals;
MIntArray intVals;
MMatrix matrixVal;
MHWRender::MSamplerStateDesc samplerDesc;
switch (ptype)
{
case MHWRender::MLightParameterInformation::kBoolean:
lightParam->getParameter( pname, intVals );
printf("\t\tLight parameter %s. Bool[%d]\n", pname.asChar(),
intVals[0]);
break;
case MHWRender::MLightParameterInformation::kInteger:
lightParam->getParameter( pname, intVals );
printf("\t\tLight parameter %s. Integer[%d]\n", pname.asChar(),
intVals[0]);
break;
case MHWRender::MLightParameterInformation::kFloat:
lightParam->getParameter( pname, floatVals );
printf("\t\tLight parameter %s. Float[%g]\n", pname.asChar(),
floatVals[0]);
break;
case MHWRender::MLightParameterInformation::kFloat2:
lightParam->getParameter( pname, floatVals );
printf("\t\tLight parameter %s. Float[%g,%g]\n", pname.asChar(),
floatVals[0], floatVals[1]);
break;
case MHWRender::MLightParameterInformation::kFloat3:
lightParam->getParameter( pname, floatVals );
printf("\t\tLight parameter %s. Float3[%g,%g,%g]\n", pname.asChar(),
floatVals[0], floatVals[1], floatVals[2]);
break;
case MHWRender::MLightParameterInformation::kFloat4:
lightParam->getParameter( pname, floatVals );
printf("\t\tLight parameter %s. Float4[%g,%g,%g,%g]\n", pname.asChar(),
floatVals[0], floatVals[1], floatVals[2], floatVals[3]);
break;
case MHWRender::MLightParameterInformation::kFloat4x4Row:
lightParam->getParameter( pname, matrixVal );
printf("\t\tLight parameter %s. Float4x4Row [%g,%g,%g,%g]\n\t\t[%g,%g,%g,%g]\n\t\t[%g,%g,%g,%g]\n\t\t[%g,%g,%g,%g]\n",
pname.asChar(),
matrixVal[0][0], matrixVal[0][1], matrixVal[0][2], matrixVal[0][3],
matrixVal[1][0], matrixVal[1][1], matrixVal[1][2], matrixVal[1][3],
matrixVal[2][0], matrixVal[2][1], matrixVal[2][2], matrixVal[2][3],
matrixVal[3][0], matrixVal[3][1], matrixVal[3][2], matrixVal[3][3]
);
break;
case MHWRender::MLightParameterInformation::kFloat4x4Col:
lightParam->getParameter( pname, matrixVal );
printf("\t\tLight parameter %s. Float4x4Row\n", pname.asChar() );
break;
case MHWRender::MLightParameterInformation::kTexture2:
{
void *handle = lightParam->getParameterTextureHandle( pname );
printf("\t\tLight texture parameter %s. OpenGL texture id = %d\n", pname.asChar(),
*((int *)handle));
break;
}
case MHWRender::MLightParameterInformation::kSampler:
lightParam->getParameter( pname, samplerDesc );
printf("\t\tLight sampler parameter %s. filter = %d\n", pname.asChar(),
samplerDesc.filter );
break;
default:
break;
}
MHWRender::MLightParameterInformation::StockParameterSemantic semantic = lightParam->parameterSemantic( pname );
switch (semantic)
{
case MHWRender::MLightParameterInformation::kLightEnabled:
printf("\t\t- Parameter semantic : light enabled\n");
break;
case MHWRender::MLightParameterInformation::kWorldPosition:
printf("\t\t- Parameter semantic : world position\n");
position += MFloatPoint( floatVals[0], floatVals[1], floatVals[2] );
positionCount++;
hasPosition = true;
break;
case MHWRender::MLightParameterInformation::kWorldDirection:
printf("\t\t- Parameter semantic : world direction\n");
direction = MFloatVector( floatVals[0], floatVals[1], floatVals[2] );
hasDirection = true;
break;
case MHWRender::MLightParameterInformation::kIntensity:
printf("\t\t- Parameter semantic : intensity\n");
intensity = floatVals[0];
break;
case MHWRender::MLightParameterInformation::kColor:
printf("\t\t- Parameter semantic : color\n");
color = MColor( floatVals[0], floatVals[1], floatVals[2] );
break;
case MHWRender::MLightParameterInformation::kEmitsDiffuse:
printf("\t\t- Parameter semantic : emits-diffuse\n");
break;
case MHWRender::MLightParameterInformation::kEmitsSpecular:
printf("\t\t- Parameter semantic : emits-specular\n");
break;
case MHWRender::MLightParameterInformation::kDecayRate:
printf("\t\t- Parameter semantic : decay rate\n");
break;
case MHWRender::MLightParameterInformation::kDropoff:
printf("\t\t- Parameter semantic : drop-off\n");
break;
case MHWRender::MLightParameterInformation::kCosConeAngle:
printf("\t\t- Parameter semantic : cosine cone angle\n");
break;
case MHWRender::MLightParameterInformation::kShadowMap:
printf("\t\t- Parameter semantic : shadow map\n");
break;
case MHWRender::MLightParameterInformation::kShadowSamp:
printf("\t\t- Parameter semantic : shadow map sampler\n");
break;
case MHWRender::MLightParameterInformation::kShadowBias:
printf("\t\t- Parameter semantic : shadow map bias\n");
break;
case MHWRender::MLightParameterInformation::kShadowMapSize:
printf("\t\t- Parameter semantic : shadow map size\n");
break;
case MHWRender::MLightParameterInformation::kShadowViewProj:
printf("\t\t- Parameter semantic : shadow map view projection matrix\n");
break;
case MHWRender::MLightParameterInformation::kShadowColor:
printf("\t\t- Parameter semantic : shadow color\n");
break;
case MHWRender::MLightParameterInformation::kGlobalShadowOn:
printf("\t\t- Parameter semantic : global shadows on \n");
break;
case MHWRender::MLightParameterInformation::kShadowOn:
printf("\t\t- Parameter semantic : local shadows on\n");
break;
default:
break;
}
}
if (positionCount > 1)
{
position[0] /= (float)positionCount;
position[1] /= (float)positionCount;
position[2] /= (float)positionCount;
printf("\t\tCompute average position [%g,%g,%g]\n", position[0],
position[1], position[2]);
}
printf("\t}\n");
}
}
MHWRender::MRenderer *theRenderer = MHWRender::MRenderer::theRenderer();
if (theRenderer && theRenderer->drawAPIIsOpenGL() && visualizeLighting
&& lightCount < 8)
{
GLenum light = GL_LIGHT0+i;
float ambient[3] = { 0.0f, 0.0f, 0.0f };
float specular[3] = { 1.0f, 1.0f, 1.0f };
glLightfv(light, GL_AMBIENT, &ambient[0]);
color[0] *= intensity;
color[1] *= intensity;
color[2] *= intensity;
glLightfv(light, GL_DIFFUSE, &color[0]);
glLightfv(light, GL_SPECULAR, &specular[0]);
glLightf(light, GL_CONSTANT_ATTENUATION, 1.0f);
glLightf(light, GL_LINEAR_ATTENUATION, 0.0f);
glLightf(light, GL_QUADRATIC_ATTENUATION, 0.0f);
glPushMatrix();
glLoadMatrixd( identity.matrix[0] );
if (hasPosition)
glLightfv(light, GL_POSITION, &position[0]);
else {
position[0] = position[1] = position[2] = 0.0f;
glLightfv(light, GL_POSITION, &position[0]);
}
if (hasDirection)
{
glLightf(light, GL_SPOT_CUTOFF, 90.0f);
glLightf(light, GL_SPOT_EXPONENT, 64.0f);
glLightfv(light, GL_SPOT_DIRECTION, &direction[0]);
}
else
{
glLightf(light, GL_SPOT_CUTOFF, 180.0f);
glLightf(light, GL_SPOT_EXPONENT, 0.0f);
}
glEnable(light);
glPopMatrix();
}
}
}
printf("}\n");
}
protected:
hwPhongShaderOverride(const MObject& obj)
: MHWRender::MPxShaderOverride(obj)
, fShaderNode(NULL)
, fTextureData(NULL)
, fDrawUsingShader(true)
, fShaderBound(false)
, fTexture(NULL)
, fInColorPass(false)
, fColorShaderInstance(NULL)
, fInShadowPass(false)
, fShadowShaderInstance(NULL)
, fTransparency(0.0f)
{
if (fDrawUsingShader)
{
createShaderInstance();
}
fAmbient[0] = fAmbient[1] = fAmbient[2] = 0.0f;
fDiffuse[0] = fDiffuse[1] = fDiffuse[2] = fDiffuse[3] = 0.0f;
fSpecular[0] = fSpecular[1] = fSpecular[2] = 0.0f;
fShininess[0] = fShininess[1] = fShininess[2] = 500.0f;
}
static const MHWRender::MBlendState *sBlendState;
hwPhongShader *fShaderNode;
float fTransparency;
float fAmbient[3];
float fDiffuse[4];
float fSpecular[3];
float fShininess[3];
unsigned char* fTextureData;
bool fInColorPass;
bool fInShadowPass;
bool fDrawUsingShader;
MHWRender::MTexture *fTexture;
MHWRender::MShaderInstance *fColorShaderInstance;
MHWRender::MShaderInstance *fShadowShaderInstance;
mutable bool fShaderBound;
};
const MHWRender::MBlendState* hwPhongShaderOverride::sBlendState = NULL;
MStatus initializePlugin( MObject obj )
{
TRACE_API_CALLS("initializePlugin");
MStatus status;
const MString& swatchName = MHWShaderSwatchGenerator::initialize();
const MString UserClassify( "shader/surface/utility/:drawdb/shader/surface/hwPhongShader:swatch/"+swatchName );
MFnPlugin plugin( obj, PLUGIN_COMPANY, "4.5", "Any");
status = plugin.registerNode( "hwPhongShader", hwPhongShader::id,
hwPhongShader::creator, hwPhongShader::initialize,
MPxNode::kHwShaderNode, &UserClassify );
if (!status) {
status.perror("registerNode");
return status;
}
plugin.registerDragAndDropBehavior("hwPhongShaderBehavior",
hwPhongShaderBehavior::creator);
MHWRender::MDrawRegistry::registerShaderOverrideCreator(
"drawdb/shader/surface/hwPhongShader",
sHWPhongShaderRegistrantId,
hwPhongShaderOverride::Creator);
if (status != MS::kSuccess) return status;
return MS::kSuccess;
}
MStatus uninitializePlugin( MObject obj )
{
TRACE_API_CALLS("uninitializePlugin");
MStatus status;
MFnPlugin plugin( obj );
plugin.deregisterNode( hwPhongShader::id );
if (!status) {
status.perror("deregisterNode");
return status;
}
plugin.deregisterDragAndDropBehavior("hwPhongShaderBehavior");
status = MHWRender::MDrawRegistry::deregisterShaderOverrideCreator(
"drawdb/shader/surface/hwPhongShader", sHWPhongShaderRegistrantId);
if (status != MS::kSuccess) return status;
return MS::kSuccess;
}
void * hwPhongShader::creator()
{
TRACE_API_CALLS("creator");
return new hwPhongShader();
}
MStatus hwPhongShader::initialize()
{
TRACE_API_CALLS("initialize");
MFnNumericAttribute nAttr;
aColor = nAttr.createColor( "color", "c");
nAttr.setStorable(true);
nAttr.setKeyable(true);
nAttr.setDefault(0.1f, 0.1f, 0.1f);
nAttr.setCached( true );
nAttr.setInternal( true );
nAttr.setAffectsAppearance( true );
aTransparency = nAttr.create( "transparency", "tr", MFnNumericData::kFloat );
nAttr.setStorable(true);
nAttr.setKeyable(true);
nAttr.setDefault(0.0f);
nAttr.setMax(1.0f);
nAttr.setMin(0.0f);
nAttr.setCached( true );
nAttr.setInternal( true );
nAttr.setAffectsAppearance( true );
aDiffuseColor = nAttr.createColor( "diffuseColor", "dc" );
nAttr.setStorable(true);
nAttr.setKeyable(true);
nAttr.setDefault(1.f, 0.5f, 0.5f);
nAttr.setCached( true );
nAttr.setInternal( true );
nAttr.setAffectsAppearance( true );
aSpecularColor = nAttr.createColor( "specularColor", "sc" );
nAttr.setStorable(true);
nAttr.setKeyable(true);
nAttr.setDefault(0.5f, 0.5f, 0.5f);
nAttr.setCached( true );
nAttr.setInternal( true );
nAttr.setAffectsAppearance( true );
aShininess = nAttr.createPoint( "shininess", "sh" );
nAttr.setStorable(true);
nAttr.setKeyable(true);
nAttr.setDefault(100.0f, 100.0f, 100.0f);
nAttr.setCached( true );
nAttr.setInternal( true );
nAttr.setAffectsAppearance( true );
aGeometryShape = nAttr.create( "geometryShape", "gs", MFnNumericData::kInt );
nAttr.setStorable(true);
nAttr.setKeyable(true);
nAttr.setDefault(0);
nAttr.setCached( true );
nAttr.setInternal( true );
addAttribute(aColor);
addAttribute(aTransparency);
addAttribute(aDiffuseColor);
addAttribute(aSpecularColor);
addAttribute(aShininess);
addAttribute(aGeometryShape);
attributeAffects (aColor, outColor);
attributeAffects (aTransparency, outColor);
attributeAffects (aDiffuseColor, outColor);
attributeAffects (aSpecularColor, outColor);
attributeAffects (aShininess, outColor);
return MS::kSuccess;
}
MStatus hwPhongShader::compute(
const MPlug& plug,
MDataBlock& block )
{
TRACE_API_CALLS("compute");
if ((plug != outColor) && (plug.parent() != outColor))
return MS::kUnknownParameter;
MFloatVector & color = block.inputValue( aDiffuseColor ).asFloatVector();
MDataHandle outColorHandle = block.outputValue( outColor );
MFloatVector& outColor = outColorHandle.asFloatVector();
outColor = color;
outColorHandle.setClean();
return MS::kSuccess;
}
bool hwPhongShader::setInternalValueInContext( const MPlug &plug,
const MDataHandle &handle,
MDGContext & )
{
bool handledAttribute = false;
if (plug == aColor)
{
handledAttribute = true;
float3 & val = handle.asFloat3();
if (val[0] != mAmbientColor[0] ||
val[1] != mAmbientColor[1] ||
val[2] != mAmbientColor[2])
{
mAmbientColor[0] = val[0];
mAmbientColor[1] = val[1];
mAmbientColor[2] = val[2];
mAttributesChanged = true;
mAttributesChangedVP2 = true;
}
}
else if (plug == aTransparency)
{
handledAttribute = true;
float val = handle.asFloat();
if (val != mTransparency)
{
mTransparency = val;
mAttributesChanged = true;
mAttributesChangedVP2 = true;
}
}
else if (plug == aDiffuseColor)
{
handledAttribute = true;
float3 & val = handle.asFloat3();
if (val[0] != mDiffuseColor[0] ||
val[1] != mDiffuseColor[1] ||
val[2] != mDiffuseColor[2])
{
mDiffuseColor[0] = val[0];
mDiffuseColor[1] = val[1];
mDiffuseColor[2] = val[2];
mAttributesChanged = true;
mAttributesChangedVP2 = true;
}
}
else if (plug == aSpecularColor)
{
handledAttribute = true;
float3 & val = handle.asFloat3();
if (val[0] != mSpecularColor[0] ||
val[1] != mSpecularColor[1] ||
val[2] != mSpecularColor[2])
{
mSpecularColor[0] = val[0];
mSpecularColor[1] = val[1];
mSpecularColor[2] = val[2];
mAttributesChanged = true;
mAttributesChangedVP2 = true;
}
}
else if (plug == aShininess)
{
handledAttribute = true;
float3 & val = handle.asFloat3();
if (val[0] != mShininess[0] ||
val[1] != mShininess[1] ||
val[2] != mShininess[2])
{
mShininess[0] = val[0];
mShininess[1] = val[1];
mShininess[2] = val[2];
mAttributesChanged = true;
mAttributesChangedVP2 = true;
}
}
else if (plug == aGeometryShape)
{
handledAttribute = true;
mGeometryShape = handle.asInt();
}
return handledAttribute;
}
bool
hwPhongShader::getInternalValueInContext( const MPlug& plug,
MDataHandle& handle,
MDGContext&)
{
bool handledAttribute = false;
if (plug == aColor)
{
handledAttribute = true;
handle.set( mAmbientColor[0], mAmbientColor[1], mAmbientColor[2] );
}
if (plug == aTransparency)
{
handledAttribute = true;
handle.set( mTransparency );
}
else if (plug == aDiffuseColor)
{
handledAttribute = true;
handle.set( mDiffuseColor[0], mDiffuseColor[1], mDiffuseColor[2] );
}
else if (plug == aSpecularColor)
{
handledAttribute = true;
handle.set( mSpecularColor[0], mSpecularColor[1], mSpecularColor[2] );
}
else if (plug == aShininess)
{
handledAttribute = true;
handle.set( mShininess[0], mShininess[1], mShininess[2] );
}
else if (plug == aGeometryShape)
{
handledAttribute = true;
handle.set( (int) mGeometryShape );
}
return handledAttribute;
}
MStatus hwPhongShader::bind(const MDrawRequest& request, M3dView& view)
{
TRACE_API_CALLS("bind");
init_Phong_texture ();
return MS::kSuccess;
}
MStatus hwPhongShader::glBind(const MDagPath&)
{
TRACE_API_CALLS("glBind");
init_Phong_texture ();
return MS::kSuccess;
}
MStatus hwPhongShader::unbind(const MDrawRequest& request, M3dView& view)
{
TRACE_API_CALLS("unbind");
return MS::kSuccess;
}
MStatus hwPhongShader::glUnbind(const MDagPath&)
{
TRACE_API_CALLS("glUnbind");
return MS::kSuccess;
}
MStatus hwPhongShader::geometry( const MDrawRequest& request,
M3dView& view,
int prim,
unsigned int writable,
int indexCount,
const unsigned int * indexArray,
int vertexCount,
const int * vertexIDs,
const float * vertexArray,
int normalCount,
const float ** normalArrays,
int colorCount,
const float ** colorArrays,
int texCoordCount,
const float ** texCoordArrays)
{
TRACE_API_CALLS("geometry");
MStatus stat = MStatus::kSuccess;
if (mGeometryShape != 0)
drawDefaultGeometry();
else
stat = draw( prim, writable, indexCount, indexArray, vertexCount,
vertexIDs, vertexArray, normalCount, normalArrays, colorCount,
colorArrays, texCoordCount, texCoordArrays);
return stat;
}
MStatus hwPhongShader::glGeometry(const MDagPath & path,
int prim,
unsigned int writable,
int indexCount,
const unsigned int * indexArray,
int vertexCount,
const int * vertexIDs,
const float * vertexArray,
int normalCount,
const float ** normalArrays,
int colorCount,
const float ** colorArrays,
int texCoordCount,
const float ** texCoordArrays)
{
TRACE_API_CALLS("glGeometry");
MStatus stat = MStatus::kSuccess;
if (mGeometryShape != 0)
drawDefaultGeometry();
else
stat = draw( prim, writable, indexCount, indexArray, vertexCount,
vertexIDs, vertexArray, normalCount, normalArrays, colorCount,
colorArrays, texCoordCount, texCoordArrays);
return stat;
}
MStatus
hwPhongShader::renderSwatchImage( MImage & outImage )
{
MStatus status = MStatus::kFailure;
MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
if (pRenderer)
{
const MString& backEndStr = pRenderer->backEndString();
unsigned int* pIndexing = 0;
unsigned int numberOfData = 0;
unsigned int indexCount = 0;
MHardwareRenderer::GeometricShape gshape = MHardwareRenderer::kDefaultSphere;
if (mGeometryShape == 2)
{
gshape = MHardwareRenderer::kDefaultCube;
}
else if (mGeometryShape == 3)
{
gshape = MHardwareRenderer::kDefaultPlane;
}
MGeometryData* pGeomData =
pRenderer->referenceDefaultGeometry( gshape, numberOfData, pIndexing, indexCount );
if( !pGeomData )
{
return MStatus::kFailure;
}
unsigned int width, height;
outImage.getSize( width, height );
unsigned int origWidth = width;
unsigned int origHeight = height;
MStatus status2 = pRenderer->makeSwatchContextCurrent( backEndStr, width, height );
if( status2 == MS::kSuccess )
{
glPushAttrib ( GL_ALL_ATTRIB_BITS );
{
double l, r, b, t, n, f;
pRenderer->getSwatchOrthoCameraSetting( l, r, b, t, n, f );
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho( l, r, b, t, n, f );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if (gshape == MHardwareRenderer::kDefaultCube)
glRotatef( 45, 1.0, 1.0, 1.0 );
else if (gshape == MHardwareRenderer::kDefaultPlane)
glScalef( 1.5, 1.5, 1.5 );
else
glScalef( 1.0, 1.0, 1.0 );
}
drawTheSwatch( pGeomData, pIndexing, numberOfData, indexCount );
pRenderer->readSwatchContextPixels( backEndStr, outImage );
outImage.getSize( width, height );
if (width != origWidth || height != origHeight)
{
status = MStatus::kFailure;
}
else
{
status = MStatus::kSuccess;
}
glPopAttrib();
}
else
{
pRenderer->dereferenceGeometry( pGeomData, numberOfData );
}
}
return status;
}
void
hwPhongShader::drawTheSwatch( MGeometryData* pGeomData,
unsigned int* pIndexing,
unsigned int numberOfData,
unsigned int indexCount )
{
TRACE_API_CALLS("drwaTheSwatch");
MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
if( !pRenderer ) return;
if ( mAttributesChanged || (phong_map_id == 0))
{
init_Phong_texture ();
}
float r, g, b, a;
MHWShaderSwatchGenerator::getSwatchBackgroundColor( r, g, b, a );
glClearColor( r, g, b, a );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
CubeMapTextureDrawUtility::bind( phong_map_id );
{
if (pGeomData)
{
glPushClientAttrib ( GL_CLIENT_VERTEX_ARRAY_BIT );
float *vertexData = (float *)( pGeomData[0].data() );
if (vertexData)
{
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer ( 3, GL_FLOAT, 0, vertexData );
}
float *normalData = (float *)( pGeomData[1].data() );
if (normalData)
{
glEnableClientState( GL_NORMAL_ARRAY );
glNormalPointer ( GL_FLOAT, 0, normalData );
}
if (vertexData && normalData && pIndexing )
glDrawElements ( GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, pIndexing );
glPopClientAttrib();
pRenderer->dereferenceGeometry( pGeomData, numberOfData );
}
}
CubeMapTextureDrawUtility::unbind();
}
void hwPhongShader::drawDefaultGeometry()
{
TRACE_API_CALLS("drawDefaultGeometry");
MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
if (!pRenderer)
return;
CubeMapTextureDrawUtility::bind( phong_map_id );
{
unsigned int numberOfData = 0;
unsigned int *pIndexing = 0;
unsigned int indexCount = 0;
MHardwareRenderer::GeometricShape gshape = MHardwareRenderer::kDefaultSphere;
if (mGeometryShape == 2)
{
gshape = MHardwareRenderer::kDefaultCube;
}
else if (mGeometryShape == 3)
{
gshape = MHardwareRenderer::kDefaultPlane;
}
MGeometryData * pGeomData =
pRenderer->referenceDefaultGeometry( gshape, numberOfData, pIndexing, indexCount);
if (pGeomData)
{
glPushClientAttrib ( GL_CLIENT_VERTEX_ARRAY_BIT );
float *vertexData = (float *)( pGeomData[0].data() );
if (vertexData)
{
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer ( 3, GL_FLOAT, 0, vertexData );
}
float *normalData = (float *)( pGeomData[1].data() );
if (normalData)
{
glEnableClientState( GL_NORMAL_ARRAY );
glNormalPointer ( GL_FLOAT, 0, normalData );
}
if (vertexData && normalData && pIndexing )
glDrawElements ( GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, pIndexing );
glPopClientAttrib();
pRenderer->dereferenceGeometry( pGeomData, numberOfData );
}
}
CubeMapTextureDrawUtility::unbind();
}
MStatus hwPhongShader::draw(int prim,
unsigned int writable,
int indexCount,
const unsigned int * indexArray,
int vertexCount,
const int * vertexIDs,
const float * vertexArray,
int normalCount,
const float ** normalArrays,
int colorCount,
const float ** colorArrays,
int texCoordCount,
const float ** texCoordArrays)
{
TRACE_API_CALLS("draw");
if ( prim != GL_TRIANGLES && prim != GL_TRIANGLE_STRIP) {
return MS::kFailure;
}
CubeMapTextureDrawUtility::bind( phong_map_id );
{
bool needBlending = false;
if (mTransparency > 0.0f)
{
needBlending = true;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f-mTransparency );
}
else
glColor4f(1.0, 1.0, 1.0, 1.0f);
glPushClientAttrib ( GL_CLIENT_VERTEX_ARRAY_BIT );
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_NORMAL_ARRAY );
glVertexPointer ( 3, GL_FLOAT, 0, &vertexArray[0] );
glNormalPointer ( GL_FLOAT, 0, &normalArrays[0][0] );
glDrawElements ( prim, indexCount, GL_UNSIGNED_INT, indexArray );
glPopClientAttrib();
if (needBlending)
{
glColor4f(1.0, 1.0, 1.0, 1.0f);
glDisable(GL_BLEND);
}
}
CubeMapTextureDrawUtility::unbind();
return MS::kSuccess;
}
int hwPhongShader::normalsPerVertex()
{
TRACE_API_CALLS("normalsPerVertex");
return 1;
}
int hwPhongShader::texCoordsPerVertex()
{
TRACE_API_CALLS("texCoordsPerVertex");
return 0;
}
int hwPhongShader::getTexCoordSetNames(MStringArray& names)
{
return 0;
}
bool hwPhongShader::hasTransparency()
{
return (mTransparency > 0.0f);
}