// Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 //Qt headers must be included before any others !!! #include #include #include #if QT_VERSION < 0x050000 # include # include #else # include # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 #include #include #include #include #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 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(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(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(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(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(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(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 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(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& 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 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(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(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(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 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(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(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(surfaceShape()); M3dView view = selectInfo.view(); //const std::vector& 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(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(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); }