]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/gropengl.cpp
rendering functions mostly done; more complete shader setup
[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_GL_DeleteContext(GL_context);
268         GL_context = NULL;
269
270         SDL_DestroyWindow(GL_window);
271         GL_window = NULL;
272
273         OGL_inited = false;
274 }
275
276 void gr_opengl_init()
277 {
278         if ( OGL_inited )       {
279                 gr_opengl_cleanup();
280         }
281
282         mprintf(( "Initializing OpenGL graphics device...\n" ));
283
284         OGL_inited = true;
285
286         if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
287                 Error(LOCATION, "Couldn't init SDL: %s", SDL_GetError());
288         }
289
290         GL_window = SDL_CreateWindow(os_get_title(), SDL_WINDOWPOS_CENTERED,
291                                                 SDL_WINDOWPOS_CENTERED,
292                                                 gr_screen.max_w, gr_screen.max_h, SDL_WINDOW_OPENGL);
293
294         if ( !GL_window ) {
295                 Error(LOCATION, "Couldn't create window: %s\n", SDL_GetError());
296         }
297
298         os_set_window(GL_window);
299
300         int a = 1, r = 5, g = 5, b = 5, bpp = 16;
301         int FSAA = os_config_read_uint("Video", "AntiAlias", 0);
302
303         SDL_GL_SetAttribute(SDL_GL_RED_SIZE, r);
304         SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, g);
305         SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, b);
306         SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, a);
307         SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, bpp);
308
309         if (FSAA) {
310                 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
311                 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, FSAA);
312         }
313
314         int rc = 1;
315
316         // try GL 2 first, then fall back to GL 1
317         if ( !opengl2_init() ) {
318                 rc = opengl1_init();
319         }
320
321         if ( !rc ) {
322                 Error(LOCATION, "Unable to initialize OpenGL renderer!\n");
323         }
324
325         mprintf(("  Attributes requested : ARGB %d%d%d%d, BPP %d, AA %d\n",
326                          a, r, g, b, bpp, FSAA));
327
328         SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &r);
329         SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &g);
330         SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &b);
331         SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &a);
332         SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &bpp);
333         SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &FSAA);
334
335         mprintf(("  Attributes received  : ARGB %d%d%d%d, BPP %d, AA %d\n",
336                          a, r, g, b, bpp, FSAA));
337         mprintf(("\n"));
338
339         SDL_DisableScreenSaver();
340         SDL_ShowCursor(0);
341
342         // maybe go fullscreen - should be done *after* main GL init
343         int fullscreen = os_config_read_uint("Video", "Fullscreen", 1);
344         if ( !Cmdline_window && (fullscreen || Cmdline_fullscreen) ) {
345                 SDL_SetWindowFullscreen(GL_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
346                 // poll for window events
347                 os_poll();
348         }
349
350         switch (bpp) {
351                 case 15:
352                 case 16:
353                         gr_screen.bits_per_pixel = 16;
354                         gr_screen.bytes_per_pixel = 2;
355
356                         // screen values
357                         Gr_red.bits = 5;
358                         Gr_red.shift = 11;
359                         Gr_red.scale = 8;
360                         Gr_red.mask = 0x7C01;
361
362                         Gr_green.bits = 5;
363                         Gr_green.shift = 6;
364                         Gr_green.scale = 8;
365                         Gr_green.mask = 0x3E1;
366
367                         Gr_blue.bits = 5;
368                         Gr_blue.shift = 1;
369                         Gr_blue.scale = 8;
370                         Gr_blue.mask = 0x20;
371
372                         Gr_alpha.bits = 1;
373                         Gr_alpha.shift = 0;
374                         Gr_alpha.scale = 255;
375                         Gr_alpha.mask = 0x1;
376
377                         break;
378
379                 case 24:
380                 case 32:
381                         gr_screen.bits_per_pixel = 32;
382                         gr_screen.bytes_per_pixel = 4;
383
384                         // screen values
385                         Gr_red.bits = 8;
386                         Gr_red.shift = 0;
387                         Gr_red.scale = 1;
388                         Gr_red.mask = 0xff;
389
390                         Gr_green.bits = 8;
391                         Gr_green.shift = 8;
392                         Gr_green.scale = 1;
393                         Gr_green.mask = 0xff00;
394
395                         Gr_blue.bits = 8;
396                         Gr_blue.shift = 16;
397                         Gr_blue.scale = 1;
398                         Gr_blue.mask = 0xff0000;
399
400                         Gr_alpha.bits = 8;
401                         Gr_alpha.shift = 24;
402                         Gr_alpha.scale = 1;
403                         Gr_alpha.mask = 0xff000000;
404
405                         break;
406
407                 default:
408                         Int3(); // Illegal bpp
409                         break;
410         }
411
412         // DDOI - set these so no one else does!
413         // texture values, always 5551 - 16-bit
414         Gr_t_red.mask = 0x7C01;
415         Gr_t_red.shift = 11;
416         Gr_t_red.scale = 8;
417
418         Gr_t_green.mask = 0x3E1;
419         Gr_t_green.shift = 6;
420         Gr_t_green.scale = 8;
421
422         Gr_t_blue.mask = 0x20;
423         Gr_t_blue.shift = 1;
424         Gr_t_blue.scale = 8;
425
426         Gr_t_alpha.mask = 0x1;
427         Gr_t_alpha.shift = 0;
428         Gr_t_alpha.scale = 255;
429
430         // alpha-texture values
431         Gr_ta_red.mask = 0x0f00;
432         Gr_ta_red.shift = 8;
433         Gr_ta_red.scale = 16;
434
435         Gr_ta_green.mask = 0x00f0;
436         Gr_ta_green.shift = 4;
437         Gr_ta_green.scale = 16;
438
439         Gr_ta_blue.mask = 0x000f;
440         Gr_ta_blue.shift = 0;
441         Gr_ta_blue.scale = 16;
442
443         Gr_ta_alpha.mask = 0xf000;
444         Gr_ta_alpha.shift = 12;
445         Gr_ta_alpha.scale = 16;
446
447         // default to screen
448         Gr_current_red = &Gr_red;
449         Gr_current_blue = &Gr_blue;
450         Gr_current_green = &Gr_green;
451         Gr_current_alpha = &Gr_alpha;
452
453
454         Mouse_hidden++;
455         gr_reset_clip();
456         gr_clear();
457         gr_flip();
458         gr_clear();
459         Mouse_hidden--;
460 }