aboutsummaryrefslogtreecommitdiff
path: root/mayaPlug/shaveHairUI.cpp
diff options
context:
space:
mode:
authorBen Marsh <[email protected]>2019-10-22 09:07:59 -0400
committerBen Marsh <[email protected]>2019-10-22 09:07:59 -0400
commitbd0027e737c6512397f841c22786274ed74b927f (patch)
treef7ffbdb8f3741bb7f24635616cc189cba5cb865c /mayaPlug/shaveHairUI.cpp
downloadarchived-shave-and-a-haircut-bd0027e737c6512397f841c22786274ed74b927f.tar.xz
archived-shave-and-a-haircut-bd0027e737c6512397f841c22786274ed74b927f.zip
Adding Shave-and-a-Haircut 9.6
Diffstat (limited to 'mayaPlug/shaveHairUI.cpp')
-rw-r--r--mayaPlug/shaveHairUI.cpp5777
1 files changed, 5777 insertions, 0 deletions
diff --git a/mayaPlug/shaveHairUI.cpp b/mayaPlug/shaveHairUI.cpp
new file mode 100644
index 0000000..adb3f15
--- /dev/null
+++ b/mayaPlug/shaveHairUI.cpp
@@ -0,0 +1,5777 @@
+// Shave and a Haircut
+// (c) 2019 Epic Games
+// US Patent 6720962
+
+//Qt headers must be included before any others !!!
+#include <QtCore/QEvent>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QTabletEvent>
+
+#if QT_VERSION < 0x050000
+# include <QtGui/QApplication>
+# include <QtGui/QWidget>
+#else
+# include <QtWidgets/QApplication>
+# include <QtWidgets/QWidget>
+#endif
+
+#include <vector>
+#include <sstream>
+#include <assert.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <maya/M3dView.h>
+#include <maya/MBoundingBox.h>
+#include <maya/MDrawInfo.h>
+#include <maya/MDrawRequest.h>
+#include <maya/MDrawRequestQueue.h>
+#include <maya/MFnDoubleIndexedComponent.h>
+#include <maya/MFnSingleIndexedComponent.h>
+#include <maya/MGlobal.h>
+#include <maya/MMatrix.h>
+#include <maya/MPlug.h>
+#include <maya/MPoint.h>
+#include <maya/MPointArray.h>
+#include <maya/MSelectInfo.h>
+#include <maya/MSelectionList.h>
+#include <maya/MSelectionMask.h>
+#include <maya/MFnCamera.h>
+#include <maya/MAnimControl.h>
+#include <maya/MDagPath.h>
+#include <maya/MFloatPointArray.h>
+#include <maya/MIOStream.h>
+
+#include "shaveCheckObjectVisibility.h"
+#include "shaveCursorCtx.h"
+#include "shaveGlobals.h"
+#include "shaveHairShape.h"
+#include "shaveHairUI.h"
+#include "shaveMaya.h"
+#include "shaveRender.h"
+#include "shaveSDKTYPES.h"
+#include "shaveStyleCmd.h"
+#include "shaveTextureStore.h"
+#include "shaveUtil.h"
+
+#ifdef OSMac_
+#include <mach-o/dyld.h>
+#include <stdlib.h>
+#include <string.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#endif
+
+//
+// Some magic numbers which the API *should* give you, but doesn't.
+//
+static const int LEAD_COLOR = 18;
+static const int ACTIVE_SURFACE_COLOR = 15;
+static const int DORMANT_SURFACE_COLOR = 4;
+static const int ACTIVE_TEMPLATE_COLOR = 19;
+static const int ACTIVE_AFFECTED_COLOR = 8;
+static const int HILITE_COLOR = 17;
+static const int ACTIVE_VERTEX_COLOR = 16;
+static const int DORMANT_VERTEX_COLOR = 8;
+static const int ACTIVE_ISOPARM_COLOR = 16;
+
+static const int DORMANT_GUIDE_COMPONENT_COLOR = 22;
+static const int ACTIVE_GUIDE_COMPONENT_COLOR = LEAD_COLOR;
+static const int LEAD_HAIR_COLOR = 22;
+static const int ACTIVE_HAIR_COLOR = 2;
+
+static const float POINT_SIZE = 3.0f;
+
+#ifdef NEW_INSTNACE_DISPLAY
+#ifndef GL_ACTIVE_TEXTURE
+PFNGLATCIVETEXTUREPROC glActiveTexture = NULL;
+#endif
+#endif
+
+///// shaders
+#if defined(_WIN32) || defined(LINUX)
+typedef GLuint (APIENTRY * PFNGLCREATESHADERPROC) (GLenum shaderType);
+PFNGLCREATESHADERPROC glCreateShader = NULL;
+
+typedef void (APIENTRY * PFNGLCOMPILESHADERPROC) (GLuint shader);
+PFNGLCOMPILESHADERPROC glCompileShader = NULL;
+
+typedef void (APIENTRY * PFNGATTACHSHADERPROC) (GLuint program, GLuint shader);
+PFNGATTACHSHADERPROC glAttachShader = NULL;
+
+typedef void (APIENTRY * PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
+PFNGLDETACHSHADERPROC glDetachShader = NULL;
+
+typedef void (APIENTRY * PFNGLDELETESHADERPROC) (GLuint shader);
+PFNGLDELETESHADERPROC glDeleteShader = NULL;
+
+typedef void (APIENTRY * PFNGLGETSHADDERIVPROC) (GLuint shader, GLenum pname, GLint *params);
+PFNGLGETSHADDERIVPROC glGetShaderiv = NULL;
+
+typedef void (APIENTRY * PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei maxLength, GLsizei *length, char *infoLog);
+PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = NULL;
+
+#if GL_GLEXT_VERSION > 71
+typedef void (APIENTRY * PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
+PFNGLSHADERSOURCEPROC glShaderSource = NULL;
+#else
+typedef void (APIENTRY * PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const char **string, const GLint *length);
+PFNGLSHADERSOURCEPROC glShaderSource = NULL;
+#endif
+
+
+/////// programs
+typedef GLuint (APIENTRY * PFNGLCREATEPROGRAMPROC) (void);
+PFNGLCREATEPROGRAMPROC glCreateProgram = NULL;
+
+typedef void (APIENTRY * PFNGLDELETEPROGRAMPROC) (GLuint program);
+PFNGLDELETEPROGRAMPROC glDeleteProgram = NULL;
+
+typedef void (APIENTRY * PFNGLLINKPROGRAMPROC) (GLuint program);
+PFNGLLINKPROGRAMPROC glLinkProgram = NULL;
+
+typedef void (APIENTRY * PFNGLUSEPROGRAMPROC) (GLuint program);
+PFNGLUSEPROGRAMPROC glUseProgram = NULL;
+
+typedef void (APIENTRY * PFNVALIDATEPROGRAMPROC) (GLuint program);
+PFNVALIDATEPROGRAMPROC glValidateProgram = NULL;
+
+typedef void (APIENTRY * PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
+PFNGLGETPROGRAMIVPROC glGetProgramiv = NULL;
+
+typedef void (APIENTRY * PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei maxLength, GLsizei *length, char *infoLog);
+PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = NULL;
+
+typedef GLint (APIENTRY * PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const char *name);
+PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = NULL;
+
+/////// uniforms
+typedef void (APIENTRY * PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+PFNGLUNIFORM3FPROC glUniform3f = NULL;
+
+typedef void (APIENTRY * PFNGLUNIFORM1FPROC) (GLint location, GLfloat f);
+PFNGLUNIFORM1FPROC glUniform1f = NULL;
+
+typedef void (APIENTRY * PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
+PFNGLUNIFORM1IPROC glUniform1i = NULL;
+
+//////per vertex attributes
+typedef GLint (APIENTRY * PFNGLGETATTRIBLOCATION)(GLuint program, char *name);
+PFNGLGETATTRIBLOCATION glGetAttribLocation = NULL;
+
+typedef void (APIENTRY * PFNGLVERTEXATTRIB1FV)(GLuint index, GLfloat v);
+PFNGLVERTEXATTRIB1FV glVertexAttrib1f = NULL;
+
+typedef void (APIENTRY * PFNGLVERTEXATTRIB3FV)(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2);
+PFNGLVERTEXATTRIB3FV glVertexAttrib3f = NULL;
+
+typedef void (APIENTRY * PFNGLVERTEXATTRIBPOINTER)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer);
+PFNGLVERTEXATTRIBPOINTER glVertexAttribPointer = NULL;
+
+typedef void (APIENTRY * PFNGLENABLEVERTEXATTRIBARRAY)(GLuint index);
+PFNGLENABLEVERTEXATTRIBARRAY glEnableVertexAttribArray = NULL;
+
+/////////FBO
+typedef void (APIENTRY * PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);
+PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL;
+
+typedef void (APIENTRY * PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);
+PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL;
+
+typedef void (APIENTRY * PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);
+PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL;
+
+typedef GLenum (APIENTRY * PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);
+PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL;
+
+typedef void (APIENTRY * PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+ PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL;
+
+typedef void (APIENTRY * PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL;
+
+typedef void (APIENTRY * PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL;
+
+typedef void (APIENTRY * PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);
+PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL;
+
+typedef void (APIENTRY * PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);
+PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL;
+
+typedef void (APIENTRY * PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);
+PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL;
+
+typedef void (APIENTRY * PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL;
+
+typedef void (APIENTRY * PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL;
+
+typedef GLboolean (APIENTRY * PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer);
+PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL;
+
+typedef void (APIENTRY * PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT = NULL;
+
+typedef void (APIENTRY * PFNGLBLITFRAMEBUFFEREXT)( GLint,GLint,GLint,GLint,GLint,GLint,GLint,GLint,GLbitfield,GLenum);
+PFNGLBLITFRAMEBUFFEREXT glBlitFramebufferEXT = NULL;
+
+////MISC
+typedef void (APIENTRY * PFNGLGENERATEMIPMAPEXTPROC) (GLenum texture);
+PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL;
+#endif
+
+
+////////////////////////////////////////////////////////////// Profiling ////////////////////////////////////////////////////////
+#ifdef DO_PROFILE
+namespace Profile {
+
+//// out
+
+class LStrFile {
+public:
+ const static char* NUM_PATTERNS_TAG;
+ const static char* PATTERN_TAG;
+ const static char* NO_STR_VAL;
+
+ enum _e_consts
+ {
+ eMaxStringLen = 300
+ };
+
+ enum _e_errcodes
+ {
+ eOK = 1,
+ eIOError = 0, //GetLastError() should be used for details
+ eTagError = -1,
+ eDataError = -2
+ };
+
+ LStrFile(const char *filename,const char *mode)
+{
+ _stream() = NULL;
+ Open(filename, mode);
+}
+ ~LStrFile()
+{
+ Close();
+}
+
+ bool IsNULL() const {return stream() == NULL;}
+
+ int Close()
+{
+ int result=0;
+ if(stream())
+ result = fclose(_stream());
+
+ _stream() = NULL;
+ return result;
+}
+ bool Open(const char *filename,const char *mode)
+{
+ Close();
+ _stream() = fopen(filename,mode);
+ //errno_t err = fopen_s(&_stream(),filename,mode); //vc8.0 stuff
+ return (stream() != NULL);
+}
+
+ int Write(const char* buf)
+{
+ if(stream())
+ {
+ int res = fprintf(_stream(),"%s",buf);
+ //int res = fprintf_s(_stream(),"[%s] %i [/%s] \n",NUM_PATTERNS_TAG, n, NUM_PATTERNS_TAG); //vc8.0 stuff
+ if(res > 0)
+ fflush(_stream());
+
+ return (res > 0) ? eOK : eIOError;
+ }
+ return eOK;
+}
+
+protected:
+ inline const FILE* stream() const {return m_stream;}
+ inline FILE*& _stream() {return m_stream;}
+
+private:
+ FILE* m_stream;
+
+};
+
+class LDiagFile {
+public:
+ LStrFile* diagDump;
+ LDiagFile()
+ {
+ diagDump = NULL;
+ }
+ ~LDiagFile()
+ {
+ if(diagDump)
+ delete diagDump;
+ }
+};
+static LDiagFile diag;
+
+
+
+LStrFile* OpenDiagFile()
+{
+ MString mdir;
+ MGlobal::executeCommand("internalVar -userTmpDir",mdir);
+ if(mdir != "")
+ {
+ MString log = mdir + "shave_profile.log";
+
+
+ diag.diagDump = new LStrFile(log.asChar(),"wt");
+
+ if(diag.diagDump->IsNULL())
+ {
+ printf("Shave: can't write log to %s\n",log.asChar());
+ fflush(stdout);
+
+ MGlobal::displayError(MString("Shave: can't write log to ") + log);
+
+ return NULL;
+ }
+ MGlobal::displayInfo(MString("LipService: writing log to ") + log);
+ return diag.diagDump;
+ }
+ else
+ {
+ printf("cant write log, internalVar -userBitmapsDir returned empty path\n");
+ fflush(stdout);
+ return NULL;
+ }
+}
+
+void CloseDiagFile()
+{
+ if(diag.diagDump)
+ {
+ delete diag.diagDump;
+ diag.diagDump = NULL;
+ }
+}
+
+LStrFile* GetDiagFile()
+{
+ return diag.diagDump;
+}
+
+//// frofile functions
+
+int numZeros(long N) //nuber of traling zeros for nano
+{
+ int d = 0;
+ while(N > 0) {
+ d++;
+ N/=10;
+ }
+ int z = 9 - d;
+ return z;
+}
+
+static bool just_started = false;
+#ifdef WIN32
+//static unsigned int last = 0;
+//static unsigned int start = 0;
+LARGE_INTEGER last;
+LARGE_INTEGER start;
+#elif defined(LINUX)
+timespec last;
+timespec start;
+
+timespec diff(timespec start, timespec end)
+{
+ timespec temp;
+ if ((end.tv_nsec-start.tv_nsec)<0) {
+ temp.tv_sec = end.tv_sec-start.tv_sec-1;
+ temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
+ } else {
+ temp.tv_sec = end.tv_sec-start.tv_sec;
+ temp.tv_nsec = end.tv_nsec-start.tv_nsec;
+ }
+ return temp;
+}
+#endif
+
+
+
+void ProfileStart(LStrFile* f)
+{
+ if(f==NULL)
+ f = OpenDiagFile();
+
+ just_started = true;
+
+ char tbuf[100];
+ time_t t = time(0);
+ struct tm* tnow = localtime(&t);
+ sprintf(tbuf,"%i:%i:%i", tnow->tm_hour, tnow->tm_min, tnow->tm_sec);
+
+#ifdef WIN32
+#if 0
+ QueryPerformanceCounter(&last);
+ QueryPerformanceCounter(&start);
+#endif
+ if(f)
+ {
+ char buf[100]; sprintf(buf,"[%s] initalized \n",tbuf);
+ f->Write(buf);
+ }
+ else
+ {
+ fprintf(stdout,"[%s] initalized\n",tbuf);
+ fflush(stdout);
+ }
+#elif defined(LINUX)
+#if 0
+ int res1 = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
+ int res2 = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &last);
+
+ if(f)
+ {
+ char buf[100];
+ if(res1 != -1 && res2 != -1)
+ sprintf(buf,"[%s] initalized \n",tbuf);
+ else
+ sprintf(buf,"Profiling: start failed!\n");
+
+ f->Write(buf);
+ }
+ else
+ {
+ if(res1 != -1 && res2 != -1)
+ fprintf(stdout,"[%s] initalized\n",tbuf);
+ else
+ fprintf(stdout,"Profiling: failed!\n");
+
+ fflush(stdout);
+ }
+#else
+ if(f)
+ {
+ char buf[100]; sprintf(buf,"[%s] initalized\n",tbuf);
+ f->Write(buf);
+ }
+ else
+ {
+ fprintf(stdout,"[%s] initalized\n",tbuf);
+ fflush(stdout);
+ }
+#endif
+
+#else
+
+#endif
+
+}
+
+void ProfileDump(char* msg, LStrFile* f)
+{
+ if(f==NULL)
+ f=GetDiagFile();
+
+ char tbuf[100];
+ time_t t = time(0);
+ struct tm* now = localtime(&t);
+ sprintf(tbuf,"%i:%i:%i", now->tm_hour, now->tm_min, now->tm_sec);
+
+ if(just_started)
+ {
+#ifdef WIN32
+ QueryPerformanceCounter(&last);
+ QueryPerformanceCounter(&start);
+
+ if(f)
+ {
+ char buf[100]; sprintf(buf,"[%s] started | %s\n",tbuf,msg);
+ f->Write(buf);
+ }
+ else
+ {
+ fprintf(stdout,"[%s] started | %s \n",tbuf,msg);
+ fflush(stdout);
+ }
+#elif defined(LINUX)
+ int res1 = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
+ int res2 = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &last);
+
+ if(f)
+ {
+ char buf[100];
+ if(res1 != -1 && res2 != -1)
+ sprintf(buf,"[%s] started | %s\n",tbuf,msg);
+ else
+ sprintf(buf,"Profiling: start failed! | %s\n",msg);
+
+ f->Write(buf);
+ }
+ else
+ {
+ if(res1 != -1 && res2 != -1)
+ fprintf(stdout,"[%s] started | %s\n",tbuf,msg);
+ else
+ fprintf(stdout,"Profiling: start failed! | %s\n",msg);
+
+ fflush(stdout);
+ }
+#else
+
+#endif
+ just_started = false;
+ }
+ else
+ {
+#ifdef WIN32
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+
+ LARGE_INTEGER freq;
+ QueryPerformanceFrequency(&freq);
+
+ long long from_start = now.QuadPart - start.QuadPart;
+ long long from_last = now.QuadPart - last.QuadPart;
+
+ last = now;
+ float t1 = (float)(from_last*1000.0/freq.QuadPart);
+ float t2 = (float)(from_start*1000.0/freq.QuadPart);
+ if(f)
+ {
+ char buf[200];sprintf(buf,"[%s] %f (total %f) | %s\n",tbuf,t1,t2,msg);
+ f->Write(buf);
+ }
+ else
+ {
+ fprintf(stdout,"[%s] %f (total %f) | %s\n",tbuf,t1,t2,msg);
+ fflush(stdout);
+ }
+ /////////////
+ //int s, n;
+ //char buf0[20] = ""; int nz = numZeros(n);for(int k = 0; k < nz; k++) strcat(buf0,"0");
+ //char buf[200];sprintf(buf,"[%s] %u.%u (total %u.%u) | %s\n",tbuf,s,buf0,n);
+ ////////////
+#elif defined(LINUX)
+ timespec now;
+ int res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &now);
+ if(res != -1)
+ {
+ timespec tdiff = diff(last,now);
+ timespec tdiff2 = diff(start,now);
+ last=now;
+
+ char buf1[20] = ""; int nz1 = numZeros(tdiff.tv_nsec);for(int k = 0; k < nz1; k++) strcat(buf1,"0");
+ char buf2[20] = ""; int nz2 = numZeros(tdiff2.tv_nsec);for(int k = 0; k < nz2; k++) strcat(buf2,"0");
+ char buf[200];sprintf(buf,"[%s] %u.%s%u (total %u.%s%u) | %s\n",tbuf,
+ (unsigned int)tdiff.tv_sec, buf1, (unsigned int)tdiff.tv_nsec,
+ (unsigned int)tdiff2.tv_sec, buf2, (unsigned int)tdiff2.tv_nsec,
+ msg);
+
+ if(f)
+ {
+
+ f->Write(buf);
+ }
+ else
+ {
+ fprintf(stdout,"%s\n",buf);
+ fflush(stdout);
+ }
+ }
+#endif
+ }
+
+}
+
+void ProfileEnd(LStrFile* f)
+{
+ if(f==NULL)
+ f=GetDiagFile();
+
+ char tbuf[100];
+ time_t t = time(0);
+ struct tm* fnow = localtime(&t);
+ sprintf(tbuf,"%i:%i:%i", fnow->tm_hour, fnow->tm_min, fnow->tm_sec);
+
+#ifdef WIN32
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+
+ LARGE_INTEGER freq;
+ QueryPerformanceFrequency(&freq);
+
+ long long from_start = now.QuadPart - start.QuadPart;
+
+ if(f)
+ {
+ char buf[200];sprintf(buf,"[%s] finished: %f\n",tbuf,(float)(from_start*1000.0/freq.QuadPart));
+ f->Write(buf);
+ }
+ else
+ {
+ fprintf(stdout,"[%s] finished: %f \n",tbuf,(float)(from_start*1000.0/freq.QuadPart));
+ fflush(stdout);
+ }
+#elif defined(LINUX)
+ timespec now;
+ int res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &now);
+ if(res != -1)
+ {
+ timespec tdiff = diff(start,now);
+ now = last;
+ char buf1[20] = ""; int nz1 = numZeros(tdiff.tv_nsec);for(int k = 0; k < nz1; k++) strcat(buf1,"0");
+ char buf[200];sprintf(buf,"[%s] finished: %u.%s%u \n",tbuf,(unsigned int)tdiff.tv_sec, buf1, (unsigned int)tdiff.tv_nsec);
+ if(f)
+ {
+
+ f->Write(buf);
+ }
+ else
+ {
+ fprintf(stdout,"%s\n",tbuf,(unsigned int)tdiff.tv_sec, (unsigned int)tdiff.tv_nsec);
+ fflush(stdout);
+ }
+ }
+#else
+#endif
+}
+
+} //end of namespace LServiceSDK
+#endif
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////// GL EXT INITIALIZATION ////////////////////////////
+
+static bool glFuncionsInited = false;
+
+bool GLFunctionsInited()
+{
+ return glFuncionsInited;
+}
+
+bool InitGLFunctionPointers()
+{
+#ifdef _WIN32
+ assert(_CrtCheckMemory());
+#endif
+
+ bool ret=true;
+ MGlobal::displayInfo("InitGLFunctionPointers");
+
+ //// these are delcalred in OSX's gl.h so no need to get ptrs
+#ifdef WIN32
+ //glNewBufferRegionEXT = (PFNGLNEWBUFFERREGIONEXTPROC) getGlFncPtr("glNewBufferRegionEXT");
+// if(!glNewBufferRegionEXT)
+// {
+// MGlobal::displayInfo(MString("glNewBufferRegionEXTT not found (error")+ GetLastError() + ")");
+// return false;
+// }
+
+//glDeleteBufferRegionEXT = (PFNGLDELETEBUFFERREGIONEXTPROC) getGlFncPtr("glDeleteBufferRegionEXT");
+// if(!glDeleteBufferRegionEXT)
+// {
+// MGlobal::displayInfo(MString("glDeleteBufferRegionEXT not found (error")+ GetLastError() + ")");
+// ret= false;
+// }
+
+//glReadBufferRegionEXT = (PFNGLREADBUFFERREGIONEXTPROC) getGlFncPtr("glReadBufferRegionEXT");
+// if(!glReadBufferRegionEXT)
+// {
+// MGlobal::displayInfo(MString("glReadBufferRegionEXT not found (error")+ GetLastError() + ")");
+// ret= false;
+// }
+
+//glDrawBufferRegionEXT = (PFNGLDRAWBUFFERREGIONEXTPROC) getGlFncPtr("glDrawBufferRegionEXT");
+// if(!glDrawBufferRegionEXT)
+// {
+// MGlobal::displayInfo(MString("glDrawBufferRegionEXT not found (error")+ GetLastError() + ")");
+// ret= false;
+// }
+
+//glBufferRegionEnabledEXT = (PFNGLBUFFERREGIONENABLEDEXTPROC) getGlFncPtr("glBufferRegionEnabledEXT");
+// if(!glBufferRegionEnabledEXT)
+// {
+// MGlobal::displayInfo(MString("glBufferRegionEnabledEXT not found (error")+ GetLastError() + ")");
+// ret= false;
+// }
+ glActiveTexture = (PFNGLATCIVETEXTUREPROC) getGlFncPtr("glActiveTexture");
+ if(!glActiveTexture)
+ {
+ MGlobal::displayInfo(MString("glActiveTexture not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ assert(_CrtCheckMemory());
+#if 0
+ glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC) getGlFncPtr("glMultiTexCoord2f");
+ if(!glMultiTexCoord2f)
+ {
+ MGlobal::displayInfo(MString("glMultiTexCoord2f not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+#endif
+ glAttachShader = (PFNGATTACHSHADERPROC) getGlFncPtr("glAttachShader");
+ if(!glAttachShader)
+ {
+ MGlobal::displayInfo(MString("glAttachShader not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ // ret= false;
+
+ glCompileShader = (PFNGLCOMPILESHADERPROC) getGlFncPtr("glCompileShader");
+ if(!glCompileShader)
+ {
+ MGlobal::displayInfo(MString("glCompileShader not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glDetachShader = (PFNGLDETACHSHADERPROC) getGlFncPtr("glDetachShader");
+ if(!glDetachShader)
+ {
+ MGlobal::displayInfo(MString("glDetachShader not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glDeleteShader = (PFNGLDELETESHADERPROC) getGlFncPtr("glDeleteShader");
+ if(!glDeleteShader)
+ {
+ MGlobal::displayInfo(MString("glDeleteShader not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glCreateShader = (PFNGLCREATESHADERPROC) getGlFncPtr("glCreateShader");
+ if(!glCreateShader)
+ {
+ MGlobal::displayInfo(MString("glCreateShader not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glShaderSource = (PFNGLSHADERSOURCEPROC) getGlFncPtr("glShaderSource");
+ if(!glShaderSource)
+ {
+ MGlobal::displayInfo(MString("glShaderSource not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glGetShaderiv = (PFNGLGETSHADDERIVPROC) getGlFncPtr("glGetShaderiv");
+ if(!glGetShaderiv)
+ {
+ MGlobal::displayInfo(MString("glGetShaderiv not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) getGlFncPtr("glGetShaderInfoLog");
+ if(!glGetShaderInfoLog)
+ {
+ MGlobal::displayInfo(MString("glGetShaderInfoLog not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glDeleteProgram = (PFNGLDELETEPROGRAMPROC) getGlFncPtr("glDeleteProgram");
+ if(!glDeleteProgram)
+ {
+ MGlobal::displayInfo(MString("glDeleteProgram not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glCreateProgram = (PFNGLCREATEPROGRAMPROC) getGlFncPtr("glCreateProgram");
+ if(!glCreateProgram)
+ {
+ MGlobal::displayInfo(MString("glCreateProgram not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glLinkProgram = (PFNGLLINKPROGRAMPROC) getGlFncPtr("glLinkProgram");
+ if(!glLinkProgram)
+ {
+ MGlobal::displayInfo(MString("glLinkProgram not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glUseProgram = (PFNGLUSEPROGRAMPROC) getGlFncPtr("glUseProgram");
+ if(!glUseProgram)
+ {
+ MGlobal::displayInfo(MString("glUseProgram not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glGetProgramiv = (PFNGLGETPROGRAMIVPROC) getGlFncPtr("glGetProgramiv");
+ if(!glGetProgramiv)
+ {
+ MGlobal::displayInfo(MString("glGetProgramiv not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glValidateProgram = (PFNVALIDATEPROGRAMPROC) getGlFncPtr("glValidateProgram");
+ if(!glValidateProgram)
+ {
+ MGlobal::displayInfo(MString("glValidateProgram not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) getGlFncPtr("glGetProgramInfoLog");
+ if(!glGetProgramInfoLog)
+ {
+ MGlobal::displayInfo(MString("glGetProgramInfoLog not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) getGlFncPtr("glGetUniformLocation");
+ if(!glGetUniformLocation)
+ {
+ MGlobal::displayInfo(MString("glGetUniformLocation not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glUniform3f = (PFNGLUNIFORM3FPROC) getGlFncPtr("glUniform3f");
+ if(!glUniform3f)
+ {
+ MGlobal::displayInfo(MString("glUniform3f not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glUniform1f = (PFNGLUNIFORM1FPROC) getGlFncPtr("glUniform1f");
+ if(!glUniform1f)
+ {
+ MGlobal::displayInfo(MString("glUniform1f not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glUniform1i = (PFNGLUNIFORM1IPROC) getGlFncPtr("glUniform1i");
+ if(!glUniform1i)
+ {
+ MGlobal::displayInfo(MString("glUniform1i not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glVertexAttrib1f = (PFNGLVERTEXATTRIB1FV) getGlFncPtr("glVertexAttrib1f");
+ if(!glVertexAttrib1f)
+ {
+ MGlobal::displayInfo(MString("glVertexAttrib1f not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glVertexAttrib3f = (PFNGLVERTEXATTRIB3FV) getGlFncPtr("glVertexAttrib3f");
+ if(!glVertexAttrib3f)
+ {
+ MGlobal::displayInfo(MString("glVertexAttrib3f not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTER) getGlFncPtr("glVertexAttribPointer");
+ if(!glVertexAttribPointer)
+ {
+ MGlobal::displayInfo(MString("glVertexAttribPointer not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+ glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAY) getGlFncPtr("glEnableVertexAttribArray");
+ if(!glEnableVertexAttribArray)
+ {
+ MGlobal::displayInfo(MString("glEnableVertexAttribArray not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+// glWindowPos2i = (PFNGLWINDOWPOS2I) getGlFncPtr("glWindowPos2i");
+// if(!glWindowPos2i)
+// {
+// MGlobal::displayInfo(MString("glWindowPos2i not found (error")+ GetLastError() + ")");
+// ret= false;
+// }
+
+// glWindowPos3f = (PFNGLWINDOWPOS3F) getGlFncPtr("glWindowPos3f");
+// if(!glWindowPos3f)
+// {
+// MGlobal::displayInfo(MString("glWindowPos3f not found (error")+ GetLastError() + ")");
+// ret= false;
+// }
+
+ glGetAttribLocation = (PFNGLGETATTRIBLOCATION) getGlFncPtr("glGetAttribLocation");
+ if(!glGetAttribLocation)
+ {
+ MGlobal::displayInfo(MString("glGetAttribLocation not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+
+ //PBO
+// glBindBufferARB = (PFNGLBINDBUFFERARBPROC) getGlFncPtr("glBindBufferARB");
+// glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) getGlFncPtr("glDeleteBuffersARB");
+// glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) getGlFncPtr("glGenBuffersARB");
+// glBufferDataARB = (PFNGLBUFFERDATAARBPROC) getGlFncPtr("glBufferDataARB");
+
+// if(!glBindBufferARB)
+// {
+// MGlobal::displayInfo(MString("glBindBufferARB not found (error")+ GetLastError() + ")");
+// ret= false;
+// }
+
+ //FBOs
+ glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)wglGetProcAddress("glGenFramebuffersEXT");
+ if(!glGenFramebuffersEXT)
+ {
+ MGlobal::displayInfo(MString("glGenFramebuffersEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)wglGetProcAddress("glDeleteFramebuffersEXT");
+ if(!glDeleteFramebuffersEXT)
+ {
+ MGlobal::displayInfo(MString("glDeleteFramebuffersEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)wglGetProcAddress("glBindFramebufferEXT");
+ if(!glBindFramebufferEXT)
+ {
+ MGlobal::displayInfo(MString("glBindFramebufferEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)wglGetProcAddress("glCheckFramebufferStatusEXT");
+ if(!glCheckFramebufferStatusEXT)
+ {
+ MGlobal::displayInfo(MString("glCheckFramebufferStatusEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)wglGetProcAddress("glGetFramebufferAttachmentParameterivEXT");
+ if(!glGetFramebufferAttachmentParameterivEXT)
+ {
+ MGlobal::displayInfo(MString("glGetFramebufferAttachmentParameterivEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)wglGetProcAddress("glFramebufferTexture2DEXT");
+ if(!glFramebufferTexture2DEXT)
+ {
+ MGlobal::displayInfo(MString("glFramebufferTexture2DEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)wglGetProcAddress("glFramebufferRenderbufferEXT");
+ if(!glFramebufferRenderbufferEXT)
+ {
+ MGlobal::displayInfo(MString("glFramebufferRenderbufferEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)wglGetProcAddress("glGenRenderbuffersEXT");
+ if(!glGenRenderbuffersEXT)
+ {
+ MGlobal::displayInfo(MString("glGenRenderbuffersEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)wglGetProcAddress("glDeleteRenderbuffersEXT");
+ if(!glDeleteRenderbuffersEXT)
+ {
+ MGlobal::displayInfo(MString("glDeleteRenderbuffersEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)wglGetProcAddress("glBindRenderbufferEXT");
+ if(!glBindRenderbufferEXT)
+ {
+ MGlobal::displayInfo(MString("glBindRenderbufferEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)wglGetProcAddress("glRenderbufferStorageEXT");
+ if(!glRenderbufferStorageEXT)
+ {
+ MGlobal::displayInfo(MString("glRenderbufferStorageEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)wglGetProcAddress("glGetRenderbufferParameterivEXT");
+ if(!glGetRenderbufferParameterivEXT)
+ {
+ MGlobal::displayInfo(MString("glGetRenderbufferParameterivEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)wglGetProcAddress("glIsRenderbufferEXT");
+ if(!glIsRenderbufferEXT)
+ {
+ MGlobal::displayInfo(MString("glIsRenderbufferEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)getGlFncPtr("glRenderbufferStorageMultisampleEXT");
+ if(!glRenderbufferStorageMultisampleEXT)
+ {
+ MGlobal::displayInfo(MString("glRenderbufferStorageMultisampleEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXT)getGlFncPtr("glBlitFramebufferEXT");
+ if(!glBlitFramebufferEXT)
+ {
+ MGlobal::displayInfo(MString("glBlitFramebufferEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+ glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) getGlFncPtr("glGenerateMipmapEXT");
+ if(!glGenerateMipmapEXT)
+ {
+ MGlobal::displayInfo(MString("glGenerateMipmapEXT not found (error")+ GetLastError() + ")");
+ ret= false;
+ }
+
+#elif defined LINUX
+
+ //glBindBufferARB = (PFNGLBINDBUFFERARBPROC) getGlFncPtr("glBindBufferARB");
+ //if(!glBindBufferARB)
+ //{
+ // fprintf (stdout,"glAttachShader and glBindBufferARB not found\n");fflush(stdout);
+ // ret= false;
+ //}
+ //glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) getGlFncPtr("glDeleteBuffersARB");
+ //if(!glDeleteBuffersARB)
+ //{
+ // fprintf (stdout,"glAttachShader and glDeleteBuffersARB not found\n");fflush(stdout);
+ // ret= false;
+ //}
+ //glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) getGlFncPtr("glGenBuffersARB");
+ //if(!glGenBuffersARB)
+ //{
+ // fprintf (stdout,"glAttachShader and glGenBuffersARB not found\n");fflush(stdout);
+ // ret= false;
+ //}
+ //glBufferDataARB = (PFNGLBUFFERDATAARBPROC) getGlFncPtr("glBufferDataARB");
+ //if(!glBufferDataARB)
+ //{
+ // fprintf (stdout,"glAttachShader and glBufferDataARB not found\n");fflush(stdout);
+ // ret= false;
+ //}
+
+ glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTER) getGlFncPtr("glVertexAttribPointer");
+ if(!glVertexAttribPointer)
+ {
+ fprintf (stdout,"glAttachShader and glVertexAttribPointer not found\n");fflush(stdout);
+ ret= false;
+ }
+
+ glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAY) getGlFncPtr("glEnableVertexAttribArray");
+ if(!glEnableVertexAttribArray)
+ {
+ fprintf (stdout,"glAttachShader and glEnableVertexAttribArray not found\n");fflush(stdout);
+ ret= false;
+ }
+
+
+#ifndef GL_ACTIVE_TEXTURE
+ glActiveTexture = (PFNGLATCIVETEXTUREPROC) getGlFncPtr("glActiveTexture");
+ if(!glActiveTexture)
+ {
+ fprintf (stdout,"glActiveTexture not found \n");fflush(stdout);
+ ret= false;
+ }
+#endif
+ //glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC) getGlFncPtr("glMultiTexCoord2f");
+ //if(!glMultiTexCoord2f)
+ //{
+ // fprintf (stdout,"glMultiTexCoord2f not found \n");fflush(stdout);
+ // ret= false;
+ //}
+ glAttachShader = (PFNGATTACHSHADERPROC) getGlFncPtr("glAttachShader");
+ if(!glAttachShader)
+ {
+ glAttachShader = (PFNGATTACHSHADERPROC) getGlFncPtr("glAttachObjectARB");
+ if(!glAttachShader)
+ {
+ fprintf (stdout,"glAttachShader and glAttachObjectARB not found\n");fflush(stdout);
+ ret= false;
+ }
+ else
+ fprintf (stdout,"glAttachObjectARB - OK\n");
+ }
+ else
+ fprintf (stdout,"glAttachShader - OK\n");
+
+ glCompileShader = (PFNGLCOMPILESHADERPROC) getGlFncPtr("glCompileShader");
+ if(!glCompileShader)
+ {
+ fprintf (stdout,"glCompileShader not found \n");fflush(stdout);
+ ret= false;
+ }
+
+ glDetachShader = (PFNGLDETACHSHADERPROC) getGlFncPtr("glDetachShader");
+ if(!glDetachShader)
+ {
+ fprintf (stdout,"glDetachShader not found \n");fflush(stdout);
+ ret= false;
+ }
+
+ glDeleteShader = (PFNGLDELETESHADERPROC) getGlFncPtr("glDeleteShader");
+ if(!glDeleteShader)
+ {
+ fprintf (stdout,"glDeleteShader not found \n");fflush(stdout);
+ ret= false;
+ }
+
+ glCreateShader = (PFNGLCREATESHADERPROC) getGlFncPtr("glCreateShader");
+ if(!glCreateShader)
+ {
+ fprintf (stdout,"glCreateShader not found \n");fflush(stdout);
+ ret= false;
+ }
+
+ glShaderSource = (PFNGLSHADERSOURCEPROC) getGlFncPtr("glShaderSource");
+ if(!glShaderSource)
+ {
+ fprintf (stdout,"glShaderSource not found\n");fflush(stdout);
+ ret= false;
+ }
+
+ glGetShaderiv = (PFNGLGETSHADDERIVPROC) getGlFncPtr("glGetShaderiv");
+ if(!glGetShaderiv)
+ {
+ fprintf (stdout,"glGetShaderiv not found\n");fflush(stdout);
+ ret= false;
+ }
+
+ glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) getGlFncPtr("glGetShaderInfoLog");
+ if(!glGetShaderInfoLog)
+ {
+ fprintf (stdout,"glGetShaderInfoLog not found \n");fflush(stdout);
+ ret= false;
+ }
+
+ glDeleteProgram = (PFNGLDELETEPROGRAMPROC) getGlFncPtr("glDeleteProgram");
+ if(!glDeleteProgram)
+ {
+ fprintf (stdout,"glDeleteProgram not found\n");fflush(stdout);
+ ret= false;
+ }
+
+ glCreateProgram = (PFNGLCREATEPROGRAMPROC) getGlFncPtr("glCreateProgram");
+ if(!glCreateProgram)
+ {
+ fprintf (stdout,"glCreateProgram not found \n");fflush(stdout);
+ ret= false;
+ }
+
+ glLinkProgram = (PFNGLLINKPROGRAMPROC) getGlFncPtr("glLinkProgram");
+ if(!glLinkProgram)
+ {
+ fprintf (stdout,"glLinkProgram not found \n");fflush(stdout);
+ ret= false;
+ }
+
+ glUseProgram = (PFNGLUSEPROGRAMPROC) getGlFncPtr("glUseProgram");
+ if(!glUseProgram)
+ {
+ fprintf (stdout,"glUseProgram not found\n");fflush(stdout);
+ ret= false;
+ }
+
+ glGetProgramiv = (PFNGLGETPROGRAMIVPROC) getGlFncPtr("glGetProgramiv");
+ if(!glGetProgramiv)
+ {
+ fprintf (stdout,"glGetProgramiv not found\n");fflush(stdout);
+ ret= false;
+ }
+
+ glValidateProgram = (PFNVALIDATEPROGRAMPROC) getGlFncPtr("glValidateProgram");
+ if(!glValidateProgram)
+ {
+ fprintf (stdout,"glValidateProgram not found \n");fflush(stdout);
+ ret= false;
+ }
+
+ glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) getGlFncPtr("glGetProgramInfoLog");
+ if(!glGetProgramInfoLog)
+ {
+ fprintf (stdout,"glGetProgramInfoLog not found\n");fflush(stdout);
+ ret= false;
+ }
+
+ glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) getGlFncPtr("glGetUniformLocation");
+ if(!glGetUniformLocation)
+ {
+ fprintf (stdout,"glGetUniformLocation not found\n");fflush(stdout);
+ ret= false;
+ }
+
+ glUniform3f = (PFNGLUNIFORM3FPROC) getGlFncPtr("glUniform3f");
+ if(!glUniform3f)
+ {
+ fprintf (stdout,"glUniform3f not found\n");fflush(stdout);
+ ret= false;
+ }
+
+ glUniform1f = (PFNGLUNIFORM1FPROC) getGlFncPtr("glUniform1f");
+ if(!glUniform1f)
+ {
+ fprintf (stdout,"glUniform1f not found \n");fflush(stdout);
+ ret= false;
+ }
+
+ glUniform1i = (PFNGLUNIFORM1IPROC) getGlFncPtr("glUniform1i");
+ if(!glUniform1i)
+ {
+ fprintf (stdout,"glUniform1i not found \n");fflush(stdout);
+ ret= false;
+ }
+
+ glGetAttribLocation = (PFNGLGETATTRIBLOCATION) getGlFncPtr("glGetAttribLocation");
+ if(!glGetAttribLocation)
+ {
+ fprintf (stdout,"glGetAttribLocation not found\n");fflush(stdout);
+ ret= false;
+ }
+
+ glVertexAttrib1f = (PFNGLVERTEXATTRIB1FV) getGlFncPtr("glVertexAttrib1f");
+ if(!glVertexAttrib1f)
+ {
+ fprintf (stdout,"glVertexAttrib1f not found\n");fflush(stdout);
+ ret= false;
+ }
+
+ glVertexAttrib3f = (PFNGLVERTEXATTRIB3FV) getGlFncPtr("glVertexAttrib3f");
+ if(!glVertexAttrib3f)
+ {
+ fprintf (stdout,"glVertexAttrib3f not found\n");fflush(stdout);
+ ret= false;
+ }
+ //glWindowPos2i = (PFNGLWINDOWPOS2I) getGlFncPtr("glWindowPos2i");
+ //if(!glWindowPos2i)
+ //{
+ // fprintf (stdout,"glWindowPos2i not found\n");fflush(stdout);
+ // ret= false;
+ //}
+ //FBOs
+ glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)getGlFncPtr("glGenFramebuffersEXT");
+ if(!glGenFramebuffersEXT)
+ {
+ fprintf (stdout,"glGenFramebuffersEXT not found.\n");fflush(stdout);
+ ret= false;
+ }
+ glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)getGlFncPtr("glDeleteFramebuffersEXT");
+ if(!glDeleteFramebuffersEXT)
+ {
+ fprintf (stdout,"glDeleteFramebuffersEXT not found.\n");fflush(stdout);
+ ret= false;
+ }
+ glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)getGlFncPtr("glBindFramebufferEXT");
+ if(!glBindFramebufferEXT)
+ {
+ fprintf (stdout,"glBindFramebufferEXT not found.\n");fflush(stdout);
+ ret= false;
+ }
+ glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)getGlFncPtr("glCheckFramebufferStatusEXT");
+ if(!glCheckFramebufferStatusEXT)
+ {
+ fprintf (stdout,"glCheckFramebufferStatusEXT not found.\n");fflush(stdout);
+ ret= false;
+ }
+ glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)getGlFncPtr("glGetFramebufferAttachmentParameterivEXT");
+ if(!glGetFramebufferAttachmentParameterivEXT)
+ {
+ fprintf (stdout,"glGetFramebufferAttachmentParameterivEXT not found.\n");fflush(stdout);
+ ret= false;
+ }
+ glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)getGlFncPtr("glFramebufferTexture2DEXT");
+ if(!glFramebufferTexture2DEXT)
+ {
+ fprintf (stdout,"glFramebufferTexture2DEXT not found.\n");fflush(stdout);
+ ret= false;
+ }
+ glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)getGlFncPtr("glFramebufferRenderbufferEXT");
+ if(!glFramebufferRenderbufferEXT)
+ {
+ fprintf (stdout,"glFramebufferRenderbufferEXT not found.\n");fflush(stdout);
+ ret= false;
+ }
+ glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)getGlFncPtr("glGenRenderbuffersEXT");
+ if(!glGenRenderbuffersEXT)
+ {
+ fprintf (stdout,"glGenRenderbuffersEXT not found.\n");fflush(stdout);
+ ret= false;
+ }
+ glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)getGlFncPtr("glDeleteRenderbuffersEXT");
+ if(!glDeleteRenderbuffersEXT)
+ {
+ fprintf (stdout,"glDeleteRenderbuffersEXT not found.\n");fflush(stdout);
+ ret= false;
+ }
+ glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)getGlFncPtr("glBindRenderbufferEXT");
+ if(!glBindRenderbufferEXT)
+ {
+ fprintf (stdout,"glBindRenderbufferEXT not found.\n");fflush(stdout);
+ ret= false;
+ }
+ glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)getGlFncPtr("glRenderbufferStorageEXT");
+ if(!glRenderbufferStorageEXT)
+ {
+ fprintf (stdout,"glRenderbufferStorageEXT not found.\n");fflush(stdout);
+ ret= false;
+ }
+ glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)getGlFncPtr("glGetRenderbufferParameterivEXT");
+ if(!glGetRenderbufferParameterivEXT)
+ {
+ fprintf (stdout,"glGetRenderbufferParameterivEXT not found.\n");fflush(stdout);
+ ret= false;
+ }
+ glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)getGlFncPtr("glIsRenderbufferEXT");
+ if(!glIsRenderbufferEXT)
+ {
+ fprintf (stdout,"glIsRenderbufferEXT not found.\n");fflush(stdout);
+ ret= false;
+ }
+
+#endif
+
+ //////////// paltform dependent stufff //////////////
+#ifdef WIN32
+ //wglShareLists = (PFWGLSHARELISTS) wglGetProcAddress("wglShareLists");
+ //if(!wglShareLists)
+ //{
+ // fprintf (stdout,"wglShareLists not found (error %i)\n",GetLastError());fflush(stdout);
+ // // ret= false;
+ //}
+#ifdef USE_PBUFFER
+ wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC) getGlFncPtr("wglCreatePbufferARB");
+ if(!wglCreatePbufferARB)
+ {
+ fprintf (stdout,"wglCreatePbufferARB not found (error %i)\n",GetLastError());fflush(stdout);
+ ret= false;
+ }
+
+ wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) getGlFncPtr("wglChoosePixelFormatARB");
+ if(!wglChoosePixelFormatARB)
+ {
+ fprintf (stdout,"wglChoosePixelFormatARB not found (error %i)\n",GetLastError());fflush(stdout);
+ ret= false;
+ }
+
+ wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC) getGlFncPtr("wglGetPbufferDCARB");
+ if(!wglGetPbufferDCARB)
+ {
+ fprintf (stdout,"wglGetPbufferDCARB not found (error %i)\n",GetLastError());fflush(stdout);
+ ret= false;
+ }
+
+ wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC) getGlFncPtr("wglReleasePbufferDCARB");
+ if(!wglReleasePbufferDCARB)
+ {
+ fprintf (stdout,"wglReleasePbufferDCARB not found (error %i)\n",GetLastError());fflush(stdout);
+ ret= false;
+ }
+
+ wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERPROC) getGlFncPtr("wglDestroyPbufferARB");
+ if(!wglDestroyPbufferARB)
+ {
+ fprintf (stdout,"wglDestroyPbufferARB not found (error %i)\n",GetLastError());fflush(stdout);
+ ret= false;
+ }
+
+ wglQueryPbufferARB = (PFNWGLQUERYPBUFFERPROC) getGlFncPtr("wglQueryPbufferARB");
+ if(!wglQueryPbufferARB)
+ {
+ fprintf (stdout,"wglQueryPbufferARB not found (error %i)\n",GetLastError());fflush(stdout);
+ ret= false;
+ }
+
+ wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRBVARBPROC) getGlFncPtr("wglGetPixelFormatAttribivARB");
+ if(!wglGetPixelFormatAttribivARB)
+ {
+ fprintf (stdout,"wglGetPixelFormatAttribivARB not found (error %i)\n",GetLastError());fflush(stdout);
+ ret= false;
+ }
+
+ wglBindTexImageARB = (PFNWGLBINDTEXIMAGEARBPROC) getGlFncPtr("wglBindTexImageARB");
+ if(!wglBindTexImageARB)
+ {
+ fprintf (stdout,"wglBindTexImageARB not found (error %i)\n",GetLastError());fflush(stdout);
+ ret= false;
+ }
+
+ wglReleaseTexImageARB = (PFNWGLRELEASETEXIMAGEARB) getGlFncPtr("wglReleaseTexImageARB");
+ if(!wglReleaseTexImageARB)
+ {
+ fprintf (stdout,"wglReleaseTexImageARB not found (error %i)\n",GetLastError());fflush(stdout);
+ ret= false;
+ }
+#endif
+#endif //end of WIN32
+ if(ret)
+ glFuncionsInited = true;
+
+#ifdef _WIN32
+ assert(_CrtCheckMemory());
+#endif
+ return ret;
+}
+
+void FreeGLFunctionPointers()
+{
+ glFuncionsInited = false;
+}
+
+
+////////////////////////////// GLSL ///////////////////////////////////////////
+
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
+| glslGenericProgram - generic glsl shader program |
+/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+const float cDefLightXDir = 0.0f;
+const float cDefLightYDir = -0.5f;
+const float cDefLightZDir = -1.0f;
+
+glslGenericProgram::glslGenericProgram()
+{
+ //wglGetProcAddress("bla bla");
+
+ _vShader() = 0;
+ _fShader() = 0;
+ _program() = 0;
+ _numLights() = 0;
+
+ //some default light dir
+ AddLight();
+ MVector dir(cDefLightXDir, cDefLightYDir, cDefLightZDir);
+ //MVector pos(cDefLightXPos, cDefLightYPos, cDefLightZPos);
+ dir.normalize();
+ SetLightDir(0,dir);
+
+ MVector pos = -20.0f*dir;
+ SetLightPos(0,pos);
+
+ s_vertexErrDumped = false;
+ s_fragErrDumped = false;
+ s_varErrDumped = false;
+ s_linkErrDumped= false;
+
+}
+
+
+glslGenericProgram::~glslGenericProgram()
+{
+ if(vShader() && program())
+ {
+ glDetachShader(program(),vShader());
+ glDeleteShader(vShader());
+ }
+ if(fShader() && program())
+ {
+ glDetachShader(program(),fShader());
+ glDeleteShader(fShader());
+ }
+ if(program())
+ {
+ glUseProgram(0);
+ glDeleteProgram(program());
+ }
+ glFlush();
+}
+
+bool glslGenericProgram::LoadShaders(char* vShaderFile, char* fShaderFile)
+{
+
+ _vShader() = glCreateShader(GL_VERTEX_SHADER);
+ if(!loadShader( vShader(), vShaderFile))
+ {
+ MGlobal::displayError(MString("Shave GLSL: unable to load vertex shader file ") + MString(vShaderFile));
+ return false;
+ }
+
+ _fShader() = glCreateShader(GL_FRAGMENT_SHADER);
+ if(!loadShader( fShader(), fShaderFile))
+ {
+ MGlobal::displayError(MString("Shave GLSL: unable to load fragment shader file ") + MString(fShaderFile));
+ return false;
+ }
+ if(!compileShader(vShader(),eVertShader))
+ {
+ MGlobal::displayError("Shave GLSL: can not compile vertex shader\n");
+ return false;
+ }
+ if(!compileShader(fShader(),eFragShader))
+ {
+ MGlobal::displayError("Shave GLSL: can not compile fragment shader\n");
+ return false;
+ }
+ _program() = glCreateProgram();
+
+ glAttachShader(program(),vShader());
+ glAttachShader(program(),fShader());
+
+ if(!linkProgram(program()))
+ {
+ MGlobal::displayError("Shave GLSL: can not link program\n");
+ return false;
+ }
+
+ return true;
+}
+
+bool glslGenericProgram::LoadShaders()
+{
+ _vShader() = glCreateShader(GL_VERTEX_SHADER);
+ loadVertShader( vShader());
+
+ _fShader() = glCreateShader(GL_FRAGMENT_SHADER);
+ loadFragShader( fShader());
+
+ if(!compileShader(vShader(),eVertShader))
+ {
+ MGlobal::displayError("Shave GLSL: can not compile vertex shader\n");
+ return false;
+ }
+ if(!compileShader(fShader(),eFragShader))
+ {
+ MGlobal::displayError("Shave GLSL: can not compile fragment shader\n");
+ return false;
+ }
+
+ _program() = glCreateProgram();
+
+
+ glAttachShader(program(),vShader());
+ glAttachShader(program(),fShader());
+
+
+ if(!linkProgram(program()))
+ {
+ MGlobal::displayError("Shave GLSL: can not link program\n");
+ return false;
+ }
+
+ return true;
+}
+
+void glslGenericProgram::UnLoadShaders()
+{
+ if(vShader() && program())
+ {
+ glDetachShader(program(),vShader());
+ glDeleteShader(vShader());
+ }
+ if(fShader() && program())
+ {
+ glDetachShader(program(),fShader());
+ glDeleteShader(fShader());
+ }
+ if(program())
+ {
+ glUseProgram(0);
+ glDeleteProgram(program());
+ }
+}
+
+bool glslGenericProgram::IsVadlid() const
+{
+ GLint validStatus;
+ glValidateProgram(program());
+
+ glGetProgramiv(program(), GL_VALIDATE_STATUS, &validStatus);
+ return (validStatus == GL_TRUE);
+}
+
+bool glslGenericProgram::UseProgram()
+{
+ if(!program() || !vShader() || !fShader())
+ return false;
+
+ GLint validStatus;
+ glValidateProgram(program());
+
+ glGetProgramiv(program(), GL_VALIDATE_STATUS, &validStatus);
+ if(validStatus != GL_TRUE)
+ {
+ MGlobal::displayError("Shave GLSL: program is not valid");
+
+ UnLoadShaders();
+ LoadShaders();
+
+ //weird but we can not retrieve log
+ //char* infoLog;
+ //GLint infoLogLength;
+ //glGetProgramiv(program(), GL_INFO_LOG_LENGTH, &infoLogLength);
+ //if(infoLogLength)
+ //{
+ // infoLog = (char*) malloc(infoLogLength);
+
+ // glGetProgramInfoLog(program(), infoLogLength, NULL, infoLog);
+
+ // MGlobal::displayInfo(MString("Info Log:\n\n") + MString(infoLog));
+
+ // free(infoLog);
+ //}
+ }
+ glUseProgram(program());
+
+ //if we do not share resouces between contexts it can happen that shader was
+ //compiled when different context was ative so it becomes unusable for current one.
+ //we need to recompile shaders in this case for active context -- dub|16-02-2009
+ if(!setupUniformVariables())
+ {
+ UnLoadShaders();
+ LoadShaders();
+ glUseProgram(program());
+ setupUniformVariables();
+ }
+
+ return true;
+}
+
+bool glslGenericProgram::UnUseProgram()
+{
+ glUseProgram(0);
+
+ return true;
+}
+
+bool glslGenericProgram::AddLight()
+{
+ if(numLights() < eMaxNumLights)
+ {
+ _numLights()++;
+ return true;
+ }
+ return false;
+}
+
+bool glslGenericProgram::SetLightDir(int idx, float x, float y, float z)
+{
+ if(idx < numLights())
+ {
+ _lightDir(idx).x = x;
+ _lightDir(idx).y = y;
+ _lightDir(idx).z = z;
+
+ _lightDir(idx).normalize();
+
+ return true;
+ }
+ return false;
+}
+
+bool glslGenericProgram::SetLightDir(int idx, const MVector &p)
+{
+ if(idx < numLights())
+ {
+
+ _lightDir(idx) = p;
+ _lightDir(idx).normalize();
+ return true;
+ }
+ return false;
+}
+
+bool glslGenericProgram::SetLightPos(int idx, float x, float y, float z)
+{
+ if(idx < numLights())
+ {
+ _lightPos(idx).x = x;
+ _lightPos(idx).y = y;
+ _lightPos(idx).z = z;
+
+ return true;
+ }
+ return false;
+}
+
+bool glslGenericProgram::SetLightPos(int idx, const MVector &p)
+{
+ if(idx < numLights())
+ {
+ _lightPos(idx) = p;
+ return true;
+ }
+ return false;
+}
+
+
+int glslGenericProgram::GetNumLigths() const
+{
+ return numLights();
+}
+
+const MVector& glslGenericProgram::GetLightDir(int idx) const
+{
+ return lightDir(idx);
+}
+
+
+const MVector& glslGenericProgram::GetLightPos(int idx) const
+{
+ return lightPos(idx);
+}
+/*
+| protected methods
+*/
+
+bool glslGenericProgram::loadShader( GLuint shader, char* fn)
+{
+ FILE *fp;
+ GLubyte *buf;
+ GLint length;
+ bool ret = true;
+
+ if (!(fp = fopen(fn,"rb")))
+ {
+ return false;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ length = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ buf = new GLubyte[length+1];
+
+ fread( buf, 1, length, fp);
+ buf[length] = '\0'; // make it a regular C string so str* functions work
+
+ glShaderSource( shader, 1, (const char**)&buf, &length);
+
+ if (glGetError() != 0)
+ {
+ ret = false;
+ }
+
+ fclose(fp);
+
+ delete []buf;
+
+ return ret;
+}
+
+
+bool glslGenericProgram::compileShader(GLuint shader, int vert_or_frag)
+{
+ char *infoLog;
+ GLint infoLogLength = 0;
+ GLint compileStatus;
+
+ glCompileShader(shader);
+
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH,&infoLogLength);
+
+ if(compileStatus == GL_TRUE)
+ return true;
+
+
+ if((vert_or_frag == eVertShader && !s_vertexErrDumped) ||
+ (vert_or_frag == eFragShader && !s_fragErrDumped))
+ {
+ MGlobal::displayInfo(MString("Shave GLSL: Compile status: ") + compileStatus + "\n\n");
+
+ if (infoLogLength)
+ {
+ infoLog = (char*)malloc(infoLogLength);
+
+ glGetShaderInfoLog(shader, infoLogLength, NULL, infoLog);
+
+ MGlobal::displayInfo(MString("Info Log:\n\n") + MString(infoLog));
+
+ free(infoLog);
+ }
+ if(vert_or_frag == eVertShader)
+ s_vertexErrDumped = true;
+
+ if(vert_or_frag == eFragShader)
+ s_fragErrDumped = true;
+ }
+
+ return compileStatus != 0;
+}
+
+
+
+bool glslGenericProgram::linkProgram(GLuint glprog)
+{
+ char* infoLog;
+ GLint infoLogLength = 0;
+ GLint linkStatus;
+
+ glLinkProgram(glprog);
+
+ glGetProgramiv(glprog, GL_LINK_STATUS, &linkStatus);
+ glGetProgramiv(glprog, GL_INFO_LOG_LENGTH, &infoLogLength);
+
+ if(linkStatus == GL_TRUE)
+ return true;
+
+ if(!s_linkErrDumped)
+ {
+ MGlobal::displayInfo(MString("Shave GLSL: Link status: ") + linkStatus + "\n\n");
+
+ if (infoLogLength)
+ {
+ infoLog = (char*) malloc(infoLogLength);
+
+ glGetProgramInfoLog(glprog, infoLogLength, NULL, infoLog);
+
+ MGlobal::displayInfo(MString("Info Log:\n\n") + MString(infoLog));
+
+ free(infoLog);
+ }
+ s_linkErrDumped = true;
+ }
+ return linkStatus != 0;
+}
+
+
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
+| glslHairProgram - default glsl shader program |
+/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+glslHairProgram::glslHairProgram()
+{
+ _tangentLoc() = -1;
+ _specTint() = MColor(1.0f, 1.0f, 1.0f);
+ _specTint2() = MColor(0.0f, 0.0f, 0.0f);
+ _ambdiff() = 0.4f;
+ _specular() = 0.76f;
+ _specAmt() = 1.0f;
+ _useSSAO() = false;
+}
+
+glslHairProgram::~glslHairProgram()
+{
+}
+
+bool glslHairProgram::setupUniformVariables()
+{
+ //if(numLights() > 0)
+ {
+ GLint location = glGetUniformLocation(program(), "lightDir");
+
+ if(location != -1)
+ {
+ _lightDir(0).normalize();
+ glUniform3f(location, (GLfloat)lightDir(0).x, (GLfloat)lightDir(0).y, (GLfloat)lightDir(0).z);
+ }
+ else
+ {
+ MGlobal::displayError("default - uniform variable 'lightDir' not found.");
+
+ char* infoLog;
+ GLint infoLogLength = 0;
+ glGetProgramiv(program(), GL_INFO_LOG_LENGTH, &infoLogLength);
+ if(infoLogLength)
+ {
+ infoLog = (char*) malloc(infoLogLength);
+
+ glGetProgramInfoLog(program(), infoLogLength, NULL, infoLog);
+
+ MGlobal::displayInfo(MString("Info Log:\n\n") + MString(infoLog));
+
+ free(infoLog);
+ }
+ return false;
+ }
+ }
+ {
+ GLint location = glGetUniformLocation(program(),"ambdiff");
+ if(location != -1)
+ glUniform1f(location, ambdiff());
+ else
+ {
+ MGlobal::displayError("uniform variable 'ambdiff' not found.");
+ return false;
+ }
+ }
+ {
+ GLint location = glGetUniformLocation(program(),"specular");
+ if(location != -1)
+ glUniform1f(location, specular()/**0.1f*/);
+ else
+ {
+ MGlobal::displayError("uniform variable 'specular' not found.");
+ return false;
+ }
+ }
+ {
+ GLint location = glGetUniformLocation(program(),"specAmt");
+ if(location != -1)
+ glUniform1f(location, specAmt());
+ else
+ {
+ MGlobal::displayError("uniform variable 'specAmt' not found.");
+ return false;
+ }
+ }
+ {
+ GLint location = glGetUniformLocation(program(),"specTint");
+ if(location != -1)
+ glUniform3f(location, specTint().r,specTint().g,specTint().b);
+ else
+ {
+ MGlobal::displayError("uniform variable 'specTint' not found.");
+ return false;
+ }
+ }
+ {
+ GLint location = glGetUniformLocation(program(),"specTint2");
+ if(location != -1)
+ glUniform3f(location, specTint2().r,specTint2().g,specTint2().b);
+ else
+ {
+ MGlobal::displayError("uniform variable 'specTint2' not found.");
+ return false;
+ }
+ }
+ {
+ GLint location = glGetUniformLocation(program(),"useSsao");
+ if(location != -1)
+ glUniform1i(location, useSSAO());
+ else
+ {
+ MGlobal::displayError("uniform variable 'useSsao' not found.");
+ return false;
+ }
+ }
+ {
+ GLint location = glGetUniformLocation(program(),"viewWidth");
+ if(location != -1)
+ glUniform1f(location, viewWidth());
+ else
+ {
+ MGlobal::displayError("uniform variable 'viewWidth' not found.");
+ return false;
+ }
+ }
+ {
+ GLint location = glGetUniformLocation(program(),"viewHeight");
+ if(location != -1)
+ glUniform1f(location, viewHeight());
+ else
+ {
+ MGlobal::displayError("uniform variable 'viewHeight' not found.");
+ return false;
+ }
+ }
+ {
+ GLint location = glGetUniformLocation(program(),"useLights");
+ if(location != -1)
+ glUniform1i(location, useLights() ? 1:0);
+ else
+ {
+ MGlobal::displayError("uniform variable 'useLights' not found.");
+ return false;
+ }
+ }
+ {
+ GLint location = glGetUniformLocation(program(),"numLights");
+ if(location != -1)
+ glUniform1i(location, numLights());
+ else
+ {
+ MGlobal::displayError("uniform variable 'numLights' not found.");
+ return false;
+ }
+ }
+ _tangentLoc() = glGetAttribLocation(program(), "tangent");
+ if(tangentLoc() == -1)
+ {
+ MGlobal::displayError("attribute variable 'tangent' not found\n");
+ return false;
+ }
+
+ return true;
+}
+
+void glslHairProgram::loadVertShader(GLuint shader) //loads internal vert shader
+{
+ char* buf =
+ "varying vec3 normal;\n\
+ varying vec4 vert;\n\
+ varying vec4 color;\n\
+ varying vec3 tang;\n\
+ varying vec3 view;\n\
+ attribute vec3 tangent;\n\
+ void main(){\n\
+ color = gl_Color;\n\
+ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n\
+ normal = normalize(gl_NormalMatrix * gl_Normal);\n\
+ vert = gl_ModelViewMatrix * vec4(gl_Vertex.xyz,1.0);\n\
+ tang = gl_NormalMatrix * normalize(tangent);\n\
+ view = -normalize(vert.xyz);\n\
+ }\n\
+ \0";
+
+ GLint length = (int)strlen(buf);
+ glShaderSource( shader, 1, (const char**)&buf, &length);
+
+
+}
+
+void glslHairProgram::loadFragShader(GLuint shader) //loads internal frag shader
+{
+ char* buf =
+ "uniform vec3 lightDir;\n\
+ uniform vec3 specTint;\n\
+ uniform vec3 specTint2;\n\
+ uniform float ambdiff;\n\
+ uniform float specular;\n\
+ uniform float specAmt;\n\
+ uniform int useSsao;\n\
+ uniform float viewWidth;\n\
+ uniform float viewHeight;\n\
+ uniform int useLights;\n\
+ uniform int numLights;\n\
+ uniform sampler2D ssaoTex;\n\
+ varying vec3 normal;\n\
+ varying vec4 vert;\n\
+ varying vec4 color;\n\
+ varying vec3 tang;\n\
+ varying vec3 view;\n\
+ float blur8x8flat(vec2 st, float d, sampler2D sampler){\n\
+ float x = 0.0;\n\
+ float y = 0.0;\n\
+ float du = 0.0;\n\
+ float dv = 0.0;\n\
+ float s = 0.0;\n\
+ for(y = -4.0; y < 4.0; y++)\n\
+ {\n\
+ du = y*d;\n\
+ for(x = -4.0; x < 4.0; x++)\n\
+ {\n\
+ dv = x*d;\n\
+ float r = texture2D(sampler, vec2(st.x + du, st.y + dv) ).r;\n\
+ s += r;\n\
+ }\n\
+ }\n\
+ s = s/64.0;\n\
+ return s;\n\
+ }\n\
+ void main(){\n\
+ vec3 D = vec3(0.0,0.0,0.0);\n\
+ vec3 S = vec3(0.0,0.0,0.0);\n\
+ vec3 S2 = vec3(0.0,0.0,0.0);\n\
+ //vec3 N = normalize(normal);\n\
+ //float D = max(0.0, dot(N,-lightDir));\n\
+ if(useLights==1){\n\
+ for(int i=0;i<numLights;i++){\n\
+ vec3 ldir0 = gl_LightSource[i].position.xyz - vert.xyz;\n\
+ float dist = length(ldir0);\n\
+ vec3 ldir = ldir0/dist;\n\
+ //direction light\n\
+ if(gl_LightSource[i].position.w == 0.0){\n\
+ ldir = gl_LightSource[i].position.xyz;//halfVector.xyz;\n\
+ }\n\
+ //diffuse \n\
+ float diff = 0.3;\n\
+ float ltdot = dot(ldir, tang);\n\
+ float tsq = ltdot*ltdot;\n\
+ float shd2 = sqrt(1.0 - tsq);\n\
+ float shd = max(shd2, 0.0);\n\
+ shd *= ambdiff;\n\
+ shd += (1.0 - ambdiff);\n\
+ D += shd*gl_LightSource[i].diffuse.rgb;\n\
+ //specular \n\
+ float K = 1.0/(3.0*(0.101 - specular));\n\
+ //float kspec = 0.076;\n\
+ float vtdot = dot(view, tang);\n\
+ float sqr_vdot2 = sqrt(1.0 - vtdot*vtdot);\n\
+ float sp = max(shd2*sqr_vdot2 - ltdot*vtdot, 0.0);\n\
+ float spec = max(pow(sp, K), 0.0);\n\
+ S += spec*gl_LightSource[i].specular.rgb;\n\
+ //secondary specular\n\
+ vec3 ldir2 = normalize(ldir*0.7+view*0.3);\n\
+ float ltdot2 = dot(ldir2, tang);\n\
+ float sp2 = max(shd2*sqr_vdot2 - ltdot2*vtdot, 0.0);\n\
+ float spec2 = max(pow(sp2, K), 0.0);\n\
+ S2 += spec2*gl_LightSource[i].specular.rgb;\n\
+ //spotlight\n\
+ if(gl_LightSource[i].spotCutoff != 180.0){\n\
+ float spotEffect = dot(normalize(gl_LightSource[i].spotDirection), -ldir);\n\
+ if (spotEffect > gl_LightSource[i].spotCosCutoff){\n\
+ float spot = pow(spotEffect, gl_LightSource[i].spotExponent);\n\
+ D *= spot;\n\
+ S *= spot;\n\
+ S2 *= spot;\n\
+ }else{\n\
+ D = vec3(0.0,0.0,0.0); S = vec3(0.0,0.0,0.0); S2 = vec3(0.0,0.0,0.0);\n\
+ }\n\
+ }\n\
+ //attenuation\n\
+ if(gl_LightSource[i].position.w != 0.0 ){\n\
+ float decay = 1.0 / (gl_LightSource[i].constantAttenuation + \n\
+ gl_LightSource[i].linearAttenuation * dist + \n\
+ gl_LightSource[i].quadraticAttenuation * dist * dist);\n\
+ D *= decay;\n\
+ S *= decay;\n\
+ S2 *= decay;\n\
+ }\n\
+ }\n\
+ }else{\n\
+ vec3 ldir = -lightDir;\n\
+ //diffuse \n\
+ float diff = 0.3;\n\
+ float ltdot = dot(ldir, tang);\n\
+ float tsq = ltdot*ltdot;\n\
+ float shd2 = sqrt(1.0 - tsq);\n\
+ float shd = max(shd2, 0.0);\n\
+ shd *= ambdiff;\n\
+ shd += (1.0 - ambdiff);\n\
+ //D += shd*gl_LightSource[i].diffuse.rgb;\n\
+ D += shd;\n\
+ //specular \n\
+ float K = 1.0/(3.0*(0.101 - specular));\n\
+ //float kspec = 0.076;\n\
+ float vtdot = dot(view, tang);\n\
+ float sqr_vdot2 = sqrt(1.0 - vtdot*vtdot);\n\
+ float sp = max(shd2*sqr_vdot2 - ltdot*vtdot, 0.0);\n\
+ float spec = max(pow(sp, K), 0.0);\n\
+ //S += spec*gl_LightSource[i].specular.rgb;\n\
+ S += spec*vec3(1.0,1.0,1.0);\n\
+ //secondary specular\n\
+ vec3 ldir2 = normalize(ldir*0.7+view*0.3);\n\
+ float ltdot2 = dot(ldir2, tang);\n\
+ float sp2 = max(shd2*sqr_vdot2 - ltdot2*vtdot, 0.0);\n\
+ float spec2 = max(pow(sp2, K), 0.0);\n\
+ //S2 += spec2*gl_LightSource[i].specular.rgb;\n\
+ S2 += spec2*vec3(1.0,1.0,1.0);\n\
+ }\n\
+ if(D.r > 1.0) D.r = 1.0;\n\
+ if(D.g > 1.0) D.g = 1.0;\n\
+ if(D.b > 1.0) D.b = 1.0;\n\
+ if(S.r > 1.0) S.r = 1.0;\n\
+ if(S.g > 1.0) S.g = 1.0;\n\
+ if(S.b > 1.0) S.b = 1.0;\n\
+ if(S2.r > 1.0) S2.r = 1.0;\n\
+ if(S2.g > 1.0) S2.g = 1.0;\n\
+ if(S2.b > 1.0) S2.b = 1.0;\n\
+ //SSAO\n\
+ float ssao = 1.0;\n\
+ if(useSsao != 0){\n\
+ vec2 uv = gl_FragCoord.xy;\n\
+ uv.x /= viewWidth; \n\
+ uv.y /= viewHeight; \n\
+ ssao = 0.25 + 0.75*blur8x8flat(uv,0.001, ssaoTex);\n\
+ ssao *= 1.15;\n\
+ if (ssao>1.0) ssao=1.0;\n\
+ }\n\
+ gl_FragColor.xyz = (D*ssao)*color.xyz + specAmt*(S*specTint + S2*specTint2);\n\
+ gl_FragColor.a = color.a;\n\
+ }";
+
+ GLint length = (int)strlen(buf);
+ glShaderSource( shader, 1, (const char**)&buf, &length);
+
+}
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
+| glslSSAOdepthShader - for ssao pass 1) |
+/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+bool glslSSAOdepthShader::setupUniformVariables()
+{
+ bool ok = true;
+ GLint location;
+
+
+ location = glGetUniformLocation(program(), "far");
+ if(location != -1)
+ glUniform1f(location, zfar());
+ else
+ {
+ ok &= false;
+ if(!s_varErrDumped)
+ MGlobal::displayError("uniform variable 'far' not found.");
+ }
+ location = glGetUniformLocation(program(), "near");
+ if(location != -1)
+ glUniform1f(location, znear());
+ else
+ {
+ ok &= false;
+ if(!s_varErrDumped)
+ MGlobal::displayError("uniform variable 'near' not found.");
+ }
+
+ return ok;
+}
+
+void glslSSAOdepthShader::loadVertShader(GLuint shader) //loads internal vert shader
+{
+ char* buf = "\n\
+ uniform float far; \n\
+ uniform float near; \n\
+ varying float depth; // in eye space\n\
+ void main( void ){\n\
+ vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;\n\
+ depth = (-viewPos.z - near)/(far - near); \n\
+ gl_Position = ftransform();\n\
+ }\n\0";
+
+ GLint length = (int)strlen(buf);
+ glShaderSource( shader, 1, (const char**)&buf, &length);
+}
+
+void glslSSAOdepthShader::loadFragShader(GLuint shader) //loads internal frag shader
+{
+ char* buf = "\n\
+ varying float depth;\n\
+ void main( void )\n\
+ {\n\
+ float R = depth*255.0;\n\
+ int Ri = int(R); \n\
+ R = float(Ri);\n\
+ float G = depth*255.0 - R;\n\
+ R /= 255.0;\n\
+ gl_FragColor = vec4(R,G,0.0,depth);\n\
+ }\n\0";
+
+ GLint length = (int)strlen(buf);
+ glShaderSource( shader, 1, (const char**)&buf, &length);
+}
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
+| glslSSAOshader - (pass 2) shader used to render map used for SSAO |
+/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+glslSSAOshader::glslSSAOshader()
+{
+ _radius() = 0.03f;
+ _samples() = 20;
+}
+
+bool glslSSAOshader::setupUniformVariables()
+{
+ bool ok = true;
+ GLint location;
+
+ location = glGetUniformLocation(program(), "rad");
+ if(location != -1)
+ glUniform1f(location, radius());
+ else
+ {
+ ok &= false;
+ if(!s_varErrDumped)
+ MGlobal::displayError("uniform variable 'rad' not found.");
+ }
+
+ location = glGetUniformLocation(program(), "samples");
+ if(location != -1)
+ glUniform1i(location, samples());
+ else
+ {
+ ok &= false;
+ if(!s_varErrDumped)
+ MGlobal::displayError("uniform variable 'samples' not found.");
+ }
+
+ //location = glGetUniformLocation(program(), "rnm");
+ //if(location != -1)
+ // glUniform1i(location, 0);
+ //else
+ //{
+ // ok &= false;
+ // if(!s_varErrDumped)
+ // MGlobal::displayError("uniform variable 'rnm' not found.");
+ //}
+
+ location = glGetUniformLocation(program(), "normalMap");
+ if(location != -1)
+ glUniform1i(location, 1);
+ else
+ {
+ ok &= false;
+ if(!s_varErrDumped)
+ MGlobal::displayError("uniform variable 'normalMap' not found.");
+ }
+ return ok;
+}
+
+void glslSSAOshader::loadVertShader(GLuint shader) //loads internal vert shader
+{
+ char* buf = "\n\
+ varying vec2 uv; \n\
+ void main(void) \n\
+ { \n\
+ gl_Position = ftransform(); \n\
+ gl_Position = sign( gl_Position ); \n\
+ // Texture coordinate for screen aligned (in correct range): \n\
+ //uv = (vec2( gl_Position.x, - gl_Position.y ) + vec2( 1.0 ) ) * 0.5; \n\
+ uv = (vec2( gl_Position.x, gl_Position.y ) + vec2( 1.0 ) ) * 0.5; \n\
+ }\n\0";
+
+ GLint length = (int)strlen(buf);
+ glShaderSource( shader, 1, (const char**)&buf, &length);
+}
+
+void glslSSAOshader::loadFragShader(GLuint shader) //loads internal frag shader
+{
+ char* buf = "\n\
+ uniform float rad; ///0.006; \n\
+ uniform sampler2D rnm; \n\
+ uniform sampler2D normalMap; \n\
+ uniform int samples;\n\
+ \n\
+ varying vec2 uv; \n\
+ void main(void) \n\
+ { \n\
+ int x = 0;\n\
+ int y = 0;\n\
+ int half_size = samples/2;\n\
+ float du = 0.0;\n\
+ float dv = 0.0;\n\
+ int nsamp = 0;\n\
+ int close = 0;\n\
+ vec4 vd = texture2D(normalMap, uv ); //line 17\n\
+ if(vd.a == 0.0)\n\
+ {\n\
+ gl_FragColor.r = 0.1;\n\
+ return; \n\
+ }\n\
+ float D = vd.r + vd.g/255.0; \n\
+ D -= 0.01; // out of loop \n\
+ for(y = -half_size; y < half_size; y++)\n\
+ {\n\
+ du = float(y)*rad;\n\
+ for(x = -half_size; x < half_size; x++)\n\
+ {\n\
+ dv = float(x)*rad;\n\
+ vec4 zv = texture2D(normalMap, vec2(uv.x + du, uv.y + dv) ); \n\
+ if(zv.a != 0.0)\n\
+ {\n\
+ float z = zv.r + zv.g/255.0;\n\
+ nsamp++;\n\
+ if(D < z) \n\
+ close++;\n\
+ }\n\
+ }\n\
+ }\n\
+ float ssao = 1.0;\n\
+ if(nsamp != 0) ssao = float(close)/float(nsamp);\n\
+ //dither \n\
+ gl_FragColor.r = ssao; \n\
+ \n\
+ }\n\0";
+
+ GLint length = (int)strlen(buf);
+ glShaderSource( shader, 1, (const char**)&buf, &length);
+}
+
+
+
+/////////////////////////// SSAO /////////////////////////////////////////////
+
+//utilities
+
+std::string convertInternalFormatToString(GLenum format)
+{
+ std::string formatName;
+
+ switch(format)
+ {
+ case GL_STENCIL_INDEX:
+ formatName = "GL_STENCIL_INDEX";
+ break;
+ case GL_DEPTH_COMPONENT:
+ formatName = "GL_DEPTH_COMPONENT";
+ break;
+ case GL_ALPHA:
+ formatName = "GL_ALPHA";
+ break;
+ case GL_RGB:
+ formatName = "GL_RGB";
+ break;
+ case GL_RGBA:
+ formatName = "GL_RGBA";
+ break;
+ case GL_LUMINANCE:
+ formatName = "GL_LUMINANCE";
+ break;
+ case GL_LUMINANCE_ALPHA:
+ formatName = "GL_LUMINANCE_ALPHA";
+ break;
+ case GL_ALPHA4:
+ formatName = "GL_ALPHA4";
+ break;
+ case GL_ALPHA8:
+ formatName = "GL_ALPHA8";
+ break;
+ case GL_ALPHA12:
+ formatName = "GL_ALPHA12";
+ break;
+ case GL_ALPHA16:
+ formatName = "GL_ALPHA16";
+ break;
+ case GL_LUMINANCE4:
+ formatName = "GL_LUMINANCE4";
+ break;
+ case GL_LUMINANCE8:
+ formatName = "GL_LUMINANCE8";
+ break;
+ case GL_LUMINANCE12:
+ formatName = "GL_LUMINANCE12";
+ break;
+ case GL_LUMINANCE16:
+ formatName = "GL_LUMINANCE16";
+ break;
+ case GL_LUMINANCE4_ALPHA4:
+ formatName = "GL_LUMINANCE4_ALPHA4";
+ break;
+ case GL_LUMINANCE6_ALPHA2:
+ formatName = "GL_LUMINANCE6_ALPHA2";
+ break;
+ case GL_LUMINANCE8_ALPHA8:
+ formatName = "GL_LUMINANCE8_ALPHA8";
+ break;
+ case GL_LUMINANCE12_ALPHA4:
+ formatName = "GL_LUMINANCE12_ALPHA4";
+ break;
+ case GL_LUMINANCE12_ALPHA12:
+ formatName = "GL_LUMINANCE12_ALPHA12";
+ break;
+ case GL_LUMINANCE16_ALPHA16:
+ formatName = "GL_LUMINANCE16_ALPHA16";
+ break;
+ case GL_INTENSITY:
+ formatName = "GL_INTENSITY";
+ break;
+ case GL_INTENSITY4:
+ formatName = "GL_INTENSITY4";
+ break;
+ case GL_INTENSITY8:
+ formatName = "GL_INTENSITY8";
+ break;
+ case GL_INTENSITY12:
+ formatName = "GL_INTENSITY12";
+ break;
+ case GL_INTENSITY16:
+ formatName = "GL_INTENSITY16";
+ break;
+ case GL_R3_G3_B2:
+ formatName = "GL_R3_G3_B2";
+ break;
+ case GL_RGB4:
+ formatName = "GL_RGB4";
+ break;
+ case GL_RGB5:
+ formatName = "GL_RGB4";
+ break;
+ case GL_RGB8:
+ formatName = "GL_RGB8";
+ break;
+ case GL_RGB10:
+ formatName = "GL_RGB10";
+ break;
+ case GL_RGB12:
+ formatName = "GL_RGB12";
+ break;
+ case GL_RGB16:
+ formatName = "GL_RGB16";
+ break;
+ case GL_RGBA2:
+ formatName = "GL_RGBA2";
+ break;
+ case GL_RGBA4:
+ formatName = "GL_RGBA4";
+ break;
+ case GL_RGB5_A1:
+ formatName = "GL_RGB5_A1";
+ break;
+ case GL_RGBA8:
+ formatName = "GL_RGBA8";
+ break;
+ case GL_RGB10_A2:
+ formatName = "GL_RGB10_A2";
+ break;
+ case GL_RGBA12:
+ formatName = "GL_RGBA12";
+ break;
+ case GL_RGBA16:
+ formatName = "GL_RGBA16";
+ break;
+ default:
+ formatName = "Unknown Format";
+ }
+
+ return formatName;
+}
+
+
+std::string getTextureParameters(GLuint id)
+{
+ if(glIsTexture(id) == GL_FALSE)
+ return "Not texture object";
+
+ GLint width, height, format;
+ std::string formatName;
+ glBindTexture(GL_TEXTURE_2D, id);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); // get texture width
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); // get texture height
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format); // get texture internal format
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ formatName = convertInternalFormatToString(format);
+
+ std::stringstream ss;
+ ss << width << "x" << height << ", " << formatName;
+ return ss.str();
+}
+
+std::string getRenderbufferParameters(GLuint id)
+{
+ if(glIsRenderbufferEXT(id) == GL_FALSE)
+ return "Not Renderbuffer object";
+
+ GLint width, height, format;
+ std::string formatName;
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id);
+ glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_WIDTH_EXT, &width); // get renderbuffer width
+ glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_HEIGHT_EXT, &height); // get renderbuffer height
+ glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_INTERNAL_FORMAT_EXT, &format); // get renderbuffer internal format
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+
+ formatName = convertInternalFormatToString(format);
+
+ std::stringstream ss;
+ ss << width << "x" << height << ", " << formatName;
+ return ss.str();
+}
+
+void glhDumpFBOinfo()
+{
+ std::cout << "\n***** FBO STATUS *****\n";
+
+ // print max # of colorbuffers supported by FBO
+ GLint colorBufferCount = 0;
+ glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &colorBufferCount);
+ std::cout << "Max Number of Color Buffer Attachment Points: " << colorBufferCount << std::endl;
+
+ GLint objectType;
+ GLint objectId;
+
+ // print info of the colorbuffer attachable image
+ for(int i = 0; i < colorBufferCount; ++i)
+ {
+ glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT+i,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT,
+ &objectType);
+ if(objectType != GL_NONE)
+ {
+ glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT+i,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT,
+ &objectId);
+
+ std::string formatName;
+
+ std::cout << "Color Attachment " << i << ": ";
+ if(objectType == GL_TEXTURE)
+ std::cout << "GL_TEXTURE, " << getTextureParameters(objectId) << std::endl;
+ else if(objectType == GL_RENDERBUFFER_EXT)
+ std::cout << "GL_RENDERBUFFER_EXT, " << getRenderbufferParameters(objectId) << std::endl;
+ }
+ }
+
+ // print info of the depthbuffer attachable image
+ glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER_EXT,
+ GL_DEPTH_ATTACHMENT_EXT,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT,
+ &objectType);
+ if(objectType != GL_NONE)
+ {
+ glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER_EXT,
+ GL_DEPTH_ATTACHMENT_EXT,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT,
+ &objectId);
+
+ std::cout << "Depth Attachment: ";
+ switch(objectType)
+ {
+ case GL_TEXTURE:
+ std::cout << "GL_TEXTURE, " << getTextureParameters(objectId) << std::endl;
+ break;
+ case GL_RENDERBUFFER_EXT:
+ std::cout << "GL_RENDERBUFFER_EXT, " << getRenderbufferParameters(objectId) << std::endl;
+ break;
+ }
+ }
+
+ // print info of the stencilbuffer attachable image
+ glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER_EXT,
+ GL_STENCIL_ATTACHMENT_EXT,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT,
+ &objectType);
+ if(objectType != GL_NONE)
+ {
+ glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER_EXT,
+ GL_STENCIL_ATTACHMENT_EXT,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT,
+ &objectId);
+
+ std::cout << "Stencil Attachment: ";
+ switch(objectType)
+ {
+ case GL_TEXTURE:
+ std::cout << "GL_TEXTURE, " << getTextureParameters(objectId) << std::endl;
+ break;
+ case GL_RENDERBUFFER_EXT:
+ std::cout << "GL_RENDERBUFFER_EXT, " << getRenderbufferParameters(objectId) << std::endl;
+ break;
+ }
+ }
+
+ std::cout << std::endl;
+}
+
+bool glhCheckFBOstatus()
+{
+ // check FBO status
+ GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ switch(status)
+ {
+ case GL_FRAMEBUFFER_COMPLETE_EXT:
+ std::cout << "Framebuffer complete." << std::endl;
+ return true;
+
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
+ std::cout << "[ERROR] Framebuffer incomplete: Attachment is NOT complete." << std::endl;
+ return false;
+
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
+ std::cout << "[ERROR] Framebuffer incomplete: No image is attached to FBO." << std::endl;
+ return false;
+
+ case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
+ std::cout << "[ERROR] Framebuffer incomplete: Attached images have different dimensions." << std::endl;
+ return false;
+
+ case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
+ std::cout << "[ERROR] Framebuffer incomplete: Color attached images have different internal formats." << std::endl;
+ return false;
+
+ case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
+ std::cout << "[ERROR] Framebuffer incomplete: Draw buffer." << std::endl;
+ return false;
+
+ case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
+ std::cout << "[ERROR] Framebuffer incomplete: Read buffer." << std::endl;
+ return false;
+
+ case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+ std::cout << "[ERROR] Unsupported by FBO implementation." << std::endl;
+ return false;
+
+ default:
+ std::cout << "[ERROR] Unknow FBO error." << std::endl;
+ return false;
+ }
+}
+
+
+
+//FBO
+ssaoFBO::ssaoFBO(unsigned int w, unsigned int h)
+{
+ _texid() = 0;
+ _fboid() = 0;
+ _rboid() = 0;
+ _width() = w;
+ _height() = h;
+
+ _origView() = new GLint[4];
+
+ _initOK() = false;
+
+ //Init();
+}
+
+ssaoFBO::~ssaoFBO()
+{
+ delete [] origView();
+}
+
+void ssaoFBO::Init()
+{
+ // create a texture object
+ glGenTextures(1, &_texid());
+ glBindTexture(GL_TEXTURE_2D, texid());
+#ifdef OSMac_
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NONE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NONE);
+#else
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+#endif
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width(), height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // create a framebuffer object, you need to delete them when program exits.
+ glGenFramebuffersEXT(1, &_fboid());
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboid());
+
+ // create a renderbuffer object to store depth info
+ // NOTE: A depth renderable image should be attached the FBO for depth test.
+ // If we don't attach a depth renderable image to the FBO, then
+ // the rendering output will be corrupted because of missing depth test.
+ // If you also need stencil test for your rendering, then you must
+ // attach additional image to the stencil attachement point, too.
+ glGenRenderbuffersEXT(1, &_rboid());
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rboid());
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width(), height());
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+
+ // attach a texture to FBO color attachement point
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texid(), 0);
+ // attach a renderbuffer to depth attachment point
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rboid());
+
+
+ // check FBO status
+ //glhDumpFBOinfo();
+ bool status = glhCheckFBOstatus();
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+ _initOK() = true;
+}
+
+
+void ssaoFBO::Destroy()
+{
+ if(texid())
+ {
+ glDeleteTextures(1, &_texid());
+ _texid() = 0;
+ }
+ // clean up FBO, RBO
+ if(fboid())
+ {
+ glDeleteFramebuffersEXT(1, &_fboid());
+ _fboid() = 0;
+ }
+ if(fboid())
+ {
+ glDeleteRenderbuffersEXT(1, &_rboid());
+ _rboid() = 0;
+ }
+}
+
+bool ssaoFBO::MakeCurrent()
+{
+ // grab original matrices
+ glGetFloatv(GL_PROJECTION_MATRIX, _cameraProjectionMatrix());
+ glGetFloatv(GL_MODELVIEW_MATRIX, _cameraViewMatrix());
+ glGetIntegerv(GL_VIEWPORT, _origView());
+
+ glViewport(0, 0, width(), height()); //is it correct size for normal/depth map
+
+ //Setup view
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(cameraProjectionMatrix());
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboid());
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(cameraViewMatrix());
+
+ //Set parmeters
+ glEnable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+
+ glPixelTransferf(GL_DEPTH_SCALE,1.0f);
+ glPixelTransferf(GL_DEPTH_BIAS, 0.0f);
+
+ glShadeModel(GL_SMOOTH);
+ glColorMask(1, 1, 1, 1);
+ glDepthMask( GL_TRUE );
+
+
+ glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
+
+ return true;
+}
+
+bool ssaoFBO::ResetCurrent()
+{
+ /////////////////
+ //glFlush();
+ ////////////////
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // unbind
+
+ //////////////////
+ //glBindRenderbufferEXT(GL_FRAMEBUFFER_EXT, 0); // unbind
+ ////////////////
+
+ glViewport(origView()[0],origView()[1],origView()[2],origView()[3]);
+ glShadeModel(GL_SMOOTH);
+ glColorMask(1, 1, 1, 1);
+
+ //restore original matrices
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(cameraProjectionMatrix());
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(cameraViewMatrix());
+
+ return true;
+}
+
+bool ssaoFBO::ActivateTexture(int samplerIdx)
+{
+ if(texid())
+ {
+ glActiveTexture(GL_TEXTURE0 + samplerIdx);
+ glBindTexture(GL_TEXTURE_2D, texid());
+#ifdef OSMac_
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NONE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NONE);
+#else
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+#endif
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity ();
+
+#if 0
+ ///////////////////// debug ssao depth /////////////////
+ MImage mimage;
+ MStatus stat = mimage.create(width(),height(),4,MImage::kByte);
+ unsigned char* pb = mimage.pixels();
+ unsigned char* p = (unsigned char*)malloc(width()*height()*4);
+ glGetTexImage(GL_TEXTURE_2D,0,GL_RGBA,GL_UNSIGNED_BYTE,p);
+ if(stat == MStatus::kSuccess)
+ {
+ int idx = 0;
+ for(unsigned int i = 0; i < width(); i++)
+ for(unsigned int j=0; j < height(); j++)
+ {
+ pb[idx] = (unsigned char)(p[idx]);
+ pb[idx+1] = (unsigned char)(p[idx+1]);
+ pb[idx+2] = (unsigned char)(p[idx+2]);
+ pb[idx+3] = (unsigned char)(p[idx+3]);
+
+ idx+=4;
+
+ }
+
+ }
+ free(p);
+ MString mdir;
+ MGlobal::executeCommand("internalVar -userBitmapsDir",mdir);
+ MString path = mdir + samplerIdx + MString(".jpg");
+ MGlobal::displayInfo(path);
+ mimage.writeToFile(path,"jpg");
+ ///////////////// end debug ////////////////////////
+#endif
+
+ return true;
+ }
+ return false;
+}
+
+
+
+////////////////////// LEGACY DISPLAY STUFF //////////////////////////////////
+
+bool shaveHairUI::mBrushIsActive = false;
+
+static bool glslInited = false;
+static glslHairProgram hairGlsl;
+static glslSSAOdepthShader ssaodepthGlsl;
+static glslSSAOshader ssaoGlsl;
+
+ssaoFBO ssaodepth;
+ssaoFBO ssao;
+
+
+bool shaveHairUI::InitGlsl()
+{
+ bool glIsOK = true;
+ if(!GLFunctionsInited())
+ glIsOK = InitGLFunctionPointers();
+
+ if(glIsOK && !glslInited)
+ {
+ if(hairGlsl.LoadShaders()
+ && ssaodepthGlsl.LoadShaders()
+ && ssaoGlsl.LoadShaders())
+ {
+ ssaodepth.Init();
+ ssao.Init();
+ glslInited = true;
+ }
+ }
+ return glslInited;
+}
+
+void shaveHairUI::getDrawRequests(
+ const MDrawInfo& drawInfo, bool noActiveComponents, MDrawRequestQueue& queue
+)
+{
+#ifdef DO_PROFILE
+ if(!Profile::GetDiagFile())
+ Profile::ProfileStart(NULL);
+ Profile::ProfileDump("shaveHairUI::getDrawRequests", NULL);
+#endif
+
+ // If the object is invisible or intermediate, don't draw anything.
+ //
+ M3dView::DisplayStatus dStatus = drawInfo.displayStatus();
+ M3dView::DisplayStyle dStyle = drawInfo.displayStyle();
+
+ if ((dStatus == M3dView::kInvisible)
+ || (dStatus == M3dView::kIntermediateObject))
+ {
+ return;
+ }
+
+ // Maya does not necessarily call us with a displayStatus of kInvisible
+ // when we're invisible. We need to do a more exhaustive check
+ // ourselves.
+ //
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+ MObject shaveHairNode = nodePtr->thisMObject();
+ MDagPath path;
+ MDagPath::getAPathTo(shaveHairNode, path);
+
+ if (!areObjectAndParentsVisible(path, false, true, true)) return;
+
+ // Similarly, Maya does not necessarily call us with a displayStatus of
+ // kTemplate when our template attribute is true, so we have to check
+ // that ourselves.
+ //
+ bool isTemplated;
+
+ MPlug plug(shaveHairNode, shaveHairShape::isTemplated);
+ plug.getValue(isTemplated);
+
+ if (isTemplated) dStatus = M3dView::kTemplate;
+
+ //
+ // If we're displaying a bounding box, then that's all we will be
+ // displaying.
+ //
+ MDrawRequest request;
+ M3dView view = drawInfo.view();
+
+ if (dStyle == M3dView::kBoundingBox)
+ {
+ request = drawInfo.getPrototype(*this);
+ request.setToken(kDrawBBox);
+ setWireframeColor(request, view, dStatus);
+ queue.add(request);
+ }
+ else
+ {
+ // Are we displaying hairs?
+ //
+ shaveHairShape* shave = dynamic_cast<shaveHairShape*>(surfaceShape());
+ if (shave->isHairDisplayEnabled())
+ {
+ short hairDisplayMode;
+
+ plug.setAttribute(shaveHairShape::dspyMode);
+ plug.getValue(hairDisplayMode);
+
+ if (hairDisplayMode == shaveHairShape::kHairDisplayHair)
+ {
+ request = drawInfo.getPrototype(*this);
+
+ ///////////// incremental update trick ///////////////
+ //numDisplayHairs = shave->
+ //////////////////////////////////////////////////////
+
+ switch (dStyle)
+ {
+ case M3dView::kWireFrame:
+ request.setToken(kDrawHairs);
+
+ // If the display status is kHilite then we are in
+ // component selection mode, in which case we want to
+ // display the hair as dormant and let the guides
+ // handle all of the burden of selection.
+ //
+ if (dStatus == M3dView::kHilite)
+ {
+ request.setColor(
+ DORMANT_SURFACE_COLOR, M3dView::kDormantColors
+ );
+ }
+ else if (dStatus == M3dView::kLead)
+ {
+ request.setColor(
+ LEAD_HAIR_COLOR, M3dView::kActiveColors
+ );
+ }
+ else if (dStatus == M3dView::kActive)
+ {
+ request.setColor(
+ ACTIVE_HAIR_COLOR, M3dView::kActiveColors
+ );
+ }
+ else
+ setWireframeColor(request, view, dStatus);
+
+ queue.add(request);
+ break;
+
+ case M3dView::kFlatShaded:
+ case M3dView::kGouraudShaded:
+ {
+ if(!doFallbackGlob)
+ request.setToken(kDrawActiveShadedHairs);
+ else
+ switch (dStatus)
+ {
+ case M3dView::kHilite:
+ case M3dView::kLead:
+ case M3dView::kActive:
+ request.setToken(kDrawActiveShadedHairs);
+ break;
+
+ default:
+ request.setToken(kDrawInactiveShadedHairs);
+ break;
+ }
+
+ queue.add(request);
+ }
+ break;
+
+ default:
+ // No hair display.
+ break;
+ }
+ }
+//#ifdef NEW_INSTNACE_DISPLAY
+ else if (hairDisplayMode == shaveHairShape::kHairDisplayGeom)
+ {
+ shaveGlobals::Globals globals;
+ shaveGlobals::getGlobals(globals);
+
+ if(glisntGlob)
+ {
+ request = drawInfo.getPrototype(*this);
+
+ switch (dStyle)
+ {
+ case M3dView::kWireFrame:
+ request.setToken(kDrawInstancedWire);
+
+ //
+ // If the display status is kHilite then we are in
+ // component selection mode, in which case we want to
+ // display the hair as dormant and let the guides
+ // handle all of the burden of selection.
+ //
+ if (dStatus == M3dView::kHilite)
+ {
+ request.setColor(
+ DORMANT_SURFACE_COLOR, M3dView::kDormantColors
+ );
+ }
+ else if (dStatus == M3dView::kLead)
+ {
+ request.setColor(
+ LEAD_HAIR_COLOR, M3dView::kActiveColors
+ );
+ }
+ else if (dStatus == M3dView::kActive)
+ {
+ request.setColor(
+ ACTIVE_HAIR_COLOR, M3dView::kActiveColors
+ );
+ }
+ else
+ setWireframeColor(request, view, dStatus);
+
+ queue.add(request);
+ break;
+
+ case M3dView::kFlatShaded:
+ case M3dView::kGouraudShaded:
+ {
+ switch (dStatus)
+ {
+ case M3dView::kHilite:
+ case M3dView::kLead:
+ case M3dView::kActive:
+ {
+
+ if (dStatus == M3dView::kLead)
+ {
+ request.setToken(kDrawInstancedShadedOffset);
+
+ MDrawRequest request2 = drawInfo.getPrototype(*this);
+ request2.setColor(LEAD_HAIR_COLOR, M3dView::kActiveColors);
+ request2.setToken(kDrawInstancedWire);
+ queue.add(request2);
+ }
+ else
+ request.setToken(kDrawInstancedShaded);
+
+ }
+ break;
+
+ default:
+ request.setToken(kDrawInstancedShaded);
+ break;
+ }
+
+ queue.add(request);
+ }
+ break;
+
+ default:
+ // No hair display.
+ break;
+ }
+ }
+ else //we want to update texures
+ {
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+ nodePtr->updateTexLookups();
+
+ }
+ }
+//#endif
+ }
+
+ bool componentSelectionMode = (!noActiveComponents
+ && (dStatus == M3dView::kHilite));
+
+ if (componentSelectionMode)
+ {
+ // We always display guides in component selection mode.
+ // Inactive guides are displayed in the standard hilite color
+ // while active ones are display in our own active guide color.
+ //
+ request = drawInfo.getPrototype(*this);
+ request.setToken(kDrawInactiveGuides);
+ request.setColor(
+ DORMANT_GUIDE_COMPONENT_COLOR, M3dView::kDormantColors
+ );
+ queue.add(request);
+
+ request = drawInfo.getPrototype(*this);
+ request.setToken(kDrawActiveGuides);
+ request.setColor(
+ ACTIVE_GUIDE_COMPONENT_COLOR, M3dView::kActiveColors
+ );
+
+ queue.add(request);
+
+ // Get the guide selection type.
+ //
+ MString selectType;
+
+ MGlobal::executeCommand(
+ "optionVar -q shaveBrushSelectMode", selectType
+ );
+
+ // Use the selection type to determine which guide vertices to
+ // display.
+ //
+ int activeDrawToken = kDrawNone;
+ int inactiveDrawToken = kDrawNone;
+
+ if (selectType == "root")
+ {
+ activeDrawToken = kDrawActiveRoots;
+ inactiveDrawToken = kDrawInactiveRoots;
+ }
+ else if (selectType == "tip")
+ {
+ activeDrawToken = kDrawActiveTips;
+ inactiveDrawToken = kDrawInactiveTips;
+ }
+ else if (selectType == "vert")
+ {
+ activeDrawToken = kDrawActiveVerts;
+ inactiveDrawToken = kDrawInactiveVerts;
+ }
+
+ if (activeDrawToken != kDrawNone)
+ {
+ request = drawInfo.getPrototype(*this);
+ request.setToken(inactiveDrawToken);
+
+ request.setColor(
+ DORMANT_VERTEX_COLOR, M3dView::kDormantColors
+ );
+
+ queue.add(request);
+
+ request = drawInfo.getPrototype(*this);
+ request.setToken(activeDrawToken);
+
+ request.setColor(
+ ACTIVE_VERTEX_COLOR, M3dView::kActiveColors
+ );
+
+ queue.add(request);
+ }
+ }
+ // In object mode we display guides if the user has explicitly
+ // requested that we do so, or if the object is selected and a
+ // brush is active.
+ //
+ else
+ {
+ //bool displayGuides;
+ //plug.setAttribute(shaveHairShape::aDisplayGuides);
+ //plug.getValue(displayGuides);
+
+ bool displayGuides = nodePtr->getDisplayGuides();
+
+ bool selected = (dStatus == M3dView::kActive)
+ || (dStatus == M3dView::kLead);
+
+ if (displayGuides || (mBrushIsActive && selected))
+ {
+ request = drawInfo.getPrototype(*this);
+ setWireframeColor(request, view, dStatus);
+ request.setToken(kDrawGuides);
+ queue.add(request);
+ }
+ }
+ }
+#ifdef DO_PROFILE
+ Profile::ProfileDump("shaveHairUI::getDrawRequests - done", NULL);
+#endif
+}
+
+/// dummy implementation now
+void SHAVEpre_draw() {}
+void SHAVEpost_draw() {}
+
+void shaveHairUI::draw(const MDrawRequest& request, M3dView& view) const
+{
+#ifdef DO_PROFILE
+ if(!Profile::GetDiagFile())
+ Profile::ProfileStart(NULL);
+ Profile::ProfileDump("shaveHairUI::draw", NULL);
+#endif
+
+ int drawToken = request.token();
+
+ //vlad|03Jun2010 -- update shave camera
+ SHAVEpre_draw();
+
+ static int MBAAQ[] = {1,3,8,15,23};
+
+ MDagPath camPath = shaveRender::getRenderCamPath();
+ shaveRender::SceneInfo si;
+ si.shaveRenderPixels = NULL;
+ si.shaveZBuffer = NULL;
+ si.aa = MBAAQ[renderQualityGlob];
+ si.currentFrame = (float)MAnimControl::currentTime().value();
+ si.haveTracedLights = false;
+ si.height = shaveMaya::imageHeight;
+ si.shaveTraceInitialized= false;
+ si.width = shaveMaya::imageWidth;
+
+ shaveRender::doCamera(camPath,shaveConstant::kShutterOpen,si);
+ shaveRender::doCamera(camPath,shaveConstant::kShutterClose,si);
+
+ view.beginGL();
+
+ //
+ // We do all of our drawing in worldSpace, so set the current
+ // transformation to worldSpace.
+ //
+ MMatrix worldInverse = request.multiPath().inclusiveMatrixInverse();
+
+ glPushMatrix();
+ glMultMatrixd((double *)worldInverse.matrix);
+
+ switch (drawToken)
+ {
+ case kDrawBBox:
+ drawBoundingBox();
+ break;
+
+ case kDrawGuides:
+ case kDrawActiveGuides:
+ case kDrawInactiveGuides:
+ drawGuides(drawToken, view);
+ break;
+
+ case kDrawHairs:
+ case kDrawActiveShadedHairs:
+ case kDrawInactiveShadedHairs:
+ drawHairs(drawToken, view);
+ break;
+#ifdef NEW_INSTNACE_DISPLAY
+ case kDrawInstancedWire:
+ case kDrawInstancedShaded:
+ case kDrawInstancedShadedOffset:
+ drawInstances(drawToken, view);
+ break;
+#endif
+ case kDrawActiveRoots:
+ case kDrawActiveTips:
+ case kDrawActiveVerts:
+ case kDrawInactiveRoots:
+ case kDrawInactiveTips:
+ case kDrawInactiveVerts:
+ drawVerts(drawToken);
+ break;
+
+ default:
+ break;
+ }
+
+ glPopMatrix();
+ view.endGL();
+
+ //vlad|03Jun2010 -- update shave camera
+ SHAVEpost_draw();
+#ifdef DO_PROFILE
+ Profile::ProfileDump("shaveHairUI::draw - done", NULL);
+#endif
+}
+
+
+bool shaveHairUI::select(
+ MSelectInfo &selectInfo,
+ MSelectionList &selectionList,
+ MPointArray &worldSpaceSelectPts
+) const
+{
+ // If the node is not visible, return immediately.
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+ MDagPath path;
+ MDagPath::getAPathTo(nodePtr->thisMObject(), path);
+
+ if (!areObjectAndParentsVisible(path, false, true, true)) return false;
+
+ bool alreadyTriedGuides = false;
+ bool somethingSelected = false;
+ bool componentMode = (selectInfo.displayStatus() == M3dView::kHilite);
+
+ //
+ // Load the proper hair shape into the Shave engine.
+ //
+ nodePtr->makeCurrent();
+
+ //
+ // We do all of our drawing in worldSpace, so set the current
+ // transformation to worldSpace.
+ //
+ M3dView view = selectInfo.view();
+ MMatrix worldInverse = selectInfo.multiPath().inclusiveMatrixInverse();
+
+ view.beginGL();
+ glPushMatrix();
+ glMultMatrixd((double *)worldInverse.matrix);
+ view.endGL();
+
+ // If we're in component mode then try to get a hit on individual
+ // vertices or guides.
+ //
+ if (componentMode)
+ {
+ MString selectMode;
+
+ MGlobal::executeCommand(
+ "optionVar -q shaveBrushSelectMode", selectMode
+ );
+
+ if (selectMode == "guide")
+ {
+ somethingSelected = selectGuides(
+ selectInfo,
+ selectionList,
+ worldSpaceSelectPts
+ );
+ alreadyTriedGuides = true;
+ }
+ else
+ {
+ somethingSelected = selectVerts(
+ selectMode,
+ selectInfo,
+ selectionList,
+ worldSpaceSelectPts
+ );
+ }
+ }
+
+ // If we didn't get any component hits then try for an overall hit on the
+ // object.
+ //
+ if (!somethingSelected)
+ {
+ // Get the hair and guide display settings.
+ //
+ //bool displayGuides;
+
+ short hairDisplayMode;
+ MPlug plug(surfaceShape()->thisMObject(), shaveHairShape::dspyMode);
+ plug.getValue(hairDisplayMode);
+
+ //plug.setAttribute(shaveHairShape::aDisplayGuides);
+ //plug.getValue(displayGuides);
+ bool displayGuides = nodePtr->getDisplayGuides();
+
+ // If guides are being displayed, and we didn't already check them
+ // during component testing, try for a hit on them first.
+ //
+ if (!alreadyTriedGuides && (componentMode || displayGuides))
+ {
+ somethingSelected = selectObjByGuides(
+ selectInfo,
+ selectionList,
+ worldSpaceSelectPts
+ );
+ }
+
+ // If we didn't get a hit on guides and hairs are being displayed,
+ // then try them.
+ //
+ if (!somethingSelected)
+ {
+ if(hairDisplayMode == shaveHairShape::kHairDisplayHair)
+ {
+ somethingSelected = selectObjByHairs(
+ selectInfo,
+ selectionList,
+ worldSpaceSelectPts
+ );
+ }
+ else if(hairDisplayMode == shaveHairShape::kHairDisplayGeom)
+ {
+ somethingSelected = selectObjByGeom(
+ selectInfo,
+ selectionList,
+ worldSpaceSelectPts
+ );
+ }
+ }
+ }
+
+ view.beginGL();
+ glPopMatrix();
+ view.endGL();
+
+ return somethingSelected;
+}
+
+
+void shaveHairUI::setBrushActive(bool isActive)
+{
+ mBrushIsActive = isActive;
+}
+
+
+//-------------------------------------------------------------
+//
+// Utility Methods
+//
+//-------------------------------------------------------------
+
+void shaveHairUI::drawBoundingBox()
+ const
+{
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+ MBoundingBox bbox = nodePtr->boundingBoxTemp();
+ MPoint bbmin = bbox.min();
+ MPoint bbmax = bbox.max();
+
+ glBegin(GL_LINES);
+ glVertex3d(bbmin.x, bbmin.y, bbmin.z);
+ glVertex3d(bbmax.x, bbmin.y, bbmin.z);
+
+ glVertex3d(bbmin.x, bbmin.y, bbmin.z);
+ glVertex3d(bbmin.x, bbmax.y, bbmin.z);
+
+ glVertex3d(bbmin.x, bbmin.y, bbmin.z);
+ glVertex3d(bbmin.x, bbmin.y, bbmax.z);
+
+ glVertex3d(bbmax.x, bbmax.y, bbmax.z);
+ glVertex3d(bbmin.x, bbmax.y, bbmax.z);
+
+ glVertex3d(bbmax.x, bbmax.y, bbmax.z);
+ glVertex3d(bbmax.x, bbmin.y, bbmax.z);
+
+ glVertex3d(bbmax.x, bbmax.y, bbmax.z);
+ glVertex3d(bbmax.x, bbmax.y, bbmin.z);
+
+ glVertex3d(bbmax.x, bbmin.y, bbmin.z);
+ glVertex3d(bbmax.x, bbmax.y, bbmin.z);
+
+ glVertex3d(bbmax.x, bbmin.y, bbmin.z);
+ glVertex3d(bbmax.x, bbmin.y, bbmax.z);
+
+ glVertex3d(bbmin.x, bbmax.y, bbmin.z);
+ glVertex3d(bbmax.x, bbmax.y, bbmin.z);
+
+ glVertex3d(bbmin.x, bbmax.y, bbmin.z);
+ glVertex3d(bbmin.x, bbmax.y, bbmax.z);
+
+ glVertex3d(bbmin.x, bbmin.y, bbmax.z);
+ glVertex3d(bbmax.x, bbmin.y, bbmax.z);
+
+ glVertex3d(bbmin.x, bbmin.y, bbmax.z);
+ glVertex3d(bbmin.x, bbmax.y, bbmax.z);
+ glEnd();
+}
+
+
+void shaveHairUI::drawGuides(int drawToken, M3dView& view) const
+{
+#ifdef DO_PROFILE
+ if(!Profile::GetDiagFile())
+ Profile::ProfileStart(NULL);
+ Profile::ProfileDump(" shaveHairUI::drawGuides", NULL);
+#endif
+
+ // Make sure that this shaveNode is loaded into the engine.
+ //
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+
+
+ const shaveHairShape::Guides& guides = nodePtr->getGuides().guides;
+
+
+ float w = nodePtr->getGuideThinkness();
+
+
+ // Draw the guides.
+ //
+ int i;
+ shaveHairShape::Guides::const_iterator iter;
+
+ if(w == 0)
+ {
+ for (iter = guides.begin(); iter != guides.end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+
+ if (!guide.hidden)
+ {
+ // Does this guide have any selected verts?
+ //
+ bool isActive = (guide.select != 0);
+
+ // Skip this guide if it does not meet our drawing
+ // requirements.
+ //
+ if (((drawToken == kDrawActiveGuides) && !isActive)
+ || ((drawToken == kDrawInactiveGuides) && isActive))
+ {
+ continue;
+ }
+
+ glBegin(GL_LINE_STRIP);
+
+ for (i = 0; i < SHAVE_VERTS_PER_GUIDE; i++)
+ glVertex3f(guide.verts[i].x, guide.verts[i].y, guide.verts[i].z);
+
+ glEnd();
+ }
+ }
+ }
+ else
+ {
+ float ext = nodePtr->getGuideExt();
+ if(ext == 0.0f)//compute once
+ {
+ //printf("compute bbox\n");
+ //MBoundingBox bbox = nodePtr->boundingBoxTemp();
+ MBoundingBox bbox;
+ bbox.clear();
+
+ for (iter = guides.begin(); iter != guides.end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+ if (!guide.hidden)
+ {
+ MPoint v = guide.verts[SHAVE_VERTS_PER_GUIDE-1];//tip only
+ bbox.expand(v);
+ }
+ }
+ ext = (bbox.max() - bbox.min()).length();
+ nodePtr->setGuideExt(ext);
+ }
+ w *= (4.0f*ext)/1500.0f;
+
+ MVector viewDir( 0.0, 0.0, 1.0);
+ MDagPath camPath;
+ MStatus stat = MStatus::kSuccess;
+ stat = view.getCamera(camPath);
+
+ if(stat == MStatus::kSuccess)
+ {
+ MFnCamera camFn(camPath);
+ viewDir = camFn.viewDirection( MSpace::kWorld );
+ viewDir.normalize();
+ }
+
+ //
+ // Draw the guides.
+ //
+ int v;
+ for (iter = guides.begin(); iter != guides.end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+
+ if (!guide.hidden)
+ {
+ //
+ // Does this guide have any selected verts?
+ //
+ bool isActive = (guide.select != 0);
+
+ //
+ // Skip this guide if it does not meet our drawing
+ // requirements.
+ //
+ if (((drawToken == kDrawActiveGuides) && !isActive)
+ || ((drawToken == kDrawInactiveGuides) && isActive))
+ {
+ continue;
+ }
+
+ glBegin(GL_QUADS);
+
+ MVector tangent0;
+ MVector tangent1;
+ MVector p0;
+ MVector p1;
+ MVector p2;
+ int numS = SHAVE_VERTS_PER_GUIDE-1;
+
+ for (v = 0; v < numS; v++)
+ {
+ int vv = v+1;
+ int vvv = v+2;
+ if(v == 0) //root polygon
+ {
+ p0.x = guide.verts[0].x;
+ p0.y = guide.verts[0].y;
+ p0.z = guide.verts[0].z;
+ p1.x = guide.verts[1].x;
+ p1.y = guide.verts[1].y;
+ p1.z = guide.verts[1].z;
+
+ tangent0 = p1 - p0;
+ tangent0.normalize();
+ tangent1 = tangent0;
+ }
+ else if(vv == numS) //tip poly
+ {
+ p0 = p1;
+ p1.x = guide.verts[vv].x;
+ p1.y = guide.verts[vv].y;
+ p1.z = guide.verts[vv].z;
+
+ tangent0 = tangent1;
+ tangent1 = p1 - p0;
+ tangent1.normalize();
+ }
+ else
+ {
+ p0 = p1;
+ p1.x = guide.verts[vv].x;
+ p1.y = guide.verts[vv].y;
+ p1.z = guide.verts[vv].z;
+
+ tangent0 = tangent1;
+ if(vvv < SHAVE_VERTS_PER_GUIDE)
+ {
+ p2.x = guide.verts[vvv].x;
+ p2.y = guide.verts[vvv].y;
+ p2.z = guide.verts[vvv].z;
+ tangent1 = p2 - p0;
+ }
+ else
+ {
+ tangent1 = p1 - p0;
+ }
+ tangent1.normalize();
+ }
+ if(p0 == p1)
+ continue;
+
+
+ MVector d0 = tangent0^viewDir;
+ MVector d1 = tangent1^viewDir;
+ d0.normalize();
+ d1.normalize();
+
+ MVector v0 = p0 + d0*(float)w;
+ MVector v1 = p0 - d0*(float)w;
+ MVector v2 = p1 - d1*(float)w;
+ MVector v3 = p1 + d1*(float)w;
+
+
+
+ glVertex3d(v0.x, v0.y, v0.z);
+ glVertex3d(v1.x, v1.y, v1.z);
+
+ glVertex3d(v2.x, v2.y, v2.z);
+ glVertex3d(v3.x, v3.y, v3.z);
+
+ }
+ glEnd();
+ }
+ }
+ }
+#ifdef DO_PROFILE
+ Profile::ProfileDump(" shaveHairUI::drawGuides -- done", NULL);
+#endif
+}
+
+class Group {
+public:
+ MIntArray pids;
+ MIntArray hids;
+};
+
+struct Poly {
+
+ MVector t[4];
+ MVector v[4];
+ MColor c[4];
+};
+
+class PolyGroup {
+public:
+ std::vector<Poly> p;
+};
+
+
+bool incrementaldraw = false;
+
+void shaveHairUI::drawHairs(int drawToken, M3dView& view) const
+{
+ //printf("draw hairs\n"); fflush(stdout);
+#ifdef DO_PROFILE
+ if(!Profile::GetDiagFile())
+ Profile::ProfileStart(NULL);
+ Profile::ProfileDump(" shaveHairUI::drawHairs", NULL);
+#endif
+
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+
+ // We won't be able to draw hair until the node has been properly
+ // initialized. We might arrive here before initialization if Maya
+ // triggers a refresh during file I/O.
+ //
+ if ((nodePtr == 0) || !nodePtr->nodeIsInitialized()) {
+ return;
+ }
+
+ shaveDirties& dirties = nodePtr->dirties;
+ if(dirties.DIRTY_HAIRCOUNT)
+ {
+ //do something there
+ }
+ shaveGlobals::getGlobals();
+
+
+#ifndef NEW_DISPLAY // old lines code
+
+
+ const std::vector<shaveHairShape::DisplayHair>&
+ displayHairs = nodePtr->getDisplayHairs();
+
+ //
+ // Determine the number of hairs to be drawn.
+ //
+ unsigned numHairsToDraw = nodePtr->getNumDisplayHairs(false);
+
+ if (numHairsToDraw > displayHairs.size())
+ numHairsToDraw = displayHairs.size();
+
+ //
+ // Draw the hairs.
+ //
+ unsigned h;
+ unsigned s;
+ unsigned v;
+
+ for (h = 0; h < numHairsToDraw; h++)
+ {
+ const shaveHairShape::DisplayHair& hair = displayHairs[h];
+
+ for (s = 0; s < hair.size(); s++)
+ {
+ const shaveHairShape::DisplayStrand& strand = hair[s];
+
+ glBegin(GL_LINE_STRIP);
+
+ for (v = 0; v < strand.verts.length(); v++)
+ {
+ if (drawToken == kDrawActiveShadedHairs)
+ {
+ view.setDrawColor(
+ MColor(
+ strand.colors[v].r,
+ strand.colors[v].g,
+ strand.colors[v].b
+ )
+ );
+ }
+ else if (drawToken == kDrawInactiveShadedHairs)
+ {
+ view.setDrawColor(
+ MColor(
+ strand.colors[v].r * 0.5f,
+ strand.colors[v].g * 0.5f,
+ strand.colors[v].b * 0.5f
+ )
+ );
+ }
+
+ glVertex3d(
+ strand.verts[v].x, strand.verts[v].y, strand.verts[v].z
+ );
+ }
+
+ glEnd();
+ }
+ }
+#else //new poly hair code
+
+ bool doxpar = nodePtr->getDoHairXparency();
+ float xpar = nodePtr->getHairXparency();
+ bool tipfade = nodePtr->getDoTipfade();
+ bool fallback = nodePtr->getDoFallback();
+ int passes = nodePtr->getNumPasses();
+ float invPasses = 1.0f/(float)passes;
+#ifdef DO_PROFILE
+ {
+ unsigned numToDisplay = nodePtr->getNumDisplayHairs(false);
+ char buf[300]={'\0'}; sprintf(buf,"Going to get cache %i %s", numToDisplay, IsMouseDown()?"mouse down":"mose up");
+ Profile::ProfileDump(/*"Going to get cache"*/ buf, NULL);
+ }
+#endif
+
+#if 1
+ //this does not work, event are not coming
+ //ClearEvents();
+ //qApp->flush(); //gah, event are present in queue
+ unsigned numToDisplay = nodePtr->getNumDisplayHairs(false);
+ if(numToDisplay==0)
+ return;
+
+ unsigned bunchSize = nodePtr->getNumDisplayHairs(true);
+ if(bunchSize == 0) bunchSize = numToDisplay;
+
+ const shaveHairShape::DisplayHairCache& cache = nodePtr->getDisplayHairs(view,true);
+ int done=0;
+ //lets try to return there
+ //return; //15fps even for 2 hairs. so its related to not empty display cache
+#if 1
+// printf("mousedown: %s, mousemove: %s\n", IsMouseDown()?"yes":"no", GetEventsHappen()?"yes":"no");fflush(stdout);
+ //qApp->flush();
+#ifdef GLOBAL_FALLBACK
+ ClearEvents();
+#endif
+ incrementaldraw = false;
+ while(/*cache.displayHair.capacity()*/ /*numToDisplay != cache.displayHair.size()*/ numToDisplay > cache.displayHair.size()
+#ifdef GLOBAL_FALLBACK
+ && (done==0) //
+#endif
+ )
+ {
+#ifdef GLOBAL_FALLBACK
+ if (QCoreApplication::hasPendingEvents())
+ {
+ SetEventsHappen();
+ incrementaldraw = true;
+ //if(!shaveStyleCmd::redrawOnIdlDone)
+ //{
+ // printf("redrawOnIdle fired+\n");fflush(stdout);
+ // MGlobal::executeCommandOnIdle("shaveStyle -redrawOnIdle");
+ //}
+ }
+
+ // if (qApp->hasPendingEvents()) SetEventsHappen() ;
+ // qApp->processEvents();
+ // qApp->flush();
+ ///////////////////////////////////////////
+ // incrementaldraw = true;
+ // qApp->processEvents(/*0x02*/ QEventLoop::ExcludeSocketNotifiers);
+ // incrementaldraw = false;
+ //////////////////////////////////////////
+
+ if((IsMouseDown() || GetEventsHappen()) && !liveModeGlob && fallback)
+ //if(GetEventsHappen())
+ //qApp->checkQueueSize(); there is no such member
+ //if(qApp->hasPendingEvents());
+ {
+ //printf("event\n"); fflush(stdout);
+ //no, lets draw
+ //if(doxpar && tipfade && (drawToken == kDrawActiveShadedHairs || drawToken == kDrawInactiveShadedHairs))
+ //{
+ // //nodePtr->clearDisplayHairs();
+ // //return;
+ //}
+ //else
+ {
+ nodePtr->invalidateDisplayHairs();
+// printf("interrupt 01\n");fflush(stdout);
+ break;
+ }
+ }
+ if (GetEventsHappen()) done=1;
+ if (!GetEventsHappen())
+#endif
+ nodePtr->getDisplayHairs(view,false);
+ //Sleep(1);
+ }
+#ifdef GLOBAL_FALLBACK
+ ClearEvents();
+#endif
+#endif
+#else
+ const shaveHairShape::DisplayHairCache& cache = nodePtr->getDisplayHairs(view);
+#endif
+ //no computing
+ //const shaveHairShape::DisplayHairCache& cache = nodePtr->getDisplayHairs();
+
+
+ //return; //just a test
+
+ //
+ // Determine the number of hairs to be drawn.
+ //
+ unsigned numHairsToDraw = nodePtr->getNumDisplayHairs(false);
+
+
+
+ if (numHairsToDraw > cache.displayHair.size())
+ numHairsToDraw = (unsigned int)cache.displayHair.size();
+
+ // Grab view direction
+
+ MMatrix worldToCam;
+ MVector viewDir( 0.0, 0.0, 1.0);
+ MDagPath camPath;
+ MStatus stat = MStatus::kSuccess;
+ stat = view.getCamera(camPath);
+ if(stat == MStatus::kSuccess)
+ {
+ MFnCamera camFn(camPath);
+ viewDir = camFn.viewDirection( MSpace::kWorld );
+ viewDir.normalize();
+
+ worldToCam = camPath.inclusiveMatrixInverse();
+
+ }
+
+ ///////////////////////////////////////////////
+ //
+ // Draw the hairs.
+ //
+#ifdef DO_PROFILE
+ Profile::ProfileDump("Going to draw hairs", NULL);
+#endif
+ if(doxpar && (tipfade || passes > 1) && (drawToken == kDrawActiveShadedHairs || drawToken == kDrawInactiveShadedHairs))
+ {
+ unsigned int h;
+ unsigned int s;
+ int v;
+
+ MPoint centerPt(cache.center);
+ MPoint nearPt = centerPt - viewDir*cache.radius;
+ MPoint farPt = centerPt + viewDir*cache.radius;
+
+ MPoint nearSc = nearPt*worldToCam;
+ MPoint farSc = farPt*worldToCam;
+
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+ glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
+
+ //glEnable(GL_COLOR_MATERIAL);
+
+ glEnable (GL_BLEND);
+ glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ //////////// GLSL ///////////////
+ bool doGlsl = false;
+ if(glslInited)
+ {
+ doGlsl = true;
+
+ glEnable ( GL_LIGHTING );
+
+ //count OpengGL lights
+ bool uselights = false;
+ int nlights = 0;
+ //MString lightmode = "";
+ //MGlobal::executeCommand("string $editor = `modelEditor`; modelEditor -q -displayLights $editor;",lightmode);
+ //MGlobal::executeCommand("modelEditor -q -displayLights modelEditor1;",lightmode);
+ //MGlobal::displayInfo(MString("mode ") + lightmode);
+
+ M3dView::LightingMode lightmode = M3dView::kLightDefault;
+ view.getLightingMode(lightmode);
+ if(lightmode == M3dView::kLightActive ||
+ lightmode == M3dView::kLightAll)
+ {
+ uselights = true;
+
+ GLint maxlights;
+ glGetIntegerv(GL_MAX_LIGHTS,&maxlights);
+ for(int k=0; k < maxlights; k++)
+ {
+ GLboolean on;
+ glGetBooleanv(GL_LIGHT0+k,&on);
+ if(on)
+ nlights++;
+ }
+ //MGlobal::displayInfo(MString("max lights ")+maxlights+" numlight " + nlights);
+ }
+ hairGlsl.SetUseLights(uselights,nlights);
+
+ hairGlsl.SetAmbDiff(nodePtr->getAmbDiff());
+ hairGlsl.SetSpecular( nodePtr->getGloss());
+ hairGlsl.SetSpecularAmt(nodePtr->getSpecular());
+ hairGlsl.SetSpecularTint(nodePtr->getSpecularTint());
+ hairGlsl.SetSpecularTint2(nodePtr->getSpecularTint2());
+ hairGlsl.SetUseSSAO(false);
+ hairGlsl.UseProgram();
+
+ if(hairGlsl.GetUseSSAO())
+ ssao.ActivateTexture(0);
+ }
+ else
+ glEnable(GL_COLOR_MATERIAL);
+ /////////////////////////////////
+
+ bool dobreak = false;
+ unsigned int ingroups = 0;
+ int numS = 1;
+ std::vector<PolyGroup> groups;
+ groups.resize(400);
+ for(int g = (int)groups.size()-1; g >= 0; g--)
+ groups[g].p.reserve(300);
+
+ for (h = 0; h < numHairsToDraw; h++)
+ {
+ const shaveHairShape::DisplayHair& hair = cache.displayHair[h];
+ for (s = 0; s < hair.size(); s++)
+ {
+ const shaveHairShape::DisplayStrand& strand = hair[s];
+
+ MVector tangent0;
+ MVector tangent1;
+ MVector p0;
+ MVector p1;
+ MVector p2;
+ float r0;
+ float r1;
+ numS = strand.verts.length()-1;
+ float inumS = 1.0f/(float)numS;
+
+ for (v = 0; v < numS; v++)
+ {
+ int vv = v+1;
+ int vvv = v+2;
+ float t1 = vv*inumS;
+ if(v == 0) //root polygon
+ {
+ p0.x = strand.verts[0].x;
+ p0.y = strand.verts[0].y;
+ p0.z = strand.verts[0].z;
+ p1.x = strand.verts[1].x;
+ p1.y = strand.verts[1].y;
+ p1.z = strand.verts[1].z;
+
+ tangent0 = p1 - p0;
+ tangent0.normalize();
+
+ tangent1 = tangent0;
+
+ r0 = strand.rootrad;
+ r1 = strand.rootrad*(1.0f - t1) + strand.tiprad*t1;
+
+ }
+ else if(vv == numS) //tip poly
+ {
+ p0 = p1;
+ p1.x = strand.verts[vv].x;
+ p1.y = strand.verts[vv].y;
+ p1.z = strand.verts[vv].z;
+
+ tangent0 = tangent1;
+ tangent1 = p1 - p0;
+ tangent1.normalize();
+
+
+ r0 = r1;
+ r1 = strand.tiprad;
+ }
+ else
+ {
+ p0 = p1;
+ p1.x = strand.verts[vv].x;
+ p1.y = strand.verts[vv].y;
+ p1.z = strand.verts[vv].z;
+
+ tangent0 = tangent1;
+ if(vvv < (int)strand.verts.length())
+ {
+ p2.x = strand.verts[vvv].x;
+ p2.y = strand.verts[vvv].y;
+ p2.z = strand.verts[vvv].z;
+ tangent1 = p2 - p0;
+ }
+ else
+ {
+ tangent1 = p1 - p0;
+ }
+ tangent1.normalize();
+
+ r0 = r1;
+ r1 = strand.rootrad*(1.0f - t1) + strand.tiprad*t1;
+
+ }
+ if(p0 == p1)
+ continue;
+
+
+ MVector d0 = tangent0^viewDir;
+ MVector d1 = tangent1^viewDir;
+ d0.normalize();
+ d1.normalize();
+
+ MVector v0 = p0 + d0*r0;
+ MVector v1 = p0 - d0*r0;
+ MVector v2 = p1 - d1*r1;
+ MVector v3 = p1 + d1*r1;
+
+ MColor col = strand.colors[v];
+ if (drawToken == kDrawInactiveShadedHairs)
+ {
+ col.r *= 0.75f;
+ col.g *= 0.75f;
+ col.b *= 0.75f;
+ }
+ //we do get 1.0 in WFTYPE.alpha[] at the moment, lets fake it with tipfade
+ //col.a = 1.0f - vv*inumS;
+ col.a = 1.0f;
+ if(tipfade)
+ col.a -= v*inumS;
+ if(passes)
+ col.a *= invPasses;
+
+
+ Poly P;
+
+ P.v[0] = v0;
+ P.c[0] = col;
+
+ P.v[1] = v1;
+ P.c[1] = col;
+ P.t[0] = P.t[1] = tangent0;
+
+ col = strand.colors[vv];
+ if (drawToken == kDrawInactiveShadedHairs)
+ {
+ col.r *= 0.75f;
+ col.g *= 0.75f;
+ col.b *= 0.75f;
+ }
+ //we do get 1.0 in WFTYPE.alpha[] at the moment, lets fake it with tipfade
+ col.a = 1.0f - vv*inumS;
+
+ col.a = 1.0f;
+ if(tipfade)
+ col.a -= vv*inumS;
+ if(passes)
+ col.a *= invPasses;
+
+ P.v[2] = v2;
+ P.c[2] = col;
+
+ P.v[3] = v3;
+ P.c[3] = col;
+ P.t[2] = P.t[3] = tangent1;
+
+ //for Joe: what I am doing wrong with z-sort?
+ MPoint V(0.5f*(p0.x+p1.x), 0.5f*(p0.y+p1.y), 0.5f*(p0.z+p1.z));//a middle of poly
+ MPoint S = V*worldToCam; //to camera space
+ float d = (S.z-nearSc.z)/(farSc.z-nearSc.z);
+ //if(d > 1.0f) d = 1.0f;
+ //if(d < 0.0f) d = 0.0f;
+ int pos = (int)(d*(float)groups.size());
+ if(pos >= groups.size()) pos = (int)groups.size()-1;
+ if(pos < 0) pos = 0;
+
+ groups[pos].p.push_back(P);
+ }
+ ingroups++;
+
+ //if(ingroups%bunchSize==0) //no, bazilion of issues
+ //{
+ // qApp->processEvents();
+ //}
+#ifdef GLOBAL_FALLBACK
+ if((IsMouseDown() || GetEventsHappen()) && !liveModeGlob && fallback)
+ {
+ //Sleep(1);
+ if(ingroups >= bunchSize)
+ {
+ dobreak = true;
+// printf("interrupt 02\n");fflush(stdout);
+ break;
+ }
+ }
+#endif
+ }
+ if(dobreak)
+ break;
+ }
+#ifdef DO_PROFILE
+ Profile::ProfileDump("xparency groups", NULL);
+#endif
+ dobreak = false;
+ unsigned drawn = 0;
+ glBegin(GL_QUADS);
+ for(int g = (int)groups.size()-1; g >= 0; g--)
+ {
+ const PolyGroup& gr = groups[g];
+ unsigned int gs = (unsigned int)gr.p.size();
+ for(unsigned int i = 0; i < gs; i++)
+ {
+ const Poly& p = gr.p[i];
+ if(doGlsl) glVertexAttrib3f(hairGlsl.GetTangentLoc(),p.t[0].x, p.t[0].y, p.t[0].z);
+ glColor4f(p.c[0].r,p.c[0].g, p.c[0].b, p.c[0].a*xpar);
+ glVertex3d(p.v[0].x, p.v[0].y, p.v[0].z);
+
+ if(doGlsl) glVertexAttrib3f(hairGlsl.GetTangentLoc(),p.t[1].x, p.t[1].y, p.t[1].z);
+ glColor4f(p.c[1].r,p.c[1].g, p.c[1].b, p.c[1].a*xpar);
+ glVertex3d(p.v[1].x, p.v[1].y, p.v[1].z);
+
+ if(doGlsl) glVertexAttrib3f(hairGlsl.GetTangentLoc(),p.t[2].x, p.t[2].y, p.t[2].z);
+ glColor4f(p.c[2].r,p.c[2].g, p.c[2].b, p.c[2].a*xpar);
+ glVertex3d(p.v[2].x, p.v[2].y, p.v[2].z);
+
+ if(doGlsl) glVertexAttrib3f(hairGlsl.GetTangentLoc(),p.t[3].x, p.t[3].y, p.t[3].z);
+ glColor4f(p.c[3].r,p.c[3].g, p.c[3].b, p.c[3].a*xpar);
+ glVertex3d(p.v[3].x, p.v[3].y, p.v[3].z);
+
+ drawn++;
+
+// if( (drawn>bunchSize)&&((drawn/numS)%bunchSize==0) ) //no, bazilion of issues
+ // {
+ // if (qApp->hasPendingEvents()) SetEventsHappen() ;
+// }
+
+ // if((IsMouseDown() || GetEventsHappen()) && !liveModeGlob && fallback)
+ // {
+ // if(drawn/numS >= bunchSize)
+ // {
+ // dobreak = true;
+ // printf("interrupt 03\n");fflush(stdout);
+ // break;
+ // }
+ // }
+ }
+ //if(dobreak)
+ //break;
+ }
+ glEnd();
+#ifdef DO_PROFILE
+ Profile::ProfileDump(" shaveHairUI::drawHairs xparent -- done", NULL);
+#endif
+ //////////// END GLSL ///////////////
+ if(doGlsl)
+ {
+ hairGlsl.UnUseProgram();
+ }
+ glBindTexture(GL_TEXTURE_2D, 0);
+ /////////////////////////////////
+
+ glPopClientAttrib();
+ glPopAttrib();
+
+ }
+ else
+ {
+ unsigned int h;
+ unsigned int s;
+ int v;
+
+ //////////// GLSL ///////////////
+ bool doGlsl = false;
+ if(glslInited && (drawToken == kDrawActiveShadedHairs || drawToken == kDrawInactiveShadedHairs))
+ {
+ doGlsl = true;
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+ glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
+
+ glEnable ( GL_LIGHTING );
+
+ hairGlsl.SetAmbDiff(nodePtr->getAmbDiff());
+ // hairGlsl.SetSpecular(nodePtr->getSpecular());
+ // hairGlsl.SetSpecularAmt(nodePtr->getGloss());
+ hairGlsl.SetSpecular( nodePtr->getGloss());
+ hairGlsl.SetSpecularAmt(nodePtr->getSpecular());
+ hairGlsl.SetSpecularTint(nodePtr->getSpecularTint());
+ hairGlsl.SetSpecularTint2(nodePtr->getSpecularTint2());
+ hairGlsl.SetUseSSAO(false);
+ hairGlsl.SetViewSize(view.portWidth(),view.portHeight());
+ hairGlsl.UseProgram();
+
+ if(hairGlsl.GetUseSSAO())
+ ssao.ActivateTexture(0);
+ }
+ /////////////////////////////////
+
+ for (h = 0; h < numHairsToDraw; h++)
+ {
+ const shaveHairShape::DisplayHair& hair = cache.displayHair[h];
+
+ for (s = 0; s < hair.size(); s++)
+ {
+ const shaveHairShape::DisplayStrand& strand = hair[s];
+
+ glBegin(GL_QUADS);
+
+ MVector tangent0;
+ MVector tangent1;
+ MVector p0;
+ MVector p1;
+ MVector p2;
+ float r0;
+ float r1;
+ int numS = strand.verts.length()-1;
+ float inumS = 1.0f/(float)numS;
+
+ for (v = 0; v < numS; v++)
+ {
+ int vv = v+1;
+ int vvv = v+2;
+ float t1 = vv*inumS;;
+ if(v == 0) //root polygon
+ {
+ p0.x = strand.verts[0].x;
+ p0.y = strand.verts[0].y;
+ p0.z = strand.verts[0].z;
+ p1.x = strand.verts[1].x;
+ p1.y = strand.verts[1].y;
+ p1.z = strand.verts[1].z;
+
+ tangent0 = p1 - p0;
+ tangent0.normalize();
+
+ tangent1 = tangent0;
+
+ r0 = strand.rootrad;
+ r1 = strand.rootrad*(1.0f - t1) + strand.tiprad*t1;
+
+ }
+ else if(vv == numS) //tip poly
+ {
+ p0 = p1;
+ //p0.x = strand.verts[v].x;
+ //p0.y = strand.verts[v].y;
+ //p0.z = strand.verts[v].z;
+ p1.x = strand.verts[vv].x;
+ p1.y = strand.verts[vv].y;
+ p1.z = strand.verts[vv].z;
+
+ tangent0 = tangent1;
+ tangent1 = p1 - p0;
+ tangent1.normalize();
+
+
+ r0 = r1;
+ r1 = strand.tiprad;
+ }
+ else
+ {
+ p0 = p1;
+ p1.x = strand.verts[vv].x;
+ p1.y = strand.verts[vv].y;
+ p1.z = strand.verts[vv].z;
+
+ tangent0 = tangent1;
+ if(vvv < (int)strand.verts.length())
+ {
+ p2.x = strand.verts[vvv].x;
+ p2.y = strand.verts[vvv].y;
+ p2.z = strand.verts[vvv].z;
+ tangent1 = p2 - p0;
+ }
+ else
+ {
+ tangent1 = p1 - p0;
+ }
+ tangent1.normalize();
+
+ r0 = r1;
+ r1 = strand.rootrad*(1.0f - t1) + strand.tiprad*t1;
+
+ }
+ if(p0 == p1)
+ continue;
+
+
+ MVector d0 = tangent0^viewDir;
+ MVector d1 = tangent1^viewDir;
+ d0.normalize();
+ d1.normalize();
+
+ MVector v0 = p0 + d0*r0;
+ MVector v1 = p0 - d0*r0;
+ MVector v2 = p1 - d1*r1;
+ MVector v3 = p1 + d1*r1;
+
+ if(doGlsl)
+ {
+ MColor c1(strand.colors[v].r,strand.colors[v].g,strand.colors[v].b);
+ MColor c2(strand.colors[vv].r,strand.colors[vv].g,strand.colors[vv].b);
+
+ if (drawToken == kDrawInactiveShadedHairs)
+ {
+ c1 *= 0.5;
+ c2 *= 0.5;
+ }
+ glVertexAttrib3f(hairGlsl.GetTangentLoc(),tangent0.x,tangent0.y,tangent0.z);
+ glColor4f(c1.r, c1.g, c1.b, 1.0f);
+ glVertex3d(v0.x, v0.y, v0.z);
+
+ glVertexAttrib3f(hairGlsl.GetTangentLoc(),tangent0.x,tangent0.y,tangent0.z);
+ glColor4f(c1.r, c1.g, c1.b, 1.0f);
+ glVertex3d(v1.x, v1.y, v1.z);
+
+ glVertexAttrib3f(hairGlsl.GetTangentLoc(),tangent1.x,tangent1.y,tangent1.z);
+ glColor4f(c2.r, c2.g, c2.b, 1.0f);
+ glVertex3d(v2.x, v2.y, v2.z);
+
+ glVertexAttrib3f(hairGlsl.GetTangentLoc(),tangent1.x,tangent1.y,tangent1.z);
+ glColor4f(c2.r, c2.g, c2.b, 1.0f);
+ glVertex3d(v3.x, v3.y, v3.z);
+ }
+ else
+ {
+ if (drawToken == kDrawActiveShadedHairs)
+ {
+ view.setDrawColor(
+ MColor(
+ strand.colors[v].r,
+ strand.colors[v].g,
+ strand.colors[v].b
+ )
+ );
+ }
+ else if (drawToken == kDrawInactiveShadedHairs)
+ {
+ view.setDrawColor(
+ MColor(
+ strand.colors[v].r * 0.5f,
+ strand.colors[v].g * 0.5f,
+ strand.colors[v].b * 0.5f
+ )
+ );
+ }
+
+ glVertex3d(v0.x, v0.y, v0.z);
+ glVertex3d(v1.x, v1.y, v1.z);
+
+ if (drawToken == kDrawActiveShadedHairs)
+ {
+ view.setDrawColor(
+ MColor(
+ strand.colors[vv].r,
+ strand.colors[vv].g,
+ strand.colors[vv].b
+ )
+ );
+ }
+ else if (drawToken == kDrawInactiveShadedHairs)
+ {
+ view.setDrawColor(
+ MColor(
+ strand.colors[vv].r * 0.5f,
+ strand.colors[vv].g * 0.5f,
+ strand.colors[vv].b * 0.5f
+ )
+ );
+ }
+
+ glVertex3d(v2.x, v2.y, v2.z);
+ glVertex3d(v3.x, v3.y, v3.z);
+ }
+
+
+ //glVertex3d(
+ // strand.verts[v].x, strand.verts[v].y, strand.verts[v].z
+ //);
+ }
+
+ glEnd();
+
+ }
+ }
+ //////////// END GLSL ///////////////
+ if(doGlsl)
+ {
+ hairGlsl.UnUseProgram();
+
+ glPopClientAttrib();
+ glPopAttrib();
+ }
+ glBindTexture(GL_TEXTURE_2D, 0);
+ /////////////////////////////////
+
+ //ClearEvents();
+
+#ifdef DO_PROFILE
+ Profile::ProfileDump(" shaveHairUI::drawHairs -- done", NULL);
+#endif
+ }
+#endif
+ // nodePtr->dirties.BRUSH_JUST_MOVED = 0; //// crraaaaap!
+}
+
+void shaveHairUI::drawSsaoDepth( int drawToken, M3dView& view, const shaveHairShape::DisplayHairCache& cache, const MVector& viewDir ) const
+{
+
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+ unsigned int numHairsToDraw = nodePtr->getNumDisplayHairs(false);
+
+ if (numHairsToDraw > cache.displayHair.size())
+ numHairsToDraw = (unsigned int)cache.displayHair.size();
+
+ Matrix4 m;
+ glGetFloatv(GL_MODELVIEW_MATRIX, m); //already set up by maya
+
+ float maxz = -1000000.f;
+ float minz = 1000000.f;
+ float m4x4[4][4];
+ memcpy(m4x4,m.entries,16*sizeof(float));
+ MMatrix mm(m4x4);
+
+ MBoundingBox b = nodePtr->boundingBoxTemp();
+ b.transformUsing(mm);
+
+ MPoint bmin = b.min();
+ MPoint bmax = b.max();
+ float z1 = (float)(-bmin.z);
+ float z2 = (float)(-bmax.z);
+ float znear = ( z1 < z2 ) ? z1 : z2;
+ float zfar = ( z1 > z2 ) ? z1 : z2;
+ ssaodepthGlsl.SetFarNear(zfar,znear);
+
+ ssaodepth.MakeCurrent();
+
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+ glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
+
+ glEnable( GL_LIGHTING );
+ glEnable( GL_DEPTH_TEST );
+ glDisable( GL_CULL_FACE );
+
+ ssaodepthGlsl.UseProgram();
+
+ for (unsigned int h = 0; h < numHairsToDraw; h++)
+ {
+ const shaveHairShape::DisplayHair& hair = cache.displayHair[h];
+
+ for (unsigned int s = 0; s < hair.size(); s++)
+ {
+ const shaveHairShape::DisplayStrand& strand = hair[s];
+
+ glBegin(GL_QUADS);
+
+ MVector tangent0;
+ MVector tangent1;
+ MVector p0;
+ MVector p1;
+ MVector p2;
+ float r0;
+ float r1;
+ int numS = strand.verts.length()-1;
+
+ for (int v = 0; v < numS; v++)
+ {
+ int vv = v+1;
+ int vvv = v+2;
+ float t1 = vv/(float)numS;
+ if(v == 0) //root polygon
+ {
+ p0.x = strand.verts[0].x;
+ p0.y = strand.verts[0].y;
+ p0.z = strand.verts[0].z;
+ p1.x = strand.verts[1].x;
+ p1.y = strand.verts[1].y;
+ p1.z = strand.verts[1].z;
+
+ tangent0 = p1 - p0;
+ tangent0.normalize();
+
+ tangent1 = tangent0;
+
+ r0 = strand.rootrad;
+ r1 = strand.rootrad*(1.0f - t1) + strand.tiprad*t1;
+
+ }
+ else if(vv == numS) //tip poly
+ {
+ p0 = p1;
+ p1.x = strand.verts[vv].x;
+ p1.y = strand.verts[vv].y;
+ p1.z = strand.verts[vv].z;
+
+ tangent0 = tangent1;
+ tangent1 = p1 - p0;
+ tangent1.normalize();
+
+
+ r0 = r1;
+ r1 = strand.tiprad;
+ }
+ else
+ {
+ p0 = p1;
+ p1.x = strand.verts[vv].x;
+ p1.y = strand.verts[vv].y;
+ p1.z = strand.verts[vv].z;
+
+ tangent0 = tangent1;
+ if(vvv < (int)strand.verts.length())
+ {
+ p2.x = strand.verts[vvv].x;
+ p2.y = strand.verts[vvv].y;
+ p2.z = strand.verts[vvv].z;
+ tangent1 = p2 - p0;
+ }
+ else
+ {
+ tangent1 = p1 - p0;
+ }
+ tangent1.normalize();
+
+ r0 = r1;
+ r1 = strand.rootrad*(1.0f - t1) + strand.tiprad*t1;
+
+ }
+ if(p0 == p1)
+ continue;
+
+
+ MVector d0 = tangent0^viewDir;
+ MVector d1 = tangent1^viewDir;
+ d0.normalize();
+ d1.normalize();
+
+ MVector v0 = p0 + d0*r0;
+ MVector v1 = p0 - d0*r0;
+ MVector v2 = p1 - d1*r1;
+ MVector v3 = p1 + d1*r1;
+
+ glVertex3d(v0.x, v0.y, v0.z);
+ glVertex3d(v1.x, v1.y, v1.z);
+ glVertex3d(v2.x, v2.y, v2.z);
+ glVertex3d(v3.x, v3.y, v3.z);
+
+ }
+ glEnd();
+ }
+ }
+
+ ssaodepthGlsl.UnUseProgram();
+
+
+ glPopClientAttrib();
+ glPopAttrib();
+
+ ssaodepth.ResetCurrent(); //FBO
+
+}
+
+void shaveHairUI::drawSsao( int drawToken, M3dView& view, const shaveHairShape::DisplayHairCache& cache, const MVector& viewDir ) const
+{
+
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+
+ ///// BFO /////
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+ glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
+
+ glEnable( GL_LIGHTING );
+ glEnable(GL_TEXTURE_2D);
+
+ drawSsaoDepth( drawToken, view, cache, viewDir);
+
+
+ ssao.MakeCurrent();
+
+
+// if(ssaoGlsl.GetProgram() == 0 || !ssaoGlsl.IsVadlid())
+// {
+// if(ssaoGlsl.GetProgram() != 0)
+// ssaoGlsl.UnLoadShaders();
+// ssaoGlsl.LoadShaders();
+// }
+
+ //float ssaorad = 0.007;
+ //int samples = 20;
+
+
+ ssaoGlsl.SetRadius(1.0f/(float)view.portWidth());
+ ssaoGlsl.SetSamples(25);
+
+
+
+ ssaoGlsl.UseProgram();
+ ssaodepth.ActivateTexture(1);
+
+
+ //draw full screen quad
+ glMatrixMode (GL_MODELVIEW);
+ glPushMatrix ();
+ glLoadIdentity ();
+ glMatrixMode (GL_PROJECTION);
+ glPushMatrix ();
+ glLoadIdentity ();
+
+ glBegin (GL_QUADS);
+ glVertex3i (-1, -1, -1);
+ glVertex3i (1, -1, -1);
+ glVertex3i (1, 1, -1);
+ glVertex3i (-1, 1, -1);
+ glEnd ();
+
+ glPopMatrix ();
+ glMatrixMode (GL_MODELVIEW);
+ glPopMatrix ();
+
+ ssaoGlsl.UnUseProgram();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ glPopClientAttrib();
+ glPopAttrib();
+
+ ssao.ResetCurrent(); //BFO
+}
+
+
+#ifdef NEW_INSTNACE_DISPLAY
+static GLfloat material_ambient[] = {0.1f, 0.1f, 0.1f, 1.0f};
+static GLfloat material_specular[]= {0.1f, 0.1f, 0.1f, 1.0f};
+static GLfloat material_shininess[]={.1f};
+static GLfloat material_diffuse[] = {0.82f, 0.82f, 0.82f, 1.0f};
+
+
+
+void shaveHairUI::drawInstances(int drawToken, M3dView& view) const
+{
+#if defined(WIN32) || defined(LINUX)
+#ifndef GL_ACTIVE_TEXTURE
+ if(!glActiveTexture)
+ {
+ glActiveTexture = (PFNGLATCIVETEXTUREPROC) getGlFncPtr("glActiveTexture");
+ if(!glActiveTexture)
+#ifdef WIN32
+ MGlobal::displayInfo(MString("glActiveTexture not found (error")+ GetLastError() + ")");
+#else
+ MGlobal::displayInfo(MString("glActiveTexture not found"));
+#endif
+ }
+#endif
+#endif
+ MStatus stat = MStatus::kSuccess;
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+
+ shaveDirties& dirties = nodePtr->dirties;
+ if(dirties.DIRTY_HAIRCOUNT)
+ {
+ //do something there
+ }
+
+ /*const*/ shaveInstanceDisplay& cache = nodePtr->getInstanceDisplay();
+
+ //printf("draw instance for node 0x%X nf %i\n",nodePtr,cache.faceCounts.length());fflush(stdout);
+
+
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+ glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
+
+ if(drawToken == kDrawInstancedShaded ||
+ drawToken == kDrawInstancedShadedOffset )
+ {
+ if(drawToken == kDrawInstancedShadedOffset)
+ glEnable( GL_POLYGON_OFFSET_FILL );
+
+ glEnable ( GL_LIGHTING );
+ glEnable(GL_SMOOTH);
+ glEnable( GL_DEPTH_TEST );
+ glEnable (GL_BLEND);
+ glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ if(cache.diffuse != 0 /*|| cache.xparenc != 0*/)
+ glEnable(GL_TEXTURE_2D);
+
+ glPolygonMode (GL_FRONT, GL_FILL);
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
+
+ glMaterialfv(GL_FRONT,GL_AMBIENT,material_ambient);
+ glMaterialfv(GL_FRONT,GL_SPECULAR,material_specular);
+ glMaterialfv(GL_FRONT,GL_SHININESS,material_shininess);
+
+
+ if(cache.diffuse != 0)
+ {
+ if(glActiveTexture)
+ glActiveTexture(GL_TEXTURE0);
+
+ glBindTexture(GL_TEXTURE_2D, cache.diffuse);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+
+
+ }
+ else
+ glMaterialfv(GL_FRONT,GL_DIFFUSE,material_diffuse);
+
+ int oo=0;
+ glBegin(GL_TRIANGLES);
+ if(cache.hasXparency)
+ {
+ MDagPath camPath;
+ MStatus stat = view.getCamera(camPath);
+ MMatrix worldToCam = camPath.inclusiveMatrixInverse();
+
+ MFnCamera camFn(camPath);
+ MVector viewDir = camFn.viewDirection( MSpace::kWorld );
+ MPoint centerPt(cache.center);
+ MPoint nearPt = centerPt - viewDir*cache.radius;
+ MPoint farPt = centerPt + viewDir*cache.radius;
+
+ MPoint p = nearPt*worldToCam;
+ MFloatPoint nearSc((float)p.x, (float)p.y, (float)p.z);
+
+ p = farPt*worldToCam;
+ MFloatPoint farSc((float)p.x, (float)p.y, (float)p.z);
+
+ std::vector<Group> groups;
+ groups.resize(100);
+
+ for(unsigned int i = 0; i < cache.faceCounts.length(); i++)
+ {
+
+ int fc = cache.faceCounts[i];
+ if(fc != 3)
+ continue; //trianglular faces expected
+
+ int fs = cache.faceStart[i];
+ int fv = cache.faceVerts[fs];
+ const MPoint& p = cache.points[fv];
+ MPoint s = p*worldToCam;
+ //float d = s.z-nearSc.z* (farSc.z-nearSc.z/(float)groups.size());
+ float d = (s.z-nearSc.z)/(farSc.z-nearSc.z);
+ groups[(int)(d*(float)groups.size())].pids.append(i);
+ }
+ for(int xx = (int)groups.size()-1; xx >= 0; xx--)
+ //for(int xx = 0; xx < groups.size(); xx++)
+ {
+ for(unsigned int zz = 0; zz < groups[xx].pids.length(); zz++)
+ {
+ int i = groups[xx].pids[zz];
+ int fc = cache.faceCounts[i];
+ if(fc != 3)
+ continue; //trianglular faces expected
+
+ int fs = cache.faceStart[i];
+ int fe = cache.faceEnd[i];
+ int jj = 0;
+ for(int j = fs; j < fe; j++)
+ {
+ int k = cache.faceVerts[j];
+ const MFloatPoint& p = cache.points[k];
+ const MFloatPoint& t = cache.uvs[/*oo*/i*3 + jj];
+ const MFloatPoint& n = cache.normals[k];
+ //something is weird with this, normals are inverted...
+ glNormal3f(-n.x, -n.y, -n.z );
+ glTexCoord2f(t.x, t.y);
+ glVertex3f(p.x,p.y, p.z);
+ //oo++;
+ jj++;
+ }
+ }
+ }
+ }
+ else
+ {
+ for(unsigned int i = 0; i < cache.faceCounts.length(); i++)
+ {
+
+ int fc = cache.faceCounts[i];
+ if(fc != 3)
+ continue; //trianglular faces expected
+
+ int fs = cache.faceStart[i];
+ int fe = cache.faceEnd[i];
+ for(int j = fs; j < fe; j++)
+ {
+ int k = cache.faceVerts[j];
+ const MFloatPoint& p = cache.points[k];
+ const MFloatPoint& t = cache.uvs[oo];
+ const MFloatPoint& n = cache.normals[k];
+ //something is weird with this, normals are inverted...
+ glNormal3f(-n.x, -n.y, -n.z );
+ glTexCoord2f(t.x, t.y);
+ glVertex3f(p.x,p.y, p.z);
+ oo++;
+ }
+ }
+ }
+ glEnd();
+
+ if(cache.diffuse != 0)
+ {
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+ }
+ else if(drawToken == kDrawInstancedWire)
+ {
+ //glEnable( GL_POLYGON_OFFSET_LINE );
+
+ glBegin( GL_LINES );
+ for(unsigned int i = 0; i < cache.faceCounts.length(); i++)
+ {
+
+ int fc = cache.faceCounts[i];
+ if(fc != 3)
+ continue; //trianglular faces expected
+
+ int fs = cache.faceStart[i];
+ int fe = cache.faceEnd[i];
+ for(int j = fs; j < fe; j++)
+ {
+ int jj = (j < fe-1) ? j + 1 : fs;
+ int k = cache.faceVerts[j];
+ int kk = cache.faceVerts[jj];
+ const MPoint& p = cache.points[k];
+ const MPoint& pp = cache.points[kk];
+ glVertex3f(p.x,p.y, p.z);
+ glVertex3f(pp.x,pp.y, pp.z);
+ }
+ }
+ glEnd();
+ }
+
+
+ glPopClientAttrib();
+ glPopAttrib();
+
+}
+#endif
+
+
+void shaveHairUI::drawVerts(int drawToken) const
+{
+ //
+ // Which verts will we be drawing?
+ //
+ bool drawActive = false;
+ int startVert = 0;
+ int endVert = SHAVE_VERTS_PER_GUIDE - 1;
+
+ switch (drawToken)
+ {
+ case kDrawActiveRoots:
+ drawActive = true;
+ case kDrawInactiveRoots:
+ startVert = endVert = 0;
+ break;
+
+ case kDrawActiveTips:
+ drawActive = true;
+ case kDrawInactiveTips:
+ startVert = endVert = SHAVE_VERTS_PER_GUIDE - 1;
+ break;
+
+ case kDrawActiveVerts:
+ drawActive = true;
+ case kDrawInactiveVerts:
+ startVert = 0;
+ endVert = SHAVE_VERTS_PER_GUIDE - 1;
+ break;
+
+ default:
+ //
+ // We should never get here, but if somehow we do then there's
+ // nothing for us to draw.
+ //
+ return;
+ }
+
+ //
+ // Get the guides.
+ //
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+
+ const shaveHairShape::Guides& guides = nodePtr->getGuides().guides;
+
+ //
+ // Save the old point size for later restoration, and set the point
+ // size that we'll be using.
+ //
+ float oldPointSize;
+ glGetFloatv(GL_POINT_SIZE, &oldPointSize);
+ glPointSize(POINT_SIZE);
+
+ //
+ // Draw the guide vertices.
+ //
+ glBegin(GL_POINTS);
+
+ int i;
+ shaveHairShape::Guides::const_iterator iter;
+
+ for (iter = guides.begin(); iter != guides.end(); iter++)
+ {
+ const shaveHairShape::Guide& guide = *iter;
+
+ if (!guide.hidden)
+ {
+ for (i = startVert; i <= endVert ; i++)
+ {
+ //
+ // Is this vert active?
+ //
+ bool isActive = ((guide.select & (1 << i)) != 0);
+
+ //
+ // If the vert meets our drawing requirements, draw it.
+ //
+ if (drawActive == isActive)
+ {
+ glVertex3f(
+ guide.verts[i].x, guide.verts[i].y, guide.verts[i].z
+ );
+ }
+ }
+ }
+ }
+
+ glEnd();
+
+ glPointSize(oldPointSize);
+}
+
+
+bool shaveHairUI::selectGuides(
+ MSelectInfo& selectInfo,
+ MSelectionList& selectionList,
+ MPointArray& worldSpaceSelectPts
+) const
+{
+ //
+ // Create a component to store the selected guides.
+ //
+ MFnSingleIndexedComponent compFn;
+ MObject compObj;
+
+ compObj = compFn.create(shaveHairShape::kShaveGuideComponent);
+
+ //
+ // In single-selection mode we'll use the alignmentMatrix to determine
+ // which of multiple hits is closest to the viewer.
+ //
+ MMatrix alignmentMatrix;
+ MPoint singlePoint;
+ bool singleSelection = selectInfo.singleSelection();
+ MDagPath path = selectInfo.multiPath();
+
+ if (singleSelection)
+ {
+ alignmentMatrix = selectInfo.getAlignmentMatrix();
+
+ //
+ // I don't know for sure, but I'm willing to bet that the
+ // alignmentMatrix is expecting local-space points. Our points are
+ // all in worldSpace to we have to multiply in a localSpace
+ // transformation for it to work properly.
+ //
+ alignmentMatrix = path.inclusiveMatrixInverse() * alignmentMatrix;
+ }
+
+ //
+ // Make sure that this shaveNode is loaded into the engine.
+ //
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+ nodePtr->makeCurrent();
+
+ //
+ // Check the guide segments for selection hits.
+ //
+ SOFTGUIDE guide;
+ int guideIndex;
+ int i;
+ int closestGuideIndex = -1;
+ MPoint closestPt;
+ float closestXformedZ = 0.0f;
+ M3dView view = selectInfo.view();
+
+ for (guideIndex = 0;
+ SHAVEfetch_guide(guideIndex, &guide) != -1;
+ guideIndex++)
+ {
+ if (guide.hidden) continue;
+
+ view.beginSelect();
+ glBegin(GL_LINES);
+
+ // To speed things up, we skip over the even verts.
+ for (i = 0; i < SHAVE_VERTS_PER_GUIDE-2; i += 2)
+ {
+ glVertex3f(
+ guide.guide[i].x, guide.guide[i].y, guide.guide[i].z
+ );
+ glVertex3f(
+ guide.guide[i+2].x, guide.guide[i+2].y, guide.guide[i+2].z
+ );
+ }
+
+ glEnd();
+
+ if (view.endSelect() > 0)
+ {
+ //
+ // We got a hit so store it.
+ //
+ if (singleSelection)
+ {
+ //
+ // On singleSelection we only store the hit closest to
+ // the viewer. We'll use the midpoint of the guide
+ // as our hit point. (We used to test each segment
+ // individually, which gave us a more accurate result, but
+ // was much slower.)
+ //
+ MPoint currentPt(
+ (guide.guide[0].x
+ + guide.guide[SHAVE_VERTS_PER_GUIDE-1].x) / 2.0,
+ (guide.guide[0].y
+ + guide.guide[SHAVE_VERTS_PER_GUIDE-1].y) / 2.0,
+ (guide.guide[0].z
+ + guide.guide[SHAVE_VERTS_PER_GUIDE-1].z) / 2.0
+ );
+ MPoint xformedPt = currentPt;
+
+ xformedPt.homogenize();
+ xformedPt *= alignmentMatrix;
+
+ float xformedZ = (float)xformedPt.z;
+
+ if ((closestGuideIndex < 0)
+ || (xformedZ < closestXformedZ))
+ {
+ closestGuideIndex = guideIndex;
+ closestPt = currentPt;
+ closestXformedZ = xformedZ;
+ }
+ }
+ else
+ {
+ //
+ // On multiple selection we store all guides which are
+ // hit.
+ //
+ compFn.addElement(guideIndex);
+ }
+ }
+ }
+
+ //
+ // If we were doing singleSelection then store the closest hit that we
+ // got.
+ //
+ if (closestGuideIndex >= 0)
+ {
+ compFn.addElement(closestGuideIndex);
+
+ //
+ // Convert the hit point to worldspace.
+ //
+ closestPt *= path.inclusiveMatrix();
+ }
+
+
+ if (!compFn.isEmpty())
+ {
+ MSelectionList newSelections;
+
+ newSelections.add(path, compObj);
+
+ MSelectionMask mask(MSelectionMask::kSelectComponentsMask);
+
+ selectInfo.addSelection(
+ newSelections,
+ closestPt,
+ selectionList,
+ worldSpaceSelectPts,
+ mask,
+ true
+ );
+ }
+
+ return !compFn.isEmpty();
+}
+
+
+bool shaveHairUI::selectObjByGuides(
+ MSelectInfo& selectInfo,
+ MSelectionList& selectionList,
+ MPointArray& worldSpaceSelectPts
+) const
+{
+ SOFTGUIDE guide;
+ int guideIndex;
+ int i;
+ M3dView view = selectInfo.view();
+ MPoint samplePt;
+
+ view.beginSelect();
+
+ for (guideIndex = 0;
+ SHAVEfetch_guide(guideIndex, &guide) != -1;
+ guideIndex++)
+ {
+ if (guide.hidden) continue;
+
+ // In single-selection mode we need to return the point on our
+ // object which is "closest to the viewer". However, to really do
+ // that for hair is extremely expensive and slows down the picking
+ // of everything. So instead we just return the first first of
+ // the first guide. That means that if there are other objects
+ // within the pickbox then they will likely win, but the user can
+ // avoid that by using the Outliner or zooming in for a more
+ // accurate pick.
+ if (guideIndex == 0)
+ {
+ samplePt.x = (double)guide.guide[0].x;
+ samplePt.y = (double)guide.guide[0].y;
+ samplePt.z = (double)guide.guide[0].z;
+ }
+
+ glBegin(GL_LINE_STRIP);
+
+ for (i = 0; i < SHAVE_VERTS_PER_GUIDE; i++)
+ glVertex3f(guide.guide[i].x, guide.guide[i].y, guide.guide[i].z);
+
+ glEnd();
+ }
+
+ if (view.endSelect() > 0)
+ {
+ MSelectionMask priorityMask(MSelectionMask::kSelectNurbsSurfaces);
+ MSelectionList newItem;
+ MDagPath path = selectInfo.selectPath();
+
+ newItem.add(path);
+
+ selectInfo.addSelection(
+ newItem,
+ samplePt,
+ selectionList,
+ worldSpaceSelectPts,
+ priorityMask,
+ false
+ );
+
+ return true;
+ }
+
+ return false;
+}
+
+
+bool shaveHairUI::selectObjByHairs(
+ MSelectInfo& selectInfo,
+ MSelectionList& selectionList,
+ MPointArray& worldSpaceSelectPts
+) const
+{
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+ M3dView view = selectInfo.view();
+
+ //const std::vector<shaveHairShape::DisplayHair>& displayHairs = nodePtr->getDisplayHairs();
+ //M3dView view = M3dView::active3dView();
+ const shaveHairShape::DisplayHairCache& cache = nodePtr->getDisplayHairs(view);
+
+ //
+ // Determine the number of hairs to be drawn.
+ //
+ unsigned numHairsToDraw = nodePtr->getNumDisplayHairs(false);
+
+ if (numHairsToDraw > cache.displayHair.size())
+ numHairsToDraw = (unsigned int)cache.displayHair.size();
+
+ //
+ // Draw the hairs.
+ //
+ unsigned h;
+ unsigned s;
+ unsigned v;
+ MPoint samplePt;
+
+ view.beginSelect();
+
+ for (h = 0; h < numHairsToDraw; h++)
+ {
+ const shaveHairShape::DisplayHair& hair = cache.displayHair[h];
+
+ for (s = 0; s < hair.size(); s++)
+ {
+ const shaveHairShape::DisplayStrand& strand = hair[s];
+
+ // In single-selection mode we need to return the point on our
+ // object which is "closest to the viewer". However, to
+ // really do that for hair is extremely expensive and slows
+ // down the picking of everything. So instead we just return
+ // the first first of the first guide. That means that if
+ // there are other objects within the pickbox then they will
+ // likely win, but the user can avoid that by using the
+ // Outliner or zooming in for a more accurate pick.
+ if ((h == 0) && (s == 0))
+ {
+ samplePt.x = strand.verts[0].x;
+ samplePt.y = strand.verts[0].y;
+ samplePt.z = strand.verts[0].z;
+ }
+
+ glBegin(GL_LINE_STRIP);
+
+ for (v = 0; v < strand.verts.length(); v++)
+ {
+ glVertex3d(
+ strand.verts[v].x, strand.verts[v].y, strand.verts[v].z
+ );
+ }
+
+ glEnd();
+ }
+ }
+
+ if (view.endSelect() > 0)
+ {
+ MSelectionMask priorityMask(MSelectionMask::kSelectNurbsSurfaces);
+ MSelectionList newItem;
+ MDagPath path = selectInfo.selectPath();
+
+ newItem.add(path);
+
+ selectInfo.addSelection(
+ newItem,
+ samplePt,
+ selectionList,
+ worldSpaceSelectPts,
+ priorityMask,
+ false
+ );
+
+ return true;
+ }
+
+ return false;
+}
+
+bool shaveHairUI::selectObjByGeom(
+ MSelectInfo& selectInfo,
+ MSelectionList& selectionList,
+ MPointArray& worldSpaceSelectPts
+) const
+{
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+ M3dView view = selectInfo.view();
+
+ shaveInstanceDisplay& cache = nodePtr->getInstanceDisplay();
+
+ //
+ // Draw the hairs.
+ //
+ MPoint samplePt;
+
+ view.beginSelect();
+
+ glBegin( GL_LINES );
+ for(unsigned int i = 0; i < cache.faceCounts.length(); i++)
+ {
+
+ int fc = cache.faceCounts[i];
+ if(fc != 3)
+ continue; //trianglular faces expected
+
+ int fs = cache.faceStart[i];
+ int fe = cache.faceEnd[i];
+ for(int j = fs; j < fe; j++)
+ {
+ int jj = (j < fe-1) ? j + 1 : fs;
+ int k = cache.faceVerts[j];
+ int kk = cache.faceVerts[jj];
+ const MPoint& p = cache.points[k];
+ const MPoint& pp = cache.points[kk];
+ glVertex3f(p.x,p.y, p.z);
+ glVertex3f(pp.x,pp.y, pp.z);
+ }
+ }
+ glEnd();
+
+ if (view.endSelect() > 0)
+ {
+ MSelectionMask priorityMask(MSelectionMask::kSelectNurbsSurfaces);
+ MSelectionList newItem;
+ MDagPath path = selectInfo.selectPath();
+
+ newItem.add(path);
+
+ selectInfo.addSelection(
+ newItem,
+ samplePt,
+ selectionList,
+ worldSpaceSelectPts,
+ priorityMask,
+ false
+ );
+
+ return true;
+ }
+
+ return false;
+}
+
+
+
+
+bool shaveHairUI::selectVerts(
+ MString selectMode,
+ MSelectInfo& selectInfo,
+ MSelectionList& selectionList,
+ MPointArray& worldSpaceSelectPts
+) const
+{
+ // Use the guide selection mode to determine which vertices to
+ // check.
+ //
+ int startVert = 0;
+ int endVert = SHAVE_VERTS_PER_GUIDE - 1;
+ bool entireGuide = false;
+
+ if (selectMode == "root")
+ {
+ startVert = endVert = 0;
+
+ // In 'root' mode we are selecting entire guides by their root
+ // verts.
+ //
+ entireGuide = true;
+ }
+ else if (selectMode == "tip")
+ {
+ startVert = endVert = SHAVE_VERTS_PER_GUIDE - 1;
+ }
+ else if (selectMode == "vert")
+ {
+ startVert = 0;
+ endVert = SHAVE_VERTS_PER_GUIDE - 1;
+ }
+ else
+ return false;
+
+ // Create a component to store the selected verts/guides.
+ //
+ MFnSingleIndexedComponent guideCompFn;
+ MFnDoubleIndexedComponent vertCompFn;
+ MObject compObj;
+
+ if (entireGuide)
+ compObj = guideCompFn.create(shaveHairShape::kShaveGuideComponent);
+ else
+ compObj = vertCompFn.create(shaveHairShape::kShaveGuideVertComponent);
+
+ // In single-selection mode we'll use the alignmentMatrix to determine
+ // which of multiple hits is closest to the viewer.
+ //
+ MMatrix alignmentMatrix;
+ MPoint singlePoint;
+ bool singleSelection = selectInfo.singleSelection();
+ MDagPath path = selectInfo.multiPath();
+
+ if (singleSelection)
+ {
+ alignmentMatrix = selectInfo.getAlignmentMatrix();
+
+ // I don't know for sure, but I'm willing to bet that the
+ // alignmentMatrix is expecting local-space points. Our points are
+ // all in worldSpace to we have to multiply in a localSpace
+ // transformation for it to work properly.
+ //
+ alignmentMatrix = path.inclusiveMatrixInverse() * alignmentMatrix;
+ }
+
+ // Save the old point size for later restoration, and set the point
+ // size that we'll be using.
+ //
+ M3dView view = selectInfo.view();
+ float oldPointSize;
+
+ view.beginGL();
+ glGetFloatv(GL_POINT_SIZE, &oldPointSize);
+ glPointSize(POINT_SIZE);
+ view.endGL();
+
+ // Make sure that this shaveNode is loaded into the engine.
+ //
+ shaveHairShape* nodePtr = dynamic_cast<shaveHairShape*>(surfaceShape());
+ nodePtr->makeCurrent();
+
+ // Check the guide vertices for selection hits.
+ //
+ SOFTGUIDE guide;
+ int guideIndex;
+ int i;
+ int closestGuideIndex = -1;
+ int closestVertIndex = -1;
+ MPoint closestPt;
+ float closestXformedZ = 0.0f;
+
+ for (guideIndex = 0;
+ SHAVEfetch_guide(guideIndex, &guide) != -1;
+ guideIndex++)
+ {
+ if (guide.hidden) continue;
+
+ for (i = startVert; i <= endVert ; i++)
+ {
+ view.beginSelect();
+ glBegin(GL_POINTS);
+ glVertex3f(guide.guide[i].x, guide.guide[i].y, guide.guide[i].z);
+ glEnd();
+
+ if (view.endSelect() > 0)
+ {
+ // We got a hit so store it.
+ //
+ if (singleSelection)
+ {
+ // On singleSelection we only store the hit closest to
+ // the viewer.
+ //
+ MPoint currentPt(
+ guide.guide[i].x,
+ guide.guide[i].y,
+ guide.guide[i].z
+ );
+ MPoint xformedPt = currentPt;
+
+ xformedPt.homogenize();
+ xformedPt *= alignmentMatrix;
+
+ float xformedZ = (float)xformedPt.z;
+
+ if ((closestGuideIndex < 0)
+ || (xformedZ < closestXformedZ))
+ {
+ closestGuideIndex = guideIndex;
+ closestVertIndex = i;
+ closestPt = currentPt;
+ closestXformedZ = xformedZ;
+ }
+ }
+ else
+ {
+ // On multiple selection we store all hits.
+ //
+ if (entireGuide)
+ {
+ guideCompFn.addElement(guideIndex);
+ break;
+ }
+ else
+ vertCompFn.addElement(guideIndex, i);
+ }
+ }
+ }
+ }
+
+ // If we were doing singleSelection then store the closest hit that we
+ // got.
+ //
+ if (closestGuideIndex >= 0)
+ {
+ if (entireGuide)
+ guideCompFn.addElement(closestGuideIndex);
+ else
+ vertCompFn.addElement(closestGuideIndex, closestVertIndex);
+
+ // Convert the hit point to worldspace.
+ //
+ closestPt *= path.inclusiveMatrix();
+ }
+
+ bool haveSelection = !guideCompFn.isEmpty() || !vertCompFn.isEmpty();
+
+ if (haveSelection)
+ {
+ MSelectionList newSelections;
+
+ newSelections.add(path, compObj);
+
+ MSelectionMask mask(MSelectionMask::kSelectComponentsMask);
+
+ selectInfo.addSelection(
+ newSelections,
+ closestPt,
+ selectionList,
+ worldSpaceSelectPts,
+ mask,
+ true
+ );
+ }
+
+ // Restore the point size.
+ //
+ view.beginGL();
+ glPointSize(oldPointSize);
+ view.endGL();
+
+ return haveSelection;
+}
+
+
+//
+// Maya Bug: In Maya 6.5 MDrawRequest::setDisplayStatus() doesn't work,
+// so we have to pass the display status as a separate arg
+// rather than the caller setting it in 'request'.
+//
+void shaveHairUI::setWireframeColor(
+ MDrawRequest& request, M3dView& view, M3dView::DisplayStatus dStatus
+) const
+{
+ M3dView::ColorTable colorTable = M3dView::kDormantColors;
+ int colorIndex = 0;
+
+ switch (dStatus)
+ {
+ case M3dView::kActive:
+ colorIndex = ACTIVE_SURFACE_COLOR;
+ colorTable = M3dView::kActiveColors;
+ break;
+
+ case M3dView::kActiveComponent:
+ colorIndex = DORMANT_SURFACE_COLOR;
+ colorTable = M3dView::kDormantColors;
+ break;
+
+ case M3dView::kHilite:
+ colorIndex = HILITE_COLOR;
+ colorTable = M3dView::kActiveColors;
+ break;
+
+ case M3dView::kTemplate:
+ colorIndex = 0;
+ colorTable = M3dView::kTemplateColor;
+ break;
+
+ case M3dView::kActiveTemplate:
+ colorIndex = ACTIVE_TEMPLATE_COLOR;
+ colorTable = M3dView::kActiveColors;
+ break;
+
+ case M3dView::kLead:
+ colorIndex = LEAD_COLOR;
+ colorTable = M3dView::kActiveColors;
+ break;
+
+ case M3dView::kActiveAffected:
+ colorIndex = ACTIVE_AFFECTED_COLOR;
+ colorTable = M3dView::kActiveColors;
+ break;
+
+ case M3dView::kLive:
+ //
+ // %%% This is not correct. If we think we might allow
+ // hair to become a live construction surface, then we
+ // should determine the correct settings.
+ //
+ colorIndex = ACTIVE_SURFACE_COLOR;
+ colorTable = M3dView::kActiveColors;
+ break;
+
+ case M3dView::kDormant:
+ {
+ //
+ // If our drawing overrides are on, then use the specified
+ // override colour.
+ //
+ MFnDependencyNode nodeFn(surfaceShape()->thisMObject());
+ bool colourOverridden;
+
+ colorIndex = -1;
+
+ MPlug plug = nodeFn.findPlug("overrideEnabled");
+ plug.getValue(colourOverridden);
+
+ if (colourOverridden)
+ {
+ plug = nodeFn.findPlug("overrideColor");
+ plug.getValue(colorIndex);
+
+ //
+ // The colour index contained in the 'overrideColor'
+ // attribute is one greater than the actual colour index
+ // (so that 0 can represent the override colour being
+ // disabled). To get the correct colour index, we must
+ // decrement the value just retrieved by 1.
+ //
+ --colorIndex;
+ }
+
+ //
+ // If no override colour was specified, then check to
+ // see if we've been assigned a user-defined colour.
+ //
+ if (colorIndex == -1)
+ {
+ plug.setAttribute(shaveHairShape::useObjectColor);
+ plug.getValue(colourOverridden);
+
+ if (colourOverridden)
+ {
+ int userIndex;
+
+ plug.setAttribute(shaveHairShape::objectColor);
+ plug.getValue(userIndex);
+
+ colorIndex = view.userDefinedColorIndex(
+ userIndex
+ );
+ }
+ else
+ {
+ //
+ // None of the various overrides are in use, so
+ // just draw the wireframe in the default
+ // dormant surface colour.
+ //
+ colorIndex = DORMANT_SURFACE_COLOR;
+ }
+ }
+
+ colorTable = M3dView::kDormantColors;
+ }
+ break;
+
+ case M3dView::kInvisible:
+ case M3dView::kIntermediateObject:
+ case M3dView::kNoStatus:
+ default:
+ // Nothing to draw.
+ return;
+ }
+
+ request.setColor(colorIndex, colorTable);
+}