2 * Copyright (C) 2003 Robert Kooima
4 * NEVERBALL is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
21 /*---------------------------------------------------------------------------*/
23 int video_init(const char *title, const char *icon)
25 SDL_QuitSubSystem(SDL_INIT_VIDEO);
27 if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1)
29 fprintf(stderr, "%s\n", SDL_GetError());
33 /* This has to happen before mode setting... */
37 /* Initialize the video. */
39 if (!video_mode(config_get_d(CONFIG_FULLSCREEN),
40 config_get_d(CONFIG_WIDTH),
41 config_get_d(CONFIG_HEIGHT)))
43 fprintf(stderr, "%s\n", SDL_GetError());
47 /* ...and this has to happen after it. */
51 SDL_WM_SetCaption(title, title);
56 /*---------------------------------------------------------------------------*/
58 int check_extension(const char *needle)
60 const GLubyte *haystack, *c;
62 /* Search for the given string in the OpenGL extension strings. */
64 for (haystack = glGetString(GL_EXTENSIONS); *haystack; haystack++)
66 for (c = (const GLubyte *) needle; *c && *haystack; c++, haystack++)
70 if ((*c == 0) && (*haystack == ' ' || *haystack == '\0'))
77 int video_mode(int f, int w, int h)
79 int stereo = config_get_d(CONFIG_STEREO) ? 1 : 0;
80 int stencil = config_get_d(CONFIG_REFLECTION) ? 1 : 0;
81 int buffers = config_get_d(CONFIG_MULTISAMPLE) ? 1 : 0;
82 int samples = config_get_d(CONFIG_MULTISAMPLE);
83 int vsync = config_get_d(CONFIG_VSYNC) ? 1 : 0;
85 SDL_GL_SetAttribute(SDL_GL_STEREO, stereo);
86 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, stencil);
87 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, buffers);
88 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, samples);
89 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, vsync);
91 /* Require 16-bit double buffer with 16-bit depth buffer. */
93 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
94 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
95 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
96 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
97 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
99 /* Try to set the currently specified mode. */
101 if (SDL_SetVideoMode(w, h, 0, SDL_OPENGL | (f ? SDL_FULLSCREEN : 0)))
103 config_set_d(CONFIG_FULLSCREEN, f);
104 config_set_d(CONFIG_WIDTH, w);
105 config_set_d(CONFIG_HEIGHT, h);
107 glViewport(0, 0, w, h);
108 glClearColor(0.0f, 0.0f, 0.1f, 0.0f);
110 glEnable(GL_NORMALIZE);
111 glEnable(GL_CULL_FACE);
112 glEnable(GL_DEPTH_TEST);
113 glEnable(GL_TEXTURE_2D);
114 glEnable(GL_LIGHTING);
117 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,
118 GL_SEPARATE_SPECULAR_COLOR);
119 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
121 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
122 glDepthFunc(GL_LEQUAL);
125 * Mac OS X might still need this, because apparently SDL doesn't do
126 * SDL_GL_SWAP_CONTROL on OS X. TODO: investigate.
129 if (vsync) sync_init();
132 /* If GL supports multisample, and SDL got a multisample buffer... */
134 #ifdef GL_ARB_multisample
135 if (check_extension("ARB_multisample"))
137 SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &buffers);
139 glEnable(GL_MULTISAMPLE_ARB);
143 glReadBuffer(GL_FRONT);
148 /* If the mode failed, try it without stereo. */
152 config_set_d(CONFIG_STEREO, 0);
153 return video_mode(f, w, h);
156 /* If the mode failed, try decreasing the level of multisampling. */
160 config_set_d(CONFIG_MULTISAMPLE, samples / 2);
161 return video_mode(f, w, h);
164 /* If that mode failed, try it without reflections. */
168 config_set_d(CONFIG_REFLECTION, 0);
169 return video_mode(f, w, h);
172 /* If THAT mode failed, punt. */
177 /*---------------------------------------------------------------------------*/
182 static int ticks = 0;
183 static int frames = 0;
190 void video_swap(void)
194 SDL_GL_SwapBuffers();
196 /* Accumulate time passed and frames rendered. */
198 dt = (int) SDL_GetTicks() - last;
204 /* Average over 250ms. */
208 /* Round the frames-per-second value to the nearest integer. */
210 double k = 1000.0 * frames / ticks;
214 /* Compute frame time and frames-per-second stats. */
216 fps = (int) ((c - k < k - f) ? c : f);
217 ms = (float) ticks / (float) frames;
219 /* Reset the counters for the next update. */
224 /* Output statistics if configured. */
226 if (config_get_d(CONFIG_STATS))
227 fprintf(stdout, "%4d %8.4f\n", fps, ms);
231 /*---------------------------------------------------------------------------*/
233 static int grabbed = 0;
235 void video_set_grab(int w)
239 SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
241 SDL_WarpMouse(config_get_d(CONFIG_WIDTH) / 2,
242 config_get_d(CONFIG_HEIGHT) / 2);
244 SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
247 SDL_WM_GrabInput(SDL_GRAB_ON);
248 SDL_ShowCursor(SDL_DISABLE);
253 void video_clr_grab(void)
255 SDL_WM_GrabInput(SDL_GRAB_OFF);
256 SDL_ShowCursor(SDL_ENABLE);
260 int video_get_grab(void)
265 /*---------------------------------------------------------------------------*/
267 void video_push_persp(float fov, float n, float f)
271 GLdouble r = fov / 2 * V_PI / 180;
273 GLdouble c = cos(r) / s;
275 GLdouble a = ((GLdouble) config_get_d(CONFIG_WIDTH) /
276 (GLdouble) config_get_d(CONFIG_HEIGHT));
278 glMatrixMode(GL_PROJECTION);
293 m[2][2] = -(f + n) / (f - n);
297 m[3][2] = -2.0 * n * f / (f - n);
300 glMultMatrixd(&m[0][0]);
302 glMatrixMode(GL_MODELVIEW);
305 void video_push_ortho(void)
307 GLdouble w = (GLdouble) config_get_d(CONFIG_WIDTH);
308 GLdouble h = (GLdouble) config_get_d(CONFIG_HEIGHT);
310 glMatrixMode(GL_PROJECTION);
314 glOrtho(0.0, w, 0.0, h, -1.0, +1.0);
316 glMatrixMode(GL_MODELVIEW);
319 void video_pop_matrix(void)
321 glMatrixMode(GL_PROJECTION);
325 glMatrixMode(GL_MODELVIEW);
328 void video_clear(void)
330 if (config_get_d(CONFIG_REFLECTION))
331 glClear(GL_COLOR_BUFFER_BIT |
332 GL_DEPTH_BUFFER_BIT |
333 GL_STENCIL_BUFFER_BIT);
335 glClear(GL_COLOR_BUFFER_BIT |
336 GL_DEPTH_BUFFER_BIT);
339 /*---------------------------------------------------------------------------*/