]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/gropengl.cpp
first pass at OpenGL ES 2 support
[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 gr_opengl_force_windowed()
104 {
105         SDL_SetWindowFullscreen(GL_window, 0);
106 }
107
108 void gr_opengl_force_fullscreen()
109 {
110         SDL_SetWindowFullscreen(GL_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
111 }
112
113 void gr_opengl_toggle_fullscreen()
114 {
115         Uint32 flags = SDL_GetWindowFlags(GL_window);
116
117         if ( (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP ) {
118                 gr_opengl_force_windowed();
119         } else {
120                 gr_opengl_force_fullscreen();
121         }
122 }
123
124 void gr_opengl_clear()
125 {
126         glClearColor(gr_screen.current_clear_color.red / 255.0f,
127                 gr_screen.current_clear_color.green / 255.0f,
128                 gr_screen.current_clear_color.blue / 255.0f, 1.0f);
129
130         glClear( GL_COLOR_BUFFER_BIT );
131 }
132
133 void gr_opengl_reset_clip()
134 {
135         gr_screen.offset_x = 0;
136         gr_screen.offset_y = 0;
137         gr_screen.clip_left = 0;
138         gr_screen.clip_top = 0;
139         gr_screen.clip_right = gr_screen.max_w - 1;
140         gr_screen.clip_bottom = gr_screen.max_h - 1;
141         gr_screen.clip_width = gr_screen.max_w;
142         gr_screen.clip_height = gr_screen.max_h;
143
144         glDisable(GL_SCISSOR_TEST);
145 }
146
147 void gr_opengl_print_screen(const char *filename)
148 {
149         char tmp[MAX_FILENAME_LEN];
150         ubyte *buf = NULL;
151
152         SDL_strlcpy( tmp, filename, SDL_arraysize(tmp) );
153         SDL_strlcat( tmp, NOX(".tga"), SDL_arraysize(tmp) );
154
155         buf = (ubyte*)malloc(GL_viewport_w * GL_viewport_h * 3);
156
157         if (buf == NULL) {
158                 return;
159         }
160
161         CFILE *f = cfopen(tmp, "wb", CFILE_NORMAL, CF_TYPE_ROOT);
162
163         if (f == NULL) {
164                 free(buf);
165                 return;
166         }
167
168         // Write the TGA header
169         cfwrite_ubyte( 0, f );  //      IDLength;
170         cfwrite_ubyte( 0, f );  //      ColorMapType;
171         cfwrite_ubyte( 2, f );  //      ImageType;              // 2 = 24bpp, uncompressed, 10=24bpp rle compressed
172         cfwrite_ushort( 0, f ); // CMapStart;
173         cfwrite_ushort( 0, f ); //      CMapLength;
174         cfwrite_ubyte( 0, f );  // CMapDepth;
175         cfwrite_ushort( 0, f ); //      XOffset;
176         cfwrite_ushort( 0, f ); //      YOffset;
177         cfwrite_ushort( (ushort)GL_viewport_w, f );     //      Width;
178         cfwrite_ushort( (ushort)GL_viewport_h, f );     //      Height;
179         cfwrite_ubyte( 24, f ); //PixelDepth;
180         cfwrite_ubyte( 0, f );  //ImageDesc;
181
182         memset(buf, 0, GL_viewport_w * GL_viewport_h * 3);
183
184         glReadPixels(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h, GL_RGB, GL_UNSIGNED_BYTE, buf);
185
186         cfwrite(buf, GL_viewport_w * GL_viewport_h * 3, 1, f);
187
188         cfclose(f);
189
190         free(buf);
191 }
192
193 uint gr_opengl_lock()
194 {
195         return 1;
196 }
197
198 void gr_opengl_unlock()
199 {
200 }
201
202 void gr_opengl_zbias(int bias)
203 {
204         if (bias) {
205                 glEnable(GL_POLYGON_OFFSET_FILL);
206                 glPolygonOffset(0.0f, GLfloat(-bias));
207         } else {
208                 glDisable(GL_POLYGON_OFFSET_FILL);
209         }
210 }
211
212 void gr_opengl_set_cull(int cull)
213 {
214         if (cull) {
215                 glEnable (GL_CULL_FACE);
216                 glFrontFace (GL_CCW);
217         } else {
218                 glDisable (GL_CULL_FACE);
219         }
220 }
221
222 void gr_opengl_activate(int active)
223 {
224         if (active) {
225                 GL_activate++;
226
227                 // don't grab key/mouse if cmdline says so or if we're fullscreen
228         //      if(!Cmdline_no_grab && !(SDL_GetVideoSurface()->flags & SDL_FULLSCREEN)) {
229         //              SDL_WM_GrabInput(SDL_GRAB_ON);
230         //      }
231         } else {
232                 GL_deactivate++;
233
234                 // let go of mouse/keyboard
235         //      SDL_WM_GrabInput(SDL_GRAB_OFF);
236         }
237 }
238
239 void gr_opengl_cleanup()
240 {
241         opengl1_cleanup();
242         opengl2_cleanup();
243
244         opengl_free_render_buffer();
245
246         os_set_window(NULL);
247
248         SDL_GL_DeleteContext(GL_context);
249         GL_context = NULL;
250
251         SDL_DestroyWindow(GL_window);
252         GL_window = NULL;
253
254         OGL_inited = false;
255 }
256
257 void gr_opengl_init()
258 {
259         if ( OGL_inited )       {
260                 gr_opengl_cleanup();
261         }
262
263         mprintf(( "Initializing OpenGL graphics device...\n" ));
264
265         OGL_inited = true;
266
267         if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
268                 Error(LOCATION, "Couldn't init SDL: %s", SDL_GetError());
269         }
270
271         GL_window = SDL_CreateWindow(os_get_title(), SDL_WINDOWPOS_CENTERED,
272                                                 SDL_WINDOWPOS_CENTERED,
273                                                 gr_screen.max_w, gr_screen.max_h, SDL_WINDOW_OPENGL);
274
275         if ( !GL_window ) {
276                 Error(LOCATION, "Couldn't create window: %s\n", SDL_GetError());
277         }
278
279         os_set_window(GL_window);
280
281         int a = 1, r = 5, g = 5, b = 5, bpp = 16;
282         int FSAA = os_config_read_uint("Video", "AntiAlias", 0);
283
284         SDL_GL_SetAttribute(SDL_GL_RED_SIZE, r);
285         SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, g);
286         SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, b);
287         SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, a);
288         SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, bpp);
289
290         if (FSAA) {
291                 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
292                 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, FSAA);
293         }
294
295         int rc = 1;
296
297         // try GL 2 first, then fall back to GL 1
298         if ( !opengl2_init() ) {
299                 rc = opengl1_init();
300         }
301
302         if ( !rc ) {
303                 Error(LOCATION, "Unable to initialize OpenGL renderer!\n");
304         }
305
306         mprintf(("  Attributes requested : ARGB %d%d%d%d, BPP %d, AA %d\n",
307                          a, r, g, b, bpp, FSAA));
308
309         SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &r);
310         SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &g);
311         SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &b);
312         SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &a);
313         SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &bpp);
314         SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &FSAA);
315
316         mprintf(("  Attributes received  : ARGB %d%d%d%d, BPP %d, AA %d\n",
317                          a, r, g, b, bpp, FSAA));
318         mprintf(("\n"));
319
320         SDL_DisableScreenSaver();
321         SDL_ShowCursor(0);
322
323         // maybe go fullscreen - should be done *after* main GL init
324         int fullscreen = os_config_read_uint("Video", "Fullscreen", 1);
325         if ( !Cmdline_window && (fullscreen || Cmdline_fullscreen) ) {
326                 SDL_SetWindowFullscreen(GL_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
327                 // poll for window events
328                 os_poll();
329         }
330
331         switch (bpp) {
332                 case 15:
333                 case 16:
334                         gr_screen.bits_per_pixel = 16;
335                         gr_screen.bytes_per_pixel = 2;
336
337                         // screen values
338                         Gr_red.bits = 5;
339                         Gr_red.shift = 11;
340                         Gr_red.scale = 8;
341                         Gr_red.mask = 0x7C01;
342
343                         Gr_green.bits = 5;
344                         Gr_green.shift = 6;
345                         Gr_green.scale = 8;
346                         Gr_green.mask = 0x3E1;
347
348                         Gr_blue.bits = 5;
349                         Gr_blue.shift = 1;
350                         Gr_blue.scale = 8;
351                         Gr_blue.mask = 0x20;
352
353                         Gr_alpha.bits = 1;
354                         Gr_alpha.shift = 0;
355                         Gr_alpha.scale = 255;
356                         Gr_alpha.mask = 0x1;
357
358                         break;
359
360                 case 24:
361                 case 32:
362                         gr_screen.bits_per_pixel = 32;
363                         gr_screen.bytes_per_pixel = 4;
364
365                         // screen values
366                         Gr_red.bits = 8;
367                         Gr_red.shift = 16;
368                         Gr_red.scale = 1;
369                         Gr_red.mask = 0xff0000;
370
371                         Gr_green.bits = 8;
372                         Gr_green.shift = 8;
373                         Gr_green.scale = 1;
374                         Gr_green.mask = 0xff00;
375
376                         Gr_blue.bits = 8;
377                         Gr_blue.shift = 0;
378                         Gr_blue.scale = 1;
379                         Gr_blue.mask = 0xff;
380
381                         Gr_alpha.bits = 8;
382                         Gr_alpha.shift = 24;
383                         Gr_alpha.scale = 1;
384                         Gr_alpha.mask = 0xff000000;
385
386                         break;
387
388                 default:
389                         Int3(); // Illegal bpp
390                         break;
391         }
392
393         // DDOI - set these so no one else does!
394         // texture values, always 5551 - 16-bit
395         Gr_t_red.mask = 0x7C01;
396         Gr_t_red.shift = 11;
397         Gr_t_red.scale = 8;
398
399         Gr_t_green.mask = 0x3E1;
400         Gr_t_green.shift = 6;
401         Gr_t_green.scale = 8;
402
403         Gr_t_blue.mask = 0x20;
404         Gr_t_blue.shift = 1;
405         Gr_t_blue.scale = 8;
406
407         Gr_t_alpha.mask = 0x1;
408         Gr_t_alpha.shift = 0;
409         Gr_t_alpha.scale = 255;
410
411         // alpha-texture values
412         Gr_ta_red.mask = 0x0f00;
413         Gr_ta_red.shift = 8;
414         Gr_ta_red.scale = 16;
415
416         Gr_ta_green.mask = 0x00f0;
417         Gr_ta_green.shift = 4;
418         Gr_ta_green.scale = 16;
419
420         Gr_ta_blue.mask = 0x000f;
421         Gr_ta_blue.shift = 0;
422         Gr_ta_blue.scale = 16;
423
424         Gr_ta_alpha.mask = 0xf000;
425         Gr_ta_alpha.shift = 12;
426         Gr_ta_alpha.scale = 16;
427
428         // default to screen
429         Gr_current_red = &Gr_red;
430         Gr_current_blue = &Gr_blue;
431         Gr_current_green = &Gr_green;
432         Gr_current_alpha = &Gr_alpha;
433
434
435         Mouse_hidden++;
436         gr_reset_clip();
437         gr_clear();
438         gr_flip();
439         gr_clear();
440         Mouse_hidden--;
441 }