MakeHuman  0.95beta
 All Data Structures Files Functions Variables Typedefs Macros Pages
glmodule.c
Go to the documentation of this file.
1 
31 #ifdef _DEBUG
32 #undef _DEBUG
33 #include <Python.h>
34 #define _DEBUG
35 #else
36 #include <Python.h>
37 #endif
38 
39 #include <assert.h>
40 #include "glmodule.h"
41 #include "core.h"
42 
43 #ifdef __WIN32__
44 #include <windows.h>
45 #include <SDL_syswm.h>
46 #elif __APPLE__
47 #include "SDL_image/SDL_image.h"
48 #else
49 #include <X11/Xlib.h>
50 #include <X11/Xutil.h>
51 #include <GL/glx.h>
52 #endif
53 #ifdef __APPLE__
54 #include <Python/structmember.h>
55 #else
56 #include <structmember.h>
57 #endif
58 
59 static int g_savedx=0; /*saved x mouse position*/
60 static int g_savedy=0; /*saved y mouse position*/
61 static int g_desktopWidth = 0;
62 static int g_desktopHeight = 0;
63 static int g_windowWidth = 800;
64 static int g_windowHeight = 600;
65 static SDL_Surface *g_screen = NULL;
66 
67 #ifndef __APPLE__
68 typedef SDL_Surface *(*PFN_IMG_LOAD)(const char *);
69 static void *g_sdlImageHandle = NULL;
70 static PFN_IMG_LOAD IMG_Load = NULL;
71 #endif
72 
73 typedef struct
74 {
75  PyObject_HEAD
76 
77  float fovAngle;
78  float nearPlane;
79  float farPlane;
80 
82 
85 
86  float eyeX;
87  float eyeY;
88  float eyeZ;
89  float focusX;
90  float focusY;
91  float focusZ;
92  float upX;
93  float upY;
94  float upZ;
95 } Camera;
96 
97 void mhCameraPosition(Camera *camera, int eye);
98 
99 // Camera attributes directly accessed by Python
100 static PyMemberDef Camera_members[] =
101 {
102  {"fovAngle", T_FLOAT, offsetof(Camera, fovAngle), 0, "The Field Of View angle."},
103  {"nearPlane", T_FLOAT, offsetof(Camera, nearPlane), 0, "The Near Clipping Plane."},
104  {"farPlane", T_FLOAT, offsetof(Camera, farPlane), 0, "The Far Clipping Plane."},
105  {"projection", T_UINT, offsetof(Camera, projection), 0, "The projection type, 0 for orthogonal, 1 for perspective."},
106  {"stereoMode", T_UINT, offsetof(Camera, stereoMode), 0, "The Stereo Mode, 0 for no stereo, 1 for toe-in, 2 for off-axis."},
107  {"eyeSeparation", T_FLOAT, offsetof(Camera, eyeSeparation), 0, "The Eye Separation."},
108  {"eyeX", T_FLOAT, offsetof(Camera, eyeX), 0, "The x position of the eye."},
109  {"eyeY", T_FLOAT, offsetof(Camera, eyeY), 0, "The y position of the eye."},
110  {"eyeZ", T_FLOAT, offsetof(Camera, eyeZ), 0, "The z position of the eye."},
111  {"focusX", T_FLOAT, offsetof(Camera, focusX), 0, "The x position of the focus."},
112  {"focusY", T_FLOAT, offsetof(Camera, focusY), 0, "The y position of the focus."},
113  {"focusZ", T_FLOAT, offsetof(Camera, focusZ), 0, "The z position of the focus."},
114  {"upX", T_FLOAT, offsetof(Camera, upX), 0, "The x of the up vector."},
115  {"upY", T_FLOAT, offsetof(Camera, upY), 0, "The y of the up vector."},
116  {"upZ", T_FLOAT, offsetof(Camera, upZ), 0, "The z of the up vector."},
117  {NULL} /* Sentinel */
118 };
119 
120 PyObject *Camera_convertToScreen(Camera *camera, PyObject *args);
121 PyObject *Camera_convertToWorld2D(Camera *camera, PyObject *args);
122 PyObject *Camera_convertToWorld3D(Camera *camera, PyObject *args);
123 
124 // Camera Methods
125 static PyMethodDef Camera_methods[] =
126 {
127  {"convertToScreen", (PyCFunction)Camera_convertToScreen, METH_VARARGS,
128  "Converts world coordinates to screen coordinates."
129  },
130  {"convertToWorld2D", (PyCFunction)Camera_convertToWorld2D, METH_VARARGS,
131  "Converts 2D screen coordinates to world coordinates."
132  },
133  {"convertToWorld3D", (PyCFunction)Camera_convertToWorld3D, METH_VARARGS,
134  "Converts 3D screen coordinates to world coordinates."
135  },
136  {NULL} /* Sentinel */
137 };
138 
139 static PyObject *Camera_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
140 static int Camera_init(Camera *self, PyObject *args, PyObject *kwds);
141 
142 // Camera type definition
143 PyTypeObject CameraType =
144 {
145  PyObject_HEAD_INIT(NULL)
146  0, // ob_size
147  "mh.Camera", // tp_name
148  sizeof(Camera), // tp_basicsize
149  0, // tp_itemsize
150  0, // tp_dealloc
151  0, // tp_print
152  0, // tp_getattr
153  0, // tp_setattr
154  0, // tp_compare
155  0, // tp_repr
156  0, // tp_as_number
157  0, // tp_as_sequence
158  0, // tp_as_mapping
159  0, // tp_hash
160  0, // tp_call
161  0, // tp_str
162  0, // tp_getattro
163  0, // tp_setattro
164  0, // tp_as_buffer
165  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
166  "Camera object", // tp_doc
167  0, // tp_traverse
168  0, // tp_clear
169  0, // tp_richcompare
170  0, // tp_weaklistoffset
171  0, // tp_iter
172  0, // tp_iternext
173  Camera_methods, // tp_methods
174  Camera_members, // tp_members
175  0, // tp_getset
176  0, // tp_base
177  0, // tp_dict
178  0, // tp_descr_get
179  0, // tp_descr_set
180  0, // tp_dictoffset
181  (initproc)Camera_init, // tp_init
182  0, // tp_alloc
183  Camera_new, // tp_new
184 };
185 
191 void RegisterCamera(PyObject *module)
192 {
193  if (PyType_Ready(&CameraType) < 0)
194  return;
195 
196  Py_INCREF(&CameraType);
197  PyModule_AddObject(module, "Camera", (PyObject*)&CameraType);
198 }
199 
205 static PyObject *Camera_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
206 {
207  // Alloc Python data
208  Camera *self = (Camera*)type->tp_alloc(type, 0);
209 
210  // Init our data
211  if (self)
212  {
213  self->fovAngle = 25.0f;
214  self->nearPlane = 0.1f;
215  self->farPlane = 100.0f;
216 
217  self->projection = 1;
218 
219  self->stereoMode = 0;
220  self->eyeSeparation = 1.0f;
221 
222  self->eyeX = 0.0f;
223  self->eyeY = 0.0f;
224  self->eyeZ = 60.0f;
225  self->focusX = 0.0f;
226  self->focusY = 0.0f;
227  self->focusZ = 0.0f;
228  self->upX = 0.0f;
229  self->upY = 1.0f;
230  self->upZ = 0.0f;
231  }
232 
233  return (PyObject*)self;
234 }
235 
242 static int Camera_init(Camera *self, PyObject *args, PyObject *kwds)
243 {
244  char *path = NULL;
245 
246  if (!PyArg_ParseTuple(args, "|s", &path))
247  return -1;
248 
249  return 0;
250 }
251 
252 typedef struct
253 {
254  PyObject_HEAD
255  GLuint textureId;
256  int width;
257  int height;
258 } Texture;
259 
260 // Texture attributes directly accessed by Python
261 static PyMemberDef Texture_members[] =
262 {
263  {"textureId", T_UINT, offsetof(Texture, textureId), READONLY, "The id of the OpenGL texture."},
264  {"width", T_UINT, offsetof(Texture, width), READONLY, "The width of the texture in pixels."},
265  {"height", T_UINT, offsetof(Texture, height), READONLY, "The height of the texture in pixels."},
266  {NULL} /* Sentinel */
267 };
268 
269 static PyObject *Texture_loadImage(Texture *texture, PyObject *path);
270 
271 // Texture Methods
272 static PyMethodDef Texture_methods[] =
273 {
274  {"loadImage", (PyCFunction)Texture_loadImage, METH_O,
275  "Loads the specified image from file"
276  },
277  {NULL} /* Sentinel */
278 };
279 
280 static void Texture_dealloc(Texture *self);
281 static PyObject *Texture_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
282 static int Texture_init(Texture *self, PyObject *args, PyObject *kwds);
283 
284 // Texture type definition
285 PyTypeObject TextureType =
286 {
287  PyObject_HEAD_INIT(NULL)
288  0, // ob_size
289  "mh.Texture", // tp_name
290  sizeof(Texture), // tp_basicsize
291  0, // tp_itemsize
292  (destructor)Texture_dealloc, // tp_dealloc
293  0, // tp_print
294  0, // tp_getattr
295  0, // tp_setattr
296  0, // tp_compare
297  0, // tp_repr
298  0, // tp_as_number
299  0, // tp_as_sequence
300  0, // tp_as_mapping
301  0, // tp_hash
302  0, // tp_call
303  0, // tp_str
304  0, // tp_getattro
305  0, // tp_setattro
306  0, // tp_as_buffer
307  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
308  "Texture object", // tp_doc
309  0, // tp_traverse
310  0, // tp_clear
311  0, // tp_richcompare
312  0, // tp_weaklistoffset
313  0, // tp_iter
314  0, // tp_iternext
315  Texture_methods, // tp_methods
316  Texture_members, // tp_members
317  0, // tp_getset
318  0, // tp_base
319  0, // tp_dict
320  0, // tp_descr_get
321  0, // tp_descr_set
322  0, // tp_dictoffset
323  (initproc)Texture_init, // tp_init
324  0, // tp_alloc
325  Texture_new, // tp_new
326 };
327 
333 void RegisterTexture(PyObject *module)
334 {
335  if (PyType_Ready(&TextureType) < 0)
336  return;
337 
338  Py_INCREF(&TextureType);
339  PyModule_AddObject(module, "Texture", (PyObject*)&TextureType);
340 }
341 
347 static void Texture_dealloc(Texture *self)
348 {
349  // Free our data
350  glDeleteTextures(1, &self->textureId);
351 
352  // Free Python data
353  self->ob_type->tp_free((PyObject*)self);
354 }
355 
361 static PyObject *Texture_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
362 {
363  // Alloc Python data
364  Texture *self = (Texture*)type->tp_alloc(type, 0);
365 
366  // Init our data
367  if (self)
368  {
369  glGenTextures(1, &self->textureId);
370  self->width = 0;
371  self->height = 0;
372  }
373 
374  return (PyObject*)self;
375 }
376 
383 static int Texture_init(Texture *self, PyObject *args, PyObject *kwds)
384 {
385  char *path = NULL;
386 
387  if (!PyArg_ParseTuple(args, "|s", &path))
388  return -1;
389 
390  if (path && !mhLoadTexture(path, self->textureId, &self->width, &self->height))
391  return -1;
392 
393  return 0;
394 }
395 
396 static PyObject *Texture_loadImage(Texture *texture, PyObject *path)
397 {
398  if (PyString_Check(path))
399  {
400  if (!mhLoadTexture(PyString_AsString(path), texture->textureId, &texture->width, &texture->height))
401  return NULL;
402  }
403  else if (PyUnicode_Check(path))
404  {
405  path = PyUnicode_AsUTF8String(path);
406  if (!mhLoadTexture(PyString_AsString(path), texture->textureId, &texture->width, &texture->height))
407  {
408  Py_DECREF(path);
409  return NULL;
410  }
411  Py_DECREF(path);
412  }
413  else
414  {
415  PyErr_SetString(PyExc_TypeError, "String or Unicode object expected");
416  return NULL;
417  }
418 
419  return Py_BuildValue("");
420 }
421 
422 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
423 
429 static uint32_t swapLong(uint32_t inValue)
430 {
431 #ifdef __GNUC__
432 # if defined(__ppc__)
433  register uint32_t word;
434  __asm__("lwbrx %0,%2,%1" : "=r" (word) : "r" (&inValue), "b" (0));
435  return word;
436 # elif defined(__x86__) || defined(__i386__) || defined (__x86_64__)
437  register uint32_t word;
438  __asm__("bswap %0" : "=r" (word) : "0" (inValue));
439  return word;
440 # endif
441 #endif
442  return (((inValue ) & 0xff) << 24) |
443  (((inValue >> 8) & 0xff) << 16) |
444  (((inValue >> 16) & 0xff) << 8) |
445  (((inValue >> 24) & 0xff));
446 }
447 #endif // #if SDL_BYTEORDER == SDL_BIG_ENDIAN
448 
461 static int longCopyEndianSafe(uint32_t *destPtr, const uint32_t *srcPtr, size_t inLongs)
462 {
463 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
464  memcpy(destPtr, srcPtr, inLongs << 2);
465 #else /* For Big Endian we'll need to swap all bytes within the long */
466  int i;
467  for (i=0; i<inLongs; ++i)
468  {
469  *(destPtr++) = swapLong(*(srcPtr++));
470  }
471 #endif
472  return inLongs;
473 }
474 
482 static void mhFlipSurface(SDL_Surface *surface)
483 {
484  unsigned char *line = (unsigned char*)malloc(surface->pitch);
485  const size_t lineBytes = surface->pitch;
486  const size_t lineLongs = lineBytes >> 2;
487 
488  unsigned char *pixelsA;
489  unsigned char *pixelsB;
490 
491  int lineIndex;
492 
493  if (line)
494  {
495  if (SDL_MUSTLOCK(surface)) SDL_LockSurface(surface);
496 
497  pixelsA = (unsigned char*)surface->pixels;
498  pixelsB = (unsigned char*)surface->pixels + (surface->h - 1) * lineBytes;
499 
500  for (lineIndex = 0; lineIndex < surface->h >> 1; lineIndex++)
501  {
502  memcpy((uint32_t*)line, (const uint32_t*)pixelsA, lineBytes);
503  longCopyEndianSafe((uint32_t*)pixelsA, (const uint32_t*)pixelsB, lineLongs);
504  longCopyEndianSafe((uint32_t*)pixelsB, (const uint32_t*)line, lineLongs);
505 
506  pixelsA += lineBytes;
507  pixelsB -= lineBytes;
508  }
509  if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface);
510  free(line);
511  }
512 }
513 
520 GLuint mhLoadTexture(const char *fname, GLuint texture, int *width, int *height)
521 {
522  int internalFormat, format;
523  SDL_Surface *surface;
524 
525  //printf("Loading texture '%s'\n", fname);
526 
527  if (!texture)
528  glGenTextures(1, &texture);
529 
530 #ifndef __APPLE__ // OS X utilizes the SDL_image framework for image loading!
531  if (!g_sdlImageHandle)
532  {
533 #ifdef __WIN32__
534  g_sdlImageHandle = SDL_LoadObject("SDL_image");
535 #else
536  g_sdlImageHandle = SDL_LoadObject("libSDL_image-1.2.so.0");
537 #endif
538 
539  if (!g_sdlImageHandle)
540  {
541  PyErr_Format(PyExc_RuntimeError, "Could not load %s, SDL_image not found", fname);
542  return 0;
543  }
544 
545  IMG_Load = (PFN_IMG_LOAD)SDL_LoadFunction(g_sdlImageHandle, "IMG_Load");
546  }
547 
548  if (!IMG_Load)
549  {
550  PyErr_Format(PyExc_RuntimeError, "Could not load %s, IMG_Load not found", fname);
551  return 0;
552  }
553 #endif // ifndef __APPLE__
554  surface = (SDL_Surface*)IMG_Load(fname);
555 
556  if (!surface)
557  {
558  PyErr_Format(PyExc_RuntimeError, "Could not load %s, %s", fname, SDL_GetError());
559  return 0;
560  }
561 
562  switch (surface->format->BytesPerPixel)
563  {
564  case 1:
565  internalFormat = GL_ALPHA8;
566  format = GL_ALPHA;
567  break;
568  case 3:
569  internalFormat = 3;
570  if (surface->format->Rshift) // If there is a shift on the red value, we need to tell that red and blue are switched
571  format = GL_BGR;
572  else
573  format = GL_RGB;
574  break;
575  case 4:
576  internalFormat = 4;
577  if (surface->format->Rshift) // If there is a shift on the red value, we need to tell that red and blue are switched
578  format = GL_BGRA;
579  else
580  format = GL_RGBA;
581  break;
582  default:
583  SDL_FreeSurface(surface);
584  PyErr_Format(PyExc_RuntimeError, "Could not load %s, unsupported pixel format", fname);
585  return 0;
586 
587  }
588 
589  // For some reason we need to flip the surface vertically
590  mhFlipSurface(surface);
591 
592  if (surface->h == 1)
593  {
594  glBindTexture(GL_TEXTURE_1D, texture);
595  glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE_EXT);
596  glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE_EXT);
597  glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
598  glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
599  gluBuild1DMipmaps(GL_TEXTURE_1D, internalFormat, surface->w, format, GL_UNSIGNED_BYTE, surface->pixels);
600  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
601  }
602  else
603  {
604  glBindTexture(GL_TEXTURE_2D, texture);
605  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE_EXT);
606  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE_EXT);
607 
608 // hdusel: Just a test for Mac OS X in order to prevent that the fonts look so ugly (blurry) on the Mac port.
609 // So try to permit MIPMAP Interpolation for fonts.
610 #if defined(__APPLE__)
611  const int isFont = (strstr(fname, "/fonts/") != NULL);
612  if (isFont)
613  {
614  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
615  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
616  }
617  else
618  {
619  #if defined(__ppc__)
620  // On PowerPC Macs just don't use mipmapping
621  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
622  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
623  #else
624  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
625  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
626  #endif
627  }
628 #else
629  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
630  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
631 #endif
632  gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat, surface->w, surface->h, format, GL_UNSIGNED_BYTE, surface->pixels);
633 // glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, surface->w, surface->h, 0, format, GL_UNSIGNED_BYTE, surface->pixels);
634  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
635  }
636 
637  if (width)
638  *width = surface->w;
639  if (height)
640  *height = surface->h;
641 
642  SDL_FreeSurface(surface);
643 
644  return texture;
645 }
646 
647 GLuint mhCreateVertexShader(const char *source)
648 {
649  GLuint v;
650  GLint status;
651 
652  if (GLEW_VERSION_2_0)
653  {
654  v = glCreateShader(GL_VERTEX_SHADER);
655 
656  glShaderSource(v, 1, &source, NULL);
657 
658  glCompileShader(v);
659  glGetShaderiv(v, GL_COMPILE_STATUS, &status);
660  if (status != GL_TRUE)
661  {
662  GLsizei logLength;
663 
664  glGetShaderiv(v, GL_INFO_LOG_LENGTH, &logLength);
665 
666  if (logLength > 0)
667  {
668  char *log;
669  GLsizei charsWritten;
670 
671  log = (char*)malloc(logLength);
672  glGetShaderInfoLog(v, logLength, &charsWritten, log);
673  PyErr_Format(PyExc_RuntimeError, "Error compiling vertex shader: %s", log);
674  free(log);
675  }
676  else
677  PyErr_SetString(PyExc_RuntimeError, "Error compiling vertex shader");
678 
679  return 0;
680  }
681 
682  return v;
683  }
684  else if (GLEW_ARB_shader_objects)
685  {
686  v = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
687 
688  glShaderSourceARB(v, 1, &source, NULL);
689 
690  glCompileShaderARB(v);
691  glGetObjectParameterivARB(v, GL_OBJECT_COMPILE_STATUS_ARB, &status);
692  if (status != GL_TRUE)
693  {
694  GLsizei logLength;
695 
696  glGetObjectParameterivARB(v, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logLength);
697 
698  if (logLength > 0)
699  {
700  char *log;
701  GLsizei charsWritten;
702 
703  log = (char*)malloc(logLength);
704  glGetInfoLogARB(v, logLength, &charsWritten, log);
705  PyErr_Format(PyExc_RuntimeError, "Error compiling vertex shader: %s", log);
706  free(log);
707  }
708  else
709  PyErr_SetString(PyExc_RuntimeError, "Error compiling vertex shader");
710 
711  return 0;
712  }
713 
714  return v;
715  }
716  else
717  {
718  PyErr_SetString(PyExc_RuntimeError, "No shader support detected");
719  return 0;
720  }
721 }
722 
723 GLuint mhCreateFragmentShader(const char *source)
724 {
725  GLuint f;
726  GLint status;
727 
728  if (GLEW_VERSION_2_0)
729  {
730  f = glCreateShader(GL_FRAGMENT_SHADER);
731 
732  glShaderSource(f, 1, &source, NULL);
733 
734  glCompileShader(f);
735  glGetShaderiv(f, GL_COMPILE_STATUS, &status);
736  if (status != GL_TRUE)
737  {
738  GLsizei logLength;
739 
740  glGetShaderiv(f, GL_INFO_LOG_LENGTH, &logLength);
741 
742  if (logLength > 0)
743  {
744  char *log;
745  GLsizei charsWritten;
746 
747  log = (char*)malloc(logLength);
748  glGetShaderInfoLog(f, logLength, &charsWritten, log);
749  PyErr_Format(PyExc_RuntimeError, "Error compiling fragment shader: %s", log);
750  free(log);
751  }
752  else
753  PyErr_SetString(PyExc_RuntimeError, "Error compiling fragment shader");
754 
755  return 0;
756  }
757 
758  return f;
759  }
760  else if (GLEW_ARB_shader_objects)
761  {
762  f = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
763 
764  glShaderSourceARB(f, 1, &source, NULL);
765 
766  glCompileShaderARB(f);
767  glGetObjectParameterivARB(f, GL_OBJECT_COMPILE_STATUS_ARB, &status);
768  if (status != GL_TRUE)
769  {
770  GLsizei logLength;
771 
772  glGetObjectParameterivARB(f, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logLength);
773 
774  if (logLength > 0)
775  {
776  char *log;
777  GLsizei charsWritten;
778 
779  log = (char*)malloc(logLength);
780  glGetInfoLogARB(f, logLength, &charsWritten, log);
781  PyErr_Format(PyExc_RuntimeError, "Error compiling fragment shader: %s", log);
782  free(log);
783  }
784  else
785  PyErr_SetString(PyExc_RuntimeError, "Error compiling fragment shader");
786 
787  return 0;
788  }
789 
790  return f;
791  }
792  else
793  {
794  PyErr_SetString(PyExc_RuntimeError, "No shader support detected");
795  return 0;
796  }
797 }
798 
799 GLuint mhCreateShader(GLuint vertexShader, GLuint fragmentShader)
800 {
801  GLuint p;
802  GLint status;
803 
804  if (GLEW_VERSION_2_0)
805  {
806  p = glCreateProgram();
807 
808  glAttachShader(p, vertexShader);
809  glAttachShader(p, fragmentShader);
810 
811  glLinkProgram(p);
812  glGetProgramiv(p, GL_LINK_STATUS, &status);
813  if (status != GL_TRUE)
814  {
815  GLsizei logLength;
816 
817  glGetProgramiv(p, GL_INFO_LOG_LENGTH, &logLength);
818 
819  if (logLength > 0)
820  {
821  char *log;
822  GLsizei charsWritten;
823 
824  log = (char*)malloc(logLength);
825  glGetProgramInfoLog(p, logLength, &charsWritten, log);
826  PyErr_Format(PyExc_RuntimeError, "Error linking shader: %s", log);
827  free(log);
828  }
829  else
830  PyErr_SetString(PyExc_RuntimeError, "Error linking shader");
831 
832  return 0;
833  }
834 
835  return p;
836  }
837  else if (GLEW_ARB_shader_objects)
838  {
839  p = glCreateProgramObjectARB();
840 
841  glAttachObjectARB(p, vertexShader);
842  glAttachObjectARB(p, fragmentShader);
843 
844  glLinkProgramARB(p);
845  glGetObjectParameterivARB(p, GL_OBJECT_LINK_STATUS_ARB , &status);
846  if (status != GL_TRUE)
847  {
848  GLsizei logLength;
849 
850  glGetObjectParameterivARB(p, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logLength);
851 
852  if (logLength > 0)
853  {
854  char *log;
855  GLsizei charsWritten;
856 
857  log = (char*)malloc(logLength);
858  glGetInfoLogARB(p, logLength, &charsWritten, log);
859  PyErr_Format(PyExc_RuntimeError, "Error linking shader: %s", log);
860  free(log);
861  }
862  else
863  PyErr_SetString(PyExc_RuntimeError, "Error linking shader");
864 
865  return 0;
866  }
867 
868  return p;
869  }
870  else
871  {
872  PyErr_SetString(PyExc_RuntimeError, "No shader support detected");
873  return 0;
874  }
875 }
876 
888 int mhGrabScreen(int x, int y, int width, int height, const char *filename)
889 {
890  GLint viewport[4];
891  SDL_Surface *surface;
892  GLenum format;
893 
894  if (width <= 0 || height <= 0)
895  {
896  PyErr_Format(PyExc_RuntimeError, "width or height is 0");
897  return 0;
898  }
899 
900  surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24, 0xFF, 0xFF00, 0xFF0000, 0);
901  glGetIntegerv(GL_VIEWPORT, viewport);
902 
903  if (SDL_LockSurface(surface))
904  {
905  SDL_FreeSurface(surface);
906  PyErr_Format(PyExc_RuntimeError, "Could not lock surface to grab region to file %s, %s", filename, SDL_GetError());
907  return 0;
908  }
909 
910  // Draw before grabbing, to make sure we grab a rendering and not a picking buffer
911  mhDraw();
912  glPixelStorei(GL_PACK_ALIGNMENT, 4);
913 
914  /* SDL interprets each pixel as a 32-bit number, so our masks must depend
915  on the endianness (byte order) of the machine (PowerPC is big endian
916  in contrast to i386 which is little endian!) */
917 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
918  format = GL_BGR; /* For big endian Machines as based on PowerPC */
919 #else
920  format = GL_RGB; /* For little endian Machines as based on Intel x86 */
921 #endif
922  glReadPixels(x, viewport[3] - y - height, width, height, format, GL_UNSIGNED_BYTE, surface->pixels);
923  mhFlipSurface(surface);
924 
925  SDL_UnlockSurface(surface);
926 
927  if (SDL_SaveBMP(surface, filename))
928  {
929  SDL_FreeSurface(surface);
930  PyErr_Format(PyExc_RuntimeError, "Could not access file to grab region to file %s, %s", filename, SDL_GetError());
931  return 0;
932  }
933 
934  SDL_FreeSurface(surface);
935  return 1;
936 }
937 
948 void mhKeyDown(int key, unsigned short character, int modifiers)
949 {
950  callKeyDown(key, character, modifiers);
951 }
952 
953 void mhKeyUp(int key, unsigned short character, int modifiers)
954 {
955  callKeyUp(key, character, modifiers);
956 
958 }
959 
977 unsigned int mhTimerFunc(unsigned int interval, void *param)
978 {
979  SDL_Event event;
980 
981  event.type = SDL_USEREVENT;
982  event.user.code = 0;
983  event.user.data1 = param;
984  event.user.data2 = NULL;
985 
986  SDL_PushEvent(&event);
987 
988  /*reset the timer to recall the function again, after interval milliseconds*/
989  return interval;
990 }
991 
1009 void mhMouseButtonDown(int b, int x, int y)
1010 {
1011  /* Since the mouse cursor doesn't move when a button is down, we
1012  save the mouse position and restore it later to avoid jumping.
1013  We also grab the input so we can move the (invisible) mouse outside the screen.
1014  */
1015  g_savedx=x;
1016  g_savedy=y;
1017 #ifdef __WIN32__
1018  SDL_WM_GrabInput(SDL_GRAB_ON);
1019 #endif
1020 
1021  // Check which object/group was hit
1022  if (b != 4 && b != 5)
1023  mhGetPickedColor(x, y);
1024 
1025  // Notify python
1026  callMouseButtonDown(b, x, y);
1027 
1028  // Update screen
1029  mhQueueUpdate();
1030 
1031  if (b != 4 && b != 5)
1033 }
1034 
1052 void mhMouseButtonUp(int b, int x, int y)
1053 {
1054  /* Since the mouse cursor doesn't move when a button is down, we
1055  save the mouse position and restore it later to avoid jumping.
1056  We also ungrab the previously grabbed input
1057  */
1058 #ifdef __WIN32__
1059  SDL_WM_GrabInput(SDL_GRAB_OFF);
1060 #endif
1061 
1062  // Check which object/group was hit
1063  if (b != 4 && b != 5)
1064  {
1065  mhGetPickedColor(x, y);
1066  }
1067 
1068  // Notify python
1069  callMouseButtonUp(b, x, y);
1070 
1071  // Update screen
1072  mhQueueUpdate();
1073 
1075 }
1076 
1096 void mhMouseMotion(int s, int x, int y, int xrel, int yrel)
1097 {
1098  // Check which object/group was hit
1099  if (!s)
1100  mhGetPickedColor(x, y);
1101 
1102  // Notify python
1103  callMouseMotion(s, x, y, xrel, yrel);
1104 
1105  // Update screen
1106  if (s)
1107  mhQueueUpdate();
1108 }
1109 
1110 static unsigned char *pickingBuffer = NULL;
1111 static int pickingBufferSize = 0;
1112 
1114 {
1115  int i;
1116  // Get the viewport
1117  GLint viewport[4];
1118  GLint width;
1119  GLint height;
1120  glGetIntegerv(GL_VIEWPORT, viewport);
1121 
1122  width = viewport[2];
1123  height = viewport[3];
1124 
1125  // Resize the buffer in case the window size has changed
1126  if (pickingBufferSize != width * height * 3)
1127  {
1128  pickingBufferSize = width * height * 3;
1129  pickingBuffer = (unsigned char*)realloc(pickingBuffer, pickingBufferSize);
1130  assert(pickingBuffer != NULL);
1131  }
1132 
1133  // Turn off lighting
1134  glDisable(GL_LIGHTING);
1135 
1136  // Turn off antialiasing
1137  glDisable (GL_BLEND);
1138  glDisable(GL_MULTISAMPLE);
1139 
1140  // Clear screen
1141  glClearColor(0.0, 0.0, 0.0, 0.0);
1142  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1143 
1144  for (i = 0; i < PyList_Size(G.cameras); i++)
1145  {
1146  mhCameraPosition((Camera*)PyList_GetItem(G.cameras, i), 0);
1147  mhDrawMeshes(1, i);
1148  }
1149 
1150  // Make sure the data is 1 byte aligned
1151  glPixelStorei(GL_PACK_ALIGNMENT, 1);
1152  //glFlush();
1153  //glFinish();
1154  glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pickingBuffer);
1155  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1156 
1157  // Turn on antialiasing
1158  glEnable (GL_BLEND);
1159  glEnable(GL_MULTISAMPLE);
1160 
1161  /* restore lighting */
1162  glEnable(GL_LIGHTING);
1163 
1164  /* hdusel: Bugfix for http://code.google.com/p/makehuman/issues/detail?id=16
1165  * "Red and black window - 'selection rendering'"
1166  *
1167  * This error happened for the OS X port only
1168  *
1169  * So I enforce a redraw whenever the picking buffer will be updated.
1170  * But I'm not certain weather we need this for OS X only? */
1171 #ifdef __APPLE__
1172  mhDraw();
1173 #endif
1174 }
1175 
1199 void mhGetPickedColor(int x, int y)
1200 {
1201  // Viewport declaration (required before other expressions)
1202  GLint viewport[4];
1203 
1204  glGetIntegerv(GL_VIEWPORT, viewport);
1205 
1206  y = viewport[3] - y;
1207 
1208  if (y < 0 || y >= viewport[3] || x < 0 || x >= viewport[2])
1209  {
1210  memset(G.color_picked, 0, 3);
1211  return;
1212  }
1213 
1214  if (!pickingBuffer)
1216 
1217  memcpy(G.color_picked, pickingBuffer + (y * viewport[2] + x) * 3, 3);
1218 }
1219 
1229 PyObject *Camera_convertToScreen(Camera *camera, PyObject *args)
1230 {
1231  GLint viewport[4];
1232  GLdouble modelview[16], projection[16];
1233  double world[3], screen[3];
1234 
1235  if (!PyArg_ParseTuple(args, "ddd", world, world + 1, world + 2))
1236  return NULL;
1237 
1238  mhCameraPosition(camera, 0);
1239 
1240  glGetIntegerv(GL_VIEWPORT, viewport);
1241  glGetDoublev(GL_PROJECTION_MATRIX, projection);
1242  glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
1243 
1244  gluProject(world[0], world[1], world[2], modelview, projection, viewport, screen, screen + 1, screen + 2);
1245  screen[1] = viewport[3] - screen[1];
1246 
1247  return Py_BuildValue("[d,d,d]", screen[0], screen[1], screen[2]);
1248 }
1249 
1259 PyObject *Camera_convertToWorld2D(Camera *camera, PyObject *args)
1260 {
1261  GLint viewport[4];
1262  GLdouble modelview[16], projection[16];
1263  GLdouble z;
1264  double screen[2], world[3];
1265 
1266  if (!PyArg_ParseTuple(args, "dd", screen, screen + 1))
1267  return NULL;
1268 
1269  mhCameraPosition(camera, 0);
1270 
1271  glGetIntegerv(GL_VIEWPORT, viewport);
1272  glGetDoublev(GL_PROJECTION_MATRIX, projection);
1273  glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
1274 
1275  glReadPixels((GLint)screen[0], (GLint)(viewport[3] - screen[1]), 1, 1, GL_DEPTH_COMPONENT, GL_DOUBLE, &z);
1276  gluUnProject(screen[0], viewport[3] - screen[1], z, modelview, projection, viewport, world, world + 1, world + 2);
1277 
1278  return Py_BuildValue("[d,d,d]", world[0], world[1], world[2]);
1279 }
1280 
1290 PyObject *Camera_convertToWorld3D(Camera *camera, PyObject *args)
1291 {
1292  GLint viewport[4];
1293  GLdouble modelview[16], projection[16];
1294  double screen[3], world[3];
1295 
1296  if (!PyArg_ParseTuple(args, "ddd", screen, screen + 1, screen + 2))
1297  return NULL;
1298 
1299  mhCameraPosition(camera, 0);
1300 
1301  glGetIntegerv(GL_VIEWPORT, viewport);
1302  glGetDoublev(GL_PROJECTION_MATRIX, projection);
1303  glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
1304 
1305  gluUnProject(screen[0], viewport[3] - screen[1], screen[2], modelview, projection, viewport, world, world + 1, world + 2);
1306 
1307  return Py_BuildValue("[d,d,d]", world[0], world[1], world[2]);
1308 }
1309 
1316 void mhReshape(int w, int h)
1317 {
1318  /*Prevent a division by zero when minimising the window*/
1319  if (h == 0)
1320  h = 1;
1321  /*Set the drawable region of the window*/
1322  glViewport(0, 0, w, h);
1323  // set up the projection matrix
1324  glMatrixMode(GL_PROJECTION);
1325  glLoadIdentity();
1326 
1327  // go back to modelview matrix so we can move the objects about
1328  glMatrixMode(GL_MODELVIEW);
1329  G.windowHeight = h;
1330  G.windowWidth = w;
1331 
1333 }
1334 
1340 void mhDrawBegin(void)
1341 {
1342  // clear the screen & depth buffer
1343  glClearColor(G.clearColor[0], G.clearColor[1], G.clearColor[2], G.clearColor[3]);
1344  glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
1345 }
1346 
1351 void mhDrawEnd(void)
1352 {
1353  SDL_GL_SwapBuffers();
1354 }
1355 
1360 void OnInit(void)
1361 {
1362  /*Lights and materials*/
1363  const float lightPos[] = { -10.99f, 20.0f, 20.0f, 1.0f}; /* Light Position */
1364  const float ambientLight[] = { 0.0f, 0.0f, 0.0f, 1.0f}; /* Ambient Light Values */
1365  const float diffuseLight[] = { 1.0f, 1.0f, 1.0f, 1.0f}; /* Diffuse Light Values */
1366  const float specularLight[] = {1.0f, 1.0f, 1.0f, 1.0f}; /* Specular Light Values */
1367  const float MatAmb[] = {0.11f, 0.11f, 0.11f, 1.0f}; /* Material - Ambient Values */
1368  const float MatDif[] = {1.0f, 1.0f, 1.0f, 1.0f}; /* Material - Diffuse Values */
1369  const float MatSpc[] = {0.2f, 0.2f, 0.2f, 1.0f}; /* Material - Specular Values */
1370  const float MatShn[] = {10.0f}; /* Material - Shininess */
1371  //const float MatEms[] = {0.1f, 0.05f, 0.0f, 1.0f}; /* Material - emission Values */
1372 
1373  glewInit();
1374 
1375  glEnable(GL_DEPTH_TEST); /* Hidden surface removal */
1376  //glEnable(GL_CULL_FACE); /* Inside face removal */
1377  //glEnable(GL_ALPHA_TEST);
1378  //glAlphaFunc(GL_GREATER, 0.0f);
1379  glDisable(GL_DITHER);
1380  glEnable(GL_LIGHTING); /* Enable lighting */
1381  glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
1382  glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
1383  glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
1384  glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
1385  glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); // If we enable this, we have stronger specular highlights
1386  glMaterialfv(GL_FRONT, GL_AMBIENT, MatAmb); /* Set Material Ambience */
1387  glMaterialfv(GL_FRONT, GL_DIFFUSE, MatDif); /* Set Material Diffuse */
1388  glMaterialfv(GL_FRONT, GL_SPECULAR, MatSpc); /* Set Material Specular */
1389  glMaterialfv(GL_FRONT, GL_SHININESS, MatShn); /* Set Material Shininess */
1390  //glMaterialfv(GL_FRONT, GL_EMISSION, MatEms); /* Set Material Emission */
1391  glEnable(GL_LIGHT0);
1392  glEnable(GL_COLOR_MATERIAL);
1393  glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
1394  //glEnable(GL_TEXTURE_2D);
1395  glEnable(GL_BLEND);
1396  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1397  /*Activate and specify pointers to vertex and normal array*/
1398  glEnableClientState(GL_NORMAL_ARRAY);
1399  glEnableClientState(GL_COLOR_ARRAY);
1400  glEnableClientState(GL_VERTEX_ARRAY);
1401 }
1402 
1407 void OnExit(void)
1408 {
1409  /*Deactivate the pointers to vertex and normal array*/
1410  glDisableClientState(GL_VERTEX_ARRAY);
1411  glDisableClientState(GL_NORMAL_ARRAY);
1412  //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1413  glDisableClientState(GL_COLOR_ARRAY);
1414  printf("Exit from event loop\n");
1415 }
1416 
1424 void mhCameraPosition(Camera *camera, int eye)
1425 {
1426  int stereoMode = 0;
1427  if (eye)
1428  stereoMode = camera->stereoMode;
1429 
1430  switch (stereoMode)
1431  {
1432  case 0: // No stereo
1433  {
1434  glMatrixMode(GL_PROJECTION);
1435  glLoadIdentity();
1436 
1437  if (camera->projection)
1438  gluPerspective(camera->fovAngle, (float)G.windowWidth/G.windowHeight, camera->nearPlane, camera->farPlane);
1439  else
1440  glOrtho(0.0, G.windowWidth, G.windowHeight, 0.0, camera->nearPlane, camera->farPlane);
1441 
1442  glMatrixMode(GL_MODELVIEW);
1443  glLoadIdentity();
1444  gluLookAt(camera->eyeX, camera->eyeY, camera->eyeZ, // Eye
1445  camera->focusX, camera->focusY, camera->focusZ, // Focus
1446  camera->upX, camera->upY, camera->upZ); // Up
1447  break;
1448  }
1449  case 1: // Toe-in method, uses different eye positions, same focus point and projection
1450  {
1451  glMatrixMode(GL_PROJECTION);
1452  glLoadIdentity();
1453  gluPerspective(camera->fovAngle, (float)G.windowWidth/G.windowHeight, camera->nearPlane, camera->farPlane);
1454 
1455  glMatrixMode(GL_MODELVIEW);
1456  glLoadIdentity();
1457 
1458  if (eye == 1)
1459  gluLookAt(camera->eyeX - 0.5 * camera->eyeSeparation, camera->eyeY, camera->eyeZ, // Eye
1460  camera->focusX, camera->focusY, camera->focusZ, // Focus
1461  camera->upX, camera->upY, camera->upZ); // Up
1462  else if (eye == 2)
1463  gluLookAt(camera->eyeX + 0.5 * camera->eyeSeparation, camera->eyeY, camera->eyeZ, // Eye
1464  camera->focusX, camera->focusY, camera->focusZ, // Focus
1465  camera->upX, camera->upY, camera->upZ); // Up
1466 
1467  break;
1468  }
1469  case 2: // Off-axis method, uses different eye positions, focus points and projections
1470  {
1471  double aspectratio = G.windowWidth / (double)G.windowHeight;
1472  double widthdiv2 = tan(camera->fovAngle * 3.14159/360.0) * camera->nearPlane;
1473  double left = - aspectratio * widthdiv2;
1474  double right = aspectratio * widthdiv2;
1475  double top = widthdiv2;
1476  double bottom = -widthdiv2;
1477  double eyePosition;
1478 
1479  if (eye == 1) // Left
1480  eyePosition = -0.5 * camera->eyeSeparation;
1481  else if (eye == 2) // Right
1482  eyePosition = 0.5 * camera->eyeSeparation;
1483  else
1484  eyePosition = 0.0;
1485 
1486  left -= eyePosition * camera->nearPlane / camera->eyeZ;
1487  right -= eyePosition * camera->nearPlane / camera->eyeZ;
1488 
1489  // Left frustum is moved right, right frustum moved left
1490  glMatrixMode(GL_PROJECTION);
1491  glLoadIdentity();
1492  glFrustum(left, right, bottom, top, camera->nearPlane, camera->farPlane);
1493 
1494  // Left camera is moved left, right camera moved right
1495  glMatrixMode(GL_MODELVIEW);
1496  glLoadIdentity();
1497  gluLookAt(camera->eyeX + eyePosition, camera->eyeY, camera->eyeZ, // Eye
1498  camera->focusX + eyePosition, camera->focusY, camera->focusZ, // Focus
1499  camera->upX, camera->upY, camera->upZ); // Up
1500 
1501  break;
1502  }
1503  }
1504 }
1505 
1530 void mhDrawMeshes(int pickMode, int cameraType)
1531 {
1532  PyObject *iterator;
1533  Object3D *obj;
1534 
1535  if (!G.world)
1536  {
1537  return;
1538  }
1539 
1540  /*Draw all objects contained by G.world*/
1541  iterator = PyObject_GetIter(G.world);
1542 
1543  for (obj = (Object3D*)PyIter_Next(iterator); obj; obj = (Object3D*)PyIter_Next(iterator))
1544  {
1545  if (!PyObject_TypeCheck(obj, &Object3DType))
1546  continue;
1547 
1548  if (obj->inMovableCamera == cameraType)
1549  {
1550  if (obj->isVisible && (!pickMode || obj->isPickable))
1551  {
1552  /*Transform the current object*/
1553  glPushMatrix();
1554  glTranslatef(obj->x, obj->y, obj->z);
1555  glRotatef(obj->rx, 1, 0, 0);
1556  glRotatef(obj->ry, 0, 1, 0);
1557  glRotatef(obj->rz, 0, 0, 1);
1558  glScalef(obj->sx, obj->sy, obj->sz);
1559 
1560  if (obj->texture && !pickMode && obj->isSolid)
1561  {
1562  glEnable(GL_TEXTURE_2D);
1563  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1564  glBindTexture(GL_TEXTURE_2D, obj->texture);
1565  glTexCoordPointer(2, GL_FLOAT, 0, obj->UVs);
1566  }
1567 
1568  /*Fill the array pointers with object mesh data*/
1569  glVertexPointer(3, GL_FLOAT, 0, obj->verts);
1570  glNormalPointer(GL_FLOAT, 0, obj->norms);
1571 
1572  /*Because the selection is based on color, the color array can have 2 values*/
1573  if (pickMode)
1574  {
1575  /*Use color to pick i */
1576  glColorPointer(3, GL_UNSIGNED_BYTE, 0, obj->colors);
1577  }
1578  else
1579  {
1580  /*Use color to draw i */
1581  glColorPointer(4, GL_UNSIGNED_BYTE, 0, obj->colors2);
1582  }
1583 
1584  /*Disable lighting if the object is shadeless*/
1585  if (obj->shadeless || pickMode)
1586  {
1587  glDisable(GL_LIGHTING);
1588  }
1589 
1590  // Enable the shader if the driver supports it and there is a shader assigned
1591  if (!pickMode && obj->shader && obj->isSolid)
1592  {
1593  if (GLEW_VERSION_2_0)
1594  {
1595 
1596  glUseProgram(obj->shader);
1597 
1598  // This should be optimized, since we only need to do it when it's changed
1599  // Validation should also only be done when it is set
1600  if (obj->shaderParameters)
1601  {
1602  GLint parameterCount = 0;
1603  int index;
1604  int currentTextureSampler = 1;
1605 
1606  glGetProgramiv(obj->shader, GL_ACTIVE_UNIFORMS, &parameterCount);
1607 
1608  for (index = 0; index < parameterCount; index++)
1609  {
1610  GLsizei length;
1611  GLint size;
1612  GLenum type;
1613  GLchar name[32];
1614  PyObject *value;
1615 
1616  glGetActiveUniform(obj->shader, index, sizeof(name), &length, &size, &type, name);
1617 
1618  value = PyDict_GetItemString(obj->shaderParameters, name);
1619 
1620  if (value)
1621  {
1622  switch (type)
1623  {
1624  case GL_FLOAT:
1625  {
1626  glUniform1f(index, PyFloat_AsDouble(value));
1627  break;
1628  }
1629  case GL_FLOAT_VEC2:
1630  {
1631  if (!PyList_Check(value) || PyList_Size(value) != 2)
1632  break;
1633  glUniform2f(index, PyFloat_AsDouble(PyList_GetItem(value, 0)), PyFloat_AsDouble(PyList_GetItem(value, 1)));
1634  break;
1635  }
1636  case GL_FLOAT_VEC3:
1637  {
1638  if (!PyList_Check(value) || PyList_Size(value) != 3)
1639  break;
1640  glUniform3f(index, PyFloat_AsDouble(PyList_GetItem(value, 0)), PyFloat_AsDouble(PyList_GetItem(value, 1)),
1641  PyFloat_AsDouble(PyList_GetItem(value, 2)));
1642  break;
1643  }
1644  case GL_FLOAT_VEC4:
1645  {
1646  if (!PyList_Check(value) || PyList_Size(value) != 4)
1647  break;
1648  glUniform4f(index, PyFloat_AsDouble(PyList_GetItem(value, 0)), PyFloat_AsDouble(PyList_GetItem(value, 1)),
1649  PyFloat_AsDouble(PyList_GetItem(value, 2)), PyFloat_AsDouble(PyList_GetItem(value, 3)));
1650  break;
1651  }
1652  case GL_SAMPLER_1D:
1653  {
1654  glActiveTexture(GL_TEXTURE0 + currentTextureSampler);
1655  glBindTexture(GL_TEXTURE_1D, PyInt_AsLong(value));
1656  glUniform1i(index, currentTextureSampler++);
1657  break;
1658  }
1659  case GL_SAMPLER_2D:
1660  {
1661  glActiveTexture(GL_TEXTURE0 + currentTextureSampler);
1662  glBindTexture(GL_TEXTURE_2D, PyInt_AsLong(value));
1663  glUniform1i(index, currentTextureSampler++);
1664  break;
1665  }
1666  }
1667  }
1668  }
1669  }
1670  }
1671  else if (GLEW_ARB_shader_objects)
1672  {
1673  glUseProgramObjectARB(obj->shader);
1674 
1675  // This should be optimized, since we only need to do it when it's changed
1676  // Validation should also only be done when it is set
1677  if (obj->shaderParameters)
1678  {
1679  GLint parameterCount = 0;
1680  int index;
1681  int currentTextureSampler = 1;
1682 
1683  glGetObjectParameterivARB(obj->shader, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &parameterCount);
1684 
1685  for (index = 0; index < parameterCount; index++)
1686  {
1687  GLsizei length;
1688  GLint size;
1689  GLenum type;
1690  GLchar name[32];
1691  PyObject *value;
1692 
1693  glGetActiveUniformARB(obj->shader, index, sizeof(name), &length, &size, &type, name);
1694 
1695  value = PyDict_GetItemString(obj->shaderParameters, name);
1696 
1697  if (value)
1698  {
1699  switch (type)
1700  {
1701  case GL_FLOAT:
1702  {
1703  glUniform1fARB(index, PyFloat_AsDouble(value));
1704  break;
1705  }
1706  case GL_FLOAT_VEC2:
1707  {
1708  if (!PyList_Check(value) || PyList_Size(value) != 2)
1709  break;
1710  glUniform2fARB(index, PyFloat_AsDouble(PyList_GetItem(value, 0)), PyFloat_AsDouble(PyList_GetItem(value, 1)));
1711  break;
1712  }
1713  case GL_FLOAT_VEC3:
1714  {
1715  if (!PyList_Check(value) || PyList_Size(value) != 3)
1716  break;
1717  glUniform3fARB(index, PyFloat_AsDouble(PyList_GetItem(value, 0)), PyFloat_AsDouble(PyList_GetItem(value, 1)),
1718  PyFloat_AsDouble(PyList_GetItem(value, 2)));
1719  break;
1720  }
1721  case GL_FLOAT_VEC4:
1722  {
1723  if (!PyList_Check(value) || PyList_Size(value) != 4)
1724  break;
1725  glUniform4fARB(index, PyFloat_AsDouble(PyList_GetItem(value, 0)), PyFloat_AsDouble(PyList_GetItem(value, 1)),
1726  PyFloat_AsDouble(PyList_GetItem(value, 2)), PyFloat_AsDouble(PyList_GetItem(value, 3)));
1727  break;
1728  }
1729  case GL_SAMPLER_1D:
1730  {
1731  glActiveTexture(GL_TEXTURE0 + currentTextureSampler);
1732  glBindTexture(GL_TEXTURE_1D, PyInt_AsLong(value));
1733  glUniform1iARB(index, currentTextureSampler++);
1734  break;
1735  }
1736  case GL_SAMPLER_2D:
1737  {
1738  glActiveTexture(GL_TEXTURE0 + currentTextureSampler);
1739  glBindTexture(GL_TEXTURE_2D, PyInt_AsLong(value));
1740  glUniform1iARB(index, currentTextureSampler++);
1741  break;
1742  }
1743  }
1744  }
1745  }
1746  }
1747  }
1748  }
1749 
1750  /*draw the mesh*/
1751  if (!obj->isSolid && !pickMode)
1752  {
1753  glDisableClientState(GL_COLOR_ARRAY);
1754  glColor3f(0.0f, 0.0f, 0.0f);
1755  glPolygonMode(GL_FRONT_AND_BACK , GL_LINE);
1756  glDrawElements(GL_QUADS, obj->nQuads * 4, GL_UNSIGNED_INT, obj->quads);
1757  glEnableClientState(GL_COLOR_ARRAY);
1758  glPolygonMode(GL_FRONT_AND_BACK , GL_FILL);
1759  glEnable(GL_POLYGON_OFFSET_FILL);
1760  glPolygonOffset(1.0, 1.0);
1761  glDrawElements(GL_QUADS, obj->nQuads * 4, GL_UNSIGNED_INT, obj->quads);
1762  glDisable(GL_POLYGON_OFFSET_FILL);
1763  }
1764  else
1765  glDrawElements(GL_QUADS, obj->nQuads * 4, GL_UNSIGNED_INT, obj->quads);
1766 
1767  // Disable the shader if the driver supports it and there is a shader assigned
1768  if (!pickMode && obj->shader && obj->isSolid)
1769  {
1770  if (GLEW_VERSION_2_0)
1771  glUseProgram(0);
1772  else if (GLEW_ARB_shader_objects)
1773  glUseProgramObjectARB(0);
1774  glActiveTexture(GL_TEXTURE0);
1775  }
1776 
1777  /*Enable lighting if the object was shadeless*/
1778  if (obj->shadeless || pickMode)
1779  {
1780  glEnable(GL_LIGHTING);
1781  }
1782 
1783  if (obj->texture && !pickMode && obj->isSolid)
1784  {
1785  glDisable(GL_TEXTURE_2D);
1786  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1787  }
1788 
1789  glPopMatrix();
1790  }
1791  }
1792 
1793  Py_DECREF((PyObject*)obj);
1794  }
1795 
1796  Py_DECREF(iterator);
1797 }
1798 
1805 void mhDraw(void)
1806 {
1807  int i;
1808  mhDrawBegin();
1809 
1810  for (i = 0; i < PyList_Size(G.cameras); i++)
1811  {
1812  Camera *camera = (Camera*)PyList_GetItem(G.cameras, i);
1813 
1814  // draw the objects in dynamic camera
1815  if (camera->stereoMode)
1816  {
1817  glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE); // Red
1818  mhCameraPosition(camera, 1);
1819  mhDrawMeshes(0, i);
1820  glClear(GL_DEPTH_BUFFER_BIT);
1821  glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE); // Cyan
1822  mhCameraPosition(camera, 2);
1823  mhDrawMeshes(0, i);
1824  // To prevent the GUI from overwritting the red model, we need to render it again in the z-buffer
1825  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // None, only z-buffer
1826  mhCameraPosition(camera, 1);
1827  mhDrawMeshes(0, i);
1828  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // All
1829  }
1830  else
1831  {
1832  mhCameraPosition(camera, 0);
1833  mhDrawMeshes(0, i);
1834  }
1835  }
1836 
1837  mhDrawEnd();
1838 }
1839 
1847 void mhShutDown(void)
1848 {
1849  G.loop = 0;
1850 }
1851 
1858 void mhQueueUpdate(void)
1859 {
1860  SDL_Event ev;
1861 
1862  if (G.pendingUpdate)
1863  {
1864  return;
1865  }
1866 
1867  G.pendingUpdate = 1;
1868 
1869  ev.type = SDL_VIDEOEXPOSE;
1870  SDL_PushEvent(&ev);
1871 }
1872 
1881 void mhSetFullscreen(int fullscreen)
1882 {
1883  if (G.fullscreen == fullscreen)
1884  {
1885  return;
1886  }
1887 
1888  G.fullscreen = fullscreen;
1889 
1890  if (fullscreen)
1891  {
1892  G.windowWidth = g_desktopWidth;
1893  G.windowHeight = g_desktopHeight;
1894  }
1895  else
1896  {
1897  G.windowWidth = g_windowWidth;
1898  G.windowHeight = g_windowHeight;
1899  }
1900 
1901  if (!g_screen)
1902  {
1903  return;
1904  }
1905 
1906  g_screen = SDL_SetVideoMode(G.windowWidth, G.windowHeight, 24, SDL_OPENGL | (G.fullscreen ? SDL_FULLSCREEN : 0) | SDL_RESIZABLE);
1907  OnInit();
1908  mhReshape(G.windowWidth, G.windowHeight);
1909  callResize(G.windowWidth, G.windowHeight, G.fullscreen);
1910  mhDraw();
1911 }
1912 
1920 void mhCreateWindow(int useTimer)
1921 {
1922  unsigned int colorkey;
1923  SDL_Surface *image;
1924  const SDL_VideoInfo *info;
1925 
1926  atexit(SDL_Quit);
1927 
1928  if (SDL_Init(SDL_INIT_VIDEO) < 0)
1929  {
1930  printf("Unable to init SDL: %s\n", SDL_GetError());
1931  exit(1);
1932  }
1933 
1934  SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
1935  SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
1936  SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
1937  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
1938  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
1939  SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1); // This fixes flickering in compiz
1940  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
1941  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
1942 
1943  info = SDL_GetVideoInfo();
1944  g_desktopWidth = info->current_w;
1945  g_desktopHeight = info->current_h;
1946 
1947  // Load and set window icon
1948  image = SDL_LoadBMP("mh_icon.bmp");
1949  if (image)
1950  {
1951  colorkey = SDL_MapRGB(image->format, 255, 255, 255);
1952  SDL_SetColorKey(image, SDL_SRCCOLORKEY, colorkey);
1953  SDL_WM_SetIcon(image, NULL);
1954  }
1955 
1956  if (G.fullscreen)
1957  {
1958  G.windowWidth = g_desktopWidth;
1959  G.windowHeight = g_desktopHeight;
1960  }
1961  else
1962  {
1963  G.windowWidth = g_windowWidth;
1964  G.windowHeight = g_windowHeight;
1965  }
1966 
1967  g_screen = SDL_SetVideoMode(G.windowWidth, G.windowHeight, 24, SDL_OPENGL | (G.fullscreen ? SDL_FULLSCREEN : 0) | SDL_RESIZABLE);
1968  if (g_screen == NULL)
1969  {
1970  printf("No antialiasing available, turning off antialiasing.\n");
1971  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
1972  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
1973  g_screen = SDL_SetVideoMode(G.windowWidth, G.windowHeight, 24, SDL_OPENGL | (G.fullscreen ? SDL_FULLSCREEN : 0) | SDL_RESIZABLE);
1974  if (g_screen == NULL)
1975  {
1976  printf("No 24 bit z buffer available, switching to 16 bit.\n");
1977  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
1978  g_screen = SDL_SetVideoMode(G.windowWidth, G.windowHeight, 24, SDL_OPENGL | (G.fullscreen ? SDL_FULLSCREEN : 0) | SDL_RESIZABLE);
1979  if (g_screen == NULL)
1980  {
1981  printf("No 16 bit z buffer available, exiting.\n");
1982  exit(1);
1983  }
1984  }
1985  }
1986 
1987  SDL_WM_SetCaption("MakeHuman", "");
1988  SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
1989 
1990 #ifdef __WIN32__
1991  SDL_EnableUNICODE(1);
1992 
1993 #endif
1994 
1995  if (useTimer == 1)
1996  {
1997  SDL_InitSubSystem(SDL_INIT_TIMER);
1998  }
1999 
2000  OnInit();
2001  mhReshape(G.windowWidth, G.windowHeight);
2002  mhDraw();
2003 }
2004 
2005 
2011 void mhEventLoop(void)
2012 {
2013  //SDL_ShowCursor(SDL_DISABLE);
2014 
2015  while (G.loop)
2016  {
2017  SDL_Event event;
2018 
2019  Py_BEGIN_ALLOW_THREADS
2020  SDL_WaitEvent(&event);
2021  Py_END_ALLOW_THREADS
2022 
2023  /* On OS-X SDL continuously posts events even when a native dialog or
2024  * Window is opened. So if the ActiveWindow (focused Window) is not
2025  * the main window then cancel the SDL Event.
2026  */
2027 #ifdef __APPLE__
2028  extern int isMainWindowActive(); // Defined in SDLMain.mm
2029 
2030  // Consider this event only if the main window is active.
2031  if (!isMainWindowActive())
2032  continue;
2033 #endif /* __APPLE__ */
2034 
2035  switch (event.type)
2036  {
2037  case SDL_ACTIVEEVENT:
2038  if (event.active.state & SDL_APPINPUTFOCUS)
2039  {
2040  if (event.active.gain)
2041  {
2042  //SDL_ShowCursor(SDL_DISABLE);
2043  }
2044  else
2045  {
2046  //SDL_ShowCursor(SDL_ENABLE);
2047 #ifdef __WIN32__
2048  SDL_WM_GrabInput(SDL_GRAB_OFF);
2049 #endif
2050  }
2051  }
2052  break;
2053  case SDL_KEYDOWN:
2054  mhKeyDown(event.key.keysym.sym, event.key.keysym.unicode, event.key.keysym.mod);
2055  break;
2056  case SDL_KEYUP:
2057  if (event.key.keysym.sym == SDLK_F11 || (event.key.keysym.sym == SDLK_RETURN && event.key.keysym.mod & KMOD_ALT))
2058  mhSetFullscreen(!G.fullscreen); // Switch fullscreen
2059  else
2060  mhKeyUp(event.key.keysym.sym, event.key.keysym.unicode, event.key.keysym.mod);
2061  break;
2062  case SDL_MOUSEMOTION:
2063  {
2064 #if defined(WIN32) || defined(__APPLE__)
2065  mhMouseMotion(event.motion.state, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
2066 #else
2067  int x, y;
2068  SDL_GetMouseState(&x, &y);
2069  if (x == event.motion.x && y == event.motion.y)
2070  mhMouseMotion(event.motion.state, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
2071 #endif
2072  break;
2073  }
2074  case SDL_MOUSEBUTTONDOWN:
2075  mhMouseButtonDown(event.button.button, event.button.x, event.button.y);
2076  break;
2077  case SDL_MOUSEBUTTONUP:
2078  mhMouseButtonUp(event.button.button, event.button.x, event.button.y);
2079  break;
2080  case SDL_USEREVENT:
2081  switch (event.user.code)
2082  {
2083  case 0:
2084  if (!PyObject_CallFunction((PyObject*)event.user.data1, ""))
2085  PyErr_Print();
2086  break;
2087  case 1:
2088  if (!PyObject_CallFunction((PyObject*)event.user.data1, ""))
2089  PyErr_Print();
2090  Py_DECREF((PyObject*)event.user.data1);
2091  break;
2092  }
2093  break;
2094  case SDL_VIDEORESIZE:
2095  G.windowWidth = g_windowWidth = event.resize.w;
2096  G.windowHeight = g_windowHeight = event.resize.h;
2097  g_screen = SDL_SetVideoMode(G.windowWidth, G.windowHeight, 24, SDL_OPENGL | (G.fullscreen ? SDL_FULLSCREEN : 0) | SDL_RESIZABLE);
2098  OnInit();
2099  mhReshape(event.resize.w, event.resize.h);
2100  callResize(event.resize.w, event.resize.h, G.fullscreen);
2101  mhDraw();
2102  break;
2103  case SDL_VIDEOEXPOSE:
2104  mhDraw();
2105  G.pendingUpdate = 0;
2106  break;
2107  case SDL_QUIT:
2108  mhShutDown();
2109  break;
2110  }
2111  }
2112 
2113  OnExit();
2114 }