Tachyon (current)  Current Main Branch
glwin.c
Go to the documentation of this file.
1 /*
2  * glwin.c -- Simple self-contained code for opening an
3  * OpenGL-capable display window with a double buffered
4  * mono or stereoscopic visual, and for receiving
5  * and decoding window-system events from
6  * Spaceball/SpaceNavigator/Magellen 6DOF input devices.
7  *
8  * This code is primarily meant for 2-D image display
9  * or for trivial 3-D rendering usage without any GLX/WGL
10  * extensions that have to be enumerated prior to
11  * window creation.
12  *
13  * This file is part of the Tachyon ray tracer.
14  * John E. Stone - john.stone@gmail.com
15  *
16  * (C) Copyright 1994-2022 John E. Stone
17  * SPDX-License-Identifier: BSD-3-Clause
18  *
19  * $Id: glwin.c,v 1.140 2022/02/18 18:18:36 johns Exp $
20  *
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <math.h>
26 #include <string.h>
27 #include "glwin.h"
28 
29 /* Support for compilation as part of VMD for interactive */
30 /* ray tracing display. */
31 #if defined(VMDOPENGL)
32 #define USEOPENGL
33 #endif
34 
35 #if defined(USEOPENGL)
36 
37 /* The Linux OpenGL ABI 1.0 spec requires that that GL_GLEXT_PROTOTYPES be
38  * defined before including gl.h or glx.h for extensions in order to get
39  * prototypes: http://oss.sgi.com/projects/ogl-sample/ABI/index.html
40  */
41 #define GL_GLEXT_PROTOTYPES 1
42 #define GLX_GLXEXT_PROTOTYPES 1
43 
44 #if (defined(WIN32) || defined(_WIN64)) && defined(_MSC_VER)
45 /*
46  * Win32
47  */
48 #ifndef _WIN32_WINNT
49 #define _WIN32_WINNT 0x0400 /* hack for definition of wheel event codes */
50 #endif
51 #include <windows.h>
52 #include <winuser.h> /* mouse wheel event codes */
53 #include <GL/gl.h>
54 /* 3DxWare driver */
55 #if defined(VMDSPACEWARE) && (defined(WIN32) || defined(_WIN64))
56 #define OS_WIN32 1
57 #include "spwmacro.h" /* Spaceware include files */
58 #include "si.h" /* Spaceware include files */
59 #endif
60 #else
61 /*
62  * X11
63  */
64 #include <X11/Xlib.h>
65 #include <X11/keysym.h>
66 #include <X11/Xatom.h>
67 
68 #if defined(USEEGL)
69 /* use EGL for window management */
70 #include <EGL/egl.h>
71 #else
72 /* use GLX for window management */
73 #include <GL/glx.h>
74 #endif
75 
76 /* use full OpenGL */
77 #include <GL/gl.h>
78 #endif
79 
80 /*
81  * Optionally enable advanced OpenGL shaders for HMD usage, etc.
82  */
83 #if defined(USEGLEXT)
84 
85 /* NOTE: you may have to get copies of the latest OpenGL extension headers
86  * from the OpenGL web site if your Linux machine lacks them:
87  * http://oss.sgi.com/projects/ogl-sample/registry/
88  */
89 #if (defined(__linux) || defined(_MSC_VER))
90 #include <GL/glext.h>
91 #endif
92 
93 /* not needed with recent OSX 10.9 revs */
94 #if 0 && defined(__APPLE__)
95 #include <OpenGL/glext.h>
96 #endif
97 
98 /* required for Win32 calling conventions to work correctly */
99 #ifndef APIENTRY
100 #define APIENTRY
101 #endif
102 #ifndef GLAPI
103 #define GLAPI extern
104 #endif
105 
106 #endif
107 
108 /*
109  * Spaceball/Magellan/SpaceNavigator handle data structures
110  */
111 
112 /* Window system event handling data */
113 typedef struct {
114 #if (defined(WIN32) || defined(_WIN64)) && defined(_MSC_VER)
115 #if defined(USESPACEWARE)
116  /* 3DxWare driver */
117  SiHdl sball;
118  SiSpwEvent spwevent;
119  SiGetEventData spwedata;
120 #else
121  int foo;
122 #endif
123 #else
124  /* Xlib ClientMessage-based driver */
125  Display *dpy;
126  Window drv_win;
127  Window app_win;
128  Atom ev_motion;
129  Atom ev_button_press;
130  Atom ev_button_release;
131  Atom ev_command;
132 #endif
133 } spaceballhandle;
134 
135 
136 /* Platform-independent Spaceball event record */
137 typedef struct {
138  int event;
139  int rx;
140  int ry;
141  int rz;
142  int tx;
143  int ty;
144  int tz;
145  int buttons;
146  int period;
147 } spaceballevent;
148 
149 
150 #if !(defined(WIN32) || defined(_WIN64))
151 /* GLSL shader state */
152 typedef struct {
153  int isvalid;
154  GLhandleARB ProgramObject;
155  GLhandleARB VertexShaderObject;
156  GLhandleARB FragmentShaderObject;
157  int lastshader;
158 } glsl_shader;
159 #endif
160 
161 /* struct to provide access to key GLSL shader routines */
162 typedef struct {
163  int oglmajor;
164  int oglminor;
165  int oglrelease;
167  int hasglshaderobjectsarb;
168  int hasglvertexshaderarb;
169  int hasglfragmentshaderarb;
170  int hasglgeometryshader4arb;
171  int hasglsampleshadingarb;
172  int hasglshadinglangarb;
173  int hasglfborendertarget;
174  int hasgetvideosyncsgi;
175 
176 /* when extensions are found in the headers, we include them in the struct */
177 #if defined(GL_ARB_shader_objects)
178  /* GLSL fctn ptrs */
179  GLhandleARB (APIENTRY *p_glCreateShaderObjectARB)(GLenum shaderType);
180  GLhandleARB (APIENTRY *p_glCreateProgramObjectARB)(void);
181  void (APIENTRY *p_glUseProgramObjectARB)(GLhandleARB programObj);
182  void (APIENTRY *p_glDetachObjectARB)(GLhandleARB containerObj, GLhandleARB attachedObj);
183  void (APIENTRY *p_glGetInfoLogARB)(GLhandleARB obj,GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
184  void (APIENTRY *p_glGetObjectParameterivARB)(GLhandleARB obj, GLenum pname, GLint *params);
185  void (APIENTRY *p_glLinkProgramARB)(GLhandleARB programObj);
186  void (APIENTRY *p_glDeleteObjectARB)(GLhandleARB obj);
187  void (APIENTRY *p_glAttachObjectARB)(GLhandleARB containerObj, GLhandleARB obj);
188  void (APIENTRY *p_glCompileShaderARB)(GLhandleARB shaderObj);
189  void (APIENTRY *p_glShaderSourceARB)(GLhandleARB shaderObj, GLsizei count, const GLcharARB **strings, const GLint *length);
190  GLint (APIENTRY *p_glGetUniformLocationARB)(GLhandleARB programObject, const GLcharARB *name);
191  void (APIENTRY *p_glUniform1iARB)(GLint location, GLint v0);
192  void (APIENTRY *p_glUniform1fvARB)(GLint location, GLsizei count, GLfloat *value);
193  void (APIENTRY *p_glUniform2fvARB)(GLint location, GLsizei count, GLfloat *value);
194  void (APIENTRY *p_glUniform3fvARB)(GLint location, GLsizei count, GLfloat *value);
195  void (APIENTRY *p_glUniform4fvARB)(GLint location, GLsizei count, GLfloat *value);
196 
197  /* FBO and render target fctns */
198  void (APIENTRY *p_glGenFramebuffers)(GLsizei n, GLuint * framebuffers);
199  void (APIENTRY *p_glBindFramebuffer)(GLenum target, GLuint framebuffer);
200  void (APIENTRY *p_glGenRenderbuffers)(GLsizei n, GLuint * renderbuffers);
201  void (APIENTRY *p_glBindRenderbuffer)(GLenum target, GLuint renderbuffer);
202  void (APIENTRY *p_glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
203  void (APIENTRY *p_glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
204  void (APIENTRY *p_glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
205  GLenum (APIENTRY *p_glCheckFramebufferStatus)(GLenum target);
206  void (APIENTRY *p_glDeleteRenderbuffers)(GLsizei n, const GLuint * renderbuffers);
207  void (APIENTRY *p_glDeleteFramebuffers)(GLsizei n, const GLuint * framebuffers);
208  void (APIENTRY *p_glDrawBuffers)(GLsizei n, const GLenum *bufs);
209 #endif
210 
211  /* SGI video sync query extension */
212  int (APIENTRY *p_glXGetVideoSyncSGI)(GLuint *count);
213 } glwin_ext_fctns;
214 
215 
216 #if defined(GL_ARB_shader_objects)
217 /* GLSL shader functions */
218 #define GLCREATESHADEROBJECTARB ext->p_glCreateShaderObjectARB
219 #define GLCREATEPROGRAMOBJECTARB ext->p_glCreateProgramObjectARB
220 #define GLUSEPROGRAMOBJECTARB ext->p_glUseProgramObjectARB
221 #define GLDETACHOBJECTARB ext->p_glDetachObjectARB
222 #define GLGETINFOLOGARB ext->p_glGetInfoLogARB
223 #define GLGETOBJECTPARAMETERIVARB ext->p_glGetObjectParameterivARB
224 #define GLLINKPROGRAMARB ext->p_glLinkProgramARB
225 #define GLDELETEOBJECTARB ext->p_glDeleteObjectARB
226 #define GLATTACHOBJECTARB ext->p_glAttachObjectARB
227 #define GLCOMPILESHADERARB ext->p_glCompileShaderARB
228 #define GLSHADERSOURCEARB ext->p_glShaderSourceARB
229 #define GLGETUNIFORMLOCATIONARB ext->p_glGetUniformLocationARB
230 #define GLUNIFORM1IARB ext->p_glUniform1iARB
231 #define GLUNIFORM1FVARB ext->p_glUniform1fvARB
232 #define GLUNIFORM2FVARB ext->p_glUniform2fvARB
233 #define GLUNIFORM3FVARB ext->p_glUniform3fvARB
234 #define GLUNIFORM4FVARB ext->p_glUniform4fvARB
235 
236 /* FBO and render buffer management functions */
237 #define GLGENFRAMEBUFFERS ext->p_glGenFramebuffers
238 #define GLBINDFRAMEBUFFER ext->p_glBindFramebuffer
239 #define GLGENRENDERBUFFERS ext->p_glGenRenderbuffers
240 #define GLBINDRENDERBUFFER ext->p_glBindRenderbuffer
241 #define GLRENDERBUFFERSTORAGE ext->p_glRenderbufferStorage
242 #define GLFRAMEBUFFERTEXTURE2D ext->p_glFramebufferTexture2D
243 #define GLFRAMEBUFFERRENDERBUFFER ext->p_glFramebufferRenderbuffer
244 #define GLCHECKFRAMEBUFFERSTATUS ext->p_glCheckFramebufferStatus
245 #define GLDELETERENDERBUFFERS ext->p_glDeleteRenderbuffers
246 #define GLDELETEFRAMEBUFFERS ext->p_glDeleteFramebuffers
247 #define GLDRAWBUFFERS ext->p_glDrawBuffers
248 
249 /* video sync extensions */
250 #define GLXGETVIDEOSYNCSGI ext->p_glXGetVideoSyncSGI
251 #endif
252 
253 
254 /* OS and windowing system-specific handle data */
255 typedef struct {
256 #if (defined(WIN32) || defined(_WIN64)) && defined(_MSC_VER)
257  HWND hWnd;
258  HDC hDC;
259  HGLRC hRC;
260  long scrwidth;
261  long scrheight;
262  long MouseFlags;
263 #else
264  int scrnum;
265  Display *dpy;
266  Window root;
267  Window win;
268  Atom wmDeleteWindow;
269 #if defined(USEEGL)
270  EGLDisplay egldpy;
271  EGLConfig eglconf;
272  EGLSurface eglsurf;
273  EGLContext eglctx;
274 #else
275  GLXContext ctx;
276 #endif
277 #endif
278 
279  int havestencil;
280  int instereo;
282  int width;
283  int height;
284  int xpos;
285  int ypos;
286  int mousex;
287  int mousey;
288  int evdev;
289  int evval;
290  char evkey;
292  int havefocus;
293  spaceballhandle *sball;
294  spaceballevent sballevent;
296  glwin_ext_fctns *ext;
297 } oglhandle;
298 
299 
300 #if defined(USEOPENGL) && !defined(USEEGL) && !(defined(WIN32) || defined(_WIN64)) && !defined(_MSC_VER)
301 static int glx_query_extension(Display *dpy, const char *extname) {
302  char *ext;
303  char *endext;
304  if (!extname)
305  return 0;
306 
307  /* check for GLX extensions too */
308  ext = (char *) glXQueryExtensionsString(dpy, 0);
309  if (ext != NULL) {
310  endext = ext + strlen(ext);
311  while (ext < endext) {
312  size_t n = strcspn(ext, " ");
313  if ((strlen(extname) == n) && (strncmp(extname, ext, n) == 0)) {
314  return 1; /* extension is available */
315  break;
316  }
317  ext += (n + 1);
318  }
319  }
320 
321  return 0; /* False, extension is not available */
322 }
323 #endif
324 
325 
326 /* static helper routines for handling quaternions from HMDs */
327 static void quat_rot_matrix(float *m, const float *q) {
328  m[ 0] = 1.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]);
329  m[ 1] = 2.0f * (q[0] * q[1] - q[2] * q[3]);
330  m[ 2] = 2.0f * (q[2] * q[0] + q[1] * q[3]);
331  m[ 3] = 0.0f;
332 
333  m[ 4] = 2.0f * (q[0] * q[1] + q[2] * q[3]);
334  m[ 5] = 1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]);
335  m[ 6] = 2.0f * (q[1] * q[2] - q[0] * q[3]);
336  m[ 7] = 0.0f;
337 
338  m[ 8] = 2.0f * (q[2] * q[0] - q[1] * q[3]);
339  m[ 9] = 2.0f * (q[1] * q[2] + q[0] * q[3]);
340  m[10] = 1.0f - 2.0f * (q[1] * q[1] + q[0] * q[0]);
341  m[11] = 0.0f;
342 
343  m[12] = 0.0f;
344  m[13] = 0.0f;
345  m[14] = 0.0f;
346  m[15] = 1.0f;
347 }
348 
349 
350 /* prevent vendor-specific header file clashes */
351 typedef void (APIENTRY *glwin_fctnptr)(void);
352 
353 /* static helper to query GL fctn pointers */
354 void * glwin_get_procaddress(const char * procname) {
355  void *fctn = NULL;
356  if (!procname)
357  return NULL;
358 
359 #if defined(_MSC_VER)
360  /* NOTE: wgl returns a context-dependent function pointer
361  * the function can only be called within the same wgl
362  * context in which it was generated.
363  */
364  fctn = (glwin_fctnptr) wglGetProcAddress((LPCSTR) procname);
365 #else
366 
367 #if !defined(_MSC_VER) && !defined(__APPLE__)
368  /* GLX 1.4 form found on commercial Unix systems that
369  * don't bother providing the ARB extension version that Linux prefers.
370  */
371  fctn = glXGetProcAddressARB((const GLubyte *) procname);
372 #if 0
373  printf("GL fctn '%s' %s\n", procname, (fctn) ? "available" : "NULL");
374 #endif
375 #endif
376 
377 
378 #if defined(GLX_ARB_get_proc_address)
379  /* NOTE: GLX returns a context-independent function pointer that
380  * can be called anywhere, no special handling is required.
381  * This method is used on Linux
382  */
383  if (fctn == NULL) {
384  fctn = glXGetProcAddressARB((const GLubyte *) procname);
385 #if 0
386  printf("GLARB fctn '%s' %s\n", procname, (fctn) ? "available" : "NULL");
387 #endif
388  }
389 #endif
390 #endif
391 
392 #if 0
393  printf("GL fctn '%s' %s\n", procname, (fctn) ? "available" : "NULL");
394 #endif
395 
396  return fctn;
397 }
398 
399 
400 /* static helper routine to init OpenGL ext fctn pointers to NULL */
401 void glwin_init_exts(void * voidhandle) {
402  oglhandle * handle = (oglhandle *) voidhandle;
403  if (handle == NULL)
404  return;
405  glwin_ext_fctns *ext = handle->ext;
406 
407  /* clear everything to zeros, so all ptrs are NULL, */
408  /* and all flags are false. */
409  memset(ext, 0, sizeof(glwin_ext_fctns));
410 
411 #if defined(GL_ARB_shading_language_100)
412  /* check for the OpenGL Shading Language extension */
413  if (glwin_query_extension("GL_ARB_shading_language_100")) {
414  ext->hasglshadinglangarb = 1;
415  }
416 #endif
417 
418 #if defined(GL_ARB_shader_objects)
419  if (glwin_query_extension("GL_ARB_shader_objects")) {
420  ext->p_glCreateShaderObjectARB = (GLhandleARB (APIENTRY *)(GLenum)) glwin_get_procaddress("glCreateShaderObjectARB");
421  ext->p_glCreateProgramObjectARB = (GLhandleARB (APIENTRY *)(void)) glwin_get_procaddress("glCreateProgramObjectARB");
422  ext->p_glUseProgramObjectARB = (void (APIENTRY *)(GLhandleARB)) glwin_get_procaddress("glUseProgramObjectARB");
423  ext->p_glDetachObjectARB = (void (APIENTRY *)(GLhandleARB, GLhandleARB)) glwin_get_procaddress("glDetachObjectARB");
424  ext->p_glGetInfoLogARB = (void (APIENTRY *)(GLhandleARB, GLsizei, GLsizei *, GLcharARB *)) glwin_get_procaddress("glGetInfoLogARB");
425  ext->p_glGetObjectParameterivARB = (void (APIENTRY *)(GLhandleARB, GLenum, GLint *)) glwin_get_procaddress("glGetObjectParameterivARB");
426  ext->p_glLinkProgramARB = (void (APIENTRY *)(GLhandleARB)) glwin_get_procaddress("glLinkProgramARB");
427  ext->p_glDeleteObjectARB = (void (APIENTRY *)(GLhandleARB)) glwin_get_procaddress("glDeleteObjectARB");
428  ext->p_glAttachObjectARB = (void (APIENTRY *)(GLhandleARB, GLhandleARB)) glwin_get_procaddress("glAttachObjectARB");
429  ext->p_glCompileShaderARB = (void (APIENTRY *)(GLhandleARB)) glwin_get_procaddress("glCompileShaderARB");
430  ext->p_glShaderSourceARB = (void (APIENTRY *)(GLhandleARB, GLsizei, const GLcharARB **, const GLint *)) glwin_get_procaddress("glShaderSourceARB");
431  ext->p_glGetUniformLocationARB = (GLint (APIENTRY *)(GLhandleARB programObject, const GLcharARB *name)) glwin_get_procaddress("glGetUniformLocationARB");
432  ext->p_glUniform1iARB = (void (APIENTRY *)(GLint location, GLint v0)) glwin_get_procaddress("glUniform1iARB");
433  ext->p_glUniform1fvARB = (void (APIENTRY *)(GLint location, GLsizei count, GLfloat *value)) glwin_get_procaddress("glUniform1fvARB");
434  ext->p_glUniform2fvARB = (void (APIENTRY *)(GLint location, GLsizei count, GLfloat *value)) glwin_get_procaddress("glUniform2fvARB");
435  ext->p_glUniform3fvARB = (void (APIENTRY *)(GLint location, GLsizei count, GLfloat *value)) glwin_get_procaddress("glUniform3fvARB");
436  ext->p_glUniform4fvARB = (void (APIENTRY *)(GLint location, GLsizei count, GLfloat *value)) glwin_get_procaddress("glUniform4fvARB");
437 
438  if (ext->p_glCreateShaderObjectARB != NULL && ext->p_glCreateProgramObjectARB != NULL &&
439  ext->p_glUseProgramObjectARB != NULL && ext->p_glDetachObjectARB != NULL &&
440  ext->p_glGetInfoLogARB != NULL && ext->p_glGetObjectParameterivARB != NULL &&
441  ext->p_glLinkProgramARB != NULL && ext->p_glDeleteObjectARB != NULL &&
442  ext->p_glAttachObjectARB != NULL && ext->p_glCompileShaderARB != NULL &&
443  ext->p_glShaderSourceARB != NULL && ext->p_glGetUniformLocationARB != NULL &&
444  ext->p_glUniform1iARB != NULL && ext->p_glUniform1fvARB != NULL &&
445  ext->p_glUniform2fvARB != NULL && ext->p_glUniform3fvARB != NULL &&
446  ext->p_glUniform4fvARB != NULL) {
447  ext->hasglshaderobjectsarb = 1;
448  }
449  }
450 #endif
451 
452 #if defined(GL_ARB_vertex_shader)
453  if (glwin_query_extension("GL_ARB_vertex_shader")) {
454  ext->hasglvertexshaderarb = 1;
455  }
456 #endif
457 
458 #if defined(GL_ARB_fragment_shader)
459  if (glwin_query_extension("GL_ARB_fragment_shader")) {
460  ext->hasglfragmentshaderarb = 1;
461  }
462 #endif
463 
464 #if defined(GL_ARB_geometry_shader4)
465  if (glwin_query_extension("GL_ARB_geometry_shader4")) {
466  ext->hasglgeometryshader4arb = 1;
467  }
468 #endif
469 
470  if (glwin_query_extension("GL_ARB_sample_shading")) {
471  ext->hasglsampleshadingarb = 1;
472  }
473 
474 #if defined(GL_ARB_framebuffer_object)
475  /* routines for managing FBOs and render targets */
476  ext->p_glGenFramebuffers = (void (APIENTRY *)(GLsizei n, GLuint * framebuffers)) glwin_get_procaddress("glGenFramebuffers");
477  ext->p_glBindFramebuffer = (void (APIENTRY *)(GLenum target, GLuint framebuffer)) glwin_get_procaddress("glBindFramebuffer");
478  ext->p_glGenRenderbuffers = (void (APIENTRY *)(GLsizei n, GLuint * renderbuffers)) glwin_get_procaddress("glGenRenderbuffers");
479  ext->p_glBindRenderbuffer = (void (APIENTRY *)(GLenum target, GLuint renderbuffer)) glwin_get_procaddress("glBindRenderbuffer");
480  ext->p_glRenderbufferStorage = (void (APIENTRY *)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)) glwin_get_procaddress("glRenderbufferStorage");
481  ext->p_glFramebufferTexture2D = (void (APIENTRY *)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)) glwin_get_procaddress("glFramebufferTexture2D");
482  ext->p_glFramebufferRenderbuffer = (void (APIENTRY *)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)) glwin_get_procaddress("glFramebufferRenderbuffer");
483  ext->p_glCheckFramebufferStatus = (GLenum (APIENTRY *)(GLenum target)) glwin_get_procaddress("glCheckFramebufferStatus");
484  ext->p_glDeleteRenderbuffers = (void (APIENTRY *)(GLsizei n, const GLuint * renderbuffers)) glwin_get_procaddress("glDeleteRenderbuffers");
485  ext->p_glDeleteFramebuffers = (void (APIENTRY *)(GLsizei n, const GLuint * framebuffers)) glwin_get_procaddress("glDeleteFramebuffers");
486  ext->p_glDrawBuffers = (void (APIENTRY *)(GLsizei n, const GLenum *bufs)) glwin_get_procaddress("glDrawBuffers");
487 
488  if (ext->p_glGenFramebuffers != NULL &&
489  ext->p_glBindFramebuffer != NULL &&
490  ext->p_glGenRenderbuffers != NULL &&
491  ext->p_glBindRenderbuffer != NULL &&
492  ext->p_glRenderbufferStorage != NULL &&
493  ext->p_glFramebufferTexture2D != NULL &&
494  ext->p_glFramebufferRenderbuffer != NULL &&
495  ext->p_glCheckFramebufferStatus != NULL &&
496  ext->p_glDeleteRenderbuffers != NULL &&
497  ext->p_glDeleteFramebuffers != NULL &&
498  ext->p_glDrawBuffers != NULL) {
499  ext->hasglfborendertarget = 1;
500  }
501 #endif
502 
503 #if !(defined(WIN32) || defined(_WIN64))
504  if (glx_query_extension(handle->dpy, "GLX_SGI_video_sync")) {
505  ext->p_glXGetVideoSyncSGI = (int (APIENTRY *)(GLuint *count)) glwin_get_procaddress("glXGetVideoSyncSGI");
506 
507  if (ext->p_glXGetVideoSyncSGI != NULL)
508  ext->hasgetvideosyncsgi = 1;
509  }
510 #endif
511 
512 }
513 
514 
515 #if !(defined(WIN32) || defined(_WIN64)) && !defined(_MSC_VER)
516 /*
517  * X11 version
518  */
519 
520 /*
521  * Spaceball event handling routines
522  */
523 #define SBALL_COMMAND_NONE 0
524 #define SBALL_COMMAND_APP_WINDOW 27695
525 #define SBALL_COMMAND_APP_SENSITIVITY 27696
526 
527 /* enable 3Dxware Spaceball / Magellan / SpaceNavigator events */
528 static spaceballhandle * spaceball_attach(Display *dpy, Window win) {
529  /* allocate and clear handle data structure */
530  spaceballhandle *handle = (spaceballhandle *) calloc(1, sizeof(spaceballhandle));
531 
532  /* find and store X atoms for the event types we care about */
533  handle->ev_motion = XInternAtom(dpy, "MotionEvent", True);
534  handle->ev_button_press = XInternAtom(dpy, "ButtonPressEvent", True);
535  handle->ev_button_release = XInternAtom(dpy, "ButtonReleaseEvent", True);
536  handle->ev_command = XInternAtom(dpy, "CommandEvent", True);
537 
538  if (!handle->ev_motion || !handle->ev_button_press ||
539  !handle->ev_button_release || !handle->ev_command) {
540  free(handle);
541  return NULL; /* driver is not running */
542  }
543 
544  /* Find the root window of the driver */
545  Window root = RootWindow(dpy, DefaultScreen(dpy));
546 
547  /* Find the driver's window */
548  Atom ActualType;
549  int ActualFormat;
550  unsigned long NItems, BytesReturn;
551  unsigned char *PropReturn = NULL;
552  XGetWindowProperty(dpy, root, handle->ev_command, 0, 1, 0,
553  AnyPropertyType, &ActualType, &ActualFormat, &NItems,
554  &BytesReturn, &PropReturn );
555  if (PropReturn == NULL) {
556  free(handle);
557  return NULL;
558  }
559  handle->drv_win = *(Window *) PropReturn;
560  XFree(PropReturn);
561 
562  XTextProperty sball_drv_winname;
563  if (XGetWMName(dpy, handle->drv_win, &sball_drv_winname) != 0) {
564  if (!strcmp("Magellan Window", (char *) sball_drv_winname.value)) {
565  /* Send the application window to the Spaceball/Magellan driver */
566  XEvent msg;
567  msg.type = ClientMessage;
568  msg.xclient.format = 16;
569  msg.xclient.send_event = 0;
570  msg.xclient.display = dpy;
571  msg.xclient.window = handle->drv_win;
572  msg.xclient.message_type = handle->ev_command;
573 
574  msg.xclient.data.s[0] = (short) (((win)>>16)&0x0000FFFF); /* High 16 */
575  msg.xclient.data.s[1] = (short) (((win)) &0x0000FFFF); /* Low 16 */
576  msg.xclient.data.s[2] = SBALL_COMMAND_APP_WINDOW; /* 27695 */
577 
578  int rc = XSendEvent(dpy, handle->drv_win, 0, 0x0000, &msg);
579  XFlush(dpy);
580  if (rc == 0) {
581  free(handle);
582  return NULL;
583  }
584  }
585 
586  XFree(sball_drv_winname.value);
587  }
588 
589  return handle;
590 }
591 
592 
593 static void spaceball_close(spaceballhandle *handle) {
594  free(handle);
595 }
596 
597 
598 static int spaceball_decode_event(spaceballhandle *handle, const XEvent *xev, spaceballevent *sballevent) {
599  unsigned int evtype;
600 
601  if (handle == NULL || xev == NULL || sballevent == NULL)
602  return 0;
603 
604  if (xev->type != ClientMessage)
605  return 0;
606 
607  evtype = xev->xclient.message_type;
608  if (evtype == handle->ev_motion) {
609  /* We add the current control inputs to whatever we had previously, */
610  /* so that we can process all queued events and not drop any inputs */
611  sballevent->tx += xev->xclient.data.s[2]; /* X translation */
612  sballevent->ty += xev->xclient.data.s[3]; /* Y translation */
613  sballevent->tz += xev->xclient.data.s[4]; /* Z translation */
614  sballevent->rx += xev->xclient.data.s[5]; /* A rotation */
615  sballevent->ry += xev->xclient.data.s[6]; /* B rotation */
616  sballevent->rz += xev->xclient.data.s[7]; /* C rotation */
617  sballevent->period += xev->xclient.data.s[8]; /* Period in milliseconds */
618  sballevent->event = 1;
619  return 1;
620  } else if (evtype == handle->ev_button_press) {
621  sballevent->buttons |= (1 << xev->xclient.data.s[2]);
622  sballevent->event = 1;
623  return 1;
624  } else if (evtype == handle->ev_button_release) {
625  sballevent->buttons &= ~(1 << xev->xclient.data.s[2]);
626  sballevent->event = 1;
627  return 1;
628  }
629 
630  return 0;
631 }
632 
633 
634 static void spaceball_init_event(spaceballevent *sballevent) {
635  memset(sballevent, 0, sizeof(spaceballevent));
636 }
637 
638 
639 static void spaceball_clear_event(spaceballevent *sballevent) {
640  sballevent->tx = 0;
641  sballevent->ty = 0;
642  sballevent->tz = 0;
643  sballevent->rx = 0;
644  sballevent->ry = 0;
645  sballevent->rz = 0;
646  sballevent->period = 0;
647  sballevent->event = 0;
648 }
649 
650 
651 static oglhandle *glwin_alloc_init(void) {
652  oglhandle * handle = (oglhandle *) calloc(1, sizeof(oglhandle));
653  if (handle == NULL)
654  return NULL;
655 
656 #if defined(VMDOPENGL)
657  /* If this code is compiled into VMD, we honor the VMD scheme for */
658  /* directing the VMD graphics window to a particular display */
659  if (getenv("VMDGDISPLAY") != NULL) {
660  handle->dpy = XOpenDisplay(getenv("VMDGDISPLAY"));
661  } else {
662  handle->dpy = XOpenDisplay(getenv("DISPLAY"));
663  }
664 #else
665  handle->dpy = XOpenDisplay(getenv("DISPLAY"));
666 #endif
667  if (handle->dpy == NULL) {
668  free(handle);
669  return NULL;
670  }
671 
672  handle->scrnum = DefaultScreen(handle->dpy);
673  handle->root = RootWindow(handle->dpy, handle->scrnum);
674  handle->havestencil = 0;
675  handle->instereo = 0;
676  handle->evdev = GLWIN_EV_NONE;
677  handle->havefocus = 0;
678 
679  handle->ext = (glwin_ext_fctns *) calloc(1, sizeof(glwin_ext_fctns));
680 
681  return handle;
682 }
683 
684 
685 /*
686  * X11 implementation of glwin routines
687  */
688 void * glwin_create(const char * wintitle, int width, int height) {
689 #if defined(USEEGL)
690  /* EGL */
691  oglhandle * handle;
692  XSetWindowAttributes attr;
693  unsigned long mask;
694  int num_visuals;
695  XVisualInfo vistemplate;
696  XVisualInfo *vis=NULL;
697  XSizeHints sizeHints;
698  GLint stencilbits;
699  EGLint eglmaj, eglmin;
700  EGLint num_config=0;
701 
702 #if defined(USEOPENGLES2)
703 #define GLWIN_RENDERABLE_TYPE EGL_OPENGL_ES2_BIT
704 #else
705 #define GLWIN_RENDERABLE_TYPE EGL_OPENGL_BIT
706 #endif
707 
708  EGLint eglnormalattrib[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8,
709  EGL_BLUE_SIZE, 8,
710  EGL_DEPTH_SIZE, 16,
711  EGL_STENCIL_SIZE, 1,
712 /* EGL_NATIVE_RENDERABLE, */
713  EGL_RENDERABLE_TYPE, GLWIN_RENDERABLE_TYPE,
714 /* EGL_SURFACE_TYPE, EGL_WINDOW_BIT, */
715  EGL_NONE };
716  EGLint eglfailsafeattrib[] = { EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1,
717  EGL_BLUE_SIZE, 1,
718 /* EGL_DEPTH_SIZE, 16, */
719 /* EGL_NATIVE_RENDERABLE, */
720  EGL_RENDERABLE_TYPE, GLWIN_RENDERABLE_TYPE,
721 /* EGL_SURFACE_TYPE, EGL_WINDOW_BIT, */
722  EGL_NONE };
723 
724  handle = glwin_alloc_init();
725  handle->width = width;
726  handle->height = height;
727 
728  /* setup EGL state */
729 #if 1
730  handle->egldpy = eglGetDisplay(handle->dpy);
731 #else
732  handle->egldpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
733 #endif
734  if (handle->egldpy == EGL_NO_DISPLAY) {
735  printf("glwin_create(): Failed to connect to EGL display\n");
736  free(handle);
737  return NULL;
738  }
739 
740  if (eglInitialize(handle->egldpy, &eglmaj, &eglmin) == EGL_FALSE) {
741  printf("glwin_create(): Failed to initialize EGL display connection\n");
742  free(handle);
743  return NULL;
744 #if 1
745  } else {
746  printf("EGL init dpy version: %d.%d\n", eglmaj, eglmin);
747 #endif
748  }
749 
750  /* try for full stereo w/ features first */
751  handle->havestencil = 1;
752  handle->instereo = 0;
753  if (eglChooseConfig(handle->egldpy, eglnormalattrib, &handle->eglconf, 1, &num_config) == EGL_FALSE) {
754  printf("eglChooseConfig(1) %d configs\n", num_config);
755  if (eglChooseConfig(handle->egldpy, eglfailsafeattrib, &handle->eglconf, 1, &num_config) == EGL_FALSE) {
756  printf("Error: eglChooseConfig() failed\n");
757  free(handle);
758  return NULL;
759  }
760  handle->havestencil = 0;
761  }
762  printf("eglChooseConfig() %d configs\n", num_config);
763 
764 
765  EGLint vid;
766  if (eglGetConfigAttrib(handle->egldpy, handle->eglconf, EGL_NATIVE_VISUAL_ID, &vid) == EGL_FALSE) {
767  printf("Error: eglGetConfigAttrib() failed\n");
768  return NULL;
769  }
770 
771  vistemplate.visualid = vid;
772  vis = XGetVisualInfo(handle->dpy, VisualIDMask, &vistemplate, &num_visuals);
773  if (vis == NULL) {
774  printf("Error: failed to obtain EGL-compatible X visual...\n");
775  free(handle);
776  return NULL;
777  }
778 
779 
780 #if defined(USEOPENGLES2)
781  /* bind to OpenGL API since some implementations don't do this by default */
782  if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
783  printf("Error: failed to bind OpenGL ES API\n");
784  free(handle);
785  return NULL;
786  }
787 #else
788  /* bind to OpenGL API since some implementations don't do this by default */
789  if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
790  printf("Error: failed to bind full OpenGL API\n");
791  free(handle);
792  return NULL;
793  }
794 #endif
795 
796 
797  /* window attributes */
798  attr.background_pixel = 0;
799  attr.border_pixel = 0;
800  attr.colormap = XCreateColormap(handle->dpy, handle->root,
801  vis->visual, AllocNone);
802 
803  attr.event_mask = StructureNotifyMask | ExposureMask;
804  mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
805 
806  handle->win = XCreateWindow(handle->dpy, handle->root, 0, 0, width, height,
807  0, vis->depth, InputOutput,
808  vis->visual, mask, &attr );
809 
810 #if 0
811  /* XXX untested EWMH code to enable compositor bypass */
812  Atom bypasscomp = X11_XInternAtom(handle->dpy, "_NET_WM_BYPASS_COMPOSITOR", False);
813  const long bypasscomp_on = 1;
814  X11_XChangeProperty(handle->dpy, handle->win, bypasscomp, XA_CARDINAL, 32,
815  PropModeReplace, (unsigned char *) bypasscomp_on, 1);
816 #endif
817 
818  handle->eglctx = eglCreateContext(handle->dpy, handle->eglconf, EGL_NO_CONTEXT, NULL);
819 
820  handle->eglsurf = eglCreateWindowSurface(handle->egldpy, handle->eglconf, handle->win, NULL);
821  eglMakeCurrent(handle->dpy, handle->eglsurf, handle->eglsurf, handle->eglctx);
822 
823  /* initialize extensions once window has been made current... */
824  glwin_init_exts(handle);
825 
826  EGLint Context_RendererType=0;
827  eglQueryContext(handle->egldpy, handle->eglctx, EGL_CONTEXT_CLIENT_TYPE, &Context_RendererType);
828 
829  const char *glstring="uninitialized";
830  char buf[1024];
831  switch (Context_RendererType) {
832  case EGL_OPENGL_API: glstring = "OpenGL"; break;
833  case EGL_OPENGL_ES_API: glstring = "OpenGL ES"; break;
834  case EGL_OPENVG_API: glstring = "OpenVG???"; break;
835  default:
836  sprintf(buf, "Unknown API: %x", Context_RendererType);
837  glstring=buf;
838  break;
839  }
840  printf("EGL_CONTEXT_CLIENT_TYPE: %s\n", glstring);
841 
842 
843  XStoreName(handle->dpy, handle->win, wintitle);
844 
845  XSelectInput(handle->dpy, handle->win,
846  KeyPressMask | ButtonPressMask | ButtonReleaseMask |
847  PointerMotionMask | StructureNotifyMask | ExposureMask |
848  EnterWindowMask | LeaveWindowMask | FocusChangeMask);
849 
850  /* set window manager size and position hints */
851  memset((void *) &(sizeHints), 0, sizeof(sizeHints));
852  sizeHints.flags |= USSize;
853  sizeHints.flags |= USPosition;
854  sizeHints.width = width;
855  sizeHints.height = height;
856  sizeHints.x = 0;
857  sizeHints.y = 0;
858  XSetWMNormalHints(handle->dpy, handle->win, &sizeHints);
859 
860  /* cause X11 to generate a ClientMessage event when the window manager */
861  /* wants to close window, so we can gracefully exit rather than crash */
862  handle->wmDeleteWindow = XInternAtom(handle->dpy, "WM_DELETE_WINDOW", False);
863  XSetWMProtocols(handle->dpy, handle->win, &handle->wmDeleteWindow, 1);
864 
865  XMapRaised(handle->dpy, handle->win);
866 
867  /* Enable Spaceball events to this window */
868 #if 0
869  /* do focus processing for ourselves */
870  handle->sball = spaceball_attach(handle->dpy, handle->win);
871 #else
872  /* driver will do focus processing for us */
873  handle->sball = spaceball_attach(handle->dpy, InputFocus);
874 #endif
875  /* initialize spaceball event structure */
876  spaceball_init_event(&handle->sballevent);
877  spaceball_clear_event(&handle->sballevent);
878 
880 
881 #if 0
882  /* check for an OpenGL stencil buffer */
883  glGetIntegerv(GL_STENCIL_BITS, &stencilbits);
884  if (stencilbits > 0) {
885  handle->havestencil = 1;
886  }
887 #endif
888 
889  glClearColor(1.0, 0.0, 0.0, 1.0);
890  glClear(GL_COLOR_BUFFER_BIT);
891  glwin_swap_buffers(handle);
892  glClear(GL_COLOR_BUFFER_BIT);
893  glwin_swap_buffers(handle);
894 
895 
896  XFlush(handle->dpy);
897 
898  return handle;
899 #else
900  /* GLX */
901  oglhandle * handle;
902  XSetWindowAttributes attr;
903  unsigned long mask;
904  XVisualInfo *vis=NULL;
905  XSizeHints sizeHints;
906  GLint stencilbits;
907 
908  int glxstereoattrib[] = { GLX_RGBA, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8,
909  GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 16,
910  GLX_STENCIL_SIZE, 1,
911  GLX_STEREO, GLX_DOUBLEBUFFER, None };
912  int glxnormalattrib[] = { GLX_RGBA, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8,
913  GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 16,
914  GLX_STENCIL_SIZE, 1,
915  GLX_DOUBLEBUFFER, None };
916  int glxfailsafeattrib[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
917  GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 16,
918  GLX_DOUBLEBUFFER, None };
919 
920  handle = glwin_alloc_init();
921  handle->width = width;
922  handle->height = height;
923 
924  /* try for full stereo w/ features first */
925  handle->havestencil = 1;
926  handle->instereo = 1;
927  vis=glXChooseVisual(handle->dpy, handle->scrnum, glxstereoattrib);
928  if (vis == NULL) {
929  handle->havestencil = 1;
930  handle->instereo = 0;
931  /* try non-stereo w/ full features next */
932  vis=glXChooseVisual(handle->dpy, handle->scrnum, glxnormalattrib);
933  if (vis == NULL) {
934  handle->havestencil = 0;
935  handle->instereo = 0;
936  /* try minimal features last */
937  vis=glXChooseVisual(handle->dpy, handle->scrnum, glxfailsafeattrib);
938  if (vis == NULL) {
939  free(handle);
940  return NULL;
941  }
942  }
943  }
944 
945  /* window attributes */
946  attr.background_pixel = 0;
947  attr.border_pixel = 0;
948  attr.colormap = XCreateColormap(handle->dpy, handle->root,
949  vis->visual, AllocNone);
950 
951  attr.event_mask = StructureNotifyMask | ExposureMask;
952  mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
953 
954  handle->win = XCreateWindow(handle->dpy, handle->root, 0, 0, width, height,
955  0, vis->depth, InputOutput,
956  vis->visual, mask, &attr );
957 
958 #if 0
959  /* XXX untested EWMH code to enable compositor bypass */
960  Atom bypasscomp = X11_XInternAtom(handle->dpy, "_NET_WM_BYPASS_COMPOSITOR", False);
961  const long bypasscomp_on = 1;
962  X11_XChangeProperty(handle->dpy, handle->win, bypasscomp, XA_CARDINAL, 32,
963  PropModeReplace, (unsigned char *) bypasscomp_on, 1);
964 #endif
965 
966  handle->ctx = glXCreateContext( handle->dpy, vis, NULL, True );
967 
968  glXMakeCurrent( handle->dpy, handle->win, handle->ctx );
969 
970  /* initialize extensions once window has been made current... */
971  glwin_init_exts(handle);
972 
973  XStoreName(handle->dpy, handle->win, wintitle);
974 
975  XSelectInput(handle->dpy, handle->win,
976  KeyPressMask | ButtonPressMask | ButtonReleaseMask |
977  PointerMotionMask | StructureNotifyMask | ExposureMask |
978  EnterWindowMask | LeaveWindowMask | FocusChangeMask);
979 
980  /* set window manager size and position hints */
981  memset((void *) &(sizeHints), 0, sizeof(sizeHints));
982  sizeHints.flags |= USSize;
983  sizeHints.flags |= USPosition;
984  sizeHints.width = width;
985  sizeHints.height = height;
986  sizeHints.x = 0;
987  sizeHints.y = 0;
988  XSetWMNormalHints(handle->dpy, handle->win, &sizeHints);
989 
990  /* cause X11 to generate a ClientMessage event when the window manager */
991  /* wants to close window, so we can gracefully exit rather than crash */
992  handle->wmDeleteWindow = XInternAtom(handle->dpy, "WM_DELETE_WINDOW", False);
993  XSetWMProtocols(handle->dpy, handle->win, &handle->wmDeleteWindow, 1);
994 
995  XMapRaised(handle->dpy, handle->win);
996 
997  /* Enable Spaceball events to this window */
998 #if 0
999  /* do focus processing for ourselves */
1000  handle->sball = spaceball_attach(handle->dpy, handle->win);
1001 #else
1002  /* driver will do focus processing for us */
1003  handle->sball = spaceball_attach(handle->dpy, InputFocus);
1004 #endif
1005  /* initialize spaceball event structure */
1006  spaceball_init_event(&handle->sballevent);
1007  spaceball_clear_event(&handle->sballevent);
1008 
1010 
1011  /* check for an OpenGL stencil buffer */
1012  glGetIntegerv(GL_STENCIL_BITS, &stencilbits);
1013  if (stencilbits > 0) {
1014  handle->havestencil = 1;
1015  }
1016 
1017  glClearColor(0.0, 0.0, 0.0, 1.0);
1018  glClear(GL_COLOR_BUFFER_BIT);
1019  glwin_swap_buffers(handle);
1020  glClear(GL_COLOR_BUFFER_BIT);
1021  glwin_swap_buffers(handle);
1022 
1023  XFlush(handle->dpy);
1024 
1025  return handle;
1026 #endif
1027 }
1028 
1029 
1030 void glwin_destroy(void * voidhandle) {
1031  oglhandle * handle = (oglhandle *) voidhandle;
1032  if (handle == NULL)
1033  return;
1034 
1035  /* detach spaceball */
1036  if (handle->sball != NULL) {
1037  spaceball_close(handle->sball);
1038  handle->sball = NULL;
1039  }
1040 
1041  /* destroy GLSL and FBO extension fctns */
1042  if (handle->ext != NULL) {
1043  free(handle->ext);
1044  }
1045 
1046  /* close and delete window */
1047  XUnmapWindow(handle->dpy, handle->win);
1048 
1049 #if defined(USEEGL)
1050  /* EGL code path */
1051  eglMakeCurrent(handle->egldpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1052  eglDestroyContext(handle->egldpy, handle->eglctx);
1053  eglDestroySurface(handle->egldpy, handle->eglsurf);
1054  eglTerminate(handle->egldpy);
1055 #else
1056  /* GLX code path */
1057  glXMakeCurrent(handle->dpy, None, NULL);
1058 #endif
1059 
1060  XDestroyWindow(handle->dpy, handle->win);
1061  XCloseDisplay(handle->dpy);
1062 }
1063 
1064 
1065 void glwin_swap_buffers(void * voidhandle) {
1066  oglhandle * handle = (oglhandle *) voidhandle;
1067 
1068  if (handle != NULL)
1069 #if defined(USEEGL)
1070  /* EGL code path */
1071  eglSwapBuffers(handle->egldpy, handle->eglsurf);
1072 #else
1073  /* GLX code path */
1074  glXSwapBuffers(handle->dpy, handle->win);
1075 #endif
1076 }
1077 
1078 
1079 int glwin_handle_events(void * voidhandle, int evblockmode) {
1080  oglhandle * handle = (oglhandle *) voidhandle;
1081  int rc=0;
1082  char keybuf[10];
1083  int keybuflen = 9;
1084  KeySym keysym;
1085  XComposeStatus comp;
1086 
1087  if (handle == NULL)
1088  return 0;
1089 
1090  /* clear previous spaceball event state, except for button state which */
1091  /* must be left alone. */
1092  spaceball_clear_event(&handle->sballevent);
1093 
1094 #if 0
1095  if (handle) {
1096  /* check window size */
1097  XWindowAttributes xwa;
1098  XGetWindowAttributes(handle->dpy, handle->win, &xwa);
1099  handle->width = xwa.width;
1100  handle->height = xwa.height;
1101  }
1102 #endif
1103 
1104  /* only process a single recognized event and then return to the caller */
1105  /* otherwise it is too easy to drop mouse button press/release events */
1106  while (!rc && (evblockmode || XPending(handle->dpy))) {
1107  int k;
1108  unsigned int button;
1109  XEvent event;
1110 
1111  evblockmode = GLWIN_EV_POLL_NONBLOCK; /* subsequent loops don't block */
1112  XNextEvent(handle->dpy, &event);
1113  handle->evdev = GLWIN_EV_NONE;
1114  handle->evval = 0;
1115  handle->evkey = '\0';
1116 
1117  switch(event.type) {
1118  case Expose:
1119  case ReparentNotify:
1120  case MapNotify:
1121  rc=1; /* we got one event */
1122  break;
1123 
1124  case ConfigureNotify:
1125  handle->width = event.xconfigure.width;
1126  handle->height = event.xconfigure.height;
1127  handle->xpos = event.xconfigure.x;
1128  handle->ypos = event.xconfigure.y;
1129  rc=1; /* we got one event */
1130  break;
1131 
1132  case KeyPress:
1133  handle->mousex = event.xbutton.x;
1134  handle->mousey = event.xbutton.y;
1135  k = XLookupString(&(event.xkey), keybuf, keybuflen, &keysym, &comp);
1136  if (k > 0 && keybuf[0] != '\0') {
1137  handle->evdev = GLWIN_EV_KBD;
1138  handle->evkey = keybuf[0];
1139  rc=1; /* we got one event */
1140  } else {
1141  handle->evdev = GLWIN_EV_NONE;
1142  handle->evkey = 0;
1143  switch (keysym) {
1144  case XK_Up: handle->evdev = GLWIN_EV_KBD_UP; break;
1145  case XK_Down: handle->evdev = GLWIN_EV_KBD_DOWN; break;
1146  case XK_Left: handle->evdev = GLWIN_EV_KBD_LEFT; break;
1147  case XK_Right: handle->evdev = GLWIN_EV_KBD_RIGHT; break;
1148  case XK_Page_Up: handle->evdev = GLWIN_EV_KBD_PAGE_UP; break;
1149  case XK_Page_Down: handle->evdev = GLWIN_EV_KBD_PAGE_UP; break;
1150  case XK_Home: handle->evdev = GLWIN_EV_KBD_HOME; break;
1151  case XK_End: handle->evdev = GLWIN_EV_KBD_END; break;
1152  case XK_Insert: handle->evdev = GLWIN_EV_KBD_INSERT; break;
1153  case XK_Delete: handle->evdev = GLWIN_EV_KBD_DELETE; break;
1154 
1155  case XK_F1: handle->evdev = GLWIN_EV_KBD_F1; break;
1156  case XK_F2: handle->evdev = GLWIN_EV_KBD_F2; break;
1157  case XK_F3: handle->evdev = GLWIN_EV_KBD_F3; break;
1158  case XK_F4: handle->evdev = GLWIN_EV_KBD_F4; break;
1159  case XK_F5: handle->evdev = GLWIN_EV_KBD_F5; break;
1160  case XK_F6: handle->evdev = GLWIN_EV_KBD_F6; break;
1161  case XK_F7: handle->evdev = GLWIN_EV_KBD_F7; break;
1162  case XK_F8: handle->evdev = GLWIN_EV_KBD_F8; break;
1163  case XK_F9: handle->evdev = GLWIN_EV_KBD_F9; break;
1164  case XK_F10: handle->evdev = GLWIN_EV_KBD_F10; break;
1165  case XK_F11: handle->evdev = GLWIN_EV_KBD_F11; break;
1166  case XK_F12: handle->evdev = GLWIN_EV_KBD_F12; break;
1167 
1168  case XK_Escape: handle->evdev = GLWIN_EV_KBD_F12; break;
1169  }
1170  if (handle->evdev != GLWIN_EV_NONE)
1171  rc=1;
1172  }
1173  break;
1174 
1175  case MotionNotify:
1176  handle->evdev = GLWIN_EV_MOUSE_MOVE;
1177  handle->mousex = event.xmotion.x;
1178  handle->mousey = event.xmotion.y;
1179  rc=1; /* we got one event */
1180  break;
1181 
1182  case ButtonPress:
1183  case ButtonRelease:
1184  button = event.xbutton.button;
1185  handle->evval = (event.type == ButtonPress);
1186  handle->mousex = event.xbutton.x;
1187  handle->mousey = event.xbutton.y;
1188  switch (button) {
1189  case Button1:
1190  handle->evdev = GLWIN_EV_MOUSE_LEFT;
1191  rc=1; /* we got one event */
1192  break;
1193  case Button2:
1194  handle->evdev = GLWIN_EV_MOUSE_MIDDLE;
1195  rc=1; /* we got one event */
1196  break;
1197  case Button3:
1198  handle->evdev = GLWIN_EV_MOUSE_RIGHT;
1199  rc=1; /* we got one event */
1200  break;
1201  case Button4:
1202  handle->evdev = GLWIN_EV_MOUSE_WHEELUP;
1203  rc=1; /* we got one event */
1204  break;
1205  case Button5:
1206  handle->evdev = GLWIN_EV_MOUSE_WHEELDOWN;
1207  rc=1; /* we got one event */
1208  break;
1209  }
1210  break;
1211 
1212  case FocusIn:
1213  case EnterNotify:
1214  handle->havefocus=1;
1215  break;
1216 
1217  case FocusOut:
1218  case LeaveNotify:
1219  handle->havefocus=0;
1220  break;
1221 
1222  case ClientMessage:
1223  /* handle window close events */
1224  if (event.xclient.data.l[0] == handle->wmDeleteWindow) {
1225  handle->evdev = GLWIN_EV_WINDOW_CLOSE;
1226  rc=1;
1227  } else {
1228 #if 1
1229  /* let the spaceball driver take care of focus processing */
1230  /* if we have mouse/keyboard focus, then translate spaceball events */
1231  spaceball_decode_event(handle->sball, &event, &handle->sballevent);
1232 #else
1233  /* do our own focus handling */
1234  /* if we have mouse/keyboard focus, then translate spaceball events */
1235  if (handle->havefocus) {
1236  spaceball_decode_event(handle->sball, &event, &handle->sballevent);
1237  }
1238 #endif
1239  }
1240  break;
1241 
1242  }
1243  }
1244 
1245  return rc;
1246 }
1247 
1248 
1249 int glwin_resize(void *voidhandle, int width, int height) {
1250  oglhandle * handle = (oglhandle *) voidhandle;
1251  if (handle == NULL)
1252  return -1;
1253 
1254  XResizeWindow(handle->dpy, handle->win, width, height);
1255 
1256 #if 0
1257  XFlush(handle->dpy);
1258 #endif
1259 
1260  return 0;
1261 }
1262 
1263 
1264 int glwin_reposition(void *voidhandle, int xpos, int ypos) {
1265  oglhandle * handle = (oglhandle *) voidhandle;
1266  if (handle == NULL)
1267  return -1;
1268 
1269  XMoveWindow(handle->dpy, handle->win, xpos, ypos);
1270 
1271  return 0;
1272 }
1273 
1274 
1275 #if 0
1276 int glwin_switch_fullscreen_video_mode(void * voidhandle, mode...) {
1277  XF86VidModeSwitchToMode(display,defaultscreen,video_mode);
1278  XF86VidModeSetViewPort(display,DefaultScreen,0,0);
1279  XMoveResizeWindow(display,window,0,0,width,height);
1280  XMapRaised(display,window);
1281  XGrabPointer(display,window,True,0,GrabModeAsync,GrabModeAsync,window,0L,CurrentTime);
1282  XGrabKeyboard(display,window,False,GrabModeAsync,GrabModeAsync,CurrentTime);
1283 }
1284 #endif
1285 
1286 
1287 int glwin_fullscreen(void * voidhandle, int fson, int xinescreen) {
1288  struct {
1289  unsigned long flags;
1290  unsigned long functions;
1291  unsigned long decorations;
1292  long inputMode;
1293  unsigned long status;
1294  } wmhints;
1295  Atom wmproperty;
1296 
1297  oglhandle * handle = (oglhandle *) voidhandle;
1298 
1299  memset(&wmhints, 0, sizeof(wmhints));
1300  wmhints.flags = 2; /* changing window decorations */
1301  if (fson) {
1302  wmhints.decorations = 0; /* 0 (false) no window decorations */
1303  } else {
1304  wmhints.decorations = 1; /* 1 (true) window decorations enabled */
1305  }
1306  wmproperty = XInternAtom(handle->dpy, "_MOTIF_WM_HINTS", True);
1307  XChangeProperty(handle->dpy, handle->win, wmproperty, wmproperty, 32,
1308  PropModeReplace, (unsigned char *) &wmhints, 5);
1309 
1310 #if 0
1311  {
1312  XSetWindowAttributes xswa;
1313  xswa.override_redirect = False;
1314  XChangeWindowAttributes(handle->dpy, handle->win, CWOverrideRedirect, &xswa);
1315  }
1316 #endif
1317 
1318 #if 1 && defined(__linux)
1319  /* support EWMH methods for setting full-screen mode */
1320  /* http://standards.freedesktop.org/wm-spec/wm-spec-latest.html */
1321  Atom fsatom = XInternAtom(handle->dpy, "_NET_WM_STATE_FULLSCREEN", True);
1322  Atom stateatom = XInternAtom(handle->dpy, "_NET_WM_STATE", True);
1323  if (fsatom != None && stateatom != None) {
1324 #if 0
1325  XChangeProperty(handle->dpy, handle->win, stateatom,
1326  XA_ATOM, 32, PropModeReplace, (unsigned char*) &fsatom, 1);
1327 #endif
1328 
1329  XEvent xev;
1330  memset(&xev, 0, sizeof(xev));
1331  xev.type = ClientMessage;
1332  xev.xclient.window = handle->win;
1333  xev.xclient.message_type = stateatom;
1334  xev.xclient.format = 32;
1335  if (fson)
1336  xev.xclient.data.l[0] = 1; /* _NET_WM_STATE_ADD */
1337  else
1338  xev.xclient.data.l[0] = 0; /* _NET_WM_STATE_REMOVE */
1339  xev.xclient.data.l[1] = fsatom;
1340  xev.xclient.data.l[2] = 0;
1341 
1342  XSendEvent(handle->dpy, handle->root, False,
1343  SubstructureRedirectMask | SubstructureNotifyMask, &xev);
1344 
1345  XFlush(handle->dpy);
1346  }
1347 #if 0
1348  else {
1349  printf("*** failed to obtain full screen X11 atom\n");
1350  }
1351 #endif
1352 #endif
1353 
1354  /* resize window to size of either the whole X display screen, */
1355  /* or to the size of one of the Xinerama component displays */
1356  /* if Xinerama is enabled, and xinescreen is not -1. */
1357  if (fson) {
1358  int dpyScreen = DefaultScreen(handle->dpy);
1359 
1360  XSizeHints sizeHints;
1361  memset((void *) &(sizeHints), 0, sizeof(sizeHints));
1362  sizeHints.flags |= USSize;
1363  sizeHints.flags |= USPosition;
1364 
1365  sizeHints.width = DisplayWidth(handle->dpy, dpyScreen);
1366  sizeHints.height = DisplayHeight(handle->dpy, dpyScreen);
1367  sizeHints.x = 0;
1368  sizeHints.y = 0;
1369 
1370 #if defined(USEXINERAMA)
1371  if (xinescreen != -1) {
1372  int xinerr, xinevent, xinenumscreens;
1373  if (XineramaQueryExtension(handle->dpy, &xinevent, &xinerr) &&
1374  XineramaIsActive(handle->dpy)) {
1375  XineramaScreenInfo *screens =
1376  XineramaQueryScreens(handle->dpy, &xinenumscreens);
1377  if (xinescreen >= 0 && xinescreen < xinenumscreens) {
1378  sizeHints.width = screens[xinescreen].width;
1379  sizeHints.height = screens[xinescreen].height;
1380  sizeHints.x = screens[xinescreen].x_org;
1381  sizeHints.y = screens[xinescreen].y_org;
1382 #if 1 || defined(DEBUGOUTPUT)
1383  printf("*** OpenGL Stereo: Xinerama screen %d, +%d+%dx%dx%d\n",
1384  xinescreen, sizeHints.x, sizeHints.y,
1385  sizeHints.width, sizeHints.height);
1386 #endif
1387  } else {
1388  printf("*** OpenGL Stereo: no such Xinerama screen index %d\n",
1389  xinescreen);
1390  }
1391  XFree(screens);
1392  }
1393  }
1394 #endif
1395 
1396  XMoveWindow(handle->dpy, handle->win, sizeHints.x, sizeHints.y);
1397  XResizeWindow(handle->dpy, handle->win, sizeHints.width, sizeHints.height);
1398  }
1399 
1400 #if 0
1401  {
1402  XSetWindowAttributes xswa;
1403  xswa.override_redirect = True;
1404  XChangeWindowAttributes(handle->dpy, handle->win, CWOverrideRedirect, &xswa);
1405  }
1406 #endif
1407 
1408 #if 0
1409  XSync(handle->dpy, 0);
1410 #endif
1411 
1412  return 0;
1413 }
1414 
1415 
1416 #else
1417 
1418 /*
1419  * Win32 Version
1420  */
1421 
1422 /*
1423  * Spaceball event handling routines
1424  */
1425 
1426 #if defined(USESPACEWARE)
1427 
1428 static spaceballhandle * spaceball_attach(HWND hWnd) {
1429  SiOpenData oData;
1430  enum SpwRetVal res;
1431 
1432  switch (SiInitialize()) {
1433  case SPW_NO_ERROR: /* init succeeded */
1434  break;
1435 
1436  case SPW_DLL_LOAD_ERROR: /* driver not installed */
1437  default: /* error prevented init */
1438  return NULL;
1439  }
1440 
1441  /* allocate and clear handle data structure */
1442  spaceballhandle *handle = (spaceballhandle *) calloc(1, sizeof(spaceballhandle));
1443 
1444  SiOpenWinInit(&oData, hWnd); /* init win platform data */
1445  SiSetUiMode(handle->sball, SI_UI_ALL_CONTROLS); /* config softbutton display */
1446 
1447  /* start a connection to the device now that the UI mode */
1448  /* and window system data are setup. */
1449  handle->sball = SiOpen("OpenGL", SI_ANY_DEVICE, SI_NO_MASK, SI_EVENT, &oData);
1450  if ((handle->sball == NULL) || (handle->sball == SI_NO_HANDLE)) {
1451  SiTerminate(); /* shutdown spaceware input library */
1452  free(handle);
1453  return NULL;
1454  }
1455 
1456  res = SiBeep(handle->sball, "CcCc"); /* beep the spaceball */
1457  if ((handle->sball != NULL) && (handle->sball != SI_NO_HANDLE))
1458  return handle;
1459 
1460  free(handle);
1461  return NULL;
1462 }
1463 
1464 
1465 static void spaceball_close(spaceballhandle *handle) {
1466  if (handle == NULL)
1467  return;
1468 
1469  if (handle->sball != NULL) {
1470  enum SpwRetVal res;
1471  res = SiClose(handle->sball); /* close spaceball device */
1472  if (res != SPW_NO_ERROR)
1473  printf("An error occured during Spaceball shutdown.\n");
1474  SiTerminate(); /* shutdown spaceware input library */
1475  }
1476 
1477  free(handle);
1478 }
1479 
1480 
1481 static int spaceball_decode_event(spaceballhandle *handle, spaceballevent *sballevent, UINT msg, WPARAM wParam, LPARAM lParam) {
1482  if (handle == NULL)
1483  return 0;
1484 
1485  if (handle->sball == NULL)
1486  return 0; /* no spaceball attached/running */
1487 
1488  /* Check to see if this message is a spaceball message */
1489  SiGetEventWinInit(&handle->spwedata, msg, wParam, lParam);
1490 
1491  if (SiGetEvent(handle->sball, 0, &handle->spwedata, &handle->spwevent) == SI_IS_EVENT) {
1492  return 1;
1493  }
1494 
1495  return 0;
1496 }
1497 
1498 #endif /* USESPACEWARE */
1499 
1500 
1501 
1502 static void spaceball_init_event(spaceballevent *sballevent) {
1503  memset(sballevent, 0, sizeof(spaceballevent));
1504 }
1505 
1506 static void spaceball_clear_event(spaceballevent *sballevent) {
1507  sballevent->tx = 0;
1508  sballevent->ty = 0;
1509  sballevent->tz = 0;
1510  sballevent->rx = 0;
1511  sballevent->ry = 0;
1512  sballevent->rz = 0;
1513  sballevent->period = 0;
1514  sballevent->event = 0;
1515 }
1516 
1517 
1518 /*
1519  * declaration of myWindowProc()
1520  */
1521 LRESULT WINAPI myWindowProc( HWND, UINT, WPARAM, LPARAM );
1522 
1523 static const char *szClassName = "OpenGLWindow";
1524 static WNDCLASS wc;
1525 static int wc_initialized = 0;
1526 
1527 static int OpenWin32Connection(oglhandle * handle) {
1528  HINSTANCE hInstance = GetModuleHandle(NULL);
1529 
1530  if (!wc_initialized) {
1531  /* Clear (important!) and then fill in the window class structure. */
1532  memset(&wc, 0, sizeof(WNDCLASS));
1533  wc.style = CS_OWNDC;
1534  wc.lpfnWndProc = (WNDPROC) myWindowProc;
1535  wc.hInstance = hInstance;
1536  wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
1537  wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
1538  wc.hbrBackground = NULL; /* Default color */
1539  wc.lpszMenuName = NULL;
1540  wc.lpszClassName = szClassName;
1541 
1542  if(!RegisterClass(&wc)) {
1543  printf("Cannot register window class.\n");
1544  return -1;
1545  }
1546 
1547  wc_initialized = 1;
1548  }
1549 
1550  handle->scrwidth = GetSystemMetrics(SM_CXSCREEN);
1551  handle->scrheight = GetSystemMetrics(SM_CYSCREEN);
1552 
1553  return 0;
1554 }
1555 
1556 
1557 static HGLRC SetupOpenGL(oglhandle * handle) {
1558  int nMyPixelFormatID;
1559  HDC hDC;
1560  HGLRC hRC;
1561  PIXELFORMATDESCRIPTOR checkpfd;
1562  static PIXELFORMATDESCRIPTOR pfd = {
1563  sizeof (PIXELFORMATDESCRIPTOR), /* struct size */
1564  1, /* Version number */
1565  PFD_DRAW_TO_WINDOW /* Flags, draw to a window, */
1566  | PFD_DOUBLEBUFFER /* Requires Doublebuffer hw */
1567  | PFD_STEREO /* we want stereo if possible */
1568  | PFD_SUPPORT_OPENGL, /* use OpenGL */
1569  PFD_TYPE_RGBA, /* RGBA pixel values */
1570  24, /* 24-bit color */
1571  0, 0, 0, /* RGB bits & shift sizes. */
1572  0, 0, 0, /* Don't care about them */
1573  0, 0, /* No alpha buffer info */
1574  0, 0, 0, 0, 0, /* No accumulation buffer */
1575  16, /* 16-bit depth buffer */
1576  1, /* Want stencil buffer */
1577  0, /* No auxiliary buffers */
1578  PFD_MAIN_PLANE, /* Layer type */
1579  0, /* Reserved (must be 0) */
1580  0, /* No layer mask */
1581  0, /* No visible mask */
1582  0 /* No damage mask */
1583  };
1584 
1585  hDC = GetDC(handle->hWnd);
1586  nMyPixelFormatID = ChoosePixelFormat(hDC, &pfd);
1587 
1588  /*
1589  * catch errors here.
1590  * If nMyPixelFormat is zero, then there's
1591  * something wrong... most likely the window's
1592  * style bits are incorrect (in CreateWindow() )
1593  * or OpenGL isn't installed on this machine
1594  *
1595  */
1596  if (nMyPixelFormatID == 0) {
1597  printf("Error selecting OpenGL Pixel Format!!\n");
1598  return NULL;
1599  }
1600 
1601  /* check for stereo window */
1602  DescribePixelFormat(hDC, nMyPixelFormatID,
1603  sizeof(PIXELFORMATDESCRIPTOR), &checkpfd);
1604  if (checkpfd.dwFlags & PFD_STEREO)
1605  handle->instereo = 1;
1606  else
1607  handle->instereo = 0;
1608 
1609  SetPixelFormat(hDC, nMyPixelFormatID, &pfd);
1610 
1611  hRC = wglCreateContext(hDC);
1612  ReleaseDC(handle->hWnd, hDC);
1613 
1614  return hRC;
1615 }
1616 
1617 
1618 static int myCreateWindow(oglhandle * handle, const char * wintitle,
1619  int xpos, int ypos, int xs, int ys) {
1620  /* Create a main window for this application instance. */
1621  handle->hWnd =
1622  CreateWindow(
1623  szClassName, /* Window class name */
1624  wintitle, /* Text for window title bar */
1625  WS_OVERLAPPEDWINDOW /* Window style */
1626  | WS_CLIPCHILDREN
1627  | WS_CLIPSIBLINGS, /* NEED THESE for OpenGL calls to work! */
1628  xpos, ypos,
1629  xs, ys,
1630  NULL, /* no parent window */
1631  NULL, /* Use the window class menu. */
1632  GetModuleHandle(NULL), /* This instance owns this window */
1633  handle /* We don't use any extra data */
1634  );
1635 
1636  if (!handle->hWnd) {
1637  printf("Couldn't Open Window!!\n");
1638  return -1;
1639  }
1640 
1641  handle->hDC = GetDC(handle->hWnd);
1642  wglMakeCurrent(handle->hDC, handle->hRC);
1643 
1644  /* Make the window visible & update its client area */
1645  ShowWindow( handle->hWnd, SW_SHOW); /* Show the window */
1646  UpdateWindow( handle->hWnd ); /* Sends WM_PAINT message */
1647 
1648  return 0;
1649 }
1650 
1651 
1652 static void win32decodemouse(oglhandle *handle, LPARAM lParam) {
1653  int x, y;
1654  x = LOWORD(lParam);
1655  y = HIWORD(lParam);
1656  /* handle mouse capture in negative range */
1657  if (x & 1 << 15) x -= (1 << 16);
1658  if (y & 1 << 15) y -= (1 << 16);
1659  handle->mousex = x;
1660  handle->mousey = y;
1661 }
1662 
1663 
1664 LRESULT WINAPI myWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
1665  PAINTSTRUCT ps; /* Paint structure. */
1666  oglhandle *handle;
1667 
1668  /* Upon first window creation, immediately set our user-data field */
1669  /* to store caller-provided handles for this window instance */
1670  if (msg == WM_NCCREATE) {
1671 #if defined(_M_X64) || defined(_WIN64) || defined(_Wp64)
1672  SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) (((CREATESTRUCT *) lParam)->lpCreateParams));
1673 #elif 1
1674  SetWindowLong(hwnd, GWL_USERDATA, (LONG) (((CREATESTRUCT *) lParam)->lpCreateParams));
1675 #else
1676  SetProp(hwnd, "OGLHANDLE", (((CREATESTRUCT *) lParam)->lpCreateParams));
1677 #endif
1678  }
1679 
1680  /* check to make sure we have a valid window data structure in case */
1681  /* it is destroyed while there are still pending messages... */
1682 #if defined(_M_X64) || defined(_WIN64) || defined(_Wp64)
1683  handle = (oglhandle *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
1684 #elif 1
1685  handle = (oglhandle *) GetWindowLong(hwnd, GWL_USERDATA);
1686 #else
1687  handle = (oglhandle *) GetProp(hwnd, "OGLHANDLE");
1688 #endif
1689  if (handle == NULL)
1690  return DefWindowProc(hwnd, msg, wParam, lParam);
1691 
1692  switch (msg) {
1693  case WM_CREATE:
1694  handle->hWnd = hwnd; /* must be set before we do anything else */
1695  handle->hRC = SetupOpenGL(handle);
1696  return 0;
1697 
1698  case WM_MOVE:
1699  wglMakeCurrent(handle->hDC, handle->hRC);
1700  handle->xpos = LOWORD(lParam);
1701  handle->ypos = HIWORD(lParam);
1702  return 0;
1703 
1704  case WM_SIZE:
1705  wglMakeCurrent(handle->hDC, handle->hRC);
1706  handle->width = LOWORD(lParam);
1707  handle->height = HIWORD(lParam);
1708  return 0;
1709 
1710  case WM_KEYDOWN:
1711  handle->evdev = GLWIN_EV_KBD;
1712  /* try to map to ASCII first */
1713  /* handle->evkey = MapVirtualKey((UINT) wParam, MAPVK_VK_TO_CHAR); */
1714  handle->evkey = MapVirtualKey((UINT) wParam, 2);
1715 
1716  if (handle->evkey != 0) {
1717  /* Windows platforms return a raw character (upper case) */
1718  /* without applying shift-state modifiers, so we manually */
1719  /* query shift key modifier state and apply the modifier */
1720  /* ourselves w/ toupper()/tolower(). */
1721  int shiftstate = ((handle->MouseFlags & MK_SHIFT) != 0);
1722  handle->evkey = (shiftstate) ? toupper(handle->evkey) : tolower(handle->evkey);
1723  } else {
1724  /* if no ASCII code, try mapping to a virtual key scan code, */
1725  /* but don't bother distinguishing which left/right key it is */
1726  /*unsigned int keysym = MapVirtualKey((UINT) wParam, MAPVK_VK_TO_VSC);*/
1727  unsigned int keysym = (unsigned int) wParam;
1728 
1729  switch (keysym) {
1730  case VK_UP: handle->evdev = GLWIN_EV_KBD_UP; break;
1731  case VK_DOWN: handle->evdev = GLWIN_EV_KBD_DOWN; break;
1732  case VK_LEFT: handle->evdev = GLWIN_EV_KBD_LEFT; break;
1733  case VK_RIGHT: handle->evdev = GLWIN_EV_KBD_RIGHT; break;
1734  case VK_PRIOR: handle->evdev = GLWIN_EV_KBD_PAGE_UP; break;
1735  case VK_NEXT: handle->evdev = GLWIN_EV_KBD_PAGE_UP; break;
1736  case VK_HOME: handle->evdev = GLWIN_EV_KBD_HOME; break;
1737  case VK_END: handle->evdev = GLWIN_EV_KBD_END; break;
1738  case VK_INSERT: handle->evdev = GLWIN_EV_KBD_INSERT; break;
1739  case VK_DELETE: handle->evdev = GLWIN_EV_KBD_DELETE; break;
1740 
1741  case VK_F1: handle->evdev = GLWIN_EV_KBD_F1; break;
1742  case VK_F2: handle->evdev = GLWIN_EV_KBD_F2; break;
1743  case VK_F3: handle->evdev = GLWIN_EV_KBD_F3; break;
1744  case VK_F4: handle->evdev = GLWIN_EV_KBD_F4; break;
1745  case VK_F5: handle->evdev = GLWIN_EV_KBD_F5; break;
1746  case VK_F6: handle->evdev = GLWIN_EV_KBD_F6; break;
1747  case VK_F7: handle->evdev = GLWIN_EV_KBD_F7; break;
1748  case VK_F8: handle->evdev = GLWIN_EV_KBD_F8; break;
1749  case VK_F9: handle->evdev = GLWIN_EV_KBD_F9; break;
1750  case VK_F10: handle->evdev = GLWIN_EV_KBD_F10; break;
1751  case VK_F11: handle->evdev = GLWIN_EV_KBD_F11; break;
1752  case VK_F12: handle->evdev = GLWIN_EV_KBD_F12; break;
1753 
1754  case VK_ESCAPE: handle->evdev = GLWIN_EV_KBD_ESC; break;
1755 
1756  default:
1757  handle->evdev = GLWIN_EV_NONE;
1758  break;
1759  }
1760  }
1761  return 0;
1762 
1763  case WM_MOUSEMOVE:
1764  win32decodemouse(handle, lParam);
1765  handle->evdev = GLWIN_EV_MOUSE_MOVE;
1766  handle->MouseFlags = (long) wParam;
1767  if (!(handle->MouseFlags & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)))
1768  ReleaseCapture();
1769  return 0;
1770 
1771  case WM_MOUSEWHEEL:
1772  {
1773  int wheeldelta = ((short) HIWORD(wParam));
1774  if (wheeldelta > (WHEEL_DELTA / 2)) {
1775  handle->evdev = GLWIN_EV_MOUSE_WHEELUP;
1776  } else if (wheeldelta < -(WHEEL_DELTA / 2)) {
1777  handle->evdev = GLWIN_EV_MOUSE_WHEELDOWN;
1778  }
1779  }
1780  return 0;
1781 
1782  case WM_LBUTTONDOWN:
1783  SetCapture(hwnd);
1784  win32decodemouse(handle, lParam);
1785  handle->MouseFlags = (long) wParam;
1786  handle->evdev = GLWIN_EV_MOUSE_LEFT;
1787  handle->evval = 1;
1788  return 0;
1789 
1790  case WM_LBUTTONUP:
1791  win32decodemouse(handle, lParam);
1792  handle->MouseFlags = (long) wParam;
1793  handle->evdev = GLWIN_EV_MOUSE_LEFT;
1794  handle->evval = 0;
1795  if (!(handle->MouseFlags & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)))
1796  ReleaseCapture();
1797  return 0;
1798 
1799  case WM_MBUTTONDOWN:
1800  SetCapture(hwnd);
1801  win32decodemouse(handle, lParam);
1802  handle->MouseFlags = (long) wParam;
1803  handle->evdev = GLWIN_EV_MOUSE_MIDDLE;
1804  handle->evval = 1;
1805  return 0;
1806 
1807  case WM_MBUTTONUP:
1808  win32decodemouse(handle, lParam);
1809  handle->MouseFlags = (long) wParam;
1810  handle->evdev = GLWIN_EV_MOUSE_MIDDLE;
1811  handle->evval = 0;
1812  if (!(handle->MouseFlags & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)))
1813  ReleaseCapture();
1814  return 0;
1815 
1816  case WM_RBUTTONDOWN:
1817  SetCapture(hwnd);
1818  win32decodemouse(handle, lParam);
1819  handle->MouseFlags = (long) wParam;
1820  handle->evdev = GLWIN_EV_MOUSE_RIGHT;
1821  handle->evval = 1;
1822  return 0;
1823 
1824  case WM_RBUTTONUP:
1825  win32decodemouse(handle, lParam);
1826  handle->MouseFlags = (long) wParam;
1827  handle->evdev = GLWIN_EV_MOUSE_RIGHT;
1828  handle->evval = 0;
1829  if (!(handle->MouseFlags & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)))
1830  ReleaseCapture();
1831  return 0;
1832 
1833  case WM_CLOSE:
1834 #if 1
1835  DestroyWindow(handle->hWnd);
1836 #else
1837  PostQuitMessage(0);
1838 #endif
1839  return 0;
1840 
1841  case WM_PAINT:
1842  BeginPaint(hwnd, &ps);
1843  EndPaint(hwnd, &ps);
1844  return 0;
1845 
1846  case WM_SIZING:
1847  glClear(GL_COLOR_BUFFER_BIT);
1848  SwapBuffers(handle->hDC);
1849  glDrawBuffer(GL_BACK);
1850  return 0;
1851 
1852  case WM_SETCURSOR:
1853  if (LOWORD(lParam) == HTCLIENT) {
1854  SetCursor(LoadCursor(NULL, IDC_ARROW));
1855  return 0;
1856  }
1857  return DefWindowProc(hwnd, msg, wParam, lParam);
1858 
1859  default:
1860  return DefWindowProc(hwnd, msg, wParam, lParam);
1861  }
1862 
1863  return 0;
1864 }
1865 
1866 
1867 void * glwin_create(const char * wintitle, int width, int height) {
1868  oglhandle * handle;
1869  int rc;
1870  GLint stencilbits;
1871 
1872  handle = (oglhandle *) calloc(1, sizeof(oglhandle));
1873  if (handle == NULL)
1874  return NULL;
1875 
1876  handle->havestencil=0; /* initialize stencil state */
1877  handle->instereo=0; /* mark this as a non-stereo window */
1878 
1879  handle->width = width;
1880  handle->height = height;
1881  handle->evdev = GLWIN_EV_NONE;
1882 
1883  rc = OpenWin32Connection(handle);
1884  if (rc != 0) {
1885  printf("OpenWin32Connection() returned an error!\n");
1886  free(handle);
1887  return NULL;
1888  }
1889 
1890  handle->width = width;
1891  handle->height = height;
1892 
1893  rc = myCreateWindow(handle, wintitle, 0, 0, width, height);
1894  if (rc != 0) {
1895  printf("CreateWindow() returned an error!\n");
1896  free(handle);
1897  return NULL;
1898  }
1899 
1900  /* Enable Spaceball events to this window */
1901 #if 0
1902  handle->sball = spaceball_attach(handle->win);
1903 #endif
1904  /* initialize spaceball event structure */
1905  spaceball_init_event(&handle->sballevent);
1906  spaceball_clear_event(&handle->sballevent);
1907 
1908  /* check for an OpenGL stencil buffer */
1909  glGetIntegerv(GL_STENCIL_BITS, &stencilbits);
1910  if (stencilbits > 0) {
1911  handle->havestencil = 1;
1912  }
1913 
1914  return handle;
1915 }
1916 
1917 
1918 void glwin_destroy(void * voidhandle) {
1919  oglhandle * handle = (oglhandle *) voidhandle;
1920 
1921  wglDeleteContext(handle->hRC);
1922 #if 1
1923  DestroyWindow(handle->hWnd);
1924 #else
1925  PostQuitMessage( 0 );
1926 #endif
1927 
1928  /* glwin_handle_events(handle, GLWIN_EV_POLL_NONBLOCK); */
1929 }
1930 
1931 
1932 void glwin_swap_buffers(void * voidhandle) {
1933  oglhandle * handle = (oglhandle *) voidhandle;
1934  glFlush();
1935  SwapBuffers(handle->hDC);
1936  glDrawBuffer(GL_BACK);
1937 }
1938 
1939 
1940 int glwin_handle_events(void * voidhandle, int evblockmode) {
1941  oglhandle * handle = (oglhandle *) voidhandle;
1942  MSG msg;
1943  int rc=0;
1944  int pending=0;
1945 
1946  handle->evdev = GLWIN_EV_NONE;
1947  handle->evval = 0;
1948  handle->evkey = '\0';
1949 
1950  /* This pumps the Windows message queue, forcing events to be updated */
1951  /* by the time we return from DispatchMessage. */
1952  pending=PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
1953  while (!rc && (evblockmode || pending)) {
1954  if (pending) {
1955  TranslateMessage(&msg); /* translate the message */
1956  DispatchMessage(&msg); /* fire it off to the window proc */
1957  pending=0;
1958  } else if (evblockmode == GLWIN_EV_POLL_BLOCK) {
1959  if (GetMessage(&msg, NULL, 0, 0)) {
1960  TranslateMessage(&msg);
1961  DispatchMessage(&msg);
1962  }
1963  } else {
1964  if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1965  TranslateMessage(&msg); /* translate the message */
1966  DispatchMessage(&msg); /* fire it off to the window proc */
1967  }
1968  }
1969  if (handle->evdev != GLWIN_EV_NONE)
1970  rc=1;
1971  }
1972 
1973  return rc;
1974 }
1975 
1976 
1977 int glwin_resize(void *voidhandle, int width, int height) {
1978  RECT rcClient, rcWindow;
1979  POINT ptDiff;
1980  oglhandle * handle = (oglhandle *) voidhandle;
1981  if (handle == NULL)
1982  return -1;
1983 
1984  GetClientRect(handle->hWnd, &rcClient);
1985  GetWindowRect(handle->hWnd, &rcWindow);
1986  ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
1987  ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
1988  MoveWindow(handle->hWnd, rcWindow.left, rcWindow.top, width + ptDiff.x, height + ptDiff.y, TRUE);
1989 
1990  return 0;
1991 }
1992 
1993 
1994 int glwin_reposition(void *voidhandle, int xpos, int ypos) {
1995  RECT rcClient, rcWindow;
1996  oglhandle * handle = (oglhandle *) voidhandle;
1997  if (handle == NULL)
1998  return -1;
1999 
2000  GetClientRect(handle->hWnd, &rcClient);
2001  GetWindowRect(handle->hWnd, &rcWindow);
2002  MoveWindow(handle->hWnd, xpos, ypos, rcWindow.right-rcWindow.left, rcWindow.bottom-rcWindow.top, TRUE);
2003 
2004  return 0;
2005 }
2006 
2007 
2008 int glwin_fullscreen(void * voidhandle, int fson, int xinescreen) {
2009  return -1;
2010 }
2011 
2012 #endif
2013 
2014 
2015 /*
2016  * Code used for both Windows and Linux
2017  */
2018 int glwin_query_extension(const char *extname) {
2019  char *ext;
2020  char *endext;
2021  if (!extname)
2022  return 0;
2023 
2024  /* search for extension in list of available extensions */
2025  ext = (char *) glGetString(GL_EXTENSIONS);
2026  if (ext != NULL) {
2027  endext = ext + strlen(ext);
2028  while (ext < endext) {
2029  size_t n = strcspn(ext, " ");
2030  if ((strlen(extname) == n) && (strncmp(extname, ext, n) == 0)) {
2031  return 1; /* extension is available */
2032  break;
2033  }
2034  ext += (n + 1);
2035  }
2036  }
2037 
2038  return 0; /* False, extension is not available */
2039 }
2040 
2041 
2042 int glwin_query_vsync(void *voidhandle, int *onoff) {
2043  oglhandle * handle = (oglhandle *) voidhandle;
2044  if (handle == NULL)
2045  return GLWIN_ERROR;
2046 
2047 #if defined(GLX_EXT_swap_control)
2048  if (glx_query_extension(handle->dpy, "GLX_EXT_swap_control")) {
2049  int interval = 0;
2050  unsigned int tmp = -1;
2051  glXQueryDrawable(handle->dpy, glXGetCurrentDrawable(), GLX_SWAP_INTERVAL_EXT, &tmp);
2052  interval = tmp;
2053  if (interval > 0) {
2054  *onoff = 1;
2055  } else {
2056  *onoff = 0;
2057  }
2058  return GLWIN_SUCCESS;
2059  }
2060 #elif 0
2061  GLuint count = 0;
2062  glwin_ext_fctns *ext = handle->ext;
2063  if (ext->hasgetvideosyncsgi) {
2064  /* XXX this doesn't help much since we get non-zero counts */
2065  /* even when using a screen with vsync disabled */
2066  if (GLXGETVIDEOSYNCSGI(&count) == 0) {
2067  if (count > 0) {
2068  *onoff = 1;
2069  } else {
2070  *onoff = 0;
2071  }
2072  }
2073  return GLWIN_SUCCESS;
2074  }
2075 #endif
2076 
2077  return GLWIN_NOT_IMPLEMENTED;
2078 }
2079 
2080 
2081 #if !(defined(WIN32) || defined(_WIN64))
2082 
2083 typedef struct {
2084  int isvalid;
2085  GLenum drawbufs[16];
2086  GLuint fbo;
2087  GLuint tex;
2088  GLuint depth;
2089 } glwin_fbo_target;
2090 
2091 
2092 int glwin_fbo_target_bind(void *voidhandle, void *voidtarget) {
2093  oglhandle * handle = (oglhandle *) voidhandle;
2094  glwin_fbo_target * fb = (glwin_fbo_target *) voidtarget;
2095  if (handle == NULL || fb == NULL)
2096  return GLWIN_ERROR;
2097  glwin_ext_fctns *ext = handle->ext;
2098 
2099  GLBINDFRAMEBUFFER(GL_FRAMEBUFFER, fb->fbo); /* bind FBO */
2100 
2101  return GLWIN_SUCCESS;
2102 }
2103 
2104 
2105 int glwin_fbo_target_unbind(void *voidhandle, void *voidtarget) {
2106  oglhandle * handle = (oglhandle *) voidhandle;
2107  glwin_fbo_target * fb = (glwin_fbo_target *) voidtarget;
2108  if (handle == NULL || fb == NULL)
2109  return GLWIN_ERROR;
2110  glwin_ext_fctns *ext = handle->ext;
2111 
2112  GLBINDFRAMEBUFFER(GL_FRAMEBUFFER, 0); /* bind the normal framebuffer */
2113 
2114  return GLWIN_SUCCESS;
2115 }
2116 
2117 
2118 int glwin_fbo_target_destroy(void *voidhandle, void *voidtarget) {
2119  oglhandle * handle = (oglhandle *) voidhandle;
2120  glwin_fbo_target * fb = (glwin_fbo_target *) voidtarget;
2121  if (handle == NULL || fb == NULL)
2122  return GLWIN_ERROR;
2123  glwin_ext_fctns *ext = handle->ext;
2124 
2125  GLDELETERENDERBUFFERS(1, &fb->depth);
2126  GLDELETEFRAMEBUFFERS(1, &fb->fbo);
2127  glDeleteTextures(1, &fb->tex);
2128  free(fb);
2129 
2130  return GLWIN_SUCCESS;
2131 }
2132 
2133 
2134 int glwin_fbo_target_resize(void *voidhandle, void *voidtarget, int wsx, int wsy) {
2135  oglhandle * handle = (oglhandle *) voidhandle;
2136  glwin_fbo_target * fb = (glwin_fbo_target *) voidtarget;
2137  if (handle == NULL || fb == NULL)
2138  return GLWIN_ERROR;
2139  glwin_ext_fctns *ext = handle->ext;
2140 
2141 #if 0
2142  printf("\nglwin_fbo_target_resize(): W %d x %d\n", wsx, wsy);
2143 #endif
2144 
2145  GLBINDFRAMEBUFFER(GL_FRAMEBUFFER, fb->fbo);
2146 
2147  glBindTexture(GL_TEXTURE_2D, fb->tex);
2148  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, wsx, wsy, 0,
2149  GL_RGBA, GL_UNSIGNED_BYTE, 0);
2150  GLFRAMEBUFFERTEXTURE2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
2151  GL_TEXTURE_2D, fb->tex, 0);
2152  GLBINDRENDERBUFFER(GL_RENDERBUFFER, fb->depth);
2153  GLRENDERBUFFERSTORAGE(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, wsx, wsy);
2154  GLFRAMEBUFFERRENDERBUFFER(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
2155  GL_RENDERBUFFER, fb->depth);
2156  if (GLCHECKFRAMEBUFFERSTATUS(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
2157  return GLWIN_ERROR;
2158  }
2159 
2160  fb->drawbufs[0] = GL_COLOR_ATTACHMENT0;
2161  GLDRAWBUFFERS(1, fb->drawbufs);
2162 
2163  return GLWIN_SUCCESS;
2164 }
2165 
2166 
2167 void *glwin_fbo_target_create(void *voidhandle, int wsx, int wsy) {
2168  oglhandle * handle = (oglhandle *) voidhandle;
2169  if (handle == NULL)
2170  return NULL;
2171  glwin_ext_fctns *ext = handle->ext;
2172 
2173  if (!ext->hasglfborendertarget)
2174  return NULL; /* fail out if the required GL extensions aren't available */
2175 
2176  glwin_fbo_target *fb =
2177  (glwin_fbo_target *) calloc(1, sizeof(glwin_fbo_target));
2178 
2179  if (fb != NULL) {
2180  /* create target texture */
2181  glGenTextures(1, &fb->tex);
2182  glBindTexture(GL_TEXTURE_2D, fb->tex);
2183 
2184  /* set tex mode to replace... */
2185  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2186 
2187  /* we need to use nearest-pixel filtering... */
2188 #if 1
2189  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2190  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2191 #else
2192  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2193  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2194 #endif
2195  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2196  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2197 #if 1
2198  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, wsx, wsy, 0,
2199  GL_RGBA, GL_UNSIGNED_BYTE, 0);
2200 #else
2201  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, wsx, wsy, 0,
2202  GL_RGBA, GL_UNSIGNED_BYTE, 0);
2203 #endif
2204  glBindTexture(GL_TEXTURE_2D, 0); /* XXX may not need this */
2205 
2206 
2207  /* create RBO for depth buffer */
2208  GLGENRENDERBUFFERS(1, &fb->depth);
2209  GLBINDRENDERBUFFER(GL_RENDERBUFFER, fb->depth);
2210  GLRENDERBUFFERSTORAGE(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, wsx, wsy);
2211  GLBINDRENDERBUFFER(GL_RENDERBUFFER, 0); /* XXX not sure if necessary */
2212 
2213 
2214  /* create FBO */
2215  GLGENFRAMEBUFFERS(1, &fb->fbo);
2216  GLBINDFRAMEBUFFER(GL_FRAMEBUFFER, fb->fbo);
2217 
2218  /* Set "renderedTexture" as our colour attachement #0 */
2219  GLFRAMEBUFFERTEXTURE2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
2220  GL_TEXTURE_2D, fb->tex, 0);
2221 
2222  /* attach FBO to depth buffer attachment point */
2223  GLFRAMEBUFFERRENDERBUFFER(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
2224  GL_RENDERBUFFER, fb->depth);
2225 
2226  if (GLCHECKFRAMEBUFFERSTATUS(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
2227  return NULL;
2228  }
2229 
2230  /* set the list of draw buffers. */
2231  fb->drawbufs[0] = GL_COLOR_ATTACHMENT0;
2232  GLDRAWBUFFERS(1, fb->drawbufs); /* 1 is number of bufs */
2233 
2234  /* switch back to window system framebuffer */
2235  GLBINDFRAMEBUFFER(GL_FRAMEBUFFER, 0);
2236  }
2237 
2238 #if 0
2239  if (glwin_fbo_target_resize(voidhandle, fb, wsx, wsy) == GLWIN_ERROR) {
2240  glwin_fbo_target_destroy(voidhandle, fb);
2241  return NULL;
2242  }
2243 #endif
2244 
2245  return fb;
2246 }
2247 
2248 
2249 int glwin_fbo_target_draw_normal(void *voidhandle, void *voidtarget) {
2250  oglhandle * handle = (oglhandle *) voidhandle;
2251  glwin_fbo_target * fb = (glwin_fbo_target *) voidtarget;
2252  if (handle == NULL || fb == NULL)
2253  return GLWIN_ERROR;
2254  glwin_ext_fctns *ext = handle->ext;
2255 
2256  GLBINDFRAMEBUFFER(GL_FRAMEBUFFER, 0); /* bind standard framebuffer */
2257 
2258  return GLWIN_SUCCESS;
2259 }
2260 
2261 
2262 int glwin_fbo_target_draw_fbo(void *voidhandle, void *voidtarget, int wsx, int wsy) {
2263  oglhandle * handle = (oglhandle *) voidhandle;
2264  glwin_fbo_target * fb = (glwin_fbo_target *) voidtarget;
2265  if (handle == NULL || fb == NULL)
2266  return GLWIN_ERROR;
2267 
2268  /* render to the screen */
2269  glwin_fbo_target_unbind(voidhandle, voidtarget);
2270 
2271  glBindTexture(GL_TEXTURE_2D, fb->tex);
2272  glEnable(GL_TEXTURE_2D);
2273  glColor3f(0.0, 0.0, 1.0);
2274  glBegin(GL_QUADS);
2275  glTexCoord2f(0.0f, 0.0f);
2276  glVertex2f(0, 0);
2277  glTexCoord2f(0.0f, 1.0f);
2278  glVertex2f(0, wsy);
2279  glTexCoord2f(1.0f, 1.0f);
2280  glVertex2f(wsx, wsy);
2281  glTexCoord2f(1.0f, 0.0f);
2282  glVertex2f(wsx, 0);
2283  glEnd();
2284  glDisable(GL_TEXTURE_2D);
2285 
2286  return GLWIN_SUCCESS;
2287 }
2288 
2289 
2290 /*
2291  * HMD-specific FBO renderer
2292  */
2293 
2294 #define HMD_DIVCNT 10
2295 
2296 static void hmd_compute_warped_coords(int divcnt, int wsx, int wsy,
2297  float rscale, float wscale,
2298  float *xcrds, float *ycrds,
2299  const float *user_distort_coeff5) {
2300  float divs = (float) divcnt;
2301  float hwidth = wsx / 2.0f;
2302  float hwdiv = hwidth / divs;
2303  float hdiv = wsy / divs;
2304  float cx=hwidth / 2.0f;
2305  float cy=wsy / 2.0f;
2306  float x, y;
2307 
2308  /* assume Oculus DK2 coefficients if caller doesn't specify */
2309  const float dk2_warp_coeff[5] = { 1.000f, 0.000f, 0.220f, 0.000f, 0.240f };
2310 #if 0
2311  const float msr_warp_coeff[5] = { 1.000f, 0.290f, 0.195f, 0.045f, 0.360f };
2312 #endif
2313  const float *C = dk2_warp_coeff;
2314 
2315  /*
2316  * use caller-provided distortion correction coefficients when
2317  * available, otherwise assume Oculus DK2
2318  */
2319  if (user_distort_coeff5)
2320  C = user_distort_coeff5;
2321 
2322  int ix, iy;
2323  for (iy=0; iy<=divcnt; iy++) {
2324  for (ix=0; ix<=divcnt; ix++) {
2325  float drx, dry, r, r2, rnew;
2326  int addr = iy*(divcnt+1) + ix;
2327  x = ix * hwdiv;
2328  y = iy * hdiv;
2329 
2330  /* HMD image barrel distortion warping */
2331  float rnorm = wsy * 1.0f;
2332  drx = (x - cx) / rnorm;
2333  dry = (y - cy) / rnorm;
2334  r2 = drx*drx + dry*dry;
2335  r = sqrt(r2);
2336 
2337  rnew = C[0] + r*C[1] + r2*C[2] + r*r2*C[3] + r2*r2*C[4];
2338 
2339  rnew = 1.0f/rnew;
2340  rnorm *= 1.0f * rscale;
2341  x = wscale * rnorm * rnew * drx + cx;
2342  y = rnorm * rnew * dry + cy;
2343 
2344  xcrds[addr] = x;
2345  ycrds[addr] = y;
2346  }
2347  }
2348 }
2349 
2350 
2351 /* draw lines w/ HMD warp correction to check remaining optical distortions */
2352 static void hmd_draw_eye_lines(int divcnt, int xoff, int width, int height,
2353  float *xcrds, float *ycrds) {
2354  float x, y;
2355  int ix, iy;
2356 
2357  glDisable(GL_TEXTURE_2D);
2358  glColor3f(1.0f, 1.0f, 1.0f);
2359 
2360  for (iy=0; iy<=divcnt; iy++) {
2361  for (ix=0; ix<divcnt; ix++) {
2362  int addr = iy*(divcnt+1) + ix;
2363  y = ycrds[addr];
2364  x = xcrds[addr] + xoff;
2365  float xn = xcrds[addr+1] + xoff;
2366  float yn = ycrds[addr+1];
2367  glBegin(GL_LINES);
2368  glVertex2f(x, y);
2369  glVertex2f(xn, yn);
2370  glEnd();
2371  }
2372  }
2373  for (ix=0; ix<=divcnt; ix++) {
2374  for (iy=0; iy<divcnt; iy++) {
2375  int addr = iy*(divcnt+1) + ix;
2376  x = xcrds[addr] + xoff;
2377  y = ycrds[addr];
2378  float xn = xcrds[addr + divcnt+1] + xoff;
2379  float yn = ycrds[addr + divcnt+1];
2380  glBegin(GL_LINES);
2381  glVertex2f(x, y);
2382  glVertex2f(xn, yn);
2383  glEnd();
2384  }
2385  }
2386 }
2387 
2388 
2389 /* draw quads w/ HMD warp correction */
2390 static void hmd_draw_eye_texquads(int divcnt, int xoff, int width, int height,
2391  float *xcrds, float *ycrds) {
2392  float divs = (float) divcnt;
2393  float xtxdiv = 0.5f / divs;
2394  float ytxdiv = 1.0f / divs;
2395  float tx, ty;
2396  int ix, iy;
2397  float txoff = xoff / ((float) width);
2398 
2399  glBegin(GL_QUADS);
2400  for (iy=0,ty=1.0f; iy<divcnt; iy++,ty-=ytxdiv) {
2401  float tyn = ty-ytxdiv;
2402  for (ix=0,tx=0.0f; ix<divcnt; ix++,tx+=xtxdiv) {
2403  float txn = tx+xtxdiv;
2404  int addr = iy*(divcnt+1) + ix;
2405  float xx0y0 = xcrds[addr] + xoff;
2406  float yx0y0 = ycrds[addr];
2407  float xx1y0 = xcrds[addr + 1] + xoff;
2408  float yx1y0 = ycrds[addr + 1];
2409  float xx0y1 = xcrds[addr + divcnt+1] + xoff;
2410  float yx0y1 = ycrds[addr + divcnt+1];
2411  float xx1y1 = xcrds[addr + 1 + divcnt+1] + xoff;
2412  float yx1y1 = ycrds[addr + 1 + divcnt+1];
2413 
2414  glTexCoord2f(tx+txoff, ty);
2415  glVertex2f(xx0y0, yx0y0);
2416  glTexCoord2f(tx+txoff, tyn);
2417  glVertex2f(xx0y1, yx0y1);
2418  glTexCoord2f(txn+txoff, tyn);
2419  glVertex2f(xx1y1, yx1y1);
2420  glTexCoord2f(txn+txoff, ty);
2421  glVertex2f(xx1y0, yx1y0);
2422  }
2423  }
2424  glEnd();
2425 }
2426 
2427 
2428 /*
2429  * Structures for HMD spheremap display and image warping for
2430  * eye lens distortion correction
2431  */
2432 
2433 typedef struct {
2434  void *hmd_fbo;
2435  int divcnt;
2436  int wsx; /* window dimensions */
2437  int wsy;
2438  int wrot; /* flag indicating that window is rotated vs. HMD image */
2439  int ixs; /* image size */
2440  int iys;
2441  float *xcrds; /* use if there chromatic aberration is unnecessary */
2442  float *ycrds;
2443 
2444  /* chromatic aberration correction */
2445  float *Rxcrds;
2446  float *Rycrds;
2447  float *Gxcrds;
2448  float *Gycrds;
2449  float *Bxcrds;
2450  float *Bycrds;
2451 } glwin_warp_hmd;
2452 
2453 
2454 void glwin_spheremap_update_hmd_warp(void *vwin, void *voidwarp,
2455  int wsx, int wsy,
2456  int warpdivs, int ixs, int iys,
2457  const float *barrel_coeff, int force) {
2458  glwin_warp_hmd * warp = (glwin_warp_hmd *) voidwarp;
2459 
2460  if (force || warp->divcnt!=warpdivs || warp->wsx!=wsx || warp->wsy!=wsy) {
2461  const float Oculus_DK2_coeff[4] = { 1.0f, 0.22f, 0.24f, 0.0f };
2462  /* const float Oculus_DK1_coeff[4] = { 1.0f, 0.18f, 0.115f, 0.0f }; */
2463  if (!barrel_coeff)
2464  barrel_coeff = Oculus_DK2_coeff;
2465 
2466 #if 0
2467  printf("glwin_spheremap_update_hmd_warp(): W %d x %d, I %d x %d\n",
2468  wsx, wsy, ixs, iys);
2469  printf("warp: %.3f, %.3f, %.3f, %.3f\n",
2470  barrel_coeff[0], barrel_coeff[1], barrel_coeff[2], barrel_coeff[3]);
2471 #endif
2472 
2473 
2474  /* update FBO target for new window size */
2475  if (glwin_fbo_target_resize(vwin, warp->hmd_fbo, wsx, wsy) == GLWIN_ERROR) {
2476  printf("\nglwin_spheremap_update_hmd_warp(): "
2477  "an error occured resizing the FBO!\n");
2478  }
2479 
2480  /*
2481  * recompute the warp mesh
2482  */
2483  if (warp->xcrds != NULL)
2484  free(warp->xcrds);
2485  if (warp->ycrds != NULL)
2486  free(warp->ycrds);
2487 
2488  if (warp->Rxcrds != NULL)
2489  free(warp->Rxcrds);
2490  if (warp->Rycrds != NULL)
2491  free(warp->Rycrds);
2492  if (warp->Gxcrds != NULL)
2493  free(warp->Gxcrds);
2494  if (warp->Gycrds != NULL)
2495  free(warp->Gycrds);
2496  if (warp->Bxcrds != NULL)
2497  free(warp->Bxcrds);
2498  if (warp->Bycrds != NULL)
2499  free(warp->Bycrds);
2500 
2501  warp->wsx = wsx;
2502  warp->wsy = wsy;
2503  warp->divcnt = warpdivs;
2504  warp->xcrds = (float *) calloc(1, warpdivs*warpdivs*sizeof(float));
2505  warp->ycrds = (float *) calloc(1, warpdivs*warpdivs*sizeof(float));
2506  warp->Rxcrds = (float *) calloc(1, warpdivs*warpdivs*sizeof(float));
2507  warp->Rycrds = (float *) calloc(1, warpdivs*warpdivs*sizeof(float));
2508  warp->Gxcrds = (float *) calloc(1, warpdivs*warpdivs*sizeof(float));
2509  warp->Gycrds = (float *) calloc(1, warpdivs*warpdivs*sizeof(float));
2510  warp->Bxcrds = (float *) calloc(1, warpdivs*warpdivs*sizeof(float));
2511  warp->Bycrds = (float *) calloc(1, warpdivs*warpdivs*sizeof(float));
2512 
2513  /* plain image w/ no chromatic aberration correction */
2514  hmd_compute_warped_coords(warpdivs-1, wsx, wsy, 1.0f, 1.0f,
2515  warp->xcrds, warp->ycrds, barrel_coeff);
2516 
2517  /* set of RGB meshes for chromatic aberration correction */
2518  const float Rscale = 1.015f;
2519  const float Gscale = 1.000f;
2520  const float Bscale = 0.980f;
2521 
2522  hmd_compute_warped_coords(warpdivs-1, wsx,wsy, Rscale, 1.0f,
2523  warp->Rxcrds, warp->Rycrds, barrel_coeff);
2524  hmd_compute_warped_coords(warpdivs-1, wsx,wsy, Gscale, 1.0f,
2525  warp->Gxcrds, warp->Gycrds, barrel_coeff);
2526  hmd_compute_warped_coords(warpdivs-1, wsx,wsy, Bscale, 1.0f,
2527  warp->Bxcrds, warp->Bycrds, barrel_coeff);
2528  }
2529 }
2530 
2531 
2532 void glwin_spheremap_destroy_hmd_warp(void *vwin, void *voidwarp) {
2533  glwin_warp_hmd * warp = (glwin_warp_hmd *) voidwarp;
2534  glwin_fbo_target_destroy(vwin, warp->hmd_fbo);
2535 
2536  if (warp->xcrds != NULL)
2537  free(warp->xcrds);
2538  if (warp->ycrds != NULL)
2539  free(warp->ycrds);
2540 
2541  if (warp->Rxcrds != NULL)
2542  free(warp->Rxcrds);
2543  if (warp->Rycrds != NULL)
2544  free(warp->Rycrds);
2545  if (warp->Gxcrds != NULL)
2546  free(warp->Gxcrds);
2547  if (warp->Gycrds != NULL)
2548  free(warp->Gycrds);
2549  if (warp->Bxcrds != NULL)
2550  free(warp->Bxcrds);
2551  if (warp->Bycrds != NULL)
2552  free(warp->Bycrds);
2553  free(warp);
2554 }
2555 
2556 
2557 void * glwin_spheremap_create_hmd_warp(void *vwin, int wsx, int wsy, int wrot,
2558  int warpdivs, int ixs, int iys,
2559  const float *user_coeff) {
2560  glwin_warp_hmd *warp = (glwin_warp_hmd *) calloc(1, sizeof(glwin_warp_hmd));
2561  warp->hmd_fbo = glwin_fbo_target_create(vwin, wsx, wsy);
2562  warp->wrot = wrot;
2563  glwin_spheremap_update_hmd_warp(vwin, warp, wsx, wsy, warpdivs,
2564  ixs, iys, user_coeff, 1);
2565  return warp;
2566 }
2567 
2568 
2569 int glwin_spheremap_draw_hmd_warp(void *vwin, void *voidwarp,
2570  int drawimage, int drawlines, int chromcorr,
2571  int wsx, int wsy, int ixs, int iys,
2572  const float *hmdquat,
2573  float fov, float rad, int hmd_spres) {
2574  oglhandle * handle = (oglhandle *) vwin;
2575  glwin_warp_hmd * warp = (glwin_warp_hmd *) voidwarp;
2576  glwin_fbo_target * fb = (glwin_fbo_target *) warp->hmd_fbo;
2577  if (handle == NULL || warp == NULL)
2578  return GLWIN_ERROR;
2579 
2580  glBindTexture(GL_TEXTURE_2D, 0); /* bind the RT image before drawing */
2581  glEnable(GL_TEXTURE_2D);
2582 
2583  glwin_fbo_target_bind(vwin, warp->hmd_fbo);
2585  ixs, iys, hmdquat, fov, rad, hmd_spres);
2586  glwin_fbo_target_unbind(vwin, warp->hmd_fbo); /* render to the screen */
2587 
2588  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2589  glClearColor(0.0, 0.0, 0.0, 1.0); /* black */
2590  glViewport(0, 0, wsx, wsy);
2591  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2592 
2593  glShadeModel(GL_SMOOTH);
2594  glMatrixMode(GL_PROJECTION);
2595  glLoadIdentity();
2596  glOrtho(0.0, wsx, wsy, 0.0, -1.0, 1.0);
2597  glMatrixMode(GL_MODELVIEW);
2598  glLoadIdentity();
2599 
2600  float hw = wsx * 0.5f;
2601  int dm1 = warp->divcnt-1;
2602 
2603 
2604  /*
2605  * draw texture map FBO using precomputed warp meshes
2606  */
2607  if (drawimage) {
2608  glBindTexture(GL_TEXTURE_2D, fb->tex);
2609  glEnable(GL_TEXTURE_2D);
2610 
2611  /* if chromatic abberation correction is enabled, use the RGB meshes */
2612  if (chromcorr) {
2613  glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
2614  hmd_draw_eye_texquads(dm1, 0, wsx, wsy, warp->Rxcrds, warp->Rycrds);
2615  hmd_draw_eye_texquads(dm1, hw, wsx, wsy, warp->Rxcrds, warp->Rycrds);
2616  glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE);
2617  hmd_draw_eye_texquads(dm1, 0, wsx, wsy, warp->Gxcrds, warp->Gycrds);
2618  hmd_draw_eye_texquads(dm1, hw, wsx, wsy, warp->Gxcrds, warp->Gycrds);
2619  glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE);
2620  hmd_draw_eye_texquads(dm1, 0, wsx, wsy, warp->Bxcrds, warp->Bycrds);
2621  hmd_draw_eye_texquads(dm1, hw, wsx, wsy, warp->Bxcrds, warp->Bycrds);
2622  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2623  } else {
2624  hmd_draw_eye_texquads(dm1, 0, wsx, wsy, warp->xcrds, warp->ycrds);
2625  hmd_draw_eye_texquads(dm1, hw, wsx, wsy, warp->xcrds, warp->ycrds);
2626  }
2627  }
2628  glDisable(GL_TEXTURE_2D);
2629 
2630  /*
2631  * draw warp mesh grid lines over the top of the eye images if requested
2632  */
2633  if (drawlines) {
2634  /* if chromatic abberation correction is enabled, use the RGB meshes */
2635  if (chromcorr) {
2636  glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
2637  hmd_draw_eye_lines(dm1, 0, wsx, wsy, warp->Rxcrds, warp->Rycrds);
2638  hmd_draw_eye_lines(dm1, hw, wsx, wsy, warp->Rxcrds, warp->Rycrds);
2639  glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE);
2640  hmd_draw_eye_lines(dm1, 0, wsx, wsy, warp->Gxcrds, warp->Gycrds);
2641  hmd_draw_eye_lines(dm1, hw, wsx, wsy, warp->Gxcrds, warp->Gycrds);
2642  glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE);
2643  hmd_draw_eye_lines(dm1, 0, wsx, wsy, warp->Bxcrds, warp->Bycrds);
2644  hmd_draw_eye_lines(dm1, hw, wsx, wsy, warp->Bxcrds, warp->Bycrds);
2645  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2646  } else {
2647  hmd_draw_eye_lines(dm1, 0, wsx, wsy, warp->xcrds, warp->ycrds);
2648  hmd_draw_eye_lines(dm1, hw, wsx, wsy, warp->xcrds, warp->ycrds);
2649  }
2650  }
2651 
2652  return GLWIN_SUCCESS;
2653 }
2654 
2655 
2656 
2657 
2658 /*
2659  * GLSL support routines
2660  */
2661 
2662 static void glwin_print_glsl_infolog(void *voidhandle, GLhandleARB obj,
2663  const char *msg) {
2664  oglhandle *handle = (oglhandle *) voidhandle;
2665  if (handle == NULL)
2666  return;
2667  glwin_ext_fctns *ext = handle->ext;
2668 
2669  GLint blen = 0; /* length of buffer to allocate */
2670  GLint slen = 0; /* strlen actually written to buffer */
2671  GLcharARB *infoLog;
2672 
2673  GLGETOBJECTPARAMETERIVARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB , &blen);
2674  if (blen > 1) {
2675  if ((infoLog = (GLcharARB *) calloc(1, blen)) == NULL) {
2676  printf("GLSL shader compiler could not allocate InfoLog buffer\n");
2677  return;
2678  }
2679 
2680  GLGETINFOLOGARB(obj, blen, &slen, infoLog);
2681  printf(" %s\n", msg);
2682  printf(" %s\n", (char *) infoLog);
2683  free(infoLog);
2684  }
2685 }
2686 
2687 
2688 static int glwin_compile_shaders(void *voidhandle, glsl_shader *sh,
2689  const GLubyte *vertexShader,
2690  const GLubyte *fragmentShader,
2691  int verbose) {
2692  oglhandle *handle = (oglhandle *) voidhandle;
2693  glwin_ext_fctns *ext = handle->ext;
2694 
2695  GLint vert_compiled = 0;
2696  GLint frag_compiled = 0;
2697  GLint shaders_linked = 0;
2698  GLint length;
2699 
2700  /* clear shader structure before proceeding */
2701  memset(sh, 0, sizeof(glsl_shader));
2702 
2703  /* bail out if we don't have valid pointers for shader source code */
2704  if (vertexShader == NULL || fragmentShader == NULL) {
2705  return GLWIN_ERROR;
2706  }
2707 
2708  /* Hand the source code strings to OpenGL. */
2709  length = strlen((const char *) vertexShader);
2710  GLSHADERSOURCEARB(sh->VertexShaderObject, 1, (const char **) &vertexShader, &length);
2711 
2712  length = strlen((const char *) fragmentShader);
2713  GLSHADERSOURCEARB(sh->FragmentShaderObject, 1, (const char **) &fragmentShader, &length);
2714 
2715  /* Compile the vertex and fragment shader, and print out */
2716  /* the compiler log file if one is available. */
2717  GLCOMPILESHADERARB(sh->VertexShaderObject);
2718  GLGETOBJECTPARAMETERIVARB(sh->VertexShaderObject,
2719  GL_OBJECT_COMPILE_STATUS_ARB, &vert_compiled);
2720 
2721  if (verbose)
2722  glwin_print_glsl_infolog(voidhandle, sh->VertexShaderObject, "OpenGL vertex shader compilation log: ");
2723 
2724  GLCOMPILESHADERARB(sh->FragmentShaderObject);
2725  GLGETOBJECTPARAMETERIVARB(sh->FragmentShaderObject,
2726  GL_OBJECT_COMPILE_STATUS_ARB, &frag_compiled);
2727 
2728  if (verbose)
2729  glwin_print_glsl_infolog(voidhandle, sh->FragmentShaderObject, "OpenGL fragment shader compilation log: ");
2730 
2731  if (vert_compiled && frag_compiled) {
2732  /* Populate the program object with the two compiled shaders */
2733  GLATTACHOBJECTARB(sh->ProgramObject, sh->VertexShaderObject);
2734  GLATTACHOBJECTARB(sh->ProgramObject, sh->FragmentShaderObject);
2735 
2736  /* Link the whole thing together and print out the linker log file */
2737  GLLINKPROGRAMARB(sh->ProgramObject);
2738  GLGETOBJECTPARAMETERIVARB(sh->ProgramObject, GL_OBJECT_LINK_STATUS_ARB, &shaders_linked);
2739 
2740  if (verbose)
2741  glwin_print_glsl_infolog(voidhandle, sh->ProgramObject, "OpenGL shader linkage log: " );
2742  }
2743 
2744  /* We want the shaders to go away as soon as they are detached from */
2745  /* the program object (or program objects) they are attached to. We */
2746  /* can simply call delete now to achieve that. Note that calling */
2747  /* delete on a program object will result in all shaders attached to */
2748  /* that program object to be detached. If delete has been called for */
2749  /* these shaders, calling delete on the program object will result in */
2750  /* the shaders being deleted as well. */
2751  if (vert_compiled)
2752  GLDELETEOBJECTARB(sh->VertexShaderObject);
2753  if (frag_compiled)
2754  GLDELETEOBJECTARB(sh->FragmentShaderObject);
2755 
2756  if (vert_compiled && frag_compiled && shaders_linked) {
2757  sh->isvalid = 1;
2758  return GLWIN_SUCCESS;
2759  } else {
2760  memset(sh, 0, sizeof(glsl_shader));
2761  return GLWIN_ERROR;
2762  }
2763 }
2764 
2765 
2766 int glwin_destroy_shaders(void *voidhandle, glsl_shader *sh) {
2767  oglhandle *handle = (oglhandle *) voidhandle;
2768  glwin_ext_fctns *ext = handle->ext;
2769 
2770  /* destroy the GLSL shaders and associated state */
2771  if (sh->isvalid) {
2772  GLDELETEOBJECTARB(sh->ProgramObject);
2773  memset(sh, 0, sizeof(glsl_shader));
2774 
2775  return GLWIN_SUCCESS;
2776  }
2777 
2778  return GLWIN_ERROR;
2779 }
2780 
2781 
2782 /*
2783  * GLSL vertex and fragment shaders for HMD rendering
2784  */
2785 const char *hmd_vert =
2786  "// requires GLSL version 1.10 \n"
2787  "#version 110 \n"
2788  " \n"
2789  " \n"
2790  " \n"
2791  "void main(void) { \n"
2792  " // transform vertex to Eye space for user clipping plane calculations \n"
2793  " vec4 ecpos = gl_ModelViewMatrix * gl_Vertex; \n"
2794  " gl_ClipVertex = ecpos; \n"
2795  " \n"
2796  " // transform, normalize, and output normal. \n"
2797  " oglnormal = normalize(gl_NormalMatrix * gl_Normal); \n"
2798  " \n"
2799  " // pass along vertex color for use fragment shading, \n"
2800  " // fragment shader will get an interpolated color. \n"
2801  " oglcolor = vec3(gl_Color); \n"
2802  " \n"
2803  " \n"
2804 #if 1
2805  " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n"
2806 #else
2807  " gl_Position = ftransform(); \n"
2808 #endif
2809  " \n"
2810  " \n"
2811  " \n"
2812  " \n"
2813  "} \n"
2814  " \n";
2815 
2816 
2817 const char *hmd_frag =
2818  " \n"
2819  " \n"
2820  " \n"
2821  " \n"
2822  "void main(void) { \n"
2823  " \n"
2824 #if 1
2825  " // Flip the surface normal if it is facing away from the viewer, \n"
2826  " // determined by polygon winding order provided by OpenGL. \n"
2827  " vec3 N = normalize(oglnormal); \n"
2828  " if (!gl_FrontFacing) { \n"
2829  " N = -N; \n"
2830  " } \n"
2831 #endif
2832  " \n"
2833  " \n"
2834  " \n"
2835  " \n"
2836  " \n"
2837  " \n"
2838  "} \n"
2839  " \n";
2840 
2841 
2842 int glwin_compile_hmd_shaders(void *voidhandle, glsl_shader *sh) {
2843  int rc = glwin_compile_shaders(voidhandle, sh,
2844  (GLubyte *) hmd_vert, (GLubyte *) hmd_frag, 1);
2845  return rc;
2846 }
2847 
2848 #endif
2849 
2850 
2851 void glwin_draw_image(void * voidhandle, int ixs, int iys, unsigned char * img) {
2852  glRasterPos2i(0, 0);
2853  glDrawPixels(ixs, iys, GL_RGB, GL_UNSIGNED_BYTE, img);
2854  glwin_swap_buffers(voidhandle);
2855 }
2856 
2857 
2858 void glwin_draw_image_rgb3u(void *voidhandle, int stereomode, int ixs, int iys,
2859  const unsigned char *rgb3u) {
2860  int wxs=0, wys=0;
2861  glwin_get_winsize(voidhandle, &wxs, &wys);
2862  glViewport(0, 0, wxs, wys);
2863 
2864  glDrawBuffer(GL_BACK);
2865  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2866  glClearColor(0.0, 0.0, 0.0, 1.0); /* black */
2867  glClear(GL_COLOR_BUFFER_BIT);
2868 
2869  glShadeModel(GL_FLAT);
2870  glMatrixMode(GL_PROJECTION);
2871  glLoadIdentity();
2872  glOrtho(0.0, wxs, 0.0, wys, -1.0, 1.0);
2873  glMatrixMode(GL_MODELVIEW);
2874  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2875  glPixelZoom(1.0, 1.0);
2876 
2877  if (stereomode == GLWIN_STEREO_OVERUNDER) {
2878  /* printf("wsz: %dx%d bsz: %dx%d\n", wxs, wys, ixs, iys); */
2879  const unsigned char *leftimg = rgb3u;
2880  const unsigned char *rightimg = leftimg + ((ixs * (iys/2)) * 4);
2881 
2882  glDrawBuffer(GL_BACK_LEFT);
2883  glRasterPos2i(0, 0);
2884 #if 0
2885  glColorMask(GL_TRUE, GL_TRUE, GL_FALSE, GL_TRUE); /* anaglyph or testing */
2886 #endif
2887  glDrawPixels(ixs, iys/2, GL_RGBA, GL_UNSIGNED_BYTE, leftimg);
2888 
2889  glDrawBuffer(GL_BACK_RIGHT);
2890  glRasterPos2i(0, 0);
2891 #if 0
2892  glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE); /* anaglyph or testing */
2893 #endif
2894  glDrawPixels(ixs, iys/2, GL_RGBA, GL_UNSIGNED_BYTE, rightimg);
2895  } else {
2896  glRasterPos2i(0, 0);
2897  glDrawPixels(ixs, iys, GL_RGBA, GL_UNSIGNED_BYTE, rgb3u);
2898  }
2899 
2900  glwin_swap_buffers(voidhandle);
2901 }
2902 
2903 
2904 void glwin_draw_image_tex_rgb3u(void *voidhandle,
2905  int stereomode, int ixs, int iys,
2906  const unsigned char *rgb3u) {
2907  int wxs=0, wys=0;
2908  glwin_get_winsize(voidhandle, &wxs, &wys);
2909  glViewport(0, 0, wxs, wys);
2910 
2911  glDrawBuffer(GL_BACK);
2912  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2913  glClearColor(0.0, 0.0, 0.0, 1.0); /* black */
2914  glClear(GL_COLOR_BUFFER_BIT);
2915 
2916  glShadeModel(GL_FLAT);
2917  glMatrixMode(GL_PROJECTION);
2918  glLoadIdentity();
2919  glOrtho(0.0, wxs, 0.0, wys, -1.0, 1.0);
2920  glMatrixMode(GL_MODELVIEW);
2921 
2922  GLuint texName = 0;
2923  GLfloat texborder[4] = {0.0, 0.0, 0.0, 1.0};
2924  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2925  glBindTexture(GL_TEXTURE_2D, texName);
2926 
2927  /* black borders if we go rendering anything beyond texture coordinates */
2928  glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, texborder);
2929 #if defined(GL_CLAMP_TO_BORDER)
2930  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
2931  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
2932 #else
2933  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
2934  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
2935 #endif
2936 
2937  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2938  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2939  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2940 
2941  glLoadIdentity();
2942  glColor3f(1.0, 1.0, 1.0);
2943 
2944  if (stereomode == GLWIN_STEREO_OVERUNDER) {
2945  const unsigned char *leftimg = rgb3u;
2946  const unsigned char *rightimg = leftimg + ((ixs * (iys/2)) * 4);
2947 
2948  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ixs, iys, 0,
2949  GL_RGBA, GL_UNSIGNED_BYTE, leftimg);
2950  glEnable(GL_TEXTURE_2D);
2951 
2952  glDrawBuffer(GL_BACK_LEFT);
2953 #if 0
2954  glColorMask(GL_TRUE, GL_TRUE, GL_FALSE, GL_TRUE); /* anaglyph or testing */
2955 #endif
2956  glBegin(GL_QUADS);
2957  glTexCoord2f(0.0f, 0.0f);
2958  glVertex2f(0.0f, 0.0f);
2959  glTexCoord2f(0.0f, 0.5f);
2960  glVertex2f(0.0f, wys);
2961  glTexCoord2f(1.0f, 0.5f);
2962  glVertex2f(wxs, wys);
2963  glTexCoord2f(1.0f, 0.0f);
2964  glVertex2f(wxs, 0.0f);
2965  glEnd();
2966 
2967  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ixs, iys, 0,
2968  GL_RGBA, GL_UNSIGNED_BYTE, rightimg);
2969  glEnable(GL_TEXTURE_2D);
2970 
2971  glDrawBuffer(GL_BACK_RIGHT);
2972 #if 0
2973  glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE); /* anaglyph or testing */
2974 #endif
2975  glBegin(GL_QUADS);
2976  glTexCoord2f(0.0f, 0.5f);
2977  glVertex2f(0.0f, 0.0f);
2978  glTexCoord2f(0.0f, 1.0f);
2979  glVertex2f(0.0f, wys);
2980  glTexCoord2f(1.0f, 1.0f);
2981  glVertex2f(wxs, wys);
2982  glTexCoord2f(1.0f, 0.5f);
2983  glVertex2f(wxs, 0.0f);
2984  glEnd();
2985  } else {
2986  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ixs, iys, 0,
2987  GL_RGBA, GL_UNSIGNED_BYTE, rgb3u);
2988  glEnable(GL_TEXTURE_2D);
2989 
2990  glBegin(GL_QUADS);
2991  glTexCoord2f(0.0f, 0.0f);
2992  glVertex2f(0.0f, 0.0f);
2993  glTexCoord2f(0.0f, 1.0f);
2994  glVertex2f(0.0f, wys);
2995  glTexCoord2f(1.0f, 1.0f);
2996  glVertex2f(wxs, wys);
2997  glTexCoord2f(1.0f, 0.0f);
2998  glVertex2f(wxs, 0.0f);
2999  glEnd();
3000  }
3001 
3002  glDisable(GL_TEXTURE_2D);
3003 
3004  glwin_swap_buffers(voidhandle);
3005 }
3006 
3007 
3008 /*
3009  * OpenGL texture mapped sphere rendering code needed for
3010  * display of spheremap textures w/ HMDs.
3011  * The texture must wraparound in the X/longitudinal dimension
3012  * for the sphere to be drawn correctly.
3013  * The texture Y/latitude dimension doesn't have to wrap and this
3014  * code allows a single texture containing multiple images to be used
3015  * for drawing multiple spheres by offsetting the txlatstart/txlatend.
3016  */
3017 #define SPHEREMAXRES 64
3018 void glwin_draw_sphere_tex(float rad, int res, float txlatstart, float txlatend) {
3019  int i, j;
3020  float zLo, zHi, res_1;
3021 
3022  float sinLong[SPHEREMAXRES];
3023  float cosLong[SPHEREMAXRES];
3024  float sinLatVert[SPHEREMAXRES];
3025  float cosLatVert[SPHEREMAXRES];
3026  float sinLatNorm[SPHEREMAXRES];
3027  float cosLatNorm[SPHEREMAXRES];
3028  float texLat[SPHEREMAXRES];
3029  float texLong[SPHEREMAXRES];
3030 
3031  /* compute length of texture from start */
3032  float txlatsz = txlatend - txlatstart;
3033 
3034  if (res < 2)
3035  res = 2;
3036 
3037  if (res >= SPHEREMAXRES)
3038  res = SPHEREMAXRES-1;
3039 
3040  res_1 = 1.0f / res;
3041 
3042  /* longitudinal "slices" */
3043  float ang_twopi_res = 6.28318530718f * res_1;
3044  for (i=0; i<res; i++) {
3045  float angle = i * ang_twopi_res;
3046  sinLong[i] = sinf(angle);
3047  cosLong[i] = cosf(angle);
3048  texLong[i] = (res-i) * res_1;
3049  }
3050  /* ensure that longitude end point exactly matches start */
3051  sinLong[res] = 0.0f; /* sinLong[0]; */
3052  cosLong[res] = 1.0f; /* cosLong[0]; */
3053  texLong[res] = 0.0f;
3054 
3055  /* latitude "stacks" */
3056  float ang_pi_res = 3.14159265359f * res_1;
3057  for (i=0; i<=res; i++) {
3058  float angle = i * ang_pi_res;
3059  sinLatNorm[i] = sinf(angle);
3060  cosLatNorm[i] = cosf(angle);
3061  sinLatVert[i] = rad * sinLatNorm[i];
3062  cosLatVert[i] = rad * cosLatNorm[i];
3063  texLat[i] = txlatstart + (i * res_1 * txlatsz);
3064  }
3065  /* ensure top and bottom poles come to points */
3066  sinLatVert[0] = 0;
3067  sinLatVert[res] = 0;
3068 
3069  for (j=0; j<res; j++) {
3070  zLo = cosLatVert[j];
3071  zHi = cosLatVert[j+1];
3072 
3073  float stv1 = sinLatVert[j];
3074  float stv2 = sinLatVert[j+1];
3075 
3076  float stn1 = sinLatNorm[j];
3077  float ctn1 = cosLatNorm[j];
3078  float stn2 = sinLatNorm[j+1];
3079  float ctn2 = cosLatNorm[j+1];
3080 
3081  glBegin(GL_QUAD_STRIP);
3082  for (i=0; i<=res; i++) {
3083  glNormal3f(sinLong[i] * stn2, cosLong[i] * stn2, ctn2);
3084  glTexCoord2f(texLong[i], texLat[j+1]);
3085  glVertex3f(stv2 * sinLong[i], stv2 * cosLong[i], zHi);
3086 
3087  glNormal3f(sinLong[i] * stn1, cosLong[i] * stn1, ctn1);
3088  glTexCoord2f(texLong[i], texLat[j]);
3089  glVertex3f(stv1 * sinLong[i], stv1 * cosLong[i], zLo);
3090  }
3091  glEnd();
3092  }
3093 }
3094 
3095 
3096 void glwin_spheremap_draw_prepare(void *voidhandle) {
3097  glShadeModel(GL_FLAT);
3098  glDepthFunc(GL_LEQUAL);
3099  glEnable(GL_DEPTH_TEST); /* use Z-buffer for hidden-surface removal */
3100  glClearDepth(1.0);
3101 
3102  glDrawBuffer(GL_BACK);
3103  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3104  glClearColor(0.0, 0.0, 0.0, 1.0); /* black */
3105  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
3106 
3107  GLuint texName = 0;
3108  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
3109  glBindTexture(GL_TEXTURE_2D, texName);
3110 
3111  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
3112 #if !(defined(WIN32) || defined(_WIN64))
3113  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
3114 #else
3115  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
3116 #endif
3117 
3118  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
3119  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3120 
3121  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3122 }
3123 
3124 
3125 void glwin_spheremap_upload_tex_rgb3u(void *voidhandle, int ixs, int iys,
3126  const unsigned char *rgb3u) {
3127  glDisable(GL_TEXTURE_2D);
3128  GLuint texName = 0;
3129  glBindTexture(GL_TEXTURE_2D, texName);
3130  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ixs, iys, 0,
3131  GL_RGBA, GL_UNSIGNED_BYTE, rgb3u);
3132  glEnable(GL_TEXTURE_2D);
3133 }
3134 
3135 
3136 void glwin_spheremap_draw_tex(void *voidhandle, int stereomode,
3137  int ixs, int iys, const float *hmdquat,
3138  float fov, float rad, int res) {
3139  int wxs=0, wys=0;
3140  float n, f, a, t, b, r, l;
3141 
3142  glwin_get_winsize(voidhandle, &wxs, &wys);
3143  glViewport(0, 0, wxs, wys); /* clear entire window prior to rendering */
3144 
3145  glDrawBuffer(GL_BACK);
3146  glClearColor(0.0, 0.0, 0.0, 1.0); /* black */
3147  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
3148 
3149  glMatrixMode(GL_PROJECTION);
3150  glLoadIdentity();
3151 
3152  n = 1.0f; /* near clipping plane */
3153  f = 15.0f; /* far clipping plane */
3154  a = wxs / ((float) wys); /* window aspect ratio */
3155  t = n * tanf(fov * 3.14159265359f / (180.0f*2.0f)); /* top */
3156  b = -t; /* bottom */
3157  r = a * t; /* right */
3158  l = -r; /* left */
3159  glFrustum(l, r, b, t, n, f);
3160 
3161  glMatrixMode(GL_MODELVIEW);
3162  glLoadIdentity();
3163 
3164  if (hmdquat != NULL) {
3165  float hmdmat[16];
3166  quat_rot_matrix(hmdmat, hmdquat);
3167  glMultMatrixf(hmdmat);
3168  }
3169 
3170  glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
3171  glColor3f(1.0, 1.0, 1.0);
3172 
3173  /* window dims control viewport size, image dims control tex size, */
3174  /* since we will render from a spheremap that has different dims */
3175  /* than the target window */
3176  if (stereomode == GLWIN_STEREO_OVERUNDER) {
3177  /* right image is stored first */
3178  glViewport(wxs/2, 0, wxs/2, wys);
3179  glwin_draw_sphere_tex(rad, res, 0.0f, 0.5f);
3180 
3181  /* left image is stored second */
3182  glViewport(0, 0, wxs/2, wys);
3183  glwin_draw_sphere_tex(rad, res, 0.5f, 1.0f);
3184  } else {
3185  glwin_draw_sphere_tex(rad, res, 0.0f, 1.0f);
3186  }
3187 }
3188 
3189 
3190 int glwin_get_wininfo(void * voidhandle, int *instereo, int *havestencil) {
3191  oglhandle * handle = (oglhandle *) voidhandle;
3192  if (handle == NULL)
3193  return -1;
3194 
3195  if (instereo != NULL)
3196  *instereo = handle->instereo;
3197 
3198  if (havestencil != NULL)
3199  *havestencil = handle->havestencil;
3200 
3201  return 0;
3202 }
3203 
3204 
3205 int glwin_get_winsize(void * voidhandle, int *xsize, int *ysize) {
3206  oglhandle * handle = (oglhandle *) voidhandle;
3207  if (handle == NULL)
3208  return -1;
3209 
3210 #if 0
3211  if (handle) {
3212  /* check window size */
3213  XWindowAttributes xwa;
3214  XGetWindowAttributes(handle->dpy, handle->win, &xwa);
3215  handle->width = xwa.width;
3216  handle->height = xwa.height;
3217  }
3218 #endif
3219 
3220  if (xsize != NULL)
3221  *xsize = handle->width;
3222 
3223  if (ysize != NULL)
3224  *ysize = handle->height;
3225 
3226  return 0;
3227 }
3228 
3229 
3230 int glwin_get_winpos(void * voidhandle, int *xpos, int *ypos) {
3231  oglhandle * handle = (oglhandle *) voidhandle;
3232  if (handle == NULL)
3233  return -1;
3234 
3235  if (xpos != NULL)
3236  *xpos = handle->xpos;
3237 
3238  if (ypos != NULL)
3239  *ypos = handle->ypos;
3240 
3241  return 0;
3242 }
3243 
3244 
3245 int glwin_get_mousepointer(void *voidhandle, int *x, int *y) {
3246  oglhandle * handle = (oglhandle *) voidhandle;
3247  if (handle == NULL)
3248  return -1;
3249 
3250  if (x != NULL)
3251  *x = handle->mousex;
3252 
3253  if (y != NULL)
3254  *y = handle->mousey;
3255 
3256  return 0;
3257 }
3258 
3259 
3260 int glwin_get_lastevent(void * voidhandle, int *evdev, int *evval, char *evkey) {
3261  oglhandle * handle = (oglhandle *) voidhandle;
3262  if (handle == NULL)
3263  return -1;
3264 
3265  if (evdev != NULL)
3266  *evdev = handle->evdev;
3267 
3268  if (evval != NULL)
3269  *evval = handle->evval;
3270 
3271  if (evkey != NULL)
3272  *evkey = handle->evkey;
3273 
3274  return 0;
3275 }
3276 
3277 
3278 int glwin_spaceball_available(void *voidhandle) {
3279  oglhandle * handle = (oglhandle *) voidhandle;
3280 
3281  /* check to see if we have a spaceball attached */
3282  if (handle->sball != NULL)
3283  return 1;
3284 
3285  return 0;
3286 }
3287 
3288 
3289 int glwin_get_spaceball(void *voidhandle, int *rx, int *ry, int *rz, int *tx, int *ty, int *tz, int *buttons) {
3290  oglhandle * handle = (oglhandle *) voidhandle;
3291  if (handle == NULL)
3292  return 0;
3293 
3294  if ((handle->sball != NULL) && (handle->sballevent.event == 1)) {
3295  *rx = handle->sballevent.rx;
3296  *ry = handle->sballevent.ry;
3297  *rz = handle->sballevent.rz;
3298  *tx = handle->sballevent.tx;
3299  *ty = handle->sballevent.ty;
3300  *tz = handle->sballevent.tz;
3301  *buttons = handle->sballevent.buttons;
3302  return 1;
3303  }
3304 
3305  return 0;
3306 }
3307 
3308 
3309 #else
3310 
3311 
3312 /*
3313  * stub code to allow linkage
3314  */
3315 void * glwin_create(const char * wintitle, int width, int height) {
3316  return NULL;
3317 }
3318 
3319 void glwin_destroy(void * voidhandle) {
3320  return;
3321 }
3322 
3323 void glwin_swap_buffers(void * voidhandle) {
3324  return;
3325 }
3326 
3327 int glwin_handle_events(void * voidhandle, int evblockmode) {
3328  return 0;
3329 }
3330 
3331 int glwin_get_wininfo(void * voidhandle, int *instereo, int *havestencil) {
3332  return -1;
3333 }
3334 
3335 int glwin_get_winsize(void * voidhandle, int *xsize, int *ysize) {
3336  return -1;
3337 }
3338 
3339 int glwin_get_winpos(void * voidhandle, int *xpos, int *ypos) {
3340  return -1;
3341 }
3342 
3343 int glwin_get_mousepointer(void *voidhandle, int *x, int *y) {
3344  return -1;
3345 }
3346 
3347 int glwin_get_lastevent(void * voidhandle, int *evdev, int *evval, char *evkey) {
3348  return -1;
3349 }
3350 
3351 int glwin_query_extension(const char *extname) {
3352  return 0;
3353 }
3354 
3355 int glwin_query_vsync(void *voidhandle, int *onoff) {
3356  return GLWIN_NOT_IMPLEMENTED;
3357 }
3358 
3359 void glwin_draw_image(void * voidhandle, int xsize, int ysize, unsigned char * img) {
3360  return;
3361 }
3362 
3363 void glwin_draw_image_rgb3u(void *voidhandle, int stereomode, int ixs, int iys,
3364  const unsigned char *rgb3u) {
3365  return;
3366 }
3367 
3368 void glwin_draw_image_tex_rgb3u(void *voidhandle,
3369  int stereomode, int ixs, int iys,
3370  const unsigned char *rgb3u) {
3371  return;
3372 }
3373 
3374 void glwin_spheremap_draw_prepare(void *voidhandle) {
3375  return;
3376 }
3377 
3378 void glwin_spheremap_upload_tex_rgb3u(void *voidhandle, int ixs, int iys,
3379  const unsigned char *rgb3u) {
3380  return;
3381 }
3382 
3383 void glwin_draw_sphere_tex(float rad, int res, float txlatstart, float txlatend) {
3384  return;
3385 }
3386 
3387 void glwin_spheremap_draw(void *voidhandle, int stereomode, int ixs, int iys,
3388  const float *hmdquat, float fov, float rad, int res) {
3389  return;
3390 }
3391 
3392 int glwin_resize(void *voidhandle, int width, int height) {
3393  return -1;
3394 }
3395 
3396 int glwin_reposition(void *voidhandle, int xpos, int ypos) {
3397  return -1;
3398 }
3399 
3400 int glwin_fullscreen(void * voidhandle, int fson, int xinescreen) {
3401  return -1;
3402 }
3403 
3404 int glwin_spaceball_available(void *voidhandle) {
3405  return 0;
3406 }
3407 
3408 int glwin_get_spaceball(void *voidhandle, int *rx, int *ry, int *rz, int *tx, int *ty, int *tz, int *buttons) {
3409  return 0;
3410 }
3411 
3412 #endif
3413 
int glwin_get_lastevent(void *voidhandle, int *evdev, int *evval, char *evkey)
Definition: glwin.c:3347
void * glwin_fbo_target_create(void *voidhandle, int width, int height)
void * glwin_create(const char *wintitle, int width, int height)
Definition: glwin.c:3315
#define GLWIN_EV_WINDOW_CLOSE
window manager close event
Definition: glwin.h:69
void glwin_spheremap_destroy_hmd_warp(void *vwin, void *voidwarp)
#define GLWIN_EV_KBD_F4
Definition: glwin.h:49
void glwin_destroy(void *voidhandle)
Definition: glwin.c:3319
#define GLWIN_EV_KBD_F8
Definition: glwin.h:53
#define GLWIN_EV_MOUSE_WHEELUP
Definition: glwin.h:66
int glwin_handle_events(void *voidhandle, int evblockmode)
Definition: glwin.c:3327
#define GLWIN_EV_KBD_F5
Definition: glwin.h:50
int glwin_spheremap_draw_hmd_warp(void *vwin, void *voidwarp, int drawimage, int drawlines, int chromcorr, int wsx, int wsy, int ixs, int iys, const float *hmdquat, float fov, float rad, int hmd_spres)
int glwin_query_extension(const char *extname)
Definition: glwin.c:3351
void glwin_draw_sphere_tex(float rad, int res, float txlatstart, float txlatend)
Definition: glwin.c:3383
void glwin_draw_image(void *voidhandle, int xsize, int ysize, unsigned char *img)
Definition: glwin.c:3359
int glwin_fbo_target_draw_fbo(void *voidhandle, void *voidtarget, int width, int height)
#define GLWIN_EV_KBD_F1
Definition: glwin.h:46
#define GLWIN_EV_KBD_ESC
Definition: glwin.h:59
#define GLWIN_EV_KBD_PAGE_UP
Definition: glwin.h:39
#define GLWIN_EV_MOUSE_RIGHT
Definition: glwin.h:65
int glwin_get_spaceball(void *voidhandle, int *rx, int *ry, int *rz, int *tx, int *ty, int *tz, int *buttons)
Definition: glwin.c:3408
#define GLWIN_EV_MOUSE_WHEELDOWN
Definition: glwin.h:67
#define GLWIN_EV_KBD_F6
Definition: glwin.h:51
#define GLWIN_EV_KBD_DELETE
Definition: glwin.h:44
#define GLWIN_EV_MOUSE_MIDDLE
Definition: glwin.h:64
#define GLWIN_EV_KBD_INSERT
Definition: glwin.h:43
#define GLWIN_EV_KBD_F10
Definition: glwin.h:55
#define GLWIN_EV_KBD_F7
Definition: glwin.h:52
int glwin_query_vsync(void *voidhandle, int *onoff)
Definition: glwin.c:3355
#define GLWIN_ERROR
Definition: glwin.h:25
#define GLWIN_EV_POLL_NONBLOCK
Definition: glwin.h:28
int glwin_get_winsize(void *voidhandle, int *xsize, int *ysize)
Definition: glwin.c:3335
void glwin_spheremap_upload_tex_rgb3u(void *voidhandle, int ixs, int iys, const unsigned char *rgb3u)
Definition: glwin.c:3378
int glwin_fbo_target_destroy(void *voidhandle, void *voidtarget)
#define GLWIN_EV_KBD_F2
Definition: glwin.h:47
#define GLWIN_EV_KBD_F12
Definition: glwin.h:57
int glwin_fullscreen(void *voidhandle, int fson, int xinescreen)
Definition: glwin.c:3400
int glwin_fbo_target_bind(void *voidhandle, void *voidtarget)
#define GLWIN_EV_NONE
Definition: glwin.h:31
void glwin_draw_image_tex_rgb3u(void *voidhandle, int stereomode, int ixs, int iys, const unsigned char *rgb3u)
Definition: glwin.c:3368
void glwin_spheremap_draw_tex(void *voidhandle, int stereomode, int ixs, int iys, const float *hmdquat, float fov, float rad, int res)
void glwin_swap_buffers(void *voidhandle)
Definition: glwin.c:3323
#define GLWIN_EV_KBD_UP
Definition: glwin.h:35
#define GLWIN_EV_KBD
all non-special chars
Definition: glwin.h:33
void glwin_spheremap_draw_prepare(void *voidhandle)
Definition: glwin.c:3374
void glwin_spheremap_update_hmd_warp(void *vwin, void *voidwarp, int wsx, int wsy, int warpdivs, int ixs, int iys, const float *user_coeffs, int forceupdate)
#define GLWIN_EV_KBD_RIGHT
Definition: glwin.h:38
#define GLWIN_EV_MOUSE_LEFT
Definition: glwin.h:63
#define GLWIN_EV_KBD_F9
Definition: glwin.h:54
int glwin_spaceball_available(void *voidhandle)
Definition: glwin.c:3404
int glwin_fbo_target_unbind(void *voidhandle, void *voidtarget)
int glwin_fbo_target_draw_normal(void *voidhandle, void *voidtarget)
#define GLWIN_EV_KBD_LEFT
Definition: glwin.h:37
#define GLWIN_NOT_IMPLEMENTED
Definition: glwin.h:26
#define GLWIN_SUCCESS
Definition: glwin.h:24
void glwin_spheremap_draw(void *voidhandle, int stereomode, int ixs, int iys, const float *hmdquat, float fov, float rad, int res)
Definition: glwin.c:3387
int glwin_get_mousepointer(void *voidhandle, int *x, int *y)
Definition: glwin.c:3343
void glwin_draw_image_rgb3u(void *voidhandle, int stereomode, int ixs, int iys, const unsigned char *rgb3u)
Definition: glwin.c:3363
int glwin_resize(void *voidhandle, int width, int height)
Definition: glwin.c:3392
#define GLWIN_EV_MOUSE_MOVE
Definition: glwin.h:61
#define GLWIN_EV_KBD_END
Definition: glwin.h:42
#define GLWIN_EV_POLL_BLOCK
Definition: glwin.h:29
void * glwin_spheremap_create_hmd_warp(void *vwin, int wsx, int wsy, int wrot, int warpdivs, int ixs, int iys, const float *user_coeffs)
__host__ __device__ float length(const float3 &v)
#define GLWIN_EV_KBD_F11
Definition: glwin.h:56
#define GLWIN_STEREO_OVERUNDER
Definition: glwin.h:72
int glwin_get_winpos(void *voidhandle, int *xpos, int *ypos)
Definition: glwin.c:3339
#define GLWIN_EV_KBD_DOWN
Definition: glwin.h:36
#define GLWIN_EV_KBD_HOME
Definition: glwin.h:41
int glwin_reposition(void *voidhandle, int xpos, int ypos)
Definition: glwin.c:3396
int glwin_get_wininfo(void *voidhandle, int *instereo, int *havestencil)
Definition: glwin.c:3331
#define GLWIN_EV_KBD_F3
Definition: glwin.h:48
int glwin_fbo_target_resize(void *voidhandle, void *voidtarget, int width, int height)