1/***********************************************************
2 *      Copyright (C) 1997, Be Inc.  Copyright (C) 1999, Jake Hamby.
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 *
9 *  FILE:	glutInit.cpp
10 *
11 *	DESCRIPTION:	initialize GLUT state
12 ***********************************************************/
13
14/***********************************************************
15 *	Headers
16 ***********************************************************/
17#include <GL/glut.h>
18#include <string.h>
19#include <stdlib.h>
20#include <signal.h>
21#include "glutint.h"
22#include "glutState.h"
23#include "glutBlocker.h"
24#include "beos_x11.h"
25
26/***********************************************************
27 *	Global variables
28 ***********************************************************/
29GlutState gState;
30char *__glutProgramName = NULL;
31
32/***********************************************************
33 *	Private variables
34 ***********************************************************/
35static int __glutArgc;
36static char **__glutArgv;
37
38/***********************************************************
39 *	FUNCTION:	__glutInitTime
40 *
41 *	DESCRIPTION:  set up start time variable
42 ***********************************************************/
43void __glutInitTime(bigtime_t *beginning)
44{
45  static int beenhere = 0;
46  static bigtime_t genesis;
47
48  if (!beenhere) {
49    genesis = system_time();
50    beenhere = 1;
51  }
52  *beginning = genesis;
53}
54
55/***********************************************************
56 *	FUNCTION:	removeArgs
57 *
58 *	DESCRIPTION:  helper function for glutInit to remove args
59 *		from argv variable passed in
60 ***********************************************************/
61static void
62removeArgs(int *argcp, char **argv, int numToRemove)
63{
64  int i, j;
65
66  for (i = 0, j = numToRemove; argv[j]; i++, j++) {
67    argv[i] = argv[j];
68  }
69  argv[i] = NULL;
70  *argcp -= numToRemove;
71}
72
73/***********************************************************
74 *	FUNCTION:	bAppThread
75 *
76 *	DESCRIPTION:  starts the BApplication message loop running
77 ***********************************************************/
78static int32 bAppThread(void *arg) {
79	be_app->Lock();
80	return be_app->Run();
81}
82
83/***********************************************************
84 *	FUNCTION:	sigHandler
85 *
86 *	DESCRIPTION:  shuts down the app on CTRL-C
87 ***********************************************************/
88static void sigHandler(int) {
89  gState.quitAll = true;
90  gBlock.NewEvent();
91}
92
93/***********************************************************
94 *	FUNCTION:	glutInit (2.1)
95 *
96 *	DESCRIPTION:  create BApplication, parse cmd-line arguments,
97 *		and set up gState structure.
98 ***********************************************************/
99void glutInit(int *argcp, char **argv) {
100  char *str, *geometry = NULL;
101  int i;
102
103  if (gState.display) {
104    __glutWarning("glutInit being called a second time.");
105    return;
106  }
107  /* Determine temporary program name. */
108  str = strrchr(argv[0], '/');
109  if (str == NULL) {
110    __glutProgramName = argv[0];
111  } else {
112    __glutProgramName = str + 1;
113  }
114
115  /* Make private copy of command line arguments. */
116  __glutArgc = *argcp;
117  __glutArgv = (char **) malloc(__glutArgc * sizeof(char *));
118  if (!__glutArgv)
119    __glutFatalError("out of memory.");
120  for (i = 0; i < __glutArgc; i++) {
121    __glutArgv[i] = strdup(argv[i]);
122    if (!__glutArgv[i])
123      __glutFatalError("out of memory.");
124  }
125
126  /* determine permanent program name */
127  str = strrchr(__glutArgv[0], '/');
128  if (str == NULL) {
129    __glutProgramName = __glutArgv[0];
130  } else {
131    __glutProgramName = str + 1;
132  }
133
134  /* parse arguments for standard options */
135  for (i = 1; i < __glutArgc; i++) {
136    if (!strcmp(__glutArgv[i], "-display")) {
137      __glutWarning("-display option only valid for X glut.");
138      if (++i >= __glutArgc) {
139        __glutFatalError(
140          "follow -display option with X display name.");
141      }
142      removeArgs(argcp, &argv[1], 2);
143    } else if (!strcmp(__glutArgv[i], "-geometry")) {
144      if (++i >= __glutArgc) {
145        __glutFatalError(
146          "follow -geometry option with geometry parameter.");
147      }
148      geometry = __glutArgv[i];
149      removeArgs(argcp, &argv[1], 2);
150    } else if (!strcmp(__glutArgv[i], "-direct")) {
151      __glutWarning("-direct option only valid for X glut.");
152      removeArgs(argcp, &argv[1], 1);
153    } else if (!strcmp(__glutArgv[i], "-indirect")) {
154      __glutWarning("-indirect option only valid for X glut.");
155      removeArgs(argcp, &argv[1], 1);
156    } else if (!strcmp(__glutArgv[i], "-iconic")) {
157      __glutWarning("-iconic option doesn't make sense in BeOS.");
158      removeArgs(argcp, &argv[1], 1);
159    } else if (!strcmp(__glutArgv[i], "-gldebug")) {
160      gState.debug = true;
161      removeArgs(argcp, &argv[1], 1);
162    } else if (!strcmp(__glutArgv[i], "-sync")) {
163      __glutWarning("-sync option only valid for X glut.");
164      removeArgs(argcp, &argv[1], 1);
165    } else {
166      /* Once unknown option encountered, stop command line
167         processing. */
168      break;
169    }
170  }
171
172  __glutInit();  /* Create BApplication first so DisplayWidth() works */
173  if (geometry) {
174    int flags, x, y, width, height;
175
176    /* Fix bogus "{width|height} may be used before set"
177       warning */
178    width = 0;
179    height = 0;
180
181    flags = XParseGeometry(geometry, &x, &y,
182      (unsigned int *) &width, (unsigned int *) &height);
183    if (WidthValue & flags) {
184      /* Careful because X does not allow zero or negative
185         width windows */
186      if (width > 0)
187        gState.initWidth = width;
188    }
189    if (HeightValue & flags) {
190      /* Careful because X does not allow zero or negative
191         height windows */
192      if (height > 0)
193        gState.initHeight = height;
194    }
195    if (XValue & flags) {
196      if (XNegative & flags)
197        x = DisplayWidth() + x - gState.initWidth;
198      /* Play safe: reject negative X locations */
199      if (x >= 0)
200        gState.initX = x;
201    }
202    if (YValue & flags) {
203      if (YNegative & flags)
204        y = DisplayHeight() + y - gState.initHeight;
205      /* Play safe: reject negative Y locations */
206      if (y >= 0)
207        gState.initY = y;
208    }
209  }
210}
211
212/***********************************************************
213 *	FUNCTION:	__glutInit
214 *
215 *	DESCRIPTION:  create BApplication, parse cmd-line arguments,
216 *		and set up gState structure.
217 ***********************************************************/
218void __glutInit() {
219  // open BApplication
220  gState.display = new BApplication("application/x-glut-demo");
221  be_app->Unlock();
222  gState.appthread = spawn_thread(bAppThread, "BApplication", B_NORMAL_PRIORITY, 0);
223  resume_thread(gState.appthread);
224
225  bigtime_t unused;
226  __glutInitTime(&unused);
227
228  /* set atexit() function to cleanup before exiting */
229  if(atexit(__glutExitCleanup))
230  	__glutFatalError("can't set exit handler");
231
232  /* similarly, destroy all windows on CTRL-C */
233  signal(SIGINT, sigHandler);
234}
235
236
237void
238__glutExitCleanup()
239{
240	if (glutGameModeGet(GLUT_GAME_MODE_ACTIVE) > 0)
241		// Try to restore initial screen mode...
242		glutLeaveGameMode();
243
244	__glutDestroyAllWindows();
245}
246
247/***********************************************************
248 *	FUNCTION:	glutInitWindowPosition (2.2)
249 *
250 *	DESCRIPTION:  set initial window position
251 ***********************************************************/
252void glutInitWindowPosition(int x, int y) {
253	gState.initX = x;
254	gState.initY = y;
255}
256
257/***********************************************************
258 *	FUNCTION:	glutInitWindowSize (2.2)
259 *
260 *	DESCRIPTION:  set initial window size
261 ***********************************************************/
262void glutInitWindowSize(int width, int height) {
263	gState.initWidth = width;
264	gState.initHeight = height;
265}
266
267/***********************************************************
268 *	FUNCTION:	glutInitDisplayMode (2.3)
269 *
270 *	DESCRIPTION:  set initial display mode
271 ***********************************************************/
272void glutInitDisplayMode(unsigned int mode) {
273	gState.displayMode = mode;
274}
275