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
35 #include <glad/glad.h>
36 #include <glad/glad_wgl.h>
45 #define M_PI 3.14159265
53 static HINSTANCE hInst
;
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
;
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) */
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
98 gear(GLfloat inner_radius
, GLfloat outer_radius
, GLfloat width
,
99 GLint teeth
, GLfloat tooth_depth
)
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);
123 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
124 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
130 /* draw front sides of teeth */
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
),
140 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
145 glNormal3f(0.0, 0.0, -1.0);
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);
154 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
156 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
161 /* draw back sides of teeth */
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
),
169 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
171 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
172 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
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
);
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
),
194 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
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
),
201 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
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);
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);
228 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
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);
236 glTranslatef(-3.0, -2.0, 0.0);
237 glRotatef(angle
, 0.0, 0.0, 1.0);
242 glTranslatef(3.1, -2.0, 0.0);
243 glRotatef(-2.0 * angle
- 9.0, 0.0, 0.0, 1.0);
248 glTranslatef(-3.1, 4.2, 0.0);
249 glRotatef(-2.0 * angle
- 25.0, 0.0, 0.0, 1.0);
257 /* new window size or exposure */
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
);
266 glFrustum(-1.0, 1.0, -h
, h
, 5.0, 60.0);
267 glMatrixMode(GL_MODELVIEW
);
269 glTranslatef(0.0, 0.0, -40.0);
274 srgb_to_linear(GLfloat c
)
278 return powf((c
+ 0.055f
) / 1.055f
, 2.4f
);
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 };
290 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
291 glEnable(GL_CULL_FACE
);
292 glEnable(GL_LIGHTING
);
294 glEnable(GL_DEPTH_TEST
);
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
);
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);
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);
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);
323 glEnable(GL_NORMALIZE
);
327 static LRESULT CALLBACK
328 WndProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
335 /* This can be reached before wglMakeCurrent */
336 if (wglGetCurrentContext() != NULL
) {
337 reshape(LOWORD(lParam
), HIWORD(lParam
));
341 if (wParam
== VK_LEFT
)
343 else if (wParam
== VK_RIGHT
)
345 else if (wParam
== VK_UP
)
347 else if (wParam
== VK_DOWN
)
349 else if (wParam
== VK_ESCAPE
)
351 else if (wParam
== 'A')
356 EnableNonClientDpiScaling(hWnd
);
361 return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
366 * Create an RGB, double-buffered window.
367 * Return the window and context handles.
370 make_window(const char *name
, int x
, int y
, int width
, int height
)
374 DWORD dwExStyle
, dwStyle
;
375 static const PIXELFORMATDESCRIPTOR pfd
= {
376 sizeof(PIXELFORMATDESCRIPTOR
),
378 PFD_DRAW_TO_WINDOW
| PFD_SUPPORT_OPENGL
| PFD_DOUBLEBUFFER
,
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
;
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
;
412 dwExStyle
= WS_EX_APPWINDOW
| WS_EX_WINDOWEDGE
;
414 dwStyle
= WS_OVERLAPPEDWINDOW
;
415 AdjustWindowRectEx(&winrect
, dwStyle
, FALSE
, dwExStyle
);
421 hWnd
= CreateWindowEx(dwExStyle
, name
, name
,
422 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| dwStyle
,
424 winrect
.right
- winrect
.left
,
425 winrect
.bottom
- winrect
.top
,
426 NULL
, NULL
, hInst
, NULL
);
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
);
440 pixelFormat
= ChoosePixelFormat(hDC
, &pfd
);
444 SetPixelFormat(hDC
, pixelFormat
, &pfd
);
445 hRC
= wglCreateContext(hDC
);
446 wglMakeCurrent(hDC
, hRC
);
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
,
471 int_attribs
[i
++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB
;
472 int_attribs
[i
++] = TRUE
;
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 };
487 if (!wglChoosePixelFormatARB(hDC
, int_attribs
, float_attribs
, 1,
488 &pixelFormat
, &numFormats
) ||
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
);
501 hWnd
= CreateWindowEx(dwExStyle
, name
, name
,
502 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| dwStyle
,
504 winrect
.right
- winrect
.left
,
505 winrect
.bottom
- winrect
.top
,
506 NULL
, NULL
, hInst
, NULL
);
509 SetPixelFormat(hDC
, pixelFormat
, &pfd
);
510 hRC
= wglCreateContext(hDC
);
511 wglMakeCurrent(hDC
, hRC
);
516 ShowWindow(hWnd
, SW_SHOW
);
517 SetForegroundWindow(hWnd
);
522 printf("Error: couldn't get an RGB, Double-buffered");
524 printf(", Multisample");
527 printf(" pixelformat\n");
534 static int frames
= 0;
535 static double tRot0
= -1.0, tRate0
= -1.0;
536 double dt
, t
= current_time();
544 /* advance rotation for next frame */
545 angle
+= 70.0 * dt
; /* 70 degrees per second */
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
,
569 * Attempt to determine whether or not the display is synched to vblank.
575 if (GLAD_WGL_EXT_swap_control
) {
576 interval
= wglGetSwapIntervalEXT();
580 printf("Running synchronized to the vertical refresh. The framerate should be\n");
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",
598 timeGetDevCaps(&tc
, sizeof(tc
));
599 timeBeginPeriod(tc
.wPeriodMin
);
602 if (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
603 if (msg
.message
== WM_QUIT
) break;;
604 TranslateMessage(&msg
);
605 DispatchMessage(&msg
);
611 timeEndPeriod(tc
.wPeriodMin
);
616 parse_geometry(const char *str
, int *x
, int *y
, unsigned int *w
, unsigned int *h
)
624 tw
= strtol(str
, &end
, 10);
631 if (tolower(*str
) == 'x') {
633 th
= strtol(str
, &end
, 10);
640 if (*str
== '+' || *str
== '-') {
641 tx
= strtol(str
, &end
, 10);
648 if (*str
== '+' || *str
== '-') {
649 ty
= strtol(str
, &end
, 10);
667 main(int argc
, char *argv
[])
669 unsigned int winWidth
= 300, winHeight
= 300;
672 GLboolean printInfo
= GL_FALSE
;
674 for (i
= 1; i
< argc
; i
++) {
675 if (strcmp(argv
[i
], "-info") == 0) {
678 else if (strcmp(argv
[i
], "-srgb") == 0) {
681 else if (i
< argc
- 1 && strcmp(argv
[i
], "-samples") == 0) {
682 samples
= strtod(argv
[i
+ 1], NULL
);
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
);
699 SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
704 winWidth
= GetSystemMetrics(SM_CXSCREEN
);
705 winHeight
= GetSystemMetrics(SM_CYSCREEN
);
708 make_window("wglgears", x
, y
, winWidth
, winHeight
);
709 reshape(winWidth
, winHeight
);
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
));
724 wglMakeCurrent (NULL
, NULL
);
725 wglDeleteContext (hRC
);
726 ReleaseDC (hWnd
, hDC
);