Browse code

Standardize OpenGL-related #includes and #defines

We use glXGetProcAddress to load glXCreateContextAttribsARB ourselves,
so GLX_GLXEXT_PROTOTYPES is not needed.

Robert Cranston authored on 27/02/2024 02:27:47
Showing 1 changed files
... ...
@@ -42,9 +42,8 @@
42 42
 #include <stdlib.h>
43 43
 #include <stdio.h>
44 44
 #include <string.h>
45
+#define GL_GLEXT_PROTOTYPES
45 46
 #include <GL/gl.h>
46
-#define GLX_GLXEXT_PROTOTYPES
47
-#include <GL/glext.h>
48 47
 #include <X11/Xlib.h>
49 48
 #include <X11/keysym.h>
50 49
 #include <GL/glx.h>
Browse code

Enable and fix more warnings

Robert Cranston authored on 27/02/2024 02:27:44
Showing 1 changed files
... ...
@@ -83,6 +83,8 @@ static char gRunning = 1;
83 83
 
84 84
 void glutInit(int *argc, char *argv[])
85 85
 {
86
+	(void)argc;
87
+	(void)argv;
86 88
 	gettimeofday(&timeStart, NULL);
87 89
 	memset(gKeymap, 0, sizeof(gKeymap));
88 90
 }
... ...
@@ -110,16 +112,13 @@ static void checktimers();
110 112
  */
111 113
 
112 114
 static void
113
-make_window( Display *dpy, const char *name,
114
-             int x, int y, int width, int height,
115
-             Window *winRet, GLXContext *ctxRet)
115
+make_window( const char *name,
116
+             int x, int y, int width, int height)
116 117
 {
117 118
    int scrnum;
118 119
    XSetWindowAttributes attr;
119 120
    unsigned long mask;
120 121
    Window root;
121
-   Window win;
122
-   GLXContext ctx;
123 122
    XVisualInfo *visinfo;
124 123
 
125 124
    scrnum = DefaultScreen( dpy );
... ...
@@ -305,9 +304,6 @@ make_window( Display *dpy, const char *name,
305 304
    }
306 305
 
307 306
    XFree(visinfo);
308
-
309
-   *winRet = win;
310
-   *ctxRet = ctx;
311 307
 }
312 308
 
313 309
 void glutCreateWindow(const char *windowTitle)
... ...
@@ -319,7 +315,7 @@ void glutCreateWindow(const char *windowTitle)
319 315
 	     windowTitle ? windowTitle : getenv("DISPLAY"));
320 316
    }
321 317
 
322
-   make_window(dpy, windowTitle, winPosX, winPosY, winWidth, winHeight, &win, &ctx);
318
+   make_window(windowTitle, winPosX, winPosY, winWidth, winHeight);
323 319
    
324 320
    XMapWindow(dpy, win);
325 321
    glXMakeCurrent(dpy, win, ctx);
... ...
@@ -455,6 +451,7 @@ void doKeyboardEvent(XEvent event, void (*keyProc)(unsigned char key, int x, int
455 451
 
456 452
 void internaltimer(int x)
457 453
 {
454
+	(void)x;
458 455
 	glutPostRedisplay();
459 456
 }
460 457
 
Browse code

Fix warnings when compiling in C++ mode

Robert Cranston authored on 27/02/2024 02:27:43
Showing 1 changed files
... ...
@@ -479,7 +479,7 @@ void glutMainLoop()
479 479
          switch (event.type)
480 480
          {
481 481
          	case ClientMessage:
482
-         		if (event.xclient.data.l[0] == wmDeleteMessage) // quit!
482
+         		if ((Atom)event.xclient.data.l[0] == wmDeleteMessage) // quit!
483 483
          			gRunning = 0;
484 484
 	         	break;
485 485
          	case Expose: 
Browse code

Remove executable bit on files

find . -type f -exec chmod -x {} +

Robert Cranston authored on 27/02/2024 02:27:27
Showing 1 changed files
1 1
old mode 100755
2 2
new mode 100644
Browse code

Add cpp-v1

Ingemar Ragnemalm authored on 21/02/2024 20:24:28 • Robert Cranston committed on 21/02/2024 20:24:28
Showing 1 changed files
1 1
new file mode 100755
... ...
@@ -0,0 +1,831 @@
1
+// MicroGlut is a stripped-down reimplementation of the classic GLUT/FreeGLUT library. By Ingemar Ragnemalm 2012-2015.
2
+// This is the Linux version. There is also a Mac version (and drafts for a Windows version).
3
+
4
+// Why do we use MicroGlut?
5
+// 1) Transparency! Including it as a single source file makes it easy to see what it does.
6
+// 2) Editability. Missing something? Want something to work a bit different? Just hack it in.
7
+// 3) No obsolete stuff! The old GLUT has a lot of functions that are inherently obsolete. Avoid!
8
+
9
+// Please note that this is still in an early stage. A lot of functionality is still missing.
10
+// If you add/change something of interest, especially if it follows the GLUT API, please sumbit
11
+// to me so I can consider adding that to the official version.
12
+
13
+// 2012: Made a first draft by extracting context creation from other code.
14
+// 130131: Fixed bugs in keyboard and update events. Seems to work pretty well! Things are missing, GL3 untested, but otherwise it runs stable with glutgears.
15
+// 130206: Timers now tested and working. CPU load kept decent when not intentionally high.
16
+// 130907: Bug fixes, test for non-existing gReshape, glutKeyboardUpFunc corrected.
17
+// 130916: Fixed the event bug. Cleaned up most comments left from debugging.
18
+// 130926: Cleaned up warnings, added missing #includes.
19
+// 140130: A bit more cleanup for avoiding warnings (_BSD_SOURCE below).
20
+// 140401: glutKeyIsDown and glutWarpPointer added and got an extra round of testing.
21
+// 150205: glutRepeatingTimer new, better name for glutRepeatingTimerFunc
22
+// Added a default glViewport call when the window is resized.
23
+// Made a bug fix in the event processing so that mouse drag events won't stack up.
24
+// Somewhere here I added a kind of full-screen support (but without removing window borders).
25
+// 150216: Added proper OpenGL3 initalization. (Based on a patch by Sebastian Parborg.)
26
+// 150223: Finally, decent handling on the GLUT configuration!
27
+// 150227: Resize triggers an update!
28
+// 150302: Window position, multisample, even better config
29
+// 150618: Added glutMouseIsDown() (not in the old GLUT API but a nice extension!).
30
+// Added #ifdefs to produce errors if compiled on the wrong platform!
31
+// 150909: Added glutExit.
32
+// 150924: Added support for special keys.
33
+// 160302: Added glutShowCursor and glutHideCursor.
34
+// 170405: Made some globals static.
35
+// 170406: Added "const" to string arguments to make C++ happier. glutSpecialFunc and glutSpecialUpFunc are now officially supported - despite being deprecated. (I recommend that you use the same keyboard func for everything.) Added support for multiple mouse buttons (right and left).
36
+// 170410: Modified glutWarpPointer to make it more robust. Commended out some unused variables to avoid warnings.
37
+// 180124: Modifications to make it work better on recent MESA, which seems to have introduced some changes. Adds glFlush() in glutSwapBuffers and a timer when starting glutMain to invoke an update after 100 ms.
38
+// 180208: Added GLUT_WINDOW_WIDTH, GLUT_WINDOW_HEIGHT, GLUT_MOUSE_POSITION_X and GLUT_MOUSE_POSITION_Y to GlutGet. They were already in the Mac version, so let's converge the versions a bit.
39
+
40
+#define _DEFAULT_SOURCE
41
+#include <math.h>
42
+#include <stdlib.h>
43
+#include <stdio.h>
44
+#include <string.h>
45
+#include <GL/gl.h>
46
+#define GLX_GLXEXT_PROTOTYPES
47
+#include <GL/glext.h>
48
+#include <X11/Xlib.h>
49
+#include <X11/keysym.h>
50
+#include <GL/glx.h>
51
+#include "MicroGlut.h"
52
+#include <sys/time.h>
53
+#include <unistd.h>
54
+
55
+#ifndef M_PI
56
+#define M_PI 3.14159265
57
+#endif
58
+
59
+// If this is compiled on the Mac or Windows, tell me!
60
+#ifdef __APPLE__
61
+	ERROR! This is NOT the Mac version of MicroGlut and will not work on the Mac!
62
+#endif
63
+#ifdef _WIN32
64
+	ERROR! This is NOT the Windows version of MicroGlut and will not work on Windows!
65
+#endif
66
+
67
+static unsigned int winWidth = 300, winHeight = 300;
68
+static unsigned int winPosX = 40, winPosY = 40;
69
+//static int mode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
70
+static int gContextVersionMajor = 0;
71
+static int gContextVersionMinor = 0;
72
+
73
+static Display *dpy;
74
+static Window win;
75
+static GLXContext ctx;
76
+//static char *dpyName = NULL;
77
+int gMode; // NOT YET USED
78
+static char animate = 1; // Use for glutNeedsRedisplay?
79
+struct timeval timeStart;
80
+static Atom wmDeleteMessage; // To handle delete msg
81
+static char gKeymap[256];
82
+static char gRunning = 1;
83
+
84
+void glutInit(int *argc, char *argv[])
85
+{
86
+	gettimeofday(&timeStart, NULL);
87
+	memset(gKeymap, 0, sizeof(gKeymap));
88
+}
89
+void glutInitDisplayMode(unsigned int mode)
90
+{
91
+	gMode = mode; // NOT YET USED
92
+}
93
+void glutInitWindowSize(int w, int h)
94
+{
95
+	winWidth = w;
96
+	winHeight = h;
97
+}
98
+
99
+void glutInitWindowPosition (int x, int y)
100
+{
101
+	winPosX = x;
102
+	winPosY = y;
103
+}
104
+
105
+static void checktimers();
106
+
107
+/*
108
+ * Create an RGB, double-buffered window.
109
+ * Return the window and context handles.
110
+ */
111
+
112
+static void
113
+make_window( Display *dpy, const char *name,
114
+             int x, int y, int width, int height,
115
+             Window *winRet, GLXContext *ctxRet)
116
+{
117
+   int scrnum;
118
+   XSetWindowAttributes attr;
119
+   unsigned long mask;
120
+   Window root;
121
+   Window win;
122
+   GLXContext ctx;
123
+   XVisualInfo *visinfo;
124
+
125
+   scrnum = DefaultScreen( dpy );
126
+   root = RootWindow( dpy, scrnum );
127
+
128
+// 3.2 support
129
+//#ifdef glXCreateContextAttribsARB
130
+	if (gContextVersionMajor > 2)
131
+	{
132
+// We asked for OpenGL3+, but can we do it?
133
+
134
+		typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
135
+
136
+		// Verify GL driver supports glXCreateContextAttribsARB()
137
+		glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
138
+
139
+		// Verify that GLX implementation supports the new context create call
140
+		if ( strstr( glXQueryExtensionsString( dpy, scrnum ), 
141
+			"GLX_ARB_create_context" ) != 0 )
142
+		glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
143
+			glXGetProcAddress( (const GLubyte *) "glXCreateContextAttribsARB" );
144
+
145
+		if ( !glXCreateContextAttribsARB )
146
+		{
147
+			printf( "Can't create new-style GL context\n" );
148
+		}
149
+
150
+// We need this for OpenGL3
151
+		int elemc;
152
+		GLXFBConfig *fbcfg;
153
+
154
+	   int attribs[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT,
155
+                     GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, // ?
156
+                     GLX_RED_SIZE, 1, // 1 = prefer high precision
157
+                     GLX_GREEN_SIZE, 1,
158
+                     GLX_BLUE_SIZE, 1,
159
+                     GLX_ALPHA_SIZE, 1,
160
+                     None,
161
+                     None,
162
+                     None,
163
+                     None,
164
+                     None,
165
+                     None,
166
+                     None,
167
+                     None,
168
+                     None,
169
+                     None,
170
+                     None,
171
+                     None,
172
+                     None,
173
+                     None,
174
+                     None,
175
+                     None };
176
+
177
+		int i = 12;
178
+		if (gMode & GLUT_DOUBLE)
179
+		{
180
+			attribs[i++] = GLX_DOUBLEBUFFER;
181
+			attribs[i++] = 1;
182
+		}
183
+		if (gMode & GLUT_DEPTH)
184
+		{
185
+			attribs[i++] = GLX_DEPTH_SIZE;
186
+			attribs[i++] = 1;
187
+		}
188
+		if (gMode & GLUT_STENCIL)
189
+		{
190
+			attribs[i++] = GLX_STENCIL_SIZE;
191
+			attribs[i++] = 8; // Smallest available, at least 8. Configurable setting needed!
192
+		}
193
+		if (gMode & GLUT_MULTISAMPLE)
194
+		{
195
+			attribs[i++] = GLX_SAMPLE_BUFFERS;
196
+			attribs[i++] = 1;
197
+			attribs[i++] = GLX_SAMPLES;
198
+			attribs[i++] = 4;
199
+		}
200
+
201
+		fbcfg = glXChooseFBConfig(dpy, scrnum, attribs, &elemc);
202
+		if (!fbcfg)
203
+		{
204
+			fbcfg = glXChooseFBConfig(dpy, scrnum, NULL, &elemc);
205
+		}
206
+		if (!fbcfg)
207
+			printf("Couldn't get FB configs\n");
208
+
209
+		int gl3attr[] =
210
+		{
211
+			GLX_CONTEXT_MAJOR_VERSION_ARB, gContextVersionMajor,
212
+			GLX_CONTEXT_MINOR_VERSION_ARB, gContextVersionMinor,
213
+//			GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
214
+			GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
215
+			GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
216
+			None
217
+		};
218
+		ctx = glXCreateContextAttribsARB(dpy, fbcfg[0], NULL, 1, gl3attr);
219
+		if (ctx == NULL) printf("No ctx!\n");
220
+
221
+        visinfo = glXGetVisualFromFBConfig(dpy, fbcfg[0]);
222
+        if (!visinfo)
223
+            printf("Error: couldn't create OpenGL window with this pixel format.\n");
224
+
225
+	}
226
+	else // old style
227
+//#endif
228
+	{
229
+	   int attribs[] = { GLX_RGBA,
230
+                     GLX_RED_SIZE, 1, // 1 = prefer high precision
231
+                     GLX_GREEN_SIZE, 1,
232
+                     GLX_BLUE_SIZE, 1,
233
+                     None,
234
+                     None,
235
+                     None,
236
+                     None,
237
+                     None,
238
+                     None,
239
+                     None,
240
+                     None,
241
+                     None,
242
+                     None,
243
+                     None,
244
+                     None,
245
+                     None,
246
+                     None,
247
+                     None,
248
+                     None };
249
+
250
+		int i = 7;
251
+		if (gMode & GLUT_DOUBLE)
252
+			attribs[i++] = GLX_DOUBLEBUFFER;
253
+		if (gMode & GLUT_DEPTH)
254
+		{
255
+			attribs[i++] = GLX_DEPTH_SIZE;
256
+			attribs[i++] = 1;
257
+		}
258
+		if (gMode & GLUT_STENCIL)
259
+		{
260
+			attribs[i++] = GLX_STENCIL_SIZE;
261
+			attribs[i++] = 8; // Smallest available, at least 8. Configurable setting needed!
262
+		}
263
+    	visinfo = glXChooseVisual( dpy, scrnum, attribs );
264
+		if (!visinfo)
265
+		{
266
+			printf("Error: couldn't get a visual according to settings\n");
267
+			exit(1);
268
+		}
269
+
270
+		ctx = glXCreateContext( dpy, visinfo, 0, True );
271
+		if (ctx == NULL) printf("No ctx!\n");
272
+	}
273
+
274
+   /* window attributes */
275
+   attr.background_pixel = 0;
276
+   attr.border_pixel = 0;
277
+   attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
278
+   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPress | ButtonReleaseMask | Button1MotionMask | PointerMotionMask;
279
+   attr.override_redirect = 0;
280
+   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
281
+
282
+   win = XCreateWindow( dpy, root, x, y, width, height,
283
+		        0, visinfo->depth, InputOutput,
284
+		        visinfo->visual, mask, &attr );
285
+
286
+// Register delete!
287
+	wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
288
+	XSetWMProtocols(dpy, win, &wmDeleteMessage, 1); // Register
289
+
290
+   /* set hints and properties */
291
+      XSizeHints sizehints;
292
+      sizehints.x = x;
293
+      sizehints.y = y;
294
+      sizehints.width  = width;
295
+      sizehints.height = height;
296
+      sizehints.flags = USSize | USPosition;
297
+      XSetNormalHints(dpy, win, &sizehints);
298
+      XSetStandardProperties(dpy, win, name, name,
299
+                              None, (char **)NULL, 0, &sizehints);
300
+
301
+   if (!ctx)
302
+   {
303
+      printf("Error: glXCreateContext failed\n");
304
+      exit(1);
305
+   }
306
+
307
+   XFree(visinfo);
308
+
309
+   *winRet = win;
310
+   *ctxRet = ctx;
311
+}
312
+
313
+void glutCreateWindow(const char *windowTitle)
314
+{
315
+   dpy = XOpenDisplay(NULL);
316
+   if (!dpy)
317
+   {
318
+      printf("Error: couldn't open display %s\n",
319
+	     windowTitle ? windowTitle : getenv("DISPLAY"));
320
+   }
321
+
322
+   make_window(dpy, windowTitle, winPosX, winPosY, winWidth, winHeight, &win, &ctx);
323
+   
324
+   XMapWindow(dpy, win);
325
+   glXMakeCurrent(dpy, win, ctx);
326
+}
327
+
328
+void (*gDisplay)(void);
329
+void (*gReshape)(int width, int height);
330
+void (*gIdle)(void);
331
+void (*gKey)(unsigned char key, int x, int y);
332
+void (*gKeyUp)(unsigned char key, int x, int y);
333
+void (*gSpecialKey)(unsigned char key, int x, int y);
334
+void (*gSpecialKeyUp)(unsigned char key, int x, int y);
335
+void (*gMouseMoved)(int x, int y);
336
+void (*gMouseDragged)(int x, int y);
337
+void (*gMouseFunc)(int button, int state, int x, int y);
338
+int gLastMousePositionX, gLastMousePositionY; // Avoids a problem with glutWarpPointer
339
+
340
+// Maybe I should just drop these for simplicity
341
+//void (*gSpecialKey)(unsigned char key, int x, int y) = NULL;
342
+//void (*gSpecialKeyUp)(unsigned char key, int x, int y) = NULL;
343
+
344
+
345
+void glutReshapeFunc(void (*func)(int width, int height))
346
+{
347
+	gReshape = func;
348
+}
349
+void glutDisplayFunc(void (*func)(void))
350
+{
351
+	gDisplay = func;
352
+}
353
+void glutIdleFunc(void (*func)(void))
354
+{gIdle = func;}
355
+
356
+void glutKeyboardFunc(void (*func)(unsigned char key, int x, int y))
357
+{
358
+	gKey = func;
359
+}
360
+void glutKeyboardUpFunc(void (*func)(unsigned char key, int x, int y))
361
+{
362
+	gKeyUp = func;
363
+}
364
+void glutSpecialFunc(void (*func)(unsigned char key, int x, int y))
365
+{
366
+	gSpecialKey = func;
367
+}
368
+
369
+void glutSpecialUpFunc(void (*func)(unsigned char key, int x, int y))
370
+{
371
+	gSpecialKeyUp = func;
372
+}
373
+
374
+void glutMouseFunc(void (*func)(int button, int state, int x, int y))
375
+{gMouseFunc = func;}
376
+void glutMotionFunc(void (*func)(int x, int y))
377
+{gMouseDragged = func;}
378
+void glutPassiveMotionFunc(void (*func)(int x, int y))
379
+{gMouseMoved = func;}
380
+
381
+char gButtonPressed[10] = {0,0,0,0,0,0,0,0,0,0};
382
+
383
+void doKeyboardEvent(XEvent event, void (*keyProc)(unsigned char key, int x, int y), void (*specialKeyProc)(unsigned char key, int x, int y), int keyMapValue)
384
+{
385
+	char buffer[10];
386
+//	int r; // code;
387
+	
388
+	int code = ((XKeyEvent *)&event)->keycode;
389
+	
390
+//	r = 
391
+	XLookupString(&event.xkey, buffer, sizeof(buffer), NULL, NULL);
392
+	char raw = buffer[0]; // Before remapping
393
+	switch(code)
394
+	{
395
+		case 111: buffer[0] = GLUT_KEY_UP; break;
396
+		case 114: buffer[0] = GLUT_KEY_RIGHT; break;
397
+		case 116: buffer[0] = GLUT_KEY_DOWN; break;
398
+		case 113: buffer[0] = GLUT_KEY_LEFT; break;
399
+		case 67: buffer[0] = GLUT_KEY_F1; break;
400
+		case 68: buffer[0] = GLUT_KEY_F2; break;
401
+		case 69: buffer[0] = GLUT_KEY_F3; break;
402
+		case 70: buffer[0] = GLUT_KEY_F4; break;
403
+		case 71: buffer[0] = GLUT_KEY_F5; break;
404
+		case 72: buffer[0] = GLUT_KEY_F6; break;
405
+		case 73: buffer[0] = GLUT_KEY_F7; break;
406
+		case 112: buffer[0] = GLUT_KEY_PAGE_UP; break;
407
+		case 117: buffer[0] = GLUT_KEY_PAGE_DOWN; break;
408
+		case 110: buffer[0] = GLUT_KEY_HOME; break;
409
+		case 115: buffer[0] = GLUT_KEY_END; break;
410
+		case 118: buffer[0] = GLUT_KEY_INSERT; break;
411
+
412
+		case 50: buffer[0] = GLUT_KEY_LEFT_SHIFT; break;
413
+		case 62: buffer[0] = GLUT_KEY_RIGHT_SHIFT; break;
414
+		case 37:case 105: buffer[0] = GLUT_KEY_CONTROL; break;
415
+		case 64:case 108: buffer[0] = GLUT_KEY_ALT; break;
416
+		case 133:case 134: buffer[0] = GLUT_KEY_COMMAND; break;
417
+
418
+// Keypad
419
+		case 90: buffer[0] = GLUT_KEY_INSERT; break;
420
+		case 87: buffer[0] = GLUT_KEY_END; break;
421
+		case 88: buffer[0] = GLUT_KEY_DOWN; break;
422
+		case 89: buffer[0] = GLUT_KEY_PAGE_DOWN; break;
423
+		case 83: buffer[0] = GLUT_KEY_LEFT; break;
424
+//		case 84: buffer[0] = GLUT_KEY_KEYPAD_5; break;
425
+		case 85: buffer[0] = GLUT_KEY_RIGHT; break;
426
+		case 79: buffer[0] = GLUT_KEY_HOME; break;
427
+		case 80: buffer[0] = GLUT_KEY_UP; break;
428
+		case 81: buffer[0] = GLUT_KEY_PAGE_UP; break;
429
+		case 82: buffer[0] = 127; break;
430
+//		case 77: buffer[0] = GLUT_KEY_KEYPAD_NUMLOCK; break;
431
+	}	
432
+	
433
+	// If we asked for a separate callback for special ketys, call it. Otherwise call the standard one.
434
+	// I am considering removing the special callback for simplicity!
435
+	if (raw == 0)
436
+	{
437
+		if (specialKeyProc)
438
+			specialKeyProc(buffer[0], 0, 0);
439
+		else
440
+			if (keyProc)
441
+				keyProc(buffer[0], 0, 0);
442
+	}
443
+	else
444
+		if (keyProc)
445
+			keyProc(buffer[0], 0, 0);
446
+	gKeymap[(int)buffer[0]] = keyMapValue;
447
+	
448
+//	printf("%c %d %d %d\n", buffer[0], buffer[0], r, code);
449
+
450
+//	      			if (event.type == KeyPress)
451
+//		      		{	if (gKey) gKey(buffer[0], 0, 0); gKeymap[(int)buffer[0]] = 1;}
452
+//		      		else
453
+//		      		{	if (gKeyUp) gKeyUp(buffer[0], 0, 0); gKeymap[(int)buffer[0]] = 0;}
454
+}
455
+
456
+void internaltimer(int x)
457
+{
458
+	glutPostRedisplay();
459
+}
460
+
461
+void glutMainLoop()
462
+{
463
+	char pressed = 0;
464
+	int i;
465
+
466
+	XAllowEvents(dpy, AsyncBoth, CurrentTime);
467
+
468
+// 2018-01-24: An attempt to patch over the problem that recent MESA tends to fail the first update.
469
+	glutTimerFunc(100, internaltimer, 0);
470
+
471
+	while (gRunning)
472
+	{
473
+//      int op = 0;
474
+      while (XPending(dpy) > 0)
475
+      {
476
+         XEvent event;
477
+         XNextEvent(dpy, &event);
478
+
479
+         switch (event.type)
480
+         {
481
+         	case ClientMessage:
482
+         		if (event.xclient.data.l[0] == wmDeleteMessage) // quit!
483
+         			gRunning = 0;
484
+	         	break;
485
+         	case Expose: 
486
+//			op = 1; 
487
+				break; // Update event! Should do draw here.
488
+         	case ConfigureNotify:
489
+				if (gReshape)
490
+	      			gReshape(event.xconfigure.width, event.xconfigure.height);
491
+				else
492
+				{
493
+					glViewport(0, 0, event.xconfigure.width, event.xconfigure.height);
494
+				}
495
+				animate = 1;
496
+				winWidth = event.xconfigure.width;
497
+				winHeight = event.xconfigure.height;
498
+      			break;
499
+      		case KeyPress:
500
+				doKeyboardEvent(event, gKey, gSpecialKey, 1);break;
501
+      		case KeyRelease:
502
+				doKeyboardEvent(event, gKeyUp, gSpecialKeyUp, 0);break;
503
+			case ButtonPress:
504
+				gButtonPressed[event.xbutton.button] = 1;
505
+				if (gMouseFunc != NULL)
506
+				switch (event.xbutton.button)
507
+				{
508
+				case Button1:
509
+					gMouseFunc(GLUT_LEFT_BUTTON, GLUT_DOWN, event.xbutton.x, event.xbutton.y);break;
510
+				case Button2:
511
+					gMouseFunc(GLUT_MIDDLE_BUTTON, GLUT_DOWN, event.xbutton.x, event.xbutton.y);break;
512
+				case Button3:
513
+					gMouseFunc(GLUT_RIGHT_BUTTON, GLUT_DOWN, event.xbutton.x, event.xbutton.y);break;
514
+				}
515
+				break;
516
+			case ButtonRelease:
517
+				gButtonPressed[event.xbutton.button] = 0;
518
+				if (gMouseFunc != NULL)
519
+				switch (event.xbutton.button)
520
+				{
521
+				case Button1:
522
+					gMouseFunc(GLUT_LEFT_BUTTON, GLUT_UP, event.xbutton.x, event.xbutton.y);break;
523
+				case Button2:
524
+					gMouseFunc(GLUT_MIDDLE_BUTTON, GLUT_UP, event.xbutton.x, event.xbutton.y);break;
525
+				case Button3:
526
+					gMouseFunc(GLUT_RIGHT_BUTTON, GLUT_UP, event.xbutton.x, event.xbutton.y);break;
527
+				}
528
+				break;
529
+		case MotionNotify:
530
+				pressed = 0;
531
+				for (i = 0; i < 5; i++)
532
+					if (gButtonPressed[i]) pressed = 1;
533
+
534
+				// Saving the last known position in order to avoid problems for glutWarpPointer
535
+				// If we try warping to this position, don't!
536
+				gLastMousePositionX = event.xbutton.x;
537
+				gLastMousePositionY = event.xbutton.y;
538
+
539
+				if (pressed && gMouseDragged)
540
+					gMouseDragged(event.xbutton.x, event.xbutton.y);
541
+				else
542
+				if (gMouseMoved)
543
+					gMouseMoved(event.xbutton.x, event.xbutton.y);
544
+				break;
545
+
546
+		default:
547
+			break;
548
+         }
549
+      }
550
+      
551
+      if (animate)
552
+      {
553
+      	animate = 0;
554
+		if (gDisplay)
555
+		  	gDisplay();
556
+		else
557
+			printf("No display function!\n");
558
+//      	op = 0;
559
+      }
560
+		else
561
+		if (gIdle) gIdle();
562
+      checktimers();
563
+   }
564
+
565
+	glXMakeCurrent(dpy, None, NULL);
566
+   glXDestroyContext(dpy, ctx);
567
+   XDestroyWindow(dpy, win);
568
+   XCloseDisplay(dpy);
569
+}
570
+
571
+void glutSwapBuffers()
572
+{
573
+	glFlush(); // Added 2018-01-24, part of a fix for new MESA
574
+	glXSwapBuffers(dpy, win);
575
+}
576
+
577
+void glutPostRedisplay()
578
+{
579
+	animate = 1;
580
+}
581
+
582
+int glutGet(int type)
583
+{
584
+	struct timeval tv;
585
+	
586
+	switch (type)
587
+	{
588
+		case GLUT_ELAPSED_TIME:
589
+		gettimeofday(&tv, NULL);
590
+		return (tv.tv_usec - timeStart.tv_usec) / 1000 + (tv.tv_sec - timeStart.tv_sec)*1000;
591
+		case GLUT_WINDOW_WIDTH:
592
+		return winWidth;
593
+		case GLUT_WINDOW_HEIGHT:
594
+		return winHeight;
595
+		case GLUT_MOUSE_POSITION_X:
596
+		return gLastMousePositionX;
597
+		case GLUT_MOUSE_POSITION_Y:
598
+		return gLastMousePositionY;
599
+	}
600
+	return 0;
601
+}
602
+
603
+// NOTE: The timer is not designed with any multithreading in mind!
604
+typedef struct TimerRec
605
+{
606
+	int arg;
607
+	int time;
608
+	int repeatTime;
609
+	void (*func)(int arg);
610
+	char repeating;
611
+	struct TimerRec *next;
612
+	struct TimerRec *prev;
613
+} TimerRec;
614
+
615
+TimerRec *gTimers = NULL;
616
+
617
+void glutTimerFunc(int millis, void (*func)(int arg), int arg)
618
+{
619
+	TimerRec *t	= (TimerRec *)malloc(sizeof(TimerRec));
620
+	t->arg = arg;
621
+	t->time = millis + glutGet(GLUT_ELAPSED_TIME);
622
+	t->repeatTime = 0;
623
+	t->repeating = 0;
624
+	t->func = func;
625
+	t->next = gTimers;
626
+	t->prev = NULL;
627
+	if (gTimers != NULL)
628
+		gTimers->prev = t;
629
+	gTimers = t;
630
+}
631
+
632
+// Added by Ingemar
633
+// void glutRepeatingTimerFunc(int millis)
634
+void glutRepeatingTimer(int millis)
635
+{
636
+	TimerRec *t	= (TimerRec *)malloc(sizeof(TimerRec));
637
+	t->arg = 0;
638
+	t->time = millis + glutGet(GLUT_ELAPSED_TIME);
639
+	t->repeatTime = millis;
640
+	t->repeating = 1;
641
+	t->func = NULL;
642
+	t->next = gTimers;
643
+	t->prev = NULL;
644
+	if (gTimers != NULL)
645
+		gTimers->prev = t;
646
+	gTimers = t;
647
+}
648
+
649
+static void checktimers()
650
+{
651
+	if (gTimers != NULL)
652
+	{
653
+		TimerRec *t, *firethis = NULL;
654
+		int now = glutGet(GLUT_ELAPSED_TIME);
655
+		int nextTime = now + 1000; // Distant future, 1 second
656
+		t = gTimers;
657
+		for (t = gTimers; t != NULL; t = t->next)
658
+		{
659
+			if (t->time < nextTime) nextTime = t->time; // Time for the next one
660
+			if (t->time < now) // See if this is due to fire
661
+			{
662
+				firethis = t;
663
+			}
664
+		}
665
+		if (firethis != NULL)
666
+		{
667
+		// Fire the timer
668
+			if (firethis->func != NULL)
669
+				firethis->func(firethis->arg);
670
+			else
671
+				glutPostRedisplay();
672
+		// Remove the timer if it was one-shot, otherwise update the time
673
+			if (firethis->repeating)
674
+			{
675
+				firethis->time = now + firethis->repeatTime;
676
+			}
677
+			else
678
+			{
679
+				if (firethis->prev != NULL)
680
+					firethis->prev->next = firethis->next;
681
+				else
682
+					gTimers = firethis->next;
683
+                if (firethis->next != NULL)
684
+					firethis->next->prev = firethis->prev;
685
+				free(firethis);
686
+			}
687
+		}
688
+		// Otherwise, sleep until any timer should fire
689
+        if (!animate)
690
+			if (nextTime > now)
691
+            {
692
+		usleep((nextTime - now)*1000);
693
+            }
694
+	}
695
+    else
696
+// If no timer and no update, sleep a little to keep CPU load low
697
+        if (!animate)
698
+            usleep(10);
699
+}
700
+
701
+void glutInitContextVersion(int major, int minor)
702
+{
703
+	gContextVersionMajor = major;
704
+	gContextVersionMinor = minor;
705
+}
706
+
707
+// Based on FreeGlut glutWarpPointer, but with a significant improvement!
708
+/*
709
+ * Moves the mouse pointer to given window coordinates
710
+ */
711
+void glutWarpPointer( int x, int y )
712
+{
713
+    if (dpy == NULL)
714
+    {
715
+      fprintf(stderr, "glutWarpPointer failed: MicroGlut not initialized!\n");
716
+    	return;
717
+    }
718
+
719
+	if (x == gLastMousePositionX && y == gLastMousePositionY)
720
+		return; // Don't warp to where we already are - this causes event flooding!
721
+
722
+    XWarpPointer(
723
+        dpy, // fgDisplay.Display,
724
+        None,
725
+        win, // fgStructure.CurrentWindow->Window.Handle,
726
+        0, 0, 0, 0,
727
+        x, y
728
+    );
729
+    /* Make the warp visible immediately. */
730
+    XFlush( dpy );
731
+//    XFlush( fgDisplay.Display );
732
+}
733
+
734
+// Replaces glutSetMousePointer. This limits us to the two most common cases: None and arrow!
735
+void glutShowCursor()
736
+{
737
+	XUndefineCursor(dpy, win);
738
+}
739
+
740
+void glutHideCursor()
741
+{
742
+	if (dpy == NULL) 
743
+	{
744
+	   printf("glutHideCursor failed: MicroGlut not initialized!\n");
745
+   	return;
746
+	}
747
+	
748
+	Cursor invisibleCursor;
749
+	Pixmap bitmapNoData;
750
+	static char noll[] = { 0,0,0};
751
+	bitmapNoData = XCreateBitmapFromData(dpy, win, noll, 1, 1);
752
+	invisibleCursor = XCreatePixmapCursor(dpy,bitmapNoData, bitmapNoData, 
753
+	                                     (XColor *)noll, (XColor *)noll, 0, 0);
754
+	XDefineCursor(dpy,win, invisibleCursor);
755
+	XFreeCursor(dpy, invisibleCursor);
756
+	XFreePixmap(dpy, bitmapNoData);
757
+}
758
+
759
+
760
+
761
+char glutKeyIsDown(unsigned char c)
762
+{
763
+	return gKeymap[(unsigned int)c];
764
+}
765
+
766
+// Added by the Risinger/R\8Cberg/Wikstr\9Am project! But... gButtonPressed
767
+// was already here! Did I miss something?
768
+char glutMouseIsDown(unsigned char c)
769
+{
770
+	return gButtonPressed[(unsigned int)c];
771
+}
772
+
773
+
774
+
775
+// These were missing up to 150205
776
+
777
+void glutReshapeWindow(int width, int height)
778
+{
779
+	XResizeWindow(dpy, win, width, height);
780
+}
781
+void glutPositionWindow(int x, int y)
782
+{
783
+	XMoveWindow(dpy, win, x, y);
784
+}
785
+void glutSetWindowTitle(char *title)
786
+{
787
+	XStoreName(dpy, win, title);
788
+}
789
+
790
+// Not complete full screen mode yet since the window frame and menu are not hidden yet
791
+
792
+char gFullScreen = 0;
793
+unsigned int savedHeight, savedWidth;
794
+int savedX, savedY;
795
+
796
+void glutFullScreen()
797
+{
798
+	gFullScreen = 1;
799
+
800
+
801
+	Drawable d;
802
+	unsigned int a, b;
803
+
804
+	XGetGeometry(dpy, win, &d, &savedX, &savedY, &savedWidth, &savedHeight, &a, &b);
805
+
806
+    int scrnum = DefaultScreen(dpy);
807
+    int width = DisplayWidth( dpy, scrnum );
808
+    int height = DisplayHeight( dpy, scrnum );
809
+
810
+	XMoveResizeWindow(dpy, win, 0, 0, width, height);
811
+}
812
+
813
+void glutExitFullScreen()
814
+{
815
+	gFullScreen = 0;
816
+	XMoveResizeWindow(dpy, win, savedX, savedY, savedWidth, savedHeight);
817
+}
818
+
819
+void glutToggleFullScreen()
820
+{
821
+	if (gFullScreen)
822
+		glutExitFullScreen();
823
+	else
824
+		glutFullScreen();
825
+}
826
+
827
+void glutExit()
828
+{
829
+	gRunning = 0;
830
+}
831
+