diff options
| author | Ben Marsh <[email protected]> | 2019-10-22 09:07:59 -0400 |
|---|---|---|
| committer | Ben Marsh <[email protected]> | 2019-10-22 09:07:59 -0400 |
| commit | bd0027e737c6512397f841c22786274ed74b927f (patch) | |
| tree | f7ffbdb8f3741bb7f24635616cc189cba5cb865c /mayaPlug/shaveHairUI.cpp | |
| download | archived-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.cpp | 5777 |
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); +} |