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(" -samples N run in multisample mode with at least N samples\n");
80 printf(" -fullscreen run in fullscreen mode\n");
81 printf(" -info display OpenGL renderer info\n");
82 printf(" -geometry WxH+X+Y window geometry\n");
86 /* return current time (in seconds) */
90 return timeGetTime() / 1000.0;
96 * Draw a gear wheel. You'll probably want to call this function when
97 * building a display list since we do a lot of trig here.
99 * Input: inner_radius - radius of hole at center
100 * outer_radius - radius at center of teeth
101 * width - width of gear
102 * teeth - number of teeth
103 * tooth_depth - depth of tooth
106 gear(GLfloat inner_radius
, GLfloat outer_radius
, GLfloat width
,
107 GLint teeth
, GLfloat tooth_depth
)
115 r1
= outer_radius
- tooth_depth
/ 2.0;
116 r2
= outer_radius
+ tooth_depth
/ 2.0;
118 da
= 2.0 * M_PI
/ teeth
/ 4.0;
120 glShadeModel(GL_FLAT
);
122 glNormal3f(0.0, 0.0, 1.0);
124 /* draw front face */
125 glBegin(GL_QUAD_STRIP
);
126 for (i
= 0; i
<= teeth
; i
++) {
127 angle
= i
* 2.0 * M_PI
/ teeth
;
128 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
129 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
131 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
132 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
138 /* draw front sides of teeth */
140 da
= 2.0 * M_PI
/ teeth
/ 4.0;
141 for (i
= 0; i
< teeth
; i
++) {
142 angle
= i
* 2.0 * M_PI
/ teeth
;
144 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
145 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
146 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
148 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
153 glNormal3f(0.0, 0.0, -1.0);
156 glBegin(GL_QUAD_STRIP
);
157 for (i
= 0; i
<= teeth
; i
++) {
158 angle
= i
* 2.0 * M_PI
/ teeth
;
159 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
160 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
162 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
164 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
169 /* draw back sides of teeth */
171 da
= 2.0 * M_PI
/ teeth
/ 4.0;
172 for (i
= 0; i
< teeth
; i
++) {
173 angle
= i
* 2.0 * M_PI
/ teeth
;
175 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
177 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
179 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
180 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
184 /* draw outward faces of teeth */
185 glBegin(GL_QUAD_STRIP
);
186 for (i
= 0; i
< teeth
; i
++) {
187 angle
= i
* 2.0 * M_PI
/ teeth
;
189 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
190 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
191 u
= r2
* cos(angle
+ da
) - r1
* cos(angle
);
192 v
= r2
* sin(angle
+ da
) - r1
* sin(angle
);
193 len
= sqrt(u
* u
+ v
* v
);
196 glNormal3f(v
, -u
, 0.0);
197 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
198 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
199 glNormal3f(cos(angle
), sin(angle
), 0.0);
200 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
202 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
204 u
= r1
* cos(angle
+ 3 * da
) - r2
* cos(angle
+ 2 * da
);
205 v
= r1
* sin(angle
+ 3 * da
) - r2
* sin(angle
+ 2 * da
);
206 glNormal3f(v
, -u
, 0.0);
207 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
209 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
211 glNormal3f(cos(angle
), sin(angle
), 0.0);
214 glVertex3f(r1
* cos(0), r1
* sin(0), width
* 0.5);
215 glVertex3f(r1
* cos(0), r1
* sin(0), -width
* 0.5);
219 glShadeModel(GL_SMOOTH
);
221 /* draw inside radius cylinder */
222 glBegin(GL_QUAD_STRIP
);
223 for (i
= 0; i
<= teeth
; i
++) {
224 angle
= i
* 2.0 * M_PI
/ teeth
;
225 glNormal3f(-cos(angle
), -sin(angle
), 0.0);
226 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
227 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
236 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
239 glRotatef(view_rotx
, 1.0, 0.0, 0.0);
240 glRotatef(view_roty
, 0.0, 1.0, 0.0);
241 glRotatef(view_rotz
, 0.0, 0.0, 1.0);
244 glTranslatef(-3.0, -2.0, 0.0);
245 glRotatef(angle
, 0.0, 0.0, 1.0);
250 glTranslatef(3.1, -2.0, 0.0);
251 glRotatef(-2.0 * angle
- 9.0, 0.0, 0.0, 1.0);
256 glTranslatef(-3.1, 4.2, 0.0);
257 glRotatef(-2.0 * angle
- 25.0, 0.0, 0.0, 1.0);
265 /* new window size or exposure */
267 reshape(int width
, int height
)
269 GLfloat h
= (GLfloat
) height
/ (GLfloat
) width
;
271 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
272 glMatrixMode(GL_PROJECTION
);
274 glFrustum(-1.0, 1.0, -h
, h
, 5.0, 60.0);
275 glMatrixMode(GL_MODELVIEW
);
277 glTranslatef(0.0, 0.0, -40.0);
282 srgb_to_linear(GLfloat c
)
286 return powf((c
+ 0.055f
) / 1.055f
, 2.4f
);
292 static GLfloat pos
[4] = { 5.0, 5.0, 10.0, 0.0 };
293 static GLfloat red
[4] = { 0.8, 0.1, 0.0, 1.0 };
294 static GLfloat green
[4] = { 0.0, 0.8, 0.2, 1.0 };
295 static GLfloat blue
[4] = { 0.2, 0.2, 1.0, 1.0 };
297 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
298 glEnable(GL_CULL_FACE
);
299 glEnable(GL_LIGHTING
);
301 glEnable(GL_DEPTH_TEST
);
303 for (int i
= 0; i
< 3; ++i
) {
304 red
[i
] = srgb_to_linear(red
[i
]);
305 green
[i
] = srgb_to_linear(green
[i
]);
306 blue
[i
] = srgb_to_linear(blue
[i
]);
308 glEnable(GL_FRAMEBUFFER_SRGB
);
312 gear1
= glGenLists(1);
313 glNewList(gear1
, GL_COMPILE
);
314 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, red
);
315 gear(1.0, 4.0, 1.0, 20, 0.7);
318 gear2
= glGenLists(1);
319 glNewList(gear2
, GL_COMPILE
);
320 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, green
);
321 gear(0.5, 2.0, 2.0, 10, 0.7);
324 gear3
= glGenLists(1);
325 glNewList(gear3
, GL_COMPILE
);
326 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, blue
);
327 gear(1.3, 2.0, 0.5, 10, 0.7);
330 glEnable(GL_NORMALIZE
);
334 static LRESULT CALLBACK
335 WndProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
342 reshape(LOWORD(lParam
), HIWORD(lParam
));
345 if (wParam
== VK_LEFT
)
347 else if (wParam
== VK_RIGHT
)
349 else if (wParam
== VK_UP
)
351 else if (wParam
== VK_DOWN
)
353 else if (wParam
== VK_ESCAPE
)
355 else if (wParam
== 'A')
360 EnableNonClientDpiScaling(hWnd
);
365 return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
370 * Create an RGB, double-buffered window.
371 * Return the window and context handles.
374 make_window(const char *name
, int x
, int y
, int width
, int height
)
378 DWORD dwExStyle
, dwStyle
;
379 static const PIXELFORMATDESCRIPTOR pfd
= {
380 sizeof(PIXELFORMATDESCRIPTOR
),
382 PFD_DRAW_TO_WINDOW
| PFD_SUPPORT_OPENGL
| PFD_DOUBLEBUFFER
,
398 winrect
.left
= (long)0;
399 winrect
.right
= (long)width
;
400 winrect
.top
= (long) 0;
401 winrect
.bottom
= (long)height
;
403 hInst
= GetModuleHandle(NULL
);
404 wc
.style
= CS_HREDRAW
| CS_VREDRAW
| CS_OWNDC
;
405 wc
.lpfnWndProc
= (WNDPROC
)WndProc
;
408 wc
.hInstance
= hInst
;
409 wc
.hIcon
= LoadIcon(NULL
, IDI_WINLOGO
);
410 wc
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
411 wc
.hbrBackground
= NULL
;
412 wc
.lpszMenuName
= NULL
;
413 wc
.lpszClassName
= name
;
416 dwExStyle
= WS_EX_APPWINDOW
| WS_EX_WINDOWEDGE
;
418 dwStyle
= WS_OVERLAPPEDWINDOW
;
419 AdjustWindowRectEx(&winrect
, dwStyle
, FALSE
, dwExStyle
);
425 hWnd
= CreateWindowEx(dwExStyle
, name
, name
,
426 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| dwStyle
,
428 winrect
.right
- winrect
.left
,
429 winrect
.bottom
- winrect
.top
,
430 NULL
, NULL
, hInst
, NULL
);
434 memset(&devmode
, 0, sizeof(DEVMODE
));
435 devmode
.dmSize
= sizeof(DEVMODE
);
436 devmode
.dmPelsWidth
= width
;
437 devmode
.dmPelsHeight
= height
;
438 devmode
.dmBitsPerPel
= 24;
439 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
440 ChangeDisplaySettings(&devmode
, CDS_FULLSCREEN
);
444 pixelFormat
= ChoosePixelFormat(hDC
, &pfd
);
448 SetPixelFormat(hDC
, pixelFormat
, &pfd
);
449 hRC
= wglCreateContext(hDC
);
450 wglMakeCurrent(hDC
, hRC
);
452 if (use_srgb
|| samples
> 0) {
453 /* We can't query/use extension functions until after we've
454 * created and bound a rendering context (done above).
456 * We can only set the pixel format of the window once, so we need to
457 * create a new device context in order to use the pixel format returned
458 * from wglChoosePixelFormatARB, and then create a new window.
460 PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB_func
=
461 (PFNWGLCHOOSEPIXELFORMATARBPROC
)
462 wglGetProcAddress("wglChoosePixelFormatARB");
463 assert(wglChoosePixelFormatARB_func
);
465 int int_attribs
[64] = {
466 WGL_SUPPORT_OPENGL_ARB
, TRUE
,
467 WGL_DRAW_TO_WINDOW_ARB
, TRUE
,
468 WGL_COLOR_BITS_ARB
, 24, // at least 24-bits of RGB
469 WGL_DEPTH_BITS_ARB
, 24,
470 WGL_DOUBLE_BUFFER_ARB
, TRUE
,
471 WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB
, TRUE
,
476 int_attribs
[i
++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB
;
477 int_attribs
[i
++] = TRUE
;
480 int_attribs
[i
++] = WGL_SAMPLE_BUFFERS_ARB
;
481 int_attribs
[i
++] = 1;
482 int_attribs
[i
++] = WGL_SAMPLES_ARB
;
483 int_attribs
[i
++] = samples
;
486 int_attribs
[i
++] = 0;
488 static const float float_attribs
[] = { 0 };
492 if (!wglChoosePixelFormatARB_func(hDC
, int_attribs
, float_attribs
, 1,
493 &pixelFormat
, &numFormats
) ||
497 PIXELFORMATDESCRIPTOR newPfd
;
498 DescribePixelFormat(hDC
, pixelFormat
, sizeof(pfd
), &newPfd
);
500 /* now, create new context with new pixel format */
501 wglMakeCurrent(hDC
, NULL
);
502 wglDeleteContext(hRC
);
506 hWnd
= CreateWindowEx(dwExStyle
, name
, name
,
507 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| dwStyle
,
509 winrect
.right
- winrect
.left
,
510 winrect
.bottom
- winrect
.top
,
511 NULL
, NULL
, hInst
, NULL
);
514 SetPixelFormat(hDC
, pixelFormat
, &pfd
);
515 hRC
= wglCreateContext(hDC
);
516 wglMakeCurrent(hDC
, hRC
);
519 ShowWindow(hWnd
, SW_SHOW
);
520 SetForegroundWindow(hWnd
);
525 printf("Error: couldn't get an RGB, Double-buffered");
527 printf(", Multisample");
530 printf(" pixelformat\n");
537 static int frames
= 0;
538 static double tRot0
= -1.0, tRate0
= -1.0;
539 double dt
, t
= current_time();
547 /* advance rotation for next frame */
548 angle
+= 70.0 * dt
; /* 70 degrees per second */
560 if (t
- tRate0
>= 5.0) {
561 GLfloat seconds
= t
- tRate0
;
562 GLfloat fps
= frames
/ seconds
;
563 printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames
, seconds
,
572 * Determine whether or not a WGL extension is supported.
575 is_wgl_extension_supported(HDC hdc
, const char *query
)
577 static const char *wgl_extensions
= NULL
;
578 const size_t len
= strlen(query
);
581 if (wgl_extensions
== NULL
) {
582 PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB_func
=
583 (PFNWGLGETEXTENSIONSSTRINGARBPROC
)
584 wglGetProcAddress("wglGetExtensionsStringARB");
585 if (!wglGetExtensionsStringARB_func
)
588 wgl_extensions
= wglGetExtensionsStringARB_func(hdc
);
591 ptr
= strstr(wgl_extensions
, query
);
592 return ((ptr
!= NULL
) && ((ptr
[len
] == ' ') || (ptr
[len
] == '\0')));
597 * Attempt to determine whether or not the display is synched to vblank.
603 if (is_wgl_extension_supported(hDC
, "WGL_EXT_swap_control")) {
604 PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT_func
=
605 (PFNWGLGETSWAPINTERVALEXTPROC
)
606 wglGetProcAddress("wglGetSwapIntervalEXT");
607 interval
= wglGetSwapIntervalEXT_func();
611 printf("Running synchronized to the vertical refresh. The framerate should be\n");
613 printf("approximately the same as the monitor refresh rate.\n");
615 else if (interval
> 1) {
616 printf("approximately 1/%d the monitor refresh rate.\n",
629 timeGetDevCaps(&tc
, sizeof(tc
));
630 timeBeginPeriod(tc
.wPeriodMin
);
633 if (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
634 if (msg
.message
== WM_QUIT
) break;;
635 TranslateMessage(&msg
);
636 DispatchMessage(&msg
);
642 timeEndPeriod(tc
.wPeriodMin
);
647 parse_geometry(const char *str
, int *x
, int *y
, unsigned int *w
, unsigned int *h
)
655 tw
= strtol(str
, &end
, 10);
662 if (tolower(*str
) == 'x') {
664 th
= strtol(str
, &end
, 10);
671 if (*str
== '+' || *str
== '-') {
672 tx
= strtol(str
, &end
, 10);
679 if (*str
== '+' || *str
== '-') {
680 ty
= strtol(str
, &end
, 10);
698 main(int argc
, char *argv
[])
700 unsigned int winWidth
= 300, winHeight
= 300;
703 GLboolean printInfo
= GL_FALSE
;
705 for (i
= 1; i
< argc
; i
++) {
706 if (strcmp(argv
[i
], "-info") == 0) {
709 else if (strcmp(argv
[i
], "-srgb") == 0) {
712 else if (i
< argc
- 1 && strcmp(argv
[i
], "-samples") == 0) {
713 samples
= strtod(argv
[i
+ 1], NULL
);
716 else if (strcmp(argv
[i
], "-fullscreen") == 0) {
717 fullscreen
= GL_TRUE
;
719 else if (strcmp(argv
[i
], "-geometry") == 0) {
720 parse_geometry(argv
[i
+1], &x
, &y
, &winWidth
, &winHeight
);
730 SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
735 winWidth
= GetSystemMetrics(SM_CXSCREEN
);
736 winHeight
= GetSystemMetrics(SM_CYSCREEN
);
739 make_window("wglgears", x
, y
, winWidth
, winHeight
);
740 reshape(winWidth
, winHeight
);
744 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
745 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION
));
746 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR
));
747 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS
));
755 wglMakeCurrent (NULL
, NULL
);
756 wglDeleteContext (hRC
);
757 ReleaseDC (hWnd
, hDC
);