#ifdef WIN32
#pragma warning( disable : 4786 ) // Disable STL warnings.
#endif
#include <maya/MIOStream.h>
#include <math.h>
#include <maya/MString.h>
#include <maya/MPlug.h>
#include <maya/MDagPath.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MArrayDataHandle.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFnLightDataAttribute.h>
#include <maya/MFloatVector.h>
#include <maya/MFnStringData.h>
#include <maya/MFnPlugin.h>
#include <maya/MGlobal.h>
#include <maya/MSceneMessage.h>
#include <maya/MPoint.h>
#include <maya/MMatrix.h>
#include <maya/MVector.h>
#include <maya/MEulerRotation.h>
#include <maya/MFnLight.h>
#include <maya/MFnNonAmbientLight.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <gl/glext.h>
#define GLH_EXT_SINGLE_FILE
#include "glh_extensions.h"
#undef GL_NV_vertex_array_range
#include "glh_genext.h"
#include "glh_obs.h"
using namespace glh;
#include "hwAnisotropicShader_NV20.h"
#include "ShadingConnection.h"
#define TANGENT_INDEX 1 // macro to make normall array indexing a bit clearer
MTypeId hwAnisotropicShader_NV20::id( 0x00105444 );
const unsigned int hwAnisotropicShader_NV20::lookup_texture_size(256);
void hwAnisotropicShader_NV20::postConstructor( )
{
setMPSafe(false);
}
MObject hwAnisotropicShader_NV20::color;
MObject hwAnisotropicShader_NV20::colorR;
MObject hwAnisotropicShader_NV20::colorG;
MObject hwAnisotropicShader_NV20::colorB;
MObject hwAnisotropicShader_NV20::roughness;
MObject hwAnisotropicShader_NV20::kDiffuse;
MObject hwAnisotropicShader_NV20::kSpecular;
void hwAnisotropicShader_NV20::printGlError( const char *call )
{
GLenum error;
while( (error = glGetError()) != GL_NO_ERROR ) {
assert(0);
cerr << call << ":" << error << " is " << (const char *)gluErrorString( error ) << "\n";
}
}
char vertexProgramStringPointDecay[] =
"!!VP1.0\n"
"DP4 o[HPOS].x, c[0], v[0];"
"DP4 o[HPOS].y, c[1], v[0];"
"DP4 o[HPOS].z, c[2], v[0];"
"DP4 o[HPOS].w, c[3], v[0];"
"MOV R1, v[2];"
"DP3 R1.w, R1, R1;"
"RSQ R1.w, R1.w;"
"MUL R1.xyz, R1, R1.w;"
"ADD R2, c[11], -v[0];"
"DP3 R2.w, R2, R2;"
"RSQ R2.w, R2.w;"
"MUL R2.xyz, R2, R2.w;"
"ADD R0, c[12], -v[0];"
"DP3 R0.w, R0, R0;"
"RSQ R0.w, R0.w;"
"MUL R0.xyz, R0, R0.w;"
"DP3 R3.x, R1, R2;"
"DP3 R3.y, R1, R0;"
"MAD o[TEX0].x, R3.x, c[4].x, c[4].x;"
"MAD o[TEX0].y, R3.y, c[4].x, c[4].x;"
"MOV R4, c[9];"
"MOV R5, c[9];"
"MUL R5.xyz, R4, R2.w;"
"MUL o[COL0], v[3], R5;"
"END";
char vertexProgramStringPoint[] =
"!!VP1.0\n"
"DP4 o[HPOS].x, c[0], v[0];"
"DP4 o[HPOS].y, c[1], v[0];"
"DP4 o[HPOS].z, c[2], v[0];"
"DP4 o[HPOS].w, c[3], v[0];"
"MOV R1, v[2];"
"DP3 R1.w, R1, R1;"
"RSQ R1.w, R1.w;"
"MUL R1.xyz, R1, R1.w;"
"ADD R2, c[11], -v[0];"
"DP3 R2.w, R2, R2;"
"RSQ R2.w, R2.w;"
"MUL R2.xyz, R2, R2.w;"
"ADD R0, c[12], -v[0];"
"DP3 R0.w, R0, R0;"
"RSQ R0.w, R0.w;"
"MUL R0.xyz, R0, R0.w;"
"DP3 R3.x, R1, R2;"
"DP3 R3.y, R1, R0;"
"MAD o[TEX0].x, R3.x, c[4].x, c[4].x;"
"MAD o[TEX0].y, R3.y, c[4].x, c[4].x;"
"MUL o[COL0], v[3], c[9];"
"END";
char vertexProgramString[] =
"!!VP1.0\n"
"DP4 o[HPOS].x, c[0], v[0];"
"DP4 o[HPOS].y, c[1], v[0];"
"DP4 o[HPOS].z, c[2], v[0];"
"DP4 o[HPOS].w, c[3], v[0];"
"MOV R1, v[2];"
"DP3 R1.w, R1, R1;"
"RSQ R1.w, R1.w;"
"MUL R1.xyz, R1, R1.w;"
"MOV R2, c[11];"
"DP3 R2.w, R2, R2;"
"RSQ R2.w, R2.w;"
"MUL R2.xyz, R2, R2.w;"
"ADD R0, c[12], -v[0];"
"DP3 R0.w, R0, R0;"
"RSQ R0.w, R0.w;"
"MUL R0.xyz, R0, R0.w;"
"DP3 R3.x, R1, R2;"
"DP3 R3.y, R1, R0;"
"MAD o[TEX0].x, R3.x, c[4].x, c[4].x;"
"MAD o[TEX0].y, R3.y, c[4].x, c[4].x;"
"MUL o[COL0], v[3], c[9];"
"END";
void initVertexProgram(const char vertexProgramCode[], GLuint* pVertexProgramId)
{
glGenProgramsNV(1, pVertexProgramId);
GLenum error = glGetError();
assert(error == GL_NO_ERROR);
unsigned int length = strlen(vertexProgramCode);
glLoadProgramNV(GL_VERTEX_PROGRAM_NV, *pVertexProgramId, length,
(const GLubyte *) vertexProgramCode);
error = glGetError();
if (error != GL_NO_ERROR)
{
if (error == GL_INVALID_OPERATION)
{
int error_position = -2;
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_NV, &error_position);
assert(0);
}
}
}
void hwAnisotropicShader_NV20::loadVertexProgramGL()
{
GLenum error = glGetError();
assert(!error);
if (!fVertexProgramsLoaded)
{
initVertexProgram(vertexProgramString, &fVertexProgramDirectional);
initVertexProgram(vertexProgramStringPointDecay, &fVertexProgramPointDecay);
initVertexProgram(vertexProgramStringPoint, &fVertexProgramPointNoDecay);
fVertexProgramsLoaded = true;
}
}
void hwAnisotropicShader_NV20::make_lookup_texture()
{
float t_roughness = 0.025f;
float t_kd = 0.8f;
float t_ks = 0.2f;
MPlug roughPlug(thisMObject(), roughness);
MPlug diffPlug(thisMObject(), kDiffuse);
MPlug specPlug(thisMObject(), kSpecular);
roughPlug.getValue(t_roughness);
diffPlug.getValue(t_kd);
specPlug.getValue(t_ks);
if ( t_roughness < 0.0f ) t_roughness = 0.0f;
if ( t_roughness > 1.0f ) t_roughness = 1.0f;
if ( t_kd < 0.000000000001f ) t_kd = 0.000000000001f;
if ( t_kd> 1.0f ) t_kd= 1.0f;
if ( t_ks < 0.0f ) t_ks= 0.0f;
if ( t_ks > 1.0f ) t_ks = 1.0f;
boolean dirty = false;
if (currentKd != t_kd) {
dirty = true; currentKd = t_kd;
}
if (currentKs != t_ks) {
dirty = true; currentKs = t_ks;
}
if (currentRoughness != t_roughness) {
dirty = true; currentRoughness = t_roughness;
}
if (!dirty)
return;
unsigned int imgsize = lookup_texture_size;
float imgsizeM1 = (float) (imgsize - 1);
if (lookup_table == NULL)
lookup_table = new unsigned char[imgsize*imgsize*3];
if (lookup_texture == NULL)
lookup_texture = new tex_object_2D;
#ifdef _DEBUG_DUMP_LOOKUP_TEXTURE
static boolean firstTime = true;
#else
static boolean firstTime = false;
#endif
if (firstTime)
{
MImage image;
image.create(lookup_texture_size, lookup_texture_size);
unsigned char *ip = image.pixels();
float diff, spec, phong;
float lt, vt;
float h;
int i, j;
float invRough = 1.0 / t_roughness;
for (i=0; i < imgsize; i++)
{
lt = 1.0 - 2.0 * (float)i/(float)(imgsize-1);
diff= sqrt( 1.0-lt*lt );
for(j=0; j < imgsize; j++)
{
vt= 2.0 * (float)j/(float)(imgsize-1) - 1.0;
spec= diff*sqrt( 1-vt*vt ) - lt*vt;
phong= t_ks*powf( spec < 0.0 ? 0.0 : spec, invRough );
float Kddiff = t_kd*diff;
h= (Kddiff+phong)*255.0 + 0.5;
*ip++ = (h < 0.0) ? 0 : (h > 255.0 ? 255 : (int)h);
h= (Kddiff+phong)*255.0 + 0.5;
*ip++ = (h < 0.0) ? 0 : (h > 255.0 ? 255 : (int)h);
h= (Kddiff+phong)*255.0 + 0.5;
*ip++ = (h < 0.0) ? 0 : (h > 255.0 ? 255 : (int)h);
*ip++ = 1.0;
}
}
image.writeToFile("c:/aniso.iff");
firstTime = false;
}
unsigned char *ip = lookup_table;
float diff, spec, phong;
float lt, vt;
float h;
int i, j;
float invRough = 1.0 / t_roughness;
for (i=0; i < imgsize; i++)
{
lt = 1.0 - 2.0 * (float)i/(float)(imgsize-1);
diff= sqrt( 1.0-lt*lt );
for(j=0; j < imgsize; j++)
{
vt= 2.0 * (float)j/(float)(imgsize-1) - 1.0;
spec= diff*sqrt( 1-vt*vt ) - lt*vt;
phong= t_ks*powf( spec < 0.0 ? 0.0 : spec, invRough );
float Kddiff = t_kd*diff;
h= (Kddiff+phong)*255.0 + 0.5;
*ip++ = (h < 0.0) ? 0 : (h > 255.0 ? 255 : (int)h);
h= (Kddiff+phong)*255.0 + 0.5;
*ip++ = (h < 0.0) ? 0 : (h > 255.0 ? 255 : (int)h);
h= (Kddiff+phong)*255.0 + 0.5;
*ip++ = (h < 0.0) ? 0 : (h > 255.0 ? 255 : (int)h);
}
}
fLookupTextureReprocessed = true;
return;
}
void hwAnisotropicShader_NV20::bind_lookup_table()
{
make_lookup_texture();
lookup_texture->bind();
if (fLookupTextureReprocessed)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, lookup_texture_size, lookup_texture_size,
0, GL_RGB, GL_UNSIGNED_BYTE, lookup_table);
fLookupTextureReprocessed = false;
}
lookup_texture->parameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST);
lookup_texture->parameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
lookup_texture->parameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
lookup_texture->parameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
void hwAnisotropicShader_NV20::init_ext(const char * ext)
{
if(!glh_init_extension(ext))
{ cerr << "Failed to initialize " << ext << "!" << endl; exit(0); }
}
hwAnisotropicShader_NV20::hwAnisotropicShader_NV20()
{
m_pTextureCache = MTextureCache::instance();
init_ext("GL_ARB_multitexture");
init_ext("GL_NV_vertex_program");
isDirectionalLight = true;
isNonAmbientLight = false;
currentColor[0] = currentColor[1] = currentColor[2] = -1.0;
currentRoughness = -1.0;
currentKd = -1.0;
currentKs = -1.0;
lookup_texture = NULL;
lookup_table = NULL;
fLookupTextureReprocessed = false;
fBeforeNewCB = 0;
fBeforeOpenCB = 0;
fBeforeRemoveReferenceCB = 0;
fMayaExitingCB = 0;
attachSceneCallbacks();
fVertexProgramsLoaded = false;
fVertexProgramDirectional = 0;
fVertexProgramPointDecay = 0;
fVertexProgramPointNoDecay = 0;
}
hwAnisotropicShader_NV20::~hwAnisotropicShader_NV20()
{
detachSceneCallbacks();
}
void releaseVertexProgram(GLuint* pVertexProgramId)
{
if (*pVertexProgramId > 0)
{
glBindProgramNV(GL_VERTEX_PROGRAM_NV, 0);
glDeleteProgramsNV(1, pVertexProgramId);
*pVertexProgramId = 0;
}
}
void hwAnisotropicShader_NV20::releaseEverything()
{
release_lookup_texture();
if (fVertexProgramsLoaded)
{
releaseVertexProgram(&fVertexProgramDirectional);
releaseVertexProgram(&fVertexProgramPointDecay);
releaseVertexProgram(&fVertexProgramPointNoDecay);
fVertexProgramsLoaded = false;
}
m_pTextureCache->release();
if(!MTextureCache::getReferenceCount())
{
m_pTextureCache = 0;
}
}
void hwAnisotropicShader_NV20::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 hwAnisotropicShader_NV20::releaseCallback(void* clientData)
{
hwAnisotropicShader_NV20 *pThis = (hwAnisotropicShader_NV20*) clientData;
pThis->releaseEverything();
}
void hwAnisotropicShader_NV20::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;
}
MStatus initializePlugin( MObject obj )
{
MStatus status;
const MString UserClassify( "shader/surface/utility" );
MFnPlugin plugin( obj, PLUGIN_COMPANY, "4.5", "Any");
status = plugin.registerNode( "hwAnisotropicShader_NV20", hwAnisotropicShader_NV20::id,
hwAnisotropicShader_NV20::creator, hwAnisotropicShader_NV20::initialize,
MPxNode::kHwShaderNode, &UserClassify );
if (!status) {
status.perror("registerNode");
return status;
}
return MS::kSuccess;
}
MStatus uninitializePlugin( MObject obj )
{
MStatus status;
MFnPlugin plugin( obj );
plugin.deregisterNode( hwAnisotropicShader_NV20::id );
if (!status) {
status.perror("deregisterNode");
return status;
}
return MS::kSuccess;
}
void * hwAnisotropicShader_NV20::creator()
{
return new hwAnisotropicShader_NV20();
}
MStatus hwAnisotropicShader_NV20::initialize()
{
MFnNumericAttribute nAttr;
MStatus status;
MFnTypedAttribute sAttr;
colorR = nAttr.create( "colorR", "cr",MFnNumericData::kFloat);
nAttr.setStorable(true);
nAttr.setKeyable(true);
nAttr.setDefault(1.0f);
colorG = nAttr.create( "colorG", "cg",MFnNumericData::kFloat);
nAttr.setStorable(true);
nAttr.setKeyable(true);
nAttr.setDefault(0.5f);
colorB = nAttr.create( "colorB", "cb",MFnNumericData::kFloat);
nAttr.setStorable(true);
nAttr.setKeyable(true);
nAttr.setDefault(0.5f);
color = nAttr.create( "color", "c", colorR, colorG, colorB);
nAttr.setStorable(true);
nAttr.setKeyable(true);
nAttr.setDefault(1.0f, 0.5f, 0.5f);
nAttr.setUsedAsColor(true);
kDiffuse = nAttr.create( "kDiffuse", "kd", MFnNumericData::kFloat);
nAttr.setStorable(true);
nAttr.setKeyable(true);
nAttr.setMin(0.0f);
nAttr.setMax(1.0f);
nAttr.setDefault(0.2f);
kSpecular = nAttr.create( "kSpecular", "ks", MFnNumericData::kFloat);
nAttr.setStorable(true);
nAttr.setKeyable(true);
nAttr.setMin(0.0f);
nAttr.setMax(1.0f);
nAttr.setDefault(0.9f);
roughness = nAttr.create( "roughness", "rn", MFnNumericData::kFloat);
nAttr.setStorable(true);
nAttr.setKeyable(true);
nAttr.setMin(0.0f);
nAttr.setMax(1.0f);
nAttr.setDefault(0.025f);
addAttribute(color);
addAttribute(roughness);
addAttribute(kDiffuse);
addAttribute(kSpecular);
attributeAffects (colorR, outColor);
attributeAffects (colorG, outColor);
attributeAffects (colorB, outColor);
attributeAffects (color, outColor);
attributeAffects (roughness, outColor);
attributeAffects (kDiffuse, outColor);
attributeAffects (kSpecular, outColor);
return MS::kSuccess;
}
MStatus hwAnisotropicShader_NV20::getFloat3(MObject attr, float value[3])
{
MStatus status = MS::kSuccess;
MPlug plug(thisMObject(), attr);
MObject object;
status = plug.getValue(object);
if (!status)
{
status.perror("hwAnisotropicShader_NV20::getFloat3 plug.getValue.");
return status;
}
MFnNumericData data(object, &status);
if (!status)
{
status.perror("hwAnisotropicShader_NV20::getFloat3 construct data.");
return status;
}
status = data.getData(value[0], value[1], value[2]);
if (!status)
{
status.perror("hwAnisotropicShader_NV20::getFloat3 get values.");
return status;
}
return status;
}
MStatus hwAnisotropicShader_NV20::getString(MObject attr, MString &str)
{
MPlug plug(thisMObject(), attr);
MStatus status = plug.getValue( str );
return status;
}
MStatus hwAnisotropicShader_NV20::bind(const MDrawRequest& request, M3dView& view)
{
MStatus status;
float t_color[3];
getFloat3(color, t_color);
view.beginGL();
{
glPushAttrib( GL_ALL_ATTRIB_BITS );
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
glColor4f(t_color[0], t_color[1], t_color[2], 1.0f);
glActiveTextureARB( GL_TEXTURE0_ARB );
glEnable(GL_TEXTURE_2D);
bind_lookup_table();
}
view.endGL();
return MS::kSuccess;
}
MStatus hwAnisotropicShader_NV20::unbind(const MDrawRequest& request,
M3dView& view)
{
view.beginGL();
glActiveTextureARB( GL_TEXTURE0_ARB );
glDisable(GL_TEXTURE_2D);
glPopClientAttrib();
glPopAttrib();
view.endGL();
return MS::kSuccess;
}
MStatus hwAnisotropicShader_NV20::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)
{
if (prim != GL_TRIANGLES)
return MS::kSuccess;
view.beginGL();
isDirectionalLight = true;
isNonAmbientLight = false;
boolean useDefaultLight = false;
unsigned int numLights;
MDagPath lightPath;
view.getLightCount( numLights );
if (numLights)
{
M3dView::LightingMode mode;
view.getLightingMode(mode);
if (mode == M3dView::kLightDefault)
{
useDefaultLight = true;
isDirectionalLight = true;
}
else
{
view.getLightPath( 0, lightPath );
MObject lightObj = lightPath.node();
isDirectionalLight = lightObj.hasFn( MFn::kDirectionalLight );
isNonAmbientLight = lightObj.hasFn( MFn::kNonAmbientLight );
if (isNonAmbientLight)
{
MFnNonAmbientLight mNonAmbientLight(lightObj);
if (mNonAmbientLight.decayRate() == 0)
isNonAmbientLight = false;
}
}
}
loadVertexProgramGL();
if (isDirectionalLight)
glBindProgramNV(GL_VERTEX_PROGRAM_NV, fVertexProgramDirectional);
else if (isNonAmbientLight)
glBindProgramNV(GL_VERTEX_PROGRAM_NV, fVertexProgramPointDecay);
else
glBindProgramNV(GL_VERTEX_PROGRAM_NV, fVertexProgramPointNoDecay);
GLenum error = glGetError();
assert(error == GL_NO_ERROR);
glEnable(GL_VERTEX_PROGRAM_NV);
MDagPath objPath = request.multiPath();
MMatrix objMatrix = objPath.inclusiveMatrixInverse();
if (numLights)
{
if (useDefaultLight )
{
glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 11, 0, 0, 1, 1);
glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 9, 1.0, 1.0, 1.0, 1);
}
else
{
view.getLightPath( 0, lightPath );
MMatrix matrix = lightPath.inclusiveMatrix();
isDirectionalLight = lightPath.node().hasFn( MFn::kDirectionalLight );
if (isDirectionalLight)
{
MVector lightDir(0,0,1);
lightDir *= matrix;
lightDir *= objMatrix;
glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 11, -lightDir.x, -lightDir.y, -lightDir.z, 1);
}
else
{
MPoint lightPos(0,0,0);
lightPos *= matrix;
lightPos *= objMatrix;
glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 11, -lightPos.x, -lightPos.y, -lightPos.z, 1);
}
MFnLight mLight(lightPath.node());
MColor lightColor = mLight.color();
float intensity = mLight.intensity();
lightColor.r *= intensity;
lightColor.g *= intensity;
lightColor.b *= intensity;
glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 9, lightColor.r, lightColor.g, lightColor.b, 1);
}
}
else
{
glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 11, 0, 0, 1, 1);
glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 9, 1.0, 1.0, 1.0, 1);
}
float cameraPos[4] = {0.0f, 0.0f, 0.0f, 0.0f};
{
MDagPath camDag;
view.getCamera(camDag);
MPoint cameraInObject(0,0,0);
MMatrix cameraToWorldMatrix = camDag.inclusiveMatrix();
cameraInObject *= cameraToWorldMatrix;
cameraInObject *= objMatrix;
glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 12, cameraInObject.x, cameraInObject.y, cameraInObject.z, 1);
}
glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV);
glProgramParameter4fNV(GL_VERTEX_PROGRAM_NV, 4, 0.5, 1.0, 0.0, 0.0);
glVertexAttribPointerNV( 0, 3, GL_FLOAT, 0, vertexArray );
glVertexAttribPointerNV( 2, 3, GL_FLOAT, 0, normalArrays[TANGENT_INDEX] );
glEnableClientState( GL_VERTEX_ATTRIB_ARRAY0_NV );
glEnableClientState( GL_VERTEX_ATTRIB_ARRAY2_NV );
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, indexArray);
glDisableClientState( GL_VERTEX_ATTRIB_ARRAY0_NV );
glDisableClientState( GL_VERTEX_ATTRIB_ARRAY2_NV );
glDisable(GL_VERTEX_PROGRAM_NV);
view.endGL();
return MS::kSuccess;
}
int hwAnisotropicShader_NV20::normalsPerVertex()
{
return 2;
}
int hwAnisotropicShader_NV20::texCoordsPerVertex()
{
return 1;
}
void hwAnisotropicShader_NV20::release_lookup_texture()
{
if (lookup_table)
{
delete lookup_table;
lookup_table = NULL;
}
if (lookup_texture)
{
delete lookup_texture;
lookup_table = NULL;
}
}