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
36 #include <GL/wglext.h>
45 #define M_PI 3.14159265
48 #ifndef WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB
49 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9
52 #ifndef GL_FRAMEBUFFER_SRGB
53 #define GL_FRAMEBUFFER_SRGB 0x8db9
61 static HINSTANCE hInst
;
64 static GLfloat view_rotx
= 20.0, view_roty
= 30.0, view_rotz
= 0.0;
65 static GLint gear1
, gear2
, gear3
;
66 static GLfloat angle
= 0.0;
68 static GLboolean fullscreen
= GL_FALSE
;
69 static GLint samples
= 0;
70 static GLboolean use_srgb
= GL_FALSE
;
71 static GLboolean animate
= GL_TRUE
;
78 printf(" -srgb run in sRGB mode\n");
79 printf(" -stereo run in stereo mode\n");
80 printf(" -samples N run in multisample mode with at least N samples\n");
81 printf(" -fullscreen run in fullscreen mode\n");
82 printf(" -info display OpenGL renderer info\n");
83 printf(" -geometry WxH+X+Y window geometry\n");
87 /* return current time (in seconds) */
91 return timeGetTime() / 1000.0;
97 * Draw a gear wheel. You'll probably want to call this function when
98 * building a display list since we do a lot of trig here.
100 * Input: inner_radius - radius of hole at center
101 * outer_radius - radius at center of teeth
102 * width - width of gear
103 * teeth - number of teeth
104 * tooth_depth - depth of tooth
107 gear(GLfloat inner_radius
, GLfloat outer_radius
, GLfloat width
,
108 GLint teeth
, GLfloat tooth_depth
)
116 r1
= outer_radius
- tooth_depth
/ 2.0;
117 r2
= outer_radius
+ tooth_depth
/ 2.0;
119 da
= 2.0 * M_PI
/ teeth
/ 4.0;
121 glShadeModel(GL_FLAT
);
123 glNormal3f(0.0, 0.0, 1.0);
125 /* draw front face */
126 glBegin(GL_QUAD_STRIP
);
127 for (i
= 0; i
<= teeth
; i
++) {
128 angle
= i
* 2.0 * M_PI
/ teeth
;
129 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
130 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
132 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
133 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
139 /* draw front sides of teeth */
141 da
= 2.0 * M_PI
/ teeth
/ 4.0;
142 for (i
= 0; i
< teeth
; i
++) {
143 angle
= i
* 2.0 * M_PI
/ teeth
;
145 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
146 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
147 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
149 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
154 glNormal3f(0.0, 0.0, -1.0);
157 glBegin(GL_QUAD_STRIP
);
158 for (i
= 0; i
<= teeth
; i
++) {
159 angle
= i
* 2.0 * M_PI
/ teeth
;
160 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
161 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
163 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
165 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
170 /* draw back sides of teeth */
172 da
= 2.0 * M_PI
/ teeth
/ 4.0;
173 for (i
= 0; i
< teeth
; i
++) {
174 angle
= i
* 2.0 * M_PI
/ teeth
;
176 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
178 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
180 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
181 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
185 /* draw outward faces of teeth */
186 glBegin(GL_QUAD_STRIP
);
187 for (i
= 0; i
< teeth
; i
++) {
188 angle
= i
* 2.0 * M_PI
/ teeth
;
190 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
191 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
192 u
= r2
* cos(angle
+ da
) - r1
* cos(angle
);
193 v
= r2
* sin(angle
+ da
) - r1
* sin(angle
);
194 len
= sqrt(u
* u
+ v
* v
);
197 glNormal3f(v
, -u
, 0.0);
198 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
199 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
200 glNormal3f(cos(angle
), sin(angle
), 0.0);
201 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
203 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
205 u
= r1
* cos(angle
+ 3 * da
) - r2
* cos(angle
+ 2 * da
);
206 v
= r1
* sin(angle
+ 3 * da
) - r2
* sin(angle
+ 2 * da
);
207 glNormal3f(v
, -u
, 0.0);
208 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
210 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
212 glNormal3f(cos(angle
), sin(angle
), 0.0);
215 glVertex3f(r1
* cos(0), r1
* sin(0), width
* 0.5);
216 glVertex3f(r1
* cos(0), r1
* sin(0), -width
* 0.5);
220 glShadeModel(GL_SMOOTH
);
222 /* draw inside radius cylinder */
223 glBegin(GL_QUAD_STRIP
);
224 for (i
= 0; i
<= teeth
; i
++) {
225 angle
= i
* 2.0 * M_PI
/ teeth
;
226 glNormal3f(-cos(angle
), -sin(angle
), 0.0);
227 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
228 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
237 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
240 glRotatef(view_rotx
, 1.0, 0.0, 0.0);
241 glRotatef(view_roty
, 0.0, 1.0, 0.0);
242 glRotatef(view_rotz
, 0.0, 0.0, 1.0);
245 glTranslatef(-3.0, -2.0, 0.0);
246 glRotatef(angle
, 0.0, 0.0, 1.0);
251 glTranslatef(3.1, -2.0, 0.0);
252 glRotatef(-2.0 * angle
- 9.0, 0.0, 0.0, 1.0);
257 glTranslatef(-3.1, 4.2, 0.0);
258 glRotatef(-2.0 * angle
- 25.0, 0.0, 0.0, 1.0);
266 /* new window size or exposure */
268 reshape(int width
, int height
)
270 GLfloat h
= (GLfloat
) height
/ (GLfloat
) width
;
272 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
273 glMatrixMode(GL_PROJECTION
);
275 glFrustum(-1.0, 1.0, -h
, h
, 5.0, 60.0);
276 glMatrixMode(GL_MODELVIEW
);
278 glTranslatef(0.0, 0.0, -40.0);
283 srgb_to_linear(GLfloat c
)
287 return powf((c
+ 0.055f
) / 1.055f
, 2.4f
);
293 static GLfloat pos
[4] = { 5.0, 5.0, 10.0, 0.0 };
294 static GLfloat red
[4] = { 0.8, 0.1, 0.0, 1.0 };
295 static GLfloat green
[4] = { 0.0, 0.8, 0.2, 1.0 };
296 static GLfloat blue
[4] = { 0.2, 0.2, 1.0, 1.0 };
298 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
299 glEnable(GL_CULL_FACE
);
300 glEnable(GL_LIGHTING
);
302 glEnable(GL_DEPTH_TEST
);
304 for (int i
= 0; i
< 3; ++i
) {
305 red
[i
] = srgb_to_linear(red
[i
]);
306 green
[i
] = srgb_to_linear(green
[i
]);
307 blue
[i
] = srgb_to_linear(blue
[i
]);
309 glEnable(GL_FRAMEBUFFER_SRGB
);
313 gear1
= glGenLists(1);
314 glNewList(gear1
, GL_COMPILE
);
315 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, red
);
316 gear(1.0, 4.0, 1.0, 20, 0.7);
319 gear2
= glGenLists(1);
320 glNewList(gear2
, GL_COMPILE
);
321 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, green
);
322 gear(0.5, 2.0, 2.0, 10, 0.7);
325 gear3
= glGenLists(1);
326 glNewList(gear3
, GL_COMPILE
);
327 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, blue
);
328 gear(1.3, 2.0, 0.5, 10, 0.7);
331 glEnable(GL_NORMALIZE
);
335 static LRESULT CALLBACK
336 WndProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
343 reshape(LOWORD(lParam
), HIWORD(lParam
));
346 if (wParam
== VK_LEFT
)
348 else if (wParam
== VK_RIGHT
)
350 else if (wParam
== VK_UP
)
352 else if (wParam
== VK_DOWN
)
354 else if (wParam
== VK_ESCAPE
)
356 else if (wParam
== 'A')
361 EnableNonClientDpiScaling(hWnd
);
366 return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
371 * Create an RGB, double-buffered window.
372 * Return the window and context handles.
375 make_window(const char *name
, int x
, int y
, int width
, int height
)
379 DWORD dwExStyle
, dwStyle
;
380 static const PIXELFORMATDESCRIPTOR pfd
= {
381 sizeof(PIXELFORMATDESCRIPTOR
),
383 PFD_DRAW_TO_WINDOW
| PFD_SUPPORT_OPENGL
| PFD_DOUBLEBUFFER
,
399 winrect
.left
= (long)0;
400 winrect
.right
= (long)width
;
401 winrect
.top
= (long) 0;
402 winrect
.bottom
= (long)height
;
404 hInst
= GetModuleHandle(NULL
);
405 wc
.style
= CS_HREDRAW
| CS_VREDRAW
| CS_OWNDC
;
406 wc
.lpfnWndProc
= (WNDPROC
)WndProc
;
409 wc
.hInstance
= hInst
;
410 wc
.hIcon
= LoadIcon(NULL
, IDI_WINLOGO
);
411 wc
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
412 wc
.hbrBackground
= NULL
;
413 wc
.lpszMenuName
= NULL
;
414 wc
.lpszClassName
= name
;
417 dwExStyle
= WS_EX_APPWINDOW
| WS_EX_WINDOWEDGE
;
419 dwStyle
= WS_OVERLAPPEDWINDOW
;
420 AdjustWindowRectEx(&winrect
, dwStyle
, FALSE
, dwExStyle
);
426 hWnd
= CreateWindowEx(dwExStyle
, name
, name
,
427 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| dwStyle
,
429 winrect
.right
- winrect
.left
,
430 winrect
.bottom
- winrect
.top
,
431 NULL
, NULL
, hInst
, NULL
);
435 memset(&devmode
, 0, sizeof(DEVMODE
));
436 devmode
.dmSize
= sizeof(DEVMODE
);
437 devmode
.dmPelsWidth
= width
;
438 devmode
.dmPelsHeight
= height
;
439 devmode
.dmBitsPerPel
= 24;
440 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
441 ChangeDisplaySettings(&devmode
, CDS_FULLSCREEN
);
445 pixelFormat
= ChoosePixelFormat(hDC
, &pfd
);
449 SetPixelFormat(hDC
, pixelFormat
, &pfd
);
450 hRC
= wglCreateContext(hDC
);
451 wglMakeCurrent(hDC
, hRC
);
453 if (use_srgb
|| samples
> 0) {
454 /* We can't query/use extension functions until after we've
455 * created and bound a rendering context (done above).
457 * We can only set the pixel format of the window once, so we need to
458 * create a new device context in order to use the pixel format returned
459 * from wglChoosePixelFormatARB, and then create a new window.
461 PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB_func
=
462 (PFNWGLCHOOSEPIXELFORMATARBPROC
)
463 wglGetProcAddress("wglChoosePixelFormatARB");
464 assert(wglChoosePixelFormatARB_func
);
466 int int_attribs
[64] = {
467 WGL_SUPPORT_OPENGL_ARB
, TRUE
,
468 WGL_DRAW_TO_WINDOW_ARB
, TRUE
,
469 WGL_COLOR_BITS_ARB
, 24, // at least 24-bits of RGB
470 WGL_DEPTH_BITS_ARB
, 24,
471 WGL_DOUBLE_BUFFER_ARB
, TRUE
,
472 WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB
, TRUE
,
477 int_attribs
[i
++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB
;
478 int_attribs
[i
++] = TRUE
;
481 int_attribs
[i
++] = WGL_SAMPLE_BUFFERS_ARB
;
482 int_attribs
[i
++] = 1;
483 int_attribs
[i
++] = WGL_SAMPLES_ARB
;
484 int_attribs
[i
++] = samples
;
487 int_attribs
[i
++] = 0;
489 static const float float_attribs
[] = { 0 };
493 if (!wglChoosePixelFormatARB_func(hDC
, int_attribs
, float_attribs
, 1,
494 &pixelFormat
, &numFormats
) ||
498 PIXELFORMATDESCRIPTOR newPfd
;
499 DescribePixelFormat(hDC
, pixelFormat
, sizeof(pfd
), &newPfd
);
501 /* now, create new context with new pixel format */
502 wglMakeCurrent(hDC
, NULL
);
503 wglDeleteContext(hRC
);
507 hWnd
= CreateWindowEx(dwExStyle
, name
, name
,
508 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| dwStyle
,
510 winrect
.right
- winrect
.left
,
511 winrect
.bottom
- winrect
.top
,
512 NULL
, NULL
, hInst
, NULL
);
515 SetPixelFormat(hDC
, pixelFormat
, &pfd
);
516 hRC
= wglCreateContext(hDC
);
517 wglMakeCurrent(hDC
, hRC
);
520 ShowWindow(hWnd
, SW_SHOW
);
521 SetForegroundWindow(hWnd
);
526 printf("Error: couldn't get an RGB, Double-buffered");
528 printf(", Multisample");
531 printf(" pixelformat\n");
538 static int frames
= 0;
539 static double tRot0
= -1.0, tRate0
= -1.0;
540 double dt
, t
= current_time();
548 /* advance rotation for next frame */
549 angle
+= 70.0 * dt
; /* 70 degrees per second */
561 if (t
- tRate0
>= 5.0) {
562 GLfloat seconds
= t
- tRate0
;
563 GLfloat fps
= frames
/ seconds
;
564 printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames
, seconds
,
573 * Determine whether or not a WGL extension is supported.
576 is_wgl_extension_supported(HDC hdc
, const char *query
)
578 static const char *wgl_extensions
= NULL
;
579 const size_t len
= strlen(query
);
582 if (wgl_extensions
== NULL
) {
583 PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB_func
=
584 (PFNWGLGETEXTENSIONSSTRINGARBPROC
)
585 wglGetProcAddress("wglGetExtensionsStringARB");
586 if (!wglGetExtensionsStringARB_func
)
589 wgl_extensions
= wglGetExtensionsStringARB_func(hdc
);
592 ptr
= strstr(wgl_extensions
, query
);
593 return ((ptr
!= NULL
) && ((ptr
[len
] == ' ') || (ptr
[len
] == '\0')));
598 * Attempt to determine whether or not the display is synched to vblank.
604 if (is_wgl_extension_supported(hDC
, "WGL_EXT_swap_control")) {
605 PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT_func
=
606 (PFNWGLGETSWAPINTERVALEXTPROC
)
607 wglGetProcAddress("wglGetSwapIntervalEXT");
608 interval
= wglGetSwapIntervalEXT_func();
612 printf("Running synchronized to the vertical refresh. The framerate should be\n");
614 printf("approximately the same as the monitor refresh rate.\n");
616 else if (interval
> 1) {
617 printf("approximately 1/%d the monitor refresh rate.\n",
630 timeGetDevCaps(&tc
, sizeof(tc
));
631 timeBeginPeriod(tc
.wPeriodMin
);
634 if (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
635 if (msg
.message
== WM_QUIT
) break;;
636 TranslateMessage(&msg
);
637 DispatchMessage(&msg
);
643 timeEndPeriod(tc
.wPeriodMin
);
648 parse_geometry(const char *str
, int *x
, int *y
, unsigned int *w
, unsigned int *h
)
656 tw
= strtol(str
, &end
, 10);
663 if (tolower(*str
) == 'x') {
665 th
= strtol(str
, &end
, 10);
672 if (*str
== '+' || *str
== '-') {
673 tx
= strtol(str
, &end
, 10);
680 if (*str
== '+' || *str
== '-') {
681 ty
= strtol(str
, &end
, 10);
699 main(int argc
, char *argv
[])
701 unsigned int winWidth
= 300, winHeight
= 300;
704 GLboolean printInfo
= GL_FALSE
;
706 for (i
= 1; i
< argc
; i
++) {
707 if (strcmp(argv
[i
], "-info") == 0) {
710 else if (strcmp(argv
[i
], "-srgb") == 0) {
713 else if (i
< argc
- 1 && strcmp(argv
[i
], "-samples") == 0) {
714 samples
= strtod(argv
[i
+ 1], NULL
);
717 else if (strcmp(argv
[i
], "-fullscreen") == 0) {
718 fullscreen
= GL_TRUE
;
720 else if (strcmp(argv
[i
], "-geometry") == 0) {
721 parse_geometry(argv
[i
+1], &x
, &y
, &winWidth
, &winHeight
);
731 SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
736 winWidth
= GetSystemMetrics(SM_CXSCREEN
);
737 winHeight
= GetSystemMetrics(SM_CYSCREEN
);
740 make_window("wglgears", x
, y
, winWidth
, winHeight
);
741 reshape(winWidth
, winHeight
);
745 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
746 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION
));
747 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR
));
748 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS
));
756 wglMakeCurrent (NULL
, NULL
);
757 wglDeleteContext (hRC
);
758 ReleaseDC (hWnd
, hDC
);