glut: added GLUT_PPM_FILE env var to dump first frame to a PPM file
[mesa.git] / src / glut / glx / glut_init.c
1
2 /* Copyright (c) Mark J. Kilgard, 1994, 1997. */
3
4 /* This program is freely distributable without licensing fees
5 and is provided without guarantee or warrantee expressed or
6 implied. This program is -not- in the public domain. */
7
8 #ifdef __VMS
9 #include <GL/vms_x_fix.h>
10 #endif
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <stdio.h>
15
16 #if !defined(_WIN32)
17 #include <X11/Xlib.h>
18 #include <X11/Xatom.h>
19 #endif
20
21 /* SGI optimization introduced in IRIX 6.3 to avoid X server
22 round trips for interning common X atoms. */
23 #if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
24 #include <X11/SGIFastAtom.h>
25 #else
26 #define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
27 #endif
28
29 #include "glutint.h"
30
31 /* GLUT inter-file variables */
32 /* *INDENT-OFF* */
33 char *__glutProgramName = NULL;
34 int __glutArgc = 0;
35 char **__glutArgv = NULL;
36 char *__glutGeometry = NULL;
37 Display *__glutDisplay = NULL;
38 int __glutScreen;
39 Window __glutRoot;
40 int __glutScreenHeight;
41 int __glutScreenWidth;
42 GLboolean __glutIconic = GL_FALSE;
43 GLboolean __glutDebug = GL_FALSE;
44 unsigned int __glutDisplayMode =
45 GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH;
46 char *__glutDisplayString = NULL;
47 int __glutConnectionFD;
48 XSizeHints __glutSizeHints = {0};
49 int __glutInitWidth = 300, __glutInitHeight = 300;
50 int __glutInitX = -1, __glutInitY = -1;
51 GLboolean __glutForceDirect = GL_FALSE,
52 __glutTryDirect = GL_TRUE;
53 Atom __glutWMDeleteWindow;
54 char *__glutPPMFile = NULL;
55 /* *INDENT-ON* */
56
57 #ifdef _WIN32
58 void (__cdecl *__glutExitFunc)(int retval) = NULL;
59 #endif
60
61 static Bool synchronize = False;
62
63 #if defined(_WIN32)
64
65 #ifdef __BORLANDC__
66 #include <float.h> /* For masking floating point exceptions. */
67 #endif
68
69 void
70 __glutOpenWin32Connection(char* display)
71 {
72 static char *classname;
73 WNDCLASS wc;
74 HINSTANCE hInstance = GetModuleHandle(NULL);
75
76 /* Make sure we register the window only once. */
77 if(classname)
78 return;
79
80 #ifdef __BORLANDC__
81 /* Under certain conditions (e.g. while rendering solid surfaces with
82 lighting enabled) Microsoft OpenGL libraries cause some illegal
83 operations like floating point overflow or division by zero. The
84 default behaviour of Microsoft compilers is to mask (ignore)
85 floating point exceptions, while Borland compilers do not. The
86 following function of Borland RTL allows to mask exceptions.
87 Advice from Pier Giorgio Esposito (mc2172@mclink.it). */
88 _control87(MCW_EM,MCW_EM);
89 #endif
90
91 classname = "GLUT";
92
93 /* Clear (important!) and then fill in the window class structure. */
94 memset(&wc, 0, sizeof(WNDCLASS));
95 wc.style = CS_OWNDC;
96 wc.lpfnWndProc = (WNDPROC)__glutWindowProc;
97 wc.hInstance = hInstance;
98 wc.hIcon = LoadIcon(hInstance, "GLUT_ICON");
99 wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
100 wc.hbrBackground = NULL;
101 wc.lpszMenuName = NULL;
102 wc.lpszClassName = classname;
103
104 /* Fill in a default icon if one isn't specified as a resource. */
105 if(!wc.hIcon)
106 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
107
108 if(!RegisterClass(&wc)) {
109 __glutFatalError("RegisterClass() failed:"
110 "Cannot register GLUT window class.");
111 }
112
113 __glutScreenWidth = GetSystemMetrics(SM_CXSCREEN);
114 __glutScreenHeight = GetSystemMetrics(SM_CYSCREEN);
115
116 /* Set the root window to NULL because windows creates a top-level
117 window when the parent is NULL. X creates a top-level window
118 when the parent is the root window. */
119 __glutRoot = NULL;
120
121 /* Set the display to 1 -- we shouldn't be using this anywhere
122 (except as an argument to X calls). */
123 __glutDisplay = (Display*)1;
124
125 /* There isn't any concept of multiple screens in Win32, therefore,
126 we don't need to keep track of the screen we're on... it's always
127 the same one. */
128 __glutScreen = 0;
129 }
130 #else /* !_WIN32 */
131 void
132 __glutOpenXConnection(char *display)
133 {
134 int errorBase, eventBase;
135
136 __glutDisplay = XOpenDisplay(display);
137 if (!__glutDisplay)
138 __glutFatalError("could not open display: %s",
139 XDisplayName(display));
140 if (synchronize)
141 XSynchronize(__glutDisplay, True);
142 if (!glXQueryExtension(__glutDisplay, &errorBase, &eventBase))
143 __glutFatalError(
144 "OpenGL GLX extension not supported by display: %s",
145 XDisplayName(display));
146 __glutScreen = DefaultScreen(__glutDisplay);
147 __glutRoot = RootWindow(__glutDisplay, __glutScreen);
148 __glutScreenWidth = DisplayWidth(__glutDisplay, __glutScreen);
149 __glutScreenHeight = DisplayHeight(__glutDisplay,
150 __glutScreen);
151 __glutConnectionFD = ConnectionNumber(__glutDisplay);
152 __glutWMDeleteWindow = XSGIFastInternAtom(__glutDisplay,
153 "WM_DELETE_WINDOW", SGI_XA_WM_DELETE_WINDOW, False);
154 }
155 #endif /* _WIN32 */
156
157 void
158 #ifdef OLD_VMS
159 __glutInitTime(struct timeval6 *beginning)
160 #else
161 __glutInitTime(struct timeval *beginning)
162 #endif
163 {
164 static int beenhere = 0;
165 #ifdef OLD_VMS
166 static struct timeval6 genesis;
167 #else
168 static struct timeval genesis;
169 #endif
170
171 if (!beenhere) {
172 GETTIMEOFDAY(&genesis);
173 beenhere = 1;
174 }
175 *beginning = genesis;
176 }
177
178 static void
179 removeArgs(int *argcp, char **argv, int numToRemove)
180 {
181 int i, j;
182
183 for (i = 0, j = numToRemove; argv[j]; i++, j++) {
184 argv[i] = argv[j];
185 }
186 argv[i] = NULL;
187 *argcp -= numToRemove;
188 }
189
190 void GLUTAPIENTRY
191 glutInit(int *argcp, char **argv)
192 {
193 char *display = NULL;
194 char *str, *geometry = NULL;
195 #ifdef OLD_VMS
196 struct timeval6 unused;
197 #else
198 struct timeval unused;
199 #endif
200 int i;
201
202 if (__glutDisplay) {
203 __glutWarning("glutInit being called a second time.");
204 return;
205 }
206 /* Determine temporary program name. */
207 str = strrchr(argv[0], '/');
208 if (str == NULL) {
209 __glutProgramName = argv[0];
210 } else {
211 __glutProgramName = str + 1;
212 }
213
214 /* Make private copy of command line arguments. */
215 __glutArgc = *argcp;
216 __glutArgv = (char **) malloc(__glutArgc * sizeof(char *));
217 if (!__glutArgv)
218 __glutFatalError("out of memory.");
219 for (i = 0; i < __glutArgc; i++) {
220 __glutArgv[i] = __glutStrdup(argv[i]);
221 if (!__glutArgv[i])
222 __glutFatalError("out of memory.");
223 }
224
225 /* determine permanent program name */
226 str = strrchr(__glutArgv[0], '/');
227 if (str == NULL) {
228 __glutProgramName = __glutArgv[0];
229 } else {
230 __glutProgramName = str + 1;
231 }
232
233 /* parse arguments for standard options */
234 for (i = 1; i < __glutArgc; i++) {
235 if (!strcmp(__glutArgv[i], "-display")) {
236 #if defined(_WIN32)
237 __glutWarning("-display option not supported by Win32 GLUT.");
238 #endif
239 if (++i >= __glutArgc) {
240 __glutFatalError(
241 "follow -display option with X display name.");
242 }
243 display = __glutArgv[i];
244 removeArgs(argcp, &argv[1], 2);
245 } else if (!strcmp(__glutArgv[i], "-geometry")) {
246 if (++i >= __glutArgc) {
247 __glutFatalError(
248 "follow -geometry option with geometry parameter.");
249 }
250 geometry = __glutArgv[i];
251 removeArgs(argcp, &argv[1], 2);
252 } else if (!strcmp(__glutArgv[i], "-direct")) {
253 #if defined(_WIN32)
254 __glutWarning("-direct option not supported by Win32 GLUT.");
255 #endif
256 if (!__glutTryDirect)
257 __glutFatalError(
258 "cannot force both direct and indirect rendering.");
259 __glutForceDirect = GL_TRUE;
260 removeArgs(argcp, &argv[1], 1);
261 } else if (!strcmp(__glutArgv[i], "-indirect")) {
262 #if defined(_WIN32)
263 __glutWarning("-indirect option not supported by Win32 GLUT.");
264 #endif
265 if (__glutForceDirect)
266 __glutFatalError(
267 "cannot force both direct and indirect rendering.");
268 __glutTryDirect = GL_FALSE;
269 removeArgs(argcp, &argv[1], 1);
270 } else if (!strcmp(__glutArgv[i], "-iconic")) {
271 __glutIconic = GL_TRUE;
272 removeArgs(argcp, &argv[1], 1);
273 } else if (!strcmp(__glutArgv[i], "-gldebug")) {
274 __glutDebug = GL_TRUE;
275 removeArgs(argcp, &argv[1], 1);
276 } else if (!strcmp(__glutArgv[i], "-sync")) {
277 #if defined(_WIN32)
278 __glutWarning("-sync option not supported by Win32 GLUT.");
279 #endif
280 synchronize = GL_TRUE;
281 removeArgs(argcp, &argv[1], 1);
282 } else {
283 /* Once unknown option encountered, stop command line
284 processing. */
285 break;
286 }
287 }
288 #if defined(_WIN32)
289 __glutOpenWin32Connection(display);
290 #else
291 __glutOpenXConnection(display);
292 #endif
293 if (geometry) {
294 int flags, x, y, width, height;
295
296 /* Fix bogus "{width|height} may be used before set"
297 warning */
298 width = 0;
299 height = 0;
300
301 flags = XParseGeometry(geometry, &x, &y,
302 (unsigned int *) &width, (unsigned int *) &height);
303 if (WidthValue & flags) {
304 /* Careful because X does not allow zero or negative
305 width windows */
306 if (width > 0)
307 __glutInitWidth = width;
308 }
309 if (HeightValue & flags) {
310 /* Careful because X does not allow zero or negative
311 height windows */
312 if (height > 0)
313 __glutInitHeight = height;
314 }
315 glutInitWindowSize(__glutInitWidth, __glutInitHeight);
316 if (XValue & flags) {
317 if (XNegative & flags)
318 x = DisplayWidth(__glutDisplay, __glutScreen) +
319 x - __glutSizeHints.width;
320 /* Play safe: reject negative X locations */
321 if (x >= 0)
322 __glutInitX = x;
323 }
324 if (YValue & flags) {
325 if (YNegative & flags)
326 y = DisplayHeight(__glutDisplay, __glutScreen) +
327 y - __glutSizeHints.height;
328 /* Play safe: reject negative Y locations */
329 if (y >= 0)
330 __glutInitY = y;
331 }
332 glutInitWindowPosition(__glutInitX, __glutInitY);
333 }
334 __glutInitTime(&unused);
335
336 /* check if GLUT_FPS env var is set */
337 {
338 const char *fps = getenv("GLUT_FPS");
339 if (fps) {
340 sscanf(fps, "%d", &__glutFPS);
341 if (__glutFPS <= 0)
342 __glutFPS = 5000; /* 5000 milliseconds */
343 }
344 }
345
346 /* check if GLUT_PPM_FILE env var is set */
347 __glutPPMFile = getenv("GLUT_PPM_FILE");
348 }
349
350 #ifdef _WIN32
351 void GLUTAPIENTRY
352 __glutInitWithExit(int *argcp, char **argv, void (__cdecl *exitfunc)(int))
353 {
354 __glutExitFunc = exitfunc;
355 glutInit(argcp, argv);
356 }
357 #endif
358
359 /* CENTRY */
360 void GLUTAPIENTRY
361 glutInitWindowPosition(int x, int y)
362 {
363 __glutInitX = x;
364 __glutInitY = y;
365 if (x >= 0 && y >= 0) {
366 __glutSizeHints.x = x;
367 __glutSizeHints.y = y;
368 __glutSizeHints.flags |= USPosition;
369 } else {
370 __glutSizeHints.flags &= ~USPosition;
371 }
372 }
373
374 void GLUTAPIENTRY
375 glutInitWindowSize(int width, int height)
376 {
377 __glutInitWidth = width;
378 __glutInitHeight = height;
379 if (width > 0 && height > 0) {
380 __glutSizeHints.width = width;
381 __glutSizeHints.height = height;
382 __glutSizeHints.flags |= USSize;
383 } else {
384 __glutSizeHints.flags &= ~USSize;
385 }
386 }
387
388 void GLUTAPIENTRY
389 glutInitDisplayMode(unsigned int mask)
390 {
391 __glutDisplayMode = mask;
392 }
393
394 /* ENDCENTRY */