]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/gropengl.cpp
add gr_stream_*() for movie playback
[taylor/freespace2.git] / src / graphics / gropengl.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 #include "SDL_opengl.h"
10
11 #include "pstypes.h"
12 #include "osregistry.h"
13 #include "gropengl.h"
14 #include "gropenglinternal.h"
15 #include "grgl1.h"
16 #include "grgl2.h"
17 #include "2d.h"
18 #include "bmpman.h"
19 #include "grinternal.h"
20 #include "cmdline.h"
21 #include "mouse.h"
22 #include "osapi.h"
23 #include "cfile.h"
24
25
26 bool OGL_inited = false;
27 int GL_version = 0;
28
29 SDL_Window *GL_window = NULL;
30 SDL_GLContext GL_context;
31
32 volatile int GL_activate = 0;
33 volatile int GL_deactivate = 0;
34
35 int GL_viewport_x = 0;
36 int GL_viewport_y = 0;
37 int GL_viewport_w = 640;
38 int GL_viewport_h = 480;
39 float GL_viewport_scale_w = 1.0f;
40 float GL_viewport_scale_h = 1.0f;
41 int GL_min_texture_width = 0;
42 int GL_max_texture_width = 0;
43 int GL_min_texture_height = 0;
44 int GL_max_texture_height = 0;
45
46 rb_t *render_buffer = NULL;
47 static size_t render_buffer_size = 0;
48
49
50 void opengl_alloc_render_buffer(unsigned int nelems)
51 {
52         if (nelems < 1) {
53                 nelems = 1;
54         }
55
56         if ( render_buffer && (nelems <= render_buffer_size) ) {
57                 return;
58         }
59
60         if (render_buffer) {
61                 free(render_buffer);
62         }
63
64         render_buffer = (rb_t*) malloc(sizeof(rb_t) * nelems);
65         render_buffer_size = nelems;
66 }
67
68 void opengl_free_render_buffer()
69 {
70         if (render_buffer) {
71                 free(render_buffer);
72                 render_buffer = NULL;
73                 render_buffer_size = 0;
74         }
75 }
76
77 void opengl_set_variables()
78 {
79         GL_min_texture_height = 16;
80         GL_min_texture_width = 16;
81
82         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GL_max_texture_width);
83         GL_max_texture_height = GL_max_texture_width;
84
85         // no texture is larger than 1024, so maybe don't use sections
86         if (GL_max_texture_width >= 1024) {
87                 gr_screen.use_sections = 0;
88         }
89 }
90
91 void opengl_init_viewport()
92 {
93         GL_viewport_x = 0;
94         GL_viewport_y = 0;
95         GL_viewport_w = gr_screen.max_w;
96         GL_viewport_h = gr_screen.max_h;
97         GL_viewport_scale_w = 1.0f;
98         GL_viewport_scale_h = 1.0f;
99
100         glViewport(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h);
101 }
102
103 void opengl_stuff_fog_value(float z, float *f_val)
104 {
105         float f_float;
106
107         if ( !f_val ) {
108                 return;
109         }
110
111         f_float = 1.0f - ((gr_screen.fog_far - z) / (gr_screen.fog_far - gr_screen.fog_near));
112
113         if (f_float < 0.0f) {
114                 f_float = 0.0f;
115         } else if (f_float > 1.0f) {
116                 f_float = 1.0f;
117         }
118
119         *f_val = f_float;
120 }
121
122 void gr_opengl_force_windowed()
123 {
124         SDL_SetWindowFullscreen(GL_window, 0);
125 }
126
127 void gr_opengl_force_fullscreen()
128 {
129         SDL_SetWindowFullscreen(GL_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
130 }
131
132 void gr_opengl_toggle_fullscreen()
133 {
134         Uint32 flags = SDL_GetWindowFlags(GL_window);
135
136         if ( (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP ) {
137                 gr_opengl_force_windowed();
138         } else {
139                 gr_opengl_force_fullscreen();
140         }
141 }
142
143 void gr_opengl_clear()
144 {
145         glClearColor(gr_screen.current_clear_color.red / 255.0f,
146                 gr_screen.current_clear_color.green / 255.0f,
147                 gr_screen.current_clear_color.blue / 255.0f, 1.0f);
148
149         glClear( GL_COLOR_BUFFER_BIT );
150 }
151
152 void gr_opengl_reset_clip()
153 {
154         gr_screen.offset_x = 0;
155         gr_screen.offset_y = 0;
156         gr_screen.clip_left = 0;
157         gr_screen.clip_top = 0;
158         gr_screen.clip_right = gr_screen.max_w - 1;
159         gr_screen.clip_bottom = gr_screen.max_h - 1;
160         gr_screen.clip_width = gr_screen.max_w;
161         gr_screen.clip_height = gr_screen.max_h;
162
163         glDisable(GL_SCISSOR_TEST);
164 }
165
166 void gr_opengl_print_screen(const char *filename)
167 {
168         char tmp[MAX_FILENAME_LEN];
169         ubyte *buf = NULL;
170
171         SDL_strlcpy( tmp, filename, SDL_arraysize(tmp) );
172         SDL_strlcat( tmp, NOX(".tga"), SDL_arraysize(tmp) );
173
174         buf = (ubyte*)malloc(GL_viewport_w * GL_viewport_h * 3);
175
176         if (buf == NULL) {
177                 return;
178         }
179
180         CFILE *f = cfopen(tmp, "wb", CFILE_NORMAL, CF_TYPE_ROOT);
181
182         if (f == NULL) {
183                 free(buf);
184                 return;
185         }
186
187         // Write the TGA header
188         cfwrite_ubyte( 0, f );  //      IDLength;
189         cfwrite_ubyte( 0, f );  //      ColorMapType;
190         cfwrite_ubyte( 2, f );  //      ImageType;              // 2 = 24bpp, uncompressed, 10=24bpp rle compressed
191         cfwrite_ushort( 0, f ); // CMapStart;
192         cfwrite_ushort( 0, f ); //      CMapLength;
193         cfwrite_ubyte( 0, f );  // CMapDepth;
194         cfwrite_ushort( 0, f ); //      XOffset;
195         cfwrite_ushort( 0, f ); //      YOffset;
196         cfwrite_ushort( (ushort)GL_viewport_w, f );     //      Width;
197         cfwrite_ushort( (ushort)GL_viewport_h, f );     //      Height;
198         cfwrite_ubyte( 24, f ); //PixelDepth;
199         cfwrite_ubyte( 0, f );  //ImageDesc;
200
201         memset(buf, 0, GL_viewport_w * GL_viewport_h * 3);
202
203         glReadPixels(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h, GL_RGB, GL_UNSIGNED_BYTE, buf);
204
205         cfwrite(buf, GL_viewport_w * GL_viewport_h * 3, 1, f);
206
207         cfclose(f);
208
209         free(buf);
210 }
211
212 uint gr_opengl_lock()
213 {
214         return 1;
215 }
216
217 void gr_opengl_unlock()
218 {
219 }
220
221 void gr_opengl_zbias(int bias)
222 {
223         if (bias) {
224                 glEnable(GL_POLYGON_OFFSET_FILL);
225                 glPolygonOffset(0.0f, GLfloat(-bias));
226         } else {
227                 glDisable(GL_POLYGON_OFFSET_FILL);
228         }
229 }
230
231 void gr_opengl_set_cull(int cull)
232 {
233         if (cull) {
234                 glEnable (GL_CULL_FACE);
235                 glFrontFace (GL_CCW);
236         } else {
237                 glDisable (GL_CULL_FACE);
238         }
239 }
240
241 void gr_opengl_activate(int active)
242 {
243         if (active) {
244                 GL_activate++;
245
246                 // don't grab key/mouse if cmdline says so or if we're fullscreen
247         //      if(!Cmdline_no_grab && !(SDL_GetVideoSurface()->flags & SDL_FULLSCREEN)) {
248         //              SDL_WM_GrabInput(SDL_GRAB_ON);
249         //      }
250         } else {
251                 GL_deactivate++;
252
253                 // let go of mouse/keyboard
254         //      SDL_WM_GrabInput(SDL_GRAB_OFF);
255         }
256 }
257
258 void gr_opengl_cleanup()
259 {
260         opengl1_cleanup();
261         opengl2_cleanup();
262
263         opengl_free_render_buffer();
264
265         os_set_window(NULL);
266
267         SDL_DestroyWindow(GL_window);
268         GL_window = NULL;
269
270         OGL_inited = false;
271 }
272
273 void gr_opengl_init()
274 {
275         if ( OGL_inited )       {
276                 gr_opengl_cleanup();
277         }
278
279         mprintf(( "Initializing OpenGL graphics device...\n" ));
280
281         OGL_inited = true;
282
283         if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
284                 Error(LOCATION, "Couldn't init SDL: %s", SDL_GetError());
285         }
286
287         GL_window = SDL_CreateWindow(os_get_title(), SDL_WINDOWPOS_CENTERED,
288                                                 SDL_WINDOWPOS_CENTERED,
289                                                 gr_screen.max_w, gr_screen.max_h, SDL_WINDOW_OPENGL);
290
291         if ( !GL_window ) {
292                 Error(LOCATION, "Couldn't create window: %s\n", SDL_GetError());
293         }
294
295         os_set_window(GL_window);
296
297         int a = 1, r = 5, g = 5, b = 5, bpp = 16;
298         int FSAA = os_config_read_uint("Video", "AntiAlias", 0);
299
300         SDL_GL_SetAttribute(SDL_GL_RED_SIZE, r);
301         SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, g);
302         SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, b);
303         SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, a);
304         SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, bpp);
305
306         if (FSAA) {
307                 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
308                 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, FSAA);
309         }
310
311         int rc = 1;
312
313         // try GL 2 first, then fall back to GL 1
314         if ( !opengl2_init() ) {
315                 rc = opengl1_init();
316         }
317
318         if ( !rc ) {
319                 Error(LOCATION, "Unable to initialize OpenGL renderer!\n");
320         }
321
322         mprintf(("  Attributes requested : ARGB %d%d%d%d, BPP %d, AA %d\n",
323                          a, r, g, b, bpp, FSAA));
324
325         SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &r);
326         SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &g);
327         SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &b);
328         SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &a);
329         SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &bpp);
330         SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &FSAA);
331
332         mprintf(("  Attributes received  : ARGB %d%d%d%d, BPP %d, AA %d\n",
333                          a, r, g, b, bpp, FSAA));
334         mprintf(("\n"));
335
336         SDL_DisableScreenSaver();
337         SDL_ShowCursor(0);
338
339         // maybe go fullscreen - should be done *after* main GL init
340         int fullscreen = os_config_read_uint("Video", "Fullscreen", 1);
341         if ( !Cmdline_window && (fullscreen || Cmdline_fullscreen) ) {
342                 SDL_SetWindowFullscreen(GL_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
343                 // poll for window events
344                 os_poll();
345         }
346
347         switch (bpp) {
348                 case 15:
349                 case 16:
350                         gr_screen.bits_per_pixel = 16;
351                         gr_screen.bytes_per_pixel = 2;
352
353                         // screen values
354                         Gr_red.bits = 5;
355                         Gr_red.shift = 11;
356                         Gr_red.scale = 8;
357                         Gr_red.mask = 0x7C01;
358
359                         Gr_green.bits = 5;
360                         Gr_green.shift = 6;
361                         Gr_green.scale = 8;
362                         Gr_green.mask = 0x3E1;
363
364                         Gr_blue.bits = 5;
365                         Gr_blue.shift = 1;
366                         Gr_blue.scale = 8;
367                         Gr_blue.mask = 0x20;
368
369                         Gr_alpha.bits = 1;
370                         Gr_alpha.shift = 0;
371                         Gr_alpha.scale = 255;
372                         Gr_alpha.mask = 0x1;
373
374                         break;
375
376                 case 24:
377                 case 32:
378                         gr_screen.bits_per_pixel = 32;
379                         gr_screen.bytes_per_pixel = 4;
380
381                         // screen values
382                         Gr_red.bits = 8;
383                         Gr_red.shift = 0;
384                         Gr_red.scale = 1;
385                         Gr_red.mask = 0xff;
386
387                         Gr_green.bits = 8;
388                         Gr_green.shift = 8;
389                         Gr_green.scale = 1;
390                         Gr_green.mask = 0xff00;
391
392                         Gr_blue.bits = 8;
393                         Gr_blue.shift = 16;
394                         Gr_blue.scale = 1;
395                         Gr_blue.mask = 0xff0000;
396
397                         Gr_alpha.bits = 8;
398                         Gr_alpha.shift = 24;
399                         Gr_alpha.scale = 1;
400                         Gr_alpha.mask = 0xff000000;
401
402                         break;
403
404                 default:
405                         Int3(); // Illegal bpp
406                         break;
407         }
408
409         // DDOI - set these so no one else does!
410         // texture values, always 5551 - 16-bit
411         Gr_t_red.mask = 0x7C01;
412         Gr_t_red.shift = 11;
413         Gr_t_red.scale = 8;
414
415         Gr_t_green.mask = 0x3E1;
416         Gr_t_green.shift = 6;
417         Gr_t_green.scale = 8;
418
419         Gr_t_blue.mask = 0x20;
420         Gr_t_blue.shift = 1;
421         Gr_t_blue.scale = 8;
422
423         Gr_t_alpha.mask = 0x1;
424         Gr_t_alpha.shift = 0;
425         Gr_t_alpha.scale = 255;
426
427         // alpha-texture values
428         Gr_ta_red.mask = 0x0f00;
429         Gr_ta_red.shift = 8;
430         Gr_ta_red.scale = 16;
431
432         Gr_ta_green.mask = 0x00f0;
433         Gr_ta_green.shift = 4;
434         Gr_ta_green.scale = 16;
435
436         Gr_ta_blue.mask = 0x000f;
437         Gr_ta_blue.shift = 0;
438         Gr_ta_blue.scale = 16;
439
440         Gr_ta_alpha.mask = 0xf000;
441         Gr_ta_alpha.shift = 12;
442         Gr_ta_alpha.scale = 16;
443
444         // default to screen
445         Gr_current_red = &Gr_red;
446         Gr_current_blue = &Gr_blue;
447         Gr_current_green = &Gr_green;
448         Gr_current_alpha = &Gr_alpha;
449
450
451         Mouse_hidden++;
452         gr_reset_clip();
453         gr_clear();
454         gr_flip();
455         gr_clear();
456         Mouse_hidden--;
457 }