]> git.cworth.org Git - vogl/blob - src/vogltest/vogltest.cpp
Initial vogl checkin
[vogl] / src / vogltest / vogltest.cpp
1 // File: vogltest.cpp
2
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <math.h>
6
7 #include "vogl_core.h"
8 #include "vogl_colorized_console.h"
9
10 #include <GL/gl.h>
11 #include <GL/glx.h>
12
13 #include <X11/Xlib.h>
14 #include <X11/Xutil.h>
15 #include <X11/Xmd.h>
16
17 #include "regex/regex.h"
18
19 using namespace vogl;
20
21 #define PI 3.14159265
22
23 // Store all system info in one place
24 typedef struct RenderContextRec
25 {
26     GLXContext ctx;
27     Display *dpy;
28     Window win;
29     int nWinWidth;
30     int nWinHeight;
31     int nMousePosX;
32     int nMousePosY;
33
34 } RenderContext;
35
36 #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
37 #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
38
39 typedef GLXContext (*glXCreateContextAttribsARBProc)(Display *, GLXFBConfig, GLXContext, Bool, const int *);
40 static glXCreateContextAttribsARBProc glXCreateContextAttribsARBFuncPtr;
41
42 #if LOAD_LIBGLITRACE
43 typedef __GLXextFuncPtr (*glXGetProcAddressARBProc)(const GLubyte *procName);
44 static glXGetProcAddressARBProc glXGetProcAddressARBFuncPtr;
45
46 #warning Using LOAD_LIBGLITRACE path
47 typedef void(GLAPIENTRY *GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam);
48 typedef int GLfixed;
49
50 #define GL_FUNC(category, ret, name, args, params) typedef ret(*name##_func_ptr_t) args;
51 #define GL_FUNC_VOID(category, name, args, params) typedef void(*name##_func_ptr_t) args;
52 #define GL_EXT(name, major, minor)
53 #include "glfuncs.h"
54 #undef GL_FUNC
55 #undef GL_FUNC_VOID
56 #undef GL_EXT
57
58 #define GL_FUNC(category, ret, name, args, params) static name##_func_ptr_t g_##name##_func_ptr;
59 #define GL_FUNC_VOID(category, name, args, params) static name##_func_ptr_t g_##name##_func_ptr;
60 #define GL_EXT(name, major, minor)
61 #include "glfuncs.h"
62 #undef GL_FUNC
63 #undef GL_FUNC_VOID
64 #undef GL_EXT
65
66 static void *g_pLib_gl;
67
68 #include <dlfcn.h>
69 static void LoadGL()
70 {
71     g_pLib_gl = dlopen("./libvogltrace.so", RTLD_LAZY);
72     if (!g_pLib_gl)
73     {
74         fprintf(stderr, "Failed loading libvogltrace.so!\n");
75         exit(EXIT_FAILURE);
76     }
77
78     glXGetProcAddressARBFuncPtr = (glXGetProcAddressARBProc)dlsym(g_pLib_gl, "gliGetProcAddressRAD");
79     if (!glXGetProcAddressARBFuncPtr)
80     {
81         fprintf(stderr, "Failed finding dynamic symbol gliGetProcAddressRAD in libvogltrace.so!\n");
82         exit(EXIT_FAILURE);
83     }
84
85 #define GL_FUNC(category, ret, name, args, params)                                              \
86     g_##name##_func_ptr = (name##_func_ptr_t) (*glXGetProcAddressARBFuncPtr)((GLubyte *)#name); \
87     if (!g_##name##_func_ptr)                                                                   \
88     {                                                                                           \
89         fprintf(stderr, "Failed getting func %s!\n", #name);                                    \
90     }
91 #define GL_FUNC_VOID(category, name, args, params)                                              \
92     g_##name##_func_ptr = (name##_func_ptr_t) (*glXGetProcAddressARBFuncPtr)((GLubyte *)#name); \
93     if (!g_##name##_func_ptr)                                                                   \
94     {                                                                                           \
95         fprintf(stderr, "Failed getting func %s!\n", #name);                                    \
96     }
97 #define GL_EXT(name, major, minor)
98 #include "glfuncs.h"
99 #undef GL_FUNC
100 #undef GL_FUNC_VOID
101 #undef GL_EXT
102 }
103 #define CALL_GL(name) g_##name##_func_ptr
104
105 #else
106 #warning Using implicitly loaded libgl path
107
108 #define CALL_GL(name) name
109
110 static void LoadGL()
111 {
112 }
113 #endif
114
115 void EarlyInitGLXfnPointers()
116 {
117     LoadGL();
118     glXCreateContextAttribsARBFuncPtr = (glXCreateContextAttribsARBProc)CALL_GL(glXGetProcAddressARB)((GLubyte *)"glXCreateContextAttribsARB");
119
120     //printf("glXCreateContextAttribsARB = %p %p\n", glXCreateContextAttribsARB, &glXCreateContextAttribsARB);
121 }
122
123 //------------------------
124
125 void CreateWindow(RenderContext *rcx)
126 {
127     XSetWindowAttributes winAttribs;
128     GLint winmask;
129     GLint nMajorVer = 0;
130     GLint nMinorVer = 0;
131     XVisualInfo *visualInfo;
132
133     static int fbAttribs[] =
134         {
135             GLX_RENDER_TYPE, GLX_RGBA_BIT,
136             GLX_X_RENDERABLE, True,
137             GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
138             GLX_DOUBLEBUFFER, True,
139             GLX_RED_SIZE, 8,
140             GLX_BLUE_SIZE, 8,
141             GLX_GREEN_SIZE, 8,
142             0
143         };
144
145     EarlyInitGLXfnPointers();
146
147     // Tell X we are going to use the display
148     rcx->dpy = XOpenDisplay(NULL);
149
150     // Get Version info
151     CALL_GL(glXQueryVersion)(rcx->dpy, &nMajorVer, &nMinorVer);
152     printf("Supported GLX version - %d.%d\n", nMajorVer, nMinorVer);
153
154     if (nMajorVer == 1 && nMinorVer < 2)
155     {
156         printf("ERROR: GLX 1.2 or greater is necessary\n");
157         XCloseDisplay(rcx->dpy);
158         exit(0);
159     }
160
161     // Get a new fb config that meets our attrib requirements
162     GLXFBConfig *fbConfigs;
163     int numConfigs = 0;
164     fbConfigs = CALL_GL(glXChooseFBConfig)(rcx->dpy, DefaultScreen(rcx->dpy), fbAttribs, &numConfigs);
165     visualInfo = CALL_GL(glXGetVisualFromFBConfig)(rcx->dpy, fbConfigs[0]);
166
167     // Now create an X window
168     winAttribs.event_mask = ExposureMask | VisibilityChangeMask |
169                             KeyPressMask | PointerMotionMask |
170                             StructureNotifyMask;
171
172     winAttribs.border_pixel = 0;
173     winAttribs.bit_gravity = StaticGravity;
174     winAttribs.colormap = XCreateColormap(rcx->dpy,
175                                           RootWindow(rcx->dpy, visualInfo->screen),
176                                           visualInfo->visual, AllocNone);
177     winmask = CWBorderPixel | CWBitGravity | CWEventMask | CWColormap;
178
179     rcx->win = XCreateWindow(rcx->dpy, DefaultRootWindow(rcx->dpy), 20, 20,
180                              rcx->nWinWidth, rcx->nWinHeight, 0,
181                              visualInfo->depth, InputOutput,
182                              visualInfo->visual, winmask, &winAttribs);
183
184     XMapWindow(rcx->dpy, rcx->win);
185
186     Window root;
187     int x, y;
188     unsigned int width, height;
189     unsigned int border_width;
190     unsigned int depth;
191     if (XGetGeometry(rcx->dpy, rcx->win, &root, &x, &y, &width, &height, &border_width, &depth) == False)
192     {
193         fprintf(stderr, "can't get root window geometry\n");
194         exit(EXIT_FAILURE);
195     }
196     printf("%i %i\n", width, height);
197
198     // Also create a new GL context for rendering
199     GLint attribs[] =
200         {
201             GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
202             GLX_CONTEXT_MINOR_VERSION_ARB, 0,
203             //GLX_CONTEXT_MINOR_VERSION_ARB, 1,
204             0
205         };
206     rcx->ctx = glXCreateContextAttribsARBFuncPtr(rcx->dpy, fbConfigs[0], 0, True, attribs);
207     Bool status = CALL_GL(glXMakeCurrent)(rcx->dpy, rcx->win, rcx->ctx);
208     if (!status)
209     {
210         fprintf(stderr, "Failed creating GL context!\n");
211         exit(EXIT_FAILURE);
212     }
213
214     const GLubyte *s = CALL_GL(glGetString)(GL_VERSION);
215     printf("GL Version = %s\n", s);
216 }
217
218 void SetupGLState(RenderContext *rcx)
219 {
220     float aspectRatio = rcx->nWinHeight ? (float)rcx->nWinWidth / (float)rcx->nWinHeight : 1.0f;
221     float fYTop = 0.05f;
222     float fYBottom = -fYTop;
223     float fXLeft = fYTop * aspectRatio;
224     float fXRight = fYBottom * aspectRatio;
225
226     CALL_GL(glViewport)(0, 0, rcx->nWinWidth, rcx->nWinHeight);
227     CALL_GL(glScissor)(0, 0, rcx->nWinWidth, rcx->nWinHeight);
228
229     CALL_GL(glClearColor)(0.0f, 1.0f, 1.0f, 1.0f);
230     CALL_GL(glClear)(GL_COLOR_BUFFER_BIT);
231
232     // Clear matrix stack
233     CALL_GL(glMatrixMode)(GL_PROJECTION);
234     CALL_GL(glLoadIdentity)();
235     CALL_GL(glMatrixMode)(GL_MODELVIEW);
236     CALL_GL(glLoadIdentity)();
237
238     // Set the frustrum
239     CALL_GL(glFrustum)(fXLeft, fXRight, fYBottom, fYTop, 0.1f, 100.f);
240 }
241
242 void DrawCircle()
243 {
244     float fx = 0.0;
245     float fy = 0.0;
246
247     int nDegrees = 0;
248
249     // Use a triangle fan with 36 tris for the circle
250     CALL_GL(glBegin)(GL_TRIANGLE_FAN);
251
252     CALL_GL(glVertex2f)(0.0, 0.0);
253     for (nDegrees = 0; nDegrees < 360; nDegrees += 10)
254     {
255         fx = sin((float)nDegrees * PI / 180);
256         fy = cos((float)nDegrees * PI / 180);
257         CALL_GL(glVertex2f)(fx, fy);
258     }
259     CALL_GL(glVertex2f)(0.0f, 1.0f);
260
261     CALL_GL(glEnd)();
262 }
263
264 void Draw(RenderContext *rcx)
265 {
266     float fRightX = 0.0;
267     float fRightY = 0.0;
268     float fLeftX = 0.0;
269     float fLeftY = 0.0;
270
271     int nLtEyePosX = (rcx->nWinWidth) / 2 - (0.3 * ((rcx->nWinWidth) / 2));
272     int nLtEyePosY = (rcx->nWinHeight) / 2;
273     int nRtEyePosX = (rcx->nWinWidth) / 2 + (0.3 * ((rcx->nWinWidth) / 2));
274     int nRtEyePosY = (rcx->nWinHeight) / 2;
275
276     double fLtVecMag = 100;
277     double fRtVecMag = 100;
278
279     // Use the eyeball width as the minimum
280     double fMinLength = (0.1 * ((rcx->nWinWidth) / 2));
281
282     // Calculate the length of the vector from the eyeball
283     // to the mouse pointer
284     fLtVecMag = sqrt(pow((double)(rcx->nMousePosX - nLtEyePosX), 2.0) +
285                      pow((double)(rcx->nMousePosY - nLtEyePosY), 2.0));
286
287     fRtVecMag = sqrt(pow((double)(rcx->nMousePosX - nRtEyePosX), 2.0) +
288                      pow((double)(rcx->nMousePosY - nRtEyePosY), 2.0));
289
290     // Clamp the minimum magnatude
291     if (fRtVecMag < fMinLength)
292         fRtVecMag = fMinLength;
293     if (fLtVecMag < fMinLength)
294         fLtVecMag = fMinLength;
295
296     // Normalize the vector components
297     fLeftX = (float)(rcx->nMousePosX - nLtEyePosX) / fLtVecMag;
298     fLeftY = -1.0 * (float)(rcx->nMousePosY - nLtEyePosY) / fLtVecMag;
299     fRightX = (float)(rcx->nMousePosX - nRtEyePosX) / fRtVecMag;
300     fRightY = -1.0 * ((float)(rcx->nMousePosY - nRtEyePosY) / fRtVecMag);
301
302     CALL_GL(glClear)(GL_COLOR_BUFFER_BIT);
303
304     // Clear matrix stack
305     CALL_GL(glMatrixMode)(GL_PROJECTION);
306     CALL_GL(glLoadIdentity)();
307
308     CALL_GL(glMatrixMode)(GL_MODELVIEW);
309     CALL_GL(glLoadIdentity)();
310
311     // Draw left eyeball
312     CALL_GL(glColor3f)(1.0, 1.0, 1.0);
313     CALL_GL(glScalef)(0.20, 0.20, 1.0);
314     CALL_GL(glTranslatef)(-1.5, 0.0, 0.0);
315     DrawCircle();
316
317     // Draw black
318     CALL_GL(glColor3f)(0.0, 0.0, 0.0);
319     CALL_GL(glScalef)(0.40, 0.40, 1.0);
320     CALL_GL(glTranslatef)(fLeftX, fLeftY, 0.0);
321     DrawCircle();
322
323     // Draw right eyeball
324     CALL_GL(glColor3f)(1.0, 1.0, 1.0);
325     CALL_GL(glLoadIdentity)();
326     CALL_GL(glScalef)(0.20, 0.20, 1.0);
327     CALL_GL(glTranslatef)(1.5, 0.0, 0.0);
328     DrawCircle();
329
330     // Draw black
331     CALL_GL(glColor3f)(0.0, 0.0, 0.0);
332     CALL_GL(glScalef)(0.40, 0.40, 1.0);
333     CALL_GL(glTranslatef)(fRightX, fRightY, 0.0);
334     DrawCircle();
335
336     // Clear matrix stack
337     CALL_GL(glMatrixMode)(GL_MODELVIEW);
338     CALL_GL(glLoadIdentity)();
339
340     // Draw Nose
341     CALL_GL(glColor3f)(0.5, 0.0, 0.7);
342     CALL_GL(glScalef)(0.20, 0.20, 1.0);
343     CALL_GL(glTranslatef)(0.0, -1.5, 0.0);
344
345 #if 0
346         CALL_GL(glBegin)(GL_TRIANGLES);
347         CALL_GL(glVertex2f)(0.0, 1.0);
348         CALL_GL(glVertex2f)(-0.5, -1.0);
349         CALL_GL(glVertex2f)(0.5, -1.0);
350         CALL_GL(glEnd)();
351 #endif
352
353 #if 1
354     float verts[3][2] =
355         {
356             { 0.0, 1.0 },
357             { -0.5, -1.0 },
358             { 0.5, -1.0 }
359         };
360
361     CALL_GL(glVertexPointer)(2, GL_FLOAT, sizeof(float) * 2, verts);
362     CALL_GL(glEnableClientState)(GL_VERTEX_ARRAY);
363
364     CALL_GL(glDrawArrays)(GL_TRIANGLES, 0, 3);
365
366     CALL_GL(glDisableClientState)(GL_VERTEX_ARRAY);
367     CALL_GL(glVertexPointer)(4, GL_FLOAT, 0, NULL);
368 #endif
369
370     // Purposely unset the context to better test the glXSwapBuffers() hook.
371     // This does not work on Mesa 9 with a v2.1 context!
372     //CALL_GL(glXMakeCurrent)(rcx->dpy, None, NULL);
373
374     // Display rendering
375     CALL_GL(glXSwapBuffers)(rcx->dpy, rcx->win);
376
377     // Now set the context back.
378     //CALL_GL(glXMakeContextCurrent)(rcx->dpy, rcx->win, rcx->win, rcx->ctx);
379 }
380
381 void Cleanup(RenderContext *rcx)
382 {
383     // Unbind the context before deleting
384     CALL_GL(glXMakeCurrent)(rcx->dpy, None, NULL);
385
386     CALL_GL(glXDestroyContext)(rcx->dpy, rcx->ctx);
387     rcx->ctx = NULL;
388
389     XDestroyWindow(rcx->dpy, rcx->win);
390     rcx->win = (Window)NULL;
391
392     XCloseDisplay(rcx->dpy);
393     rcx->dpy = 0;
394 }
395
396 // TODO: Move this stuff intro voglcore itself
397 #include "vogl_regex.h"
398 #include "vogl_rand.h"
399 #include "vogl_bigint128.h"
400 #include "vogl_sparse_vector.h"
401 #include "vogl_strutils.h"
402 #include "vogl_sort.h"
403 #include "vogl_hash_map.h"
404 #include "vogl_map.h"
405 #include "vogl_timer.h"
406 #include "vogl_md5.h"
407 #include "vogl_rand.h"
408 #include "vogl_introsort.h"
409 #include "vogl_rh_hash_map.h"
410 #include "vogl_object_pool.h"
411
412 #include <map>
413
414 static void print_sep()
415 {
416     printf("-------------------------------------------------\n");
417 }
418
419 // TODO: Move this into its own tool.
420 static int run_tests(int argc, char *argv[])
421 {
422     VOGL_NOTE_UNUSED(argc);
423     VOGL_NOTE_UNUSED(argv);
424
425     g_random.seed(12345);
426
427     uint num_failures = 0;
428
429     print_sep();
430
431     if (!rh_hash_map_test())
432     {
433         printf("rh_hash_map_test failed!\n");
434         num_failures++;
435     }
436     else
437     {
438         printf("rh_hash_map_test passed\n");
439     }
440
441     print_sep();
442
443     if (!object_pool_test())
444     {
445         printf("object_pool_test failed!\n");
446         num_failures++;
447     }
448     else
449     {
450         printf("object_pool_test passed\n");
451     }
452
453     print_sep();
454
455     if (!dynamic_string_test())
456     {
457         printf("dynamic_string test failed!\n");
458         num_failures++;
459     }
460     else
461     {
462         printf("dynamic_string test passed\n");
463     }
464
465     print_sep();
466
467     printf("Running MD5 Test\n");
468     if (!md5_test())
469     {
470         printf("MD5 test failed!\n");
471         num_failures++;
472     }
473     else
474     {
475         printf("MD5 test passed\n");
476     }
477
478     print_sep();
479
480     printf("Running introsort test\n");
481     if (!introsort_test())
482     {
483         printf("Introsort test failed!\n");
484         num_failures++;
485     }
486     else
487     {
488         printf("Introsort test passed\n");
489     }
490
491     print_sep();
492
493     printf("rand test:\n");
494     bool rand_test_results = rand_test();
495     printf("%s\n", rand_test_results ? "Success" : "Failed");
496     num_failures += !rand_test_results;
497
498     print_sep();
499
500     printf("regexp tests:\n");
501     bool regext_test_results = regexp_test();
502     printf("%s\n", regext_test_results ? "Success" : "Failed");
503     num_failures += !regext_test_results;
504
505     print_sep();
506
507     printf("strutils test:\n");
508     bool strutils_test_results = strutils_test();
509     printf("%s\n", strutils_test_results ? "Success" : "Failed");
510     num_failures += !strutils_test_results;
511
512     print_sep();
513
514     map_perf_test(200);
515     map_perf_test(2000);
516     map_perf_test(20000);
517     //  map_perf_test(200000);
518     //  map_perf_test(2000000);
519
520     printf("skip_list tests:\n");
521     bool map_test_results = map_test();
522     printf("%s\n", map_test_results ? "Success" : "Failed");
523     num_failures += !map_test_results;
524
525     print_sep();
526
527     printf("hash_map tests:\n");
528     bool hashmap_test_results = hash_map_test();
529     printf("%s\n", hashmap_test_results ? "Success" : "Failed");
530     num_failures += !hashmap_test_results;
531
532     print_sep();
533
534     printf("sort tests:\n");
535     bool sort_test_results = sort_test();
536     printf("%s\n", sort_test_results ? "Success" : "Failed");
537     num_failures += !sort_test_results;
538
539     print_sep();
540
541     printf("sparse_vector tests:\n");
542     bool sparse_vector_results = sparse_vector_test();
543     printf("%s\n", sparse_vector_results ? "Success" : "Failed");
544     num_failures += !sparse_vector_results;
545
546     print_sep();
547
548     printf("bigint128 tests:\n");
549     bool bigint_test_results = bigint128_test();
550     printf("%s\n", bigint_test_results ? "Success" : "Failed");
551     num_failures += !bigint_test_results;
552
553     print_sep();
554
555     if (!num_failures)
556         printf("All tests succeeded\n");
557     else
558         fprintf(stderr, "**** %u test(s) failed!\n", num_failures);
559
560     return num_failures ? EXIT_FAILURE : EXIT_SUCCESS;
561 }
562
563 int main(int argc, char *argv[])
564 {
565     colorized_console::init();
566     colorized_console::set_exception_callback();
567     console::set_tool_prefix("(vogltest) ");
568
569     if ((argc >= 2) &&
570         ((!vogl::vogl_stricmp(argv[1], "-test")) || (!vogl::vogl_stricmp(argv[1], "--test"))))
571         return run_tests(argc, argv);
572
573     (void)argc;
574     (void)argv;
575
576     Bool bWinMapped = False;
577     RenderContext rcx;
578
579     // Set initial window size
580     rcx.nWinWidth = 400;
581     rcx.nWinHeight = 200;
582
583     // Set initial mouse position
584     rcx.nMousePosX = 0;
585     rcx.nMousePosY = 0;
586
587     // Setup X window and GLX context
588     CreateWindow(&rcx);
589     SetupGLState(&rcx);
590
591     // Draw the first frame before checking for messages
592     Draw(&rcx);
593
594     Atom wmDeleteMessage = XInternAtom(rcx.dpy, "WM_DELETE_WINDOW", False);
595     XSetWMProtocols(rcx.dpy, rcx.win, &wmDeleteMessage, 1);
596
597     for (;;)
598     {
599         XEvent newEvent;
600         XWindowAttributes winData;
601
602         // Watch for new X events
603         XNextEvent(rcx.dpy, &newEvent);
604
605         switch (newEvent.type)
606         {
607             case UnmapNotify:
608                 bWinMapped = False;
609                 break;
610             case MapNotify:
611                 bWinMapped = True;
612             case ConfigureNotify:
613
614                 XGetWindowAttributes(rcx.dpy, rcx.win, &winData);
615                 rcx.nWinHeight = winData.height;
616                 rcx.nWinWidth = winData.width;
617                 SetupGLState(&rcx);
618                 break;
619             case MotionNotify:
620                 rcx.nMousePosX = newEvent.xmotion.x;
621                 rcx.nMousePosY = newEvent.xmotion.y;
622                 Draw(&rcx);
623                 break;
624             //case KeyPress:
625             case DestroyNotify:
626                 Cleanup(&rcx);
627                 exit(EXIT_SUCCESS);
628                 break;
629             case ClientMessage:
630                 if (newEvent.xclient.data.l[0] == (int)wmDeleteMessage)
631                 {
632                     goto done;
633                 }
634                 break;
635         }
636
637         if (bWinMapped)
638         {
639             Draw(&rcx);
640         }
641     }
642
643 done:
644     Cleanup(&rcx);
645
646     colorized_console::deinit();
647
648     return EXIT_SUCCESS;
649 }