Use glad instead of GLEW.
[mesa-demos.git] / src / wgl / wglgears.c
blob1aef836e53787a1369d828892a031f1fcbaffbb3
1 /*
2 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
24 * Port by Brian Paul 23 March 2001
26 * Command line options:
27 * -info print GL implementation information
29 * Modified from X11/GLX to Win32/WGL by Ben Skeggs
30 * 25th October 2004
33 #include <assert.h>
34 #include <windows.h>
35 #include <glad/glad.h>
36 #include <glad/glad_wgl.h>
37 #include <math.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <math.h>
44 #ifndef M_PI
45 #define M_PI 3.14159265
46 #endif /* !M_PI */
49 /* Global vars */
50 static HDC hDC;
51 static HGLRC hRC;
52 static HWND hWnd;
53 static HINSTANCE hInst;
54 static RECT winrect;
56 static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
57 static GLint gear1, gear2, gear3;
58 static GLfloat angle = 0.0;
60 static GLboolean fullscreen = GL_FALSE;
61 static GLint samples = 0;
62 static GLboolean use_srgb = GL_FALSE;
63 static GLboolean animate = GL_TRUE;
66 static void
67 usage(void)
69 printf("Usage:\n");
70 printf(" -srgb run in sRGB mode\n");
71 printf(" -samples N run in multisample mode with at least N samples\n");
72 printf(" -fullscreen run in fullscreen mode\n");
73 printf(" -info display OpenGL renderer info\n");
74 printf(" -geometry WxH+X+Y window geometry\n");
78 /* return current time (in seconds) */
79 static double
80 current_time(void)
82 return timeGetTime() / 1000.0;
88 * Draw a gear wheel. You'll probably want to call this function when
89 * building a display list since we do a lot of trig here.
91 * Input: inner_radius - radius of hole at center
92 * outer_radius - radius at center of teeth
93 * width - width of gear
94 * teeth - number of teeth
95 * tooth_depth - depth of tooth
97 static void
98 gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
99 GLint teeth, GLfloat tooth_depth)
101 GLint i;
102 GLfloat r0, r1, r2;
103 GLfloat angle, da;
104 GLfloat u, v, len;
106 r0 = inner_radius;
107 r1 = outer_radius - tooth_depth / 2.0;
108 r2 = outer_radius + tooth_depth / 2.0;
110 da = 2.0 * M_PI / teeth / 4.0;
112 glShadeModel(GL_FLAT);
114 glNormal3f(0.0, 0.0, 1.0);
116 /* draw front face */
117 glBegin(GL_QUAD_STRIP);
118 for (i = 0; i <= teeth; i++) {
119 angle = i * 2.0 * M_PI / teeth;
120 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
121 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
122 if (i < teeth) {
123 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
124 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
125 width * 0.5);
128 glEnd();
130 /* draw front sides of teeth */
131 glBegin(GL_QUADS);
132 da = 2.0 * M_PI / teeth / 4.0;
133 for (i = 0; i < teeth; i++) {
134 angle = i * 2.0 * M_PI / teeth;
136 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
137 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
138 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
139 width * 0.5);
140 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
141 width * 0.5);
143 glEnd();
145 glNormal3f(0.0, 0.0, -1.0);
147 /* draw back face */
148 glBegin(GL_QUAD_STRIP);
149 for (i = 0; i <= teeth; i++) {
150 angle = i * 2.0 * M_PI / teeth;
151 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
152 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
153 if (i < teeth) {
154 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
155 -width * 0.5);
156 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
159 glEnd();
161 /* draw back sides of teeth */
162 glBegin(GL_QUADS);
163 da = 2.0 * M_PI / teeth / 4.0;
164 for (i = 0; i < teeth; i++) {
165 angle = i * 2.0 * M_PI / teeth;
167 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
168 -width * 0.5);
169 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
170 -width * 0.5);
171 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
172 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
174 glEnd();
176 /* draw outward faces of teeth */
177 glBegin(GL_QUAD_STRIP);
178 for (i = 0; i < teeth; i++) {
179 angle = i * 2.0 * M_PI / teeth;
181 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
182 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
183 u = r2 * cos(angle + da) - r1 * cos(angle);
184 v = r2 * sin(angle + da) - r1 * sin(angle);
185 len = sqrt(u * u + v * v);
186 u /= len;
187 v /= len;
188 glNormal3f(v, -u, 0.0);
189 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
190 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
191 glNormal3f(cos(angle), sin(angle), 0.0);
192 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
193 width * 0.5);
194 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
195 -width * 0.5);
196 u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
197 v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
198 glNormal3f(v, -u, 0.0);
199 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
200 width * 0.5);
201 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
202 -width * 0.5);
203 glNormal3f(cos(angle), sin(angle), 0.0);
206 glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
207 glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
209 glEnd();
211 glShadeModel(GL_SMOOTH);
213 /* draw inside radius cylinder */
214 glBegin(GL_QUAD_STRIP);
215 for (i = 0; i <= teeth; i++) {
216 angle = i * 2.0 * M_PI / teeth;
217 glNormal3f(-cos(angle), -sin(angle), 0.0);
218 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
219 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
221 glEnd();
225 static void
226 draw(void)
228 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
230 glPushMatrix();
231 glRotatef(view_rotx, 1.0, 0.0, 0.0);
232 glRotatef(view_roty, 0.0, 1.0, 0.0);
233 glRotatef(view_rotz, 0.0, 0.0, 1.0);
235 glPushMatrix();
236 glTranslatef(-3.0, -2.0, 0.0);
237 glRotatef(angle, 0.0, 0.0, 1.0);
238 glCallList(gear1);
239 glPopMatrix();
241 glPushMatrix();
242 glTranslatef(3.1, -2.0, 0.0);
243 glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
244 glCallList(gear2);
245 glPopMatrix();
247 glPushMatrix();
248 glTranslatef(-3.1, 4.2, 0.0);
249 glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
250 glCallList(gear3);
251 glPopMatrix();
253 glPopMatrix();
257 /* new window size or exposure */
258 static void
259 reshape(int width, int height)
261 GLfloat h = (GLfloat) height / (GLfloat) width;
263 glViewport(0, 0, (GLint) width, (GLint) height);
264 glMatrixMode(GL_PROJECTION);
265 glLoadIdentity();
266 glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
267 glMatrixMode(GL_MODELVIEW);
268 glLoadIdentity();
269 glTranslatef(0.0, 0.0, -40.0);
273 static GLfloat
274 srgb_to_linear(GLfloat c)
276 if (c <= 0.04045f)
277 return c / 12.92f;
278 return powf((c + 0.055f) / 1.055f, 2.4f);
281 static void
282 init(void)
284 static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
285 static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
286 static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
287 static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
288 int i;
290 glLightfv(GL_LIGHT0, GL_POSITION, pos);
291 glEnable(GL_CULL_FACE);
292 glEnable(GL_LIGHTING);
293 glEnable(GL_LIGHT0);
294 glEnable(GL_DEPTH_TEST);
295 if (use_srgb) {
296 for (i = 0; i < 3; ++i) {
297 red[i] = srgb_to_linear(red[i]);
298 green[i] = srgb_to_linear(green[i]);
299 blue[i] = srgb_to_linear(blue[i]);
301 glEnable(GL_FRAMEBUFFER_SRGB);
304 /* make the gears */
305 gear1 = glGenLists(1);
306 glNewList(gear1, GL_COMPILE);
307 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
308 gear(1.0, 4.0, 1.0, 20, 0.7);
309 glEndList();
311 gear2 = glGenLists(1);
312 glNewList(gear2, GL_COMPILE);
313 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
314 gear(0.5, 2.0, 2.0, 10, 0.7);
315 glEndList();
317 gear3 = glGenLists(1);
318 glNewList(gear3, GL_COMPILE);
319 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
320 gear(1.3, 2.0, 0.5, 10, 0.7);
321 glEndList();
323 glEnable(GL_NORMALIZE);
327 static LRESULT CALLBACK
328 WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
330 switch (uMsg) {
331 case WM_CLOSE:
332 PostQuitMessage(0);
333 return 0;
334 case WM_SIZE:
335 /* This can be reached before wglMakeCurrent */
336 if (wglGetCurrentContext() != NULL) {
337 reshape(LOWORD(lParam), HIWORD(lParam));
339 return 0;
340 case WM_KEYDOWN:
341 if (wParam == VK_LEFT)
342 view_roty += 5.0;
343 else if (wParam == VK_RIGHT)
344 view_roty -= 5.0;
345 else if (wParam == VK_UP)
346 view_rotx += 5.0;
347 else if (wParam == VK_DOWN)
348 view_rotx -= 5.0;
349 else if (wParam == VK_ESCAPE)
350 PostQuitMessage(0);
351 else if (wParam == 'A')
352 animate = !animate;
353 return 0;
354 #if WINVER >= 0x0605
355 case WM_NCCREATE:
356 EnableNonClientDpiScaling(hWnd);
357 break;
358 #endif
361 return DefWindowProc(hWnd, uMsg, wParam, lParam);
366 * Create an RGB, double-buffered window.
367 * Return the window and context handles.
369 static void
370 make_window(const char *name, int x, int y, int width, int height)
372 int pixelFormat;
373 WNDCLASS wc;
374 DWORD dwExStyle, dwStyle;
375 static const PIXELFORMATDESCRIPTOR pfd = {
376 sizeof(PIXELFORMATDESCRIPTOR),
378 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
379 PFD_TYPE_RGBA,
381 0, 0, 0, 0, 0, 0,
385 0, 0, 0, 0,
389 PFD_MAIN_PLANE,
391 0, 0, 0
394 winrect.left = (long)0;
395 winrect.right = (long)width;
396 winrect.top = (long) 0;
397 winrect.bottom = (long)height;
399 hInst = GetModuleHandle(NULL);
400 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
401 wc.lpfnWndProc = (WNDPROC)WndProc;
402 wc.cbClsExtra = 0;
403 wc.cbWndExtra = 0;
404 wc.hInstance = hInst;
405 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
406 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
407 wc.hbrBackground = NULL;
408 wc.lpszMenuName = NULL;
409 wc.lpszClassName = name;
410 RegisterClass(&wc);
412 dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
413 if (!fullscreen) {
414 dwStyle = WS_OVERLAPPEDWINDOW;
415 AdjustWindowRectEx(&winrect, dwStyle, FALSE, dwExStyle);
417 else {
418 dwStyle = WS_POPUP;
421 hWnd = CreateWindowEx(dwExStyle, name, name,
422 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle,
423 x, y,
424 winrect.right - winrect.left,
425 winrect.bottom - winrect.top,
426 NULL, NULL, hInst, NULL);
428 if (fullscreen) {
429 DEVMODE devmode;
430 memset(&devmode, 0, sizeof(DEVMODE));
431 devmode.dmSize = sizeof(DEVMODE);
432 devmode.dmPelsWidth = width;
433 devmode.dmPelsHeight = height;
434 devmode.dmBitsPerPel = 24;
435 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
436 ChangeDisplaySettings(&devmode, CDS_FULLSCREEN);
439 hDC = GetDC(hWnd);
440 pixelFormat = ChoosePixelFormat(hDC, &pfd);
441 if (!pixelFormat)
442 goto nopixelformat;
444 SetPixelFormat(hDC, pixelFormat, &pfd);
445 hRC = wglCreateContext(hDC);
446 wglMakeCurrent(hDC, hRC);
448 gladLoadWGL(hDC);
450 if (use_srgb || samples > 0) {
451 /* We can't query/use extension functions until after we've
452 * created and bound a rendering context (done above).
454 * We can only set the pixel format of the window once, so we need to
455 * create a new device context in order to use the pixel format returned
456 * from wglChoosePixelFormatARB, and then create a new window.
458 assert(GLAD_WGL_ARB_create_context);
460 int int_attribs[64] = {
461 WGL_SUPPORT_OPENGL_ARB, TRUE,
462 WGL_DRAW_TO_WINDOW_ARB, TRUE,
463 WGL_COLOR_BITS_ARB, 24, // at least 24-bits of RGB
464 WGL_DEPTH_BITS_ARB, 24,
465 WGL_DOUBLE_BUFFER_ARB, TRUE,
466 WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE,
468 int i = 10;
470 if (use_srgb) {
471 int_attribs[i++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
472 int_attribs[i++] = TRUE;
474 if (samples > 0) {
475 int_attribs[i++] = WGL_SAMPLE_BUFFERS_ARB;
476 int_attribs[i++] = 1;
477 int_attribs[i++] = WGL_SAMPLES_ARB;
478 int_attribs[i++] = samples;
481 int_attribs[i++] = 0;
483 static const float float_attribs[] = { 0 };
484 UINT numFormats;
486 pixelFormat = 0;
487 if (!wglChoosePixelFormatARB(hDC, int_attribs, float_attribs, 1,
488 &pixelFormat, &numFormats) ||
489 !numFormats)
490 goto nopixelformat;
492 PIXELFORMATDESCRIPTOR newPfd;
493 DescribePixelFormat(hDC, pixelFormat, sizeof(pfd), &newPfd);
495 /* now, create new context with new pixel format */
496 wglMakeCurrent(hDC, NULL);
497 wglDeleteContext(hRC);
498 DeleteDC(hDC);
500 DestroyWindow(hWnd);
501 hWnd = CreateWindowEx(dwExStyle, name, name,
502 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle,
503 x, y,
504 winrect.right - winrect.left,
505 winrect.bottom - winrect.top,
506 NULL, NULL, hInst, NULL);
508 hDC = GetDC(hWnd);
509 SetPixelFormat(hDC, pixelFormat, &pfd);
510 hRC = wglCreateContext(hDC);
511 wglMakeCurrent(hDC, hRC);
514 gladLoadGL();
516 ShowWindow(hWnd, SW_SHOW);
517 SetForegroundWindow(hWnd);
518 SetFocus(hWnd);
519 return;
521 nopixelformat:
522 printf("Error: couldn't get an RGB, Double-buffered");
523 if (samples > 0)
524 printf(", Multisample");
525 if (use_srgb)
526 printf(", sRGB");
527 printf(" pixelformat\n");
528 exit(1);
531 static void
532 draw_frame()
534 static int frames = 0;
535 static double tRot0 = -1.0, tRate0 = -1.0;
536 double dt, t = current_time();
538 if (tRot0 < 0.0)
539 tRot0 = t;
540 dt = t - tRot0;
541 tRot0 = t;
543 if (animate) {
544 /* advance rotation for next frame */
545 angle += 70.0 * dt; /* 70 degrees per second */
546 if (angle > 3600.0)
547 angle -= 3600.0;
550 draw();
551 SwapBuffers(hDC);
553 frames++;
555 if (tRate0 < 0.0)
556 tRate0 = t;
557 if (t - tRate0 >= 5.0) {
558 GLfloat seconds = t - tRate0;
559 GLfloat fps = frames / seconds;
560 printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
561 fps);
562 fflush(stdout);
563 tRate0 = t;
564 frames = 0;
569 * Attempt to determine whether or not the display is synched to vblank.
571 static void
572 query_vsync()
574 int interval = 0;
575 if (GLAD_WGL_EXT_swap_control) {
576 interval = wglGetSwapIntervalEXT();
579 if (interval > 0) {
580 printf("Running synchronized to the vertical refresh. The framerate should be\n");
581 if (interval == 1) {
582 printf("approximately the same as the monitor refresh rate.\n");
584 else if (interval > 1) {
585 printf("approximately 1/%d the monitor refresh rate.\n",
586 interval);
592 static void
593 event_loop(void)
595 MSG msg;
597 TIMECAPS tc;
598 timeGetDevCaps(&tc, sizeof(tc));
599 timeBeginPeriod(tc.wPeriodMin);
601 while(1) {
602 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
603 if (msg.message == WM_QUIT) break;;
604 TranslateMessage(&msg);
605 DispatchMessage(&msg);
608 draw_frame();
611 timeEndPeriod(tc.wPeriodMin);
615 static void
616 parse_geometry(const char *str, int *x, int *y, unsigned int *w, unsigned int *h)
618 char *end;
619 if (*str == '=')
620 str++;
622 long tw = LONG_MAX;
623 if (isdigit(*str)) {
624 tw = strtol(str, &end, 10);
625 if (str == end)
626 return;
627 str = end;
630 long th = LONG_MAX;
631 if (tolower(*str) == 'x') {
632 str++;
633 th = strtol(str, &end, 10);
634 if (str== end)
635 return;
636 str = end;
639 long tx = LONG_MAX;
640 if (*str == '+' || *str == '-') {
641 tx = strtol(str, &end, 10);
642 if (str == end)
643 return;
644 str = end;
647 long ty = LONG_MAX;
648 if (*str == '+' || *str == '-') {
649 ty = strtol(str, &end, 10);
650 if (str == end)
651 return;
652 str = end;
655 if (tw < LONG_MAX)
656 *w = tw;
657 if (th < LONG_MAX)
658 *h = th;
659 if (tx < INT_MAX)
660 *x = tx;
661 if (ty < INT_MAX)
662 *y = ty;
667 main(int argc, char *argv[])
669 unsigned int winWidth = 300, winHeight = 300;
670 int x = 0, y = 0;
671 int i;
672 GLboolean printInfo = GL_FALSE;
674 for (i = 1; i < argc; i++) {
675 if (strcmp(argv[i], "-info") == 0) {
676 printInfo = GL_TRUE;
678 else if (strcmp(argv[i], "-srgb") == 0) {
679 use_srgb = GL_TRUE;
681 else if (i < argc - 1 && strcmp(argv[i], "-samples") == 0) {
682 samples = strtod(argv[i + 1], NULL);
683 ++i;
685 else if (strcmp(argv[i], "-fullscreen") == 0) {
686 fullscreen = GL_TRUE;
688 else if (strcmp(argv[i], "-geometry") == 0) {
689 parse_geometry(argv[i+1], &x, &y, &winWidth, &winHeight);
690 i++;
692 else {
693 usage();
694 return -1;
698 #if WINVER >= 0x0605
699 SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
700 #endif
702 if (fullscreen) {
703 x = 0; y = 0;
704 winWidth = GetSystemMetrics(SM_CXSCREEN);
705 winHeight = GetSystemMetrics(SM_CYSCREEN);
708 make_window("wglgears", x, y, winWidth, winHeight);
709 reshape(winWidth, winHeight);
710 query_vsync();
712 if (printInfo) {
713 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
714 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
715 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
716 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
719 init();
721 event_loop();
723 /* cleanup */
724 wglMakeCurrent (NULL, NULL);
725 wglDeleteContext (hRC);
726 ReleaseDC (hWnd, hDC);
728 return EXIT_SUCCESS;