1 /*
2
3 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4 and the "Aleph One" developers.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 This license is contained in the file "COPYING",
17 which is included with this source code; it is available online at
18 http://www.gnu.org/licenses/gpl.html
19
20 OpenGL Renderer,
21 by Loren Petrich,
22 March 12, 2000
23
24 This contains implementations of functions intended for finding out OpenGL's presence
25 in the host system, for setting parameters for OpenGL rendering,
26 and for deciding whether to use OpenGL for rendering.
27
28 June 11, 2000
29
30 Had added XML parsing before that; most recently, added "opac_shift".
31
32 Made semitransparency optional if the void is on one side of the texture
33
34 Oct 13, 2000 (Loren Petrich)
35 Converted the OpenGL-addition accounting into Standard Template Library vectors
36
37 Nov 12, 2000 (Loren Petrich):
38 Implemented texture substitution, also moved pixel-opacity editing into here;
39 the code is carefully constructed to assume RGBA byte order whether integers are
40 big- or little-endian.
41
42 Nov 18, 2000 (Loren Petrich):
43 Added support for glow mapping; constrained it to only be present
44 when a normal texture is present, and to have the same size
45
46 Nov 26, 2000 (Loren Petrich):
47 Added system for reloading textures only when their filenames change.
48
49 Dec 17, 2000 (Loren Petrich):
50 Eliminated fog parameters from the preferences;
51 there is still a "fog present" switch, which is used to indicate
52 whether fog will not be suppressed.
53
54 Apr 27, 2001 (Loren Petrich):
55 Modified the OpenGL fog support so as to enable below-liquid fogs
56
57 Jul 8, 2001 (Loren Petrich):
58 Made it possible to read in silhouette bitmaps; one can now use the silhouette index
59 as a MML color-table index
60
61 Aug 21, 2001 (Loren Petrich):
62 Adding support for 3D-model inhabitant objects
63
64 Jan 25, 2002 (Br'fin (Jeremy Parsons)):
65 Added TARGET_API_MAC_CARBON for OpenGL.h, AGL.h
66 Removed QuickDraw3D support from Carbon
67
68 Feb 5, 2002 (Br'fin (Jeremy Parsons)):
69 Refined OGL default preferences for Carbon
70 */
71
72 #include <vector>
73 #include <string.h>
74 #include <math.h>
75 #include "cseries.h"
76
77 #ifdef HAVE_OPENGL
78
79 #include "OGL_Headers.h"
80 #include "OGL_Shader.h"
81
82 #endif
83
84 #include "shape_descriptors.h"
85 #include "OGL_Setup.h"
86 #include "OGL_LoadScreen.h"
87 #include "progress.h"
88 #include "InfoTree.h"
89
90 // Whether or not OpenGL is present and usable
91 static bool _OGL_IsPresent = false;
92
93 bool Using_sRGB = false;
94 bool Wanting_sRGB = false;
95 bool Bloom_sRGB = false;
96 bool FBO_Allowed = false;
97 bool npotTextures = false; // non-power-of-two
98
99 // Initializer
OGL_Initialize()100 bool OGL_Initialize()
101 {
102 #ifdef HAVE_OPENGL
103 #if defined(__WIN32__)
104 // glewInit();
105 #endif
106
107 return _OGL_IsPresent = true;
108 #else
109 return false;
110 #endif
111 }
112
113 // Test for presence
OGL_IsPresent()114 bool OGL_IsPresent() {return _OGL_IsPresent;}
115
OGL_CheckExtension(const std::string extension)116 bool OGL_CheckExtension(const std::string extension) {
117 #ifdef HAVE_OPENGL
118 #ifdef __WIN32__
119 return glewIsSupported(extension.c_str());
120 #else
121 char *extensions = (char *) glGetString(GL_EXTENSIONS);
122 if (!extensions) return false;
123
124 while (*extensions)
125 {
126 unsigned int length = strcspn(extensions, " ");
127
128 if (length == extension.size() &&
129 strncmp(extension.c_str(), extensions, length) == 0) {
130 return true;
131 }
132
133 extensions += length + 1;
134 }
135 #endif
136 #endif
137 return false;
138 }
139
140 static int ogl_progress;
141 static int total_ogl_progress;
142 static bool show_ogl_progress = false;
143 static int32 last_update_tick;
144
145 extern bool OGL_ClearScreen();
146
147 #ifdef HAVE_OPENGL
OGL_StartProgress(int total_progress)148 void OGL_StartProgress(int total_progress)
149 {
150 ogl_progress = 0;
151 total_ogl_progress = total_progress;
152 if (!OGL_LoadScreen::instance()->Start())
153 {
154 OGL_ClearScreen();
155 open_progress_dialog(_loading, true);
156 }
157 show_ogl_progress = true;
158 last_update_tick = SDL_GetTicks();
159 }
160
OGL_ProgressCallback(int delta_progress)161 void OGL_ProgressCallback(int delta_progress)
162 {
163 if (!show_ogl_progress) return;
164 ogl_progress += delta_progress;
165 {
166 int32 current_ticks = SDL_GetTicks();
167 if (current_ticks > last_update_tick + 33)
168 {
169 if (OGL_LoadScreen::instance()->Use())
170 OGL_LoadScreen::instance()->Progress(100 * ogl_progress / total_ogl_progress);
171 else
172 draw_progress_bar(ogl_progress, total_ogl_progress);
173 last_update_tick = current_ticks;
174 }
175 }
176 }
177
OGL_StopProgress()178 void OGL_StopProgress()
179 {
180 show_ogl_progress = false;
181 if (OGL_LoadScreen::instance()->Use())
182 OGL_LoadScreen::instance()->Stop();
183 else
184 close_progress_dialog();
185 }
186 #endif
187
188 // Sensible defaults for the fog:
189 static OGL_FogData FogData[OGL_NUMBER_OF_FOG_TYPES] =
190 {
191 {{0x8000,0x8000,0x8000},8,false,true},
192 {{0x8000,0x8000,0x8000},8,false,true}
193 };
194
195
196 // For flat landscapes:
197 const RGBColor DefaultLscpColors[4][2] =
198 {
199 {
200 {0xffff, 0xffff, 0x6666}, // Day
201 {0x3333, 0x9999, 0xffff},
202 },
203 {
204 {0x1818, 0x1818, 0x1010}, // Night
205 {0x0808, 0x0808, 0x1010},
206 },
207 {
208 {0x6666, 0x6666, 0x6666}, // Moon
209 {0x0000, 0x0000, 0x0000},
210 },
211 {
212 {0x0000, 0x0000, 0x0000}, // Outer Space
213 {0x0000, 0x0000, 0x0000},
214 },
215 };
216
217
218 // Set defaults
OGL_SetDefaults(OGL_ConfigureData & Data)219 void OGL_SetDefaults(OGL_ConfigureData& Data)
220 {
221 for (int k=0; k<OGL_NUMBER_OF_TEXTURE_TYPES; k++)
222 {
223 OGL_Texture_Configure& TxtrData = Data.TxtrConfigList[k];
224 TxtrData.NearFilter = 1; // GL_LINEAR
225 if (k == OGL_Txtr_Wall || k == OGL_Txtr_Inhabitant)
226 TxtrData.FarFilter = 5; // GL_LINEAR_MIPMAP_LINEAR
227 else
228 TxtrData.FarFilter = 1; // GL_LINEAR
229 TxtrData.Resolution = 0; // 1x
230 TxtrData.ColorFormat = 0; // 32-bit color
231 TxtrData.MaxSize = 0; // Unlimited
232 }
233
234 Data.ModelConfig.NearFilter = 1;
235 Data.ModelConfig.FarFilter = 5;
236 Data.ModelConfig.Resolution = 0;
237 Data.ModelConfig.ColorFormat = 0;
238 Data.ModelConfig.MaxSize = 0;
239
240 // Reasonable default flags
241 Data.Flags = OGL_Flag_Fader | OGL_Flag_Map |
242 OGL_Flag_HUD | OGL_Flag_LiqSeeThru | OGL_Flag_3D_Models | OGL_Flag_ZBuffer |
243 OGL_Flag_Fog;
244
245 Data.AnisotropyLevel = 0.0; // off
246 Data.Multisamples = 0; // off
247
248 Data.VoidColor = rgb_black; // Self-explanatory
249 for (int il=0; il<4; il++)
250 for (int ie=0; ie<2; ie++)
251 Data.LscpColors[il][ie] = DefaultLscpColors[il][ie];
252
253 Data.GeForceFix = false;
254 Data.WaitForVSync = true;
255 Data.Use_sRGB = false;
256 Data.Use_NPOT = false;
257 }
258
259
StringPresent(vector<char> & String)260 inline bool StringPresent(vector<char>& String)
261 {
262 return (String.size() > 1);
263 }
264
265 #ifdef HAVE_OPENGL
266
267 GLint glMaxTextureSize = 0;
268 bool hasS3TC = false;
269
Load()270 void OGL_TextureOptionsBase::Load()
271 {
272 FileSpecifier File;
273
274 GLint maxTextureSize = glMaxTextureSize;
275 if (GetMaxSize())
276 {
277 maxTextureSize = MIN(maxTextureSize, GetMaxSize());
278 }
279
280 int flags = npotTextures ? 0 : ImageLoader_ResizeToPowersOfTwo;
281
282 if (Type >= 0 && Type < OGL_NUMBER_OF_TEXTURE_TYPES && Get_OGL_ConfigureData().TxtrConfigList[Type].FarFilter > 1 /* GL_LINEAR */)
283 {
284 flags |= ImageLoader_LoadMipMaps;
285 }
286
287 if (hasS3TC)
288 {
289 flags |= ImageLoader_CanUseDXTC;
290 }
291
292 if (Get_OGL_ConfigureData().GeForceFix)
293 {
294 flags |= ImageLoader_LoadDXTC1AsDXTC3;
295 }
296
297 // Load the normal image with alpha channel
298
299 // Check to see if loading needs to be done;
300 // it does not need to be if an image is present.
301 if (NormalImg.IsPresent()) return;
302
303 NormalImg.Clear();
304
305 // Load the normal image if it has a filename specified for it
306 if (NormalColors != FileSpecifier() && NormalColors.Exists())
307 {
308 if (!NormalImg.LoadFromFile(NormalColors,ImageLoader_Colors, flags | (NormalIsPremultiplied ? ImageLoader_ImageIsAlreadyPremultiplied : 0), actual_width, actual_height, maxTextureSize))
309 {
310 // A texture must have a normal colored part
311 return;
312 }
313 }
314 else
315 {
316 return;
317 }
318
319 // load a heightmap
320 if(OffsetMap != FileSpecifier() && OffsetMap.Exists()) {
321 if(!OffsetImg.LoadFromFile(OffsetMap, ImageLoader_Colors, flags | (NormalIsPremultiplied ? ImageLoader_ImageIsAlreadyPremultiplied : 0), actual_width, actual_height, maxTextureSize)) {
322 return;
323 }
324 }
325
326 // Load the normal mask if it has a filename specified for it
327 if (NormalMask != FileSpecifier() && NormalMask.Exists())
328 {
329 NormalImg.LoadFromFile(NormalMask,ImageLoader_Opacity, flags, actual_width, actual_height, maxTextureSize);
330 }
331
332 if (maxTextureSize)
333 {
334 while (NormalImg.GetWidth() > maxTextureSize || NormalImg.GetHeight() > maxTextureSize)
335 {
336 if (!NormalImg.Minify()) break;
337 }
338
339 if(OffsetImg.IsPresent()) {
340 while (OffsetImg.GetWidth() > maxTextureSize || OffsetImg.GetHeight() > maxTextureSize) {
341 if(!OffsetImg.Minify()) { break; }
342 }
343 }
344 }
345
346 // Load the glow image with alpha channel
347 if (!GlowImg.IsPresent())
348 {
349 GlowImg.Clear();
350
351 // Load the glow image if it has a filename specified for it
352 if (GlowColors != FileSpecifier() && GlowColors.Exists())
353 {
354 if (GlowImg.LoadFromFile(GlowColors,ImageLoader_Colors, flags | (GlowIsPremultiplied ? ImageLoader_ImageIsAlreadyPremultiplied : 0), actual_width, actual_height, maxTextureSize))
355 {
356
357 // Load the glow mask if it has a
358 // filename specified for it; only
359 // loaded if an image has been loaded
360 // for it
361 if (GlowMask != FileSpecifier() && GlowMask.Exists())
362 {
363 GlowImg.LoadFromFile(GlowMask,ImageLoader_Opacity, flags, actual_width, actual_height, maxTextureSize);
364 }
365 }
366 }
367 }
368
369 if (GlowImg.IsPresent() && maxTextureSize)
370 {
371 while (GlowImg.GetWidth() > maxTextureSize || GlowImg.GetHeight() > maxTextureSize)
372 {
373 if (!GlowImg.Minify()) break;
374 }
375 }
376
377 // The rest of the code is made simpler by these constraints:
378 // that the glow texture only be present if the normal texture is also present,
379 // and that the normal and glow textures have the same dimensions
380 if (NormalImg.IsPresent())
381 {
382 int W0 = NormalImg.GetWidth();
383 int W1 = GlowImg.GetWidth();
384 int H0 = NormalImg.GetHeight();
385 int H1 = GlowImg.GetHeight();
386 if ((W1 != W0) || (H1 != H0)) GlowImg.Clear();
387 }
388 else
389 {
390 GlowImg.Clear();
391 }
392
393 }
394
Unload()395 void OGL_TextureOptionsBase::Unload()
396 {
397 NormalImg.Clear();
398 GlowImg.Clear();
399 OffsetImg.Clear();
400 }
401
GetMaxSize()402 int OGL_TextureOptionsBase::GetMaxSize()
403 {
404 if (Type >= 0 && Type < OGL_NUMBER_OF_TEXTURE_TYPES)
405 {
406 return Get_OGL_ConfigureData().TxtrConfigList[Type].MaxSize;
407 }
408 else
409 return 0; // Unlimited
410 }
411 #endif
412
413 #ifdef HAVE_OPENGL
414
OGL_CountModelsImages(short Collection)415 int OGL_CountModelsImages(short Collection)
416 {
417 return OGL_CountTextures(Collection) + OGL_CountModels(Collection);
418 }
419
420 // for managing the model and image loading and unloading
OGL_LoadModelsImages(short Collection)421 void OGL_LoadModelsImages(short Collection)
422 {
423 assert(Collection >= 0 && Collection < MAXIMUM_COLLECTIONS);
424
425 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTextureSize);
426 hasS3TC = OGL_CheckExtension("GL_ARB_texture_compression") && OGL_CheckExtension("GL_EXT_texture_compression_s3tc");
427
428 // For wall/sprite images
429 OGL_LoadTextures(Collection);
430
431 // For models, skins
432 bool UseModels = TEST_FLAG(Get_OGL_ConfigureData().Flags,OGL_Flag_3D_Models) ? true : false;
433 if (UseModels)
434 OGL_LoadModels(Collection);
435 else
436 OGL_UnloadModels(Collection);
437 }
438
OGL_UnloadModelsImages(short Collection)439 void OGL_UnloadModelsImages(short Collection)
440 {
441 assert(Collection >= 0 && Collection < MAXIMUM_COLLECTIONS);
442
443 // For wall/sprite images
444 OGL_UnloadTextures(Collection);
445
446 // For models, skins
447 OGL_UnloadModels(Collection);
448 }
449
450 #else
451
OGL_LoadModelsImages(short)452 void OGL_LoadModelsImages(short)
453 {
454 }
455
OGL_UnloadModelsImages(short)456 void OGL_UnloadModelsImages(short)
457 {
458 }
459
460 #endif // def HAVE_OPENGL
461
462
OGL_GetFogData(int Type)463 OGL_FogData *OGL_GetFogData(int Type)
464 {
465 return GetMemberWithBounds(FogData,Type,OGL_NUMBER_OF_FOG_TYPES);
466 }
467
468
469 // XML-parsing stuff
470 OGL_FogData *OriginalFogData = NULL;
471
reset_mml_opengl()472 void reset_mml_opengl()
473 {
474 reset_mml_opengl_texture();
475 reset_mml_opengl_model();
476 reset_mml_opengl_shader();
477
478 if (OriginalFogData) {
479 for (unsigned i = 0; i < OGL_NUMBER_OF_FOG_TYPES; i++)
480 FogData[i] = OriginalFogData[i];
481 free(OriginalFogData);
482 OriginalFogData = NULL;
483 }
484 }
485
parse_mml_opengl(const InfoTree & root)486 void parse_mml_opengl(const InfoTree& root)
487 {
488 // back up old values first
489 if (!OriginalFogData) {
490 OriginalFogData = (OGL_FogData *) malloc(sizeof(OGL_FogData) * OGL_NUMBER_OF_FOG_TYPES);
491 assert(OriginalFogData);
492 for (unsigned i = 0; i < OGL_NUMBER_OF_FOG_TYPES; i++)
493 OriginalFogData[i] = FogData[i];
494 }
495
496 // texture options / clear, in order
497 BOOST_FOREACH(const InfoTree::value_type &v, root)
498 {
499 if (v.first == "texture")
500 parse_mml_opengl_texture(v.second);
501 else if (v.first == "txtr_clear")
502 parse_mml_opengl_txtr_clear(v.second);
503 }
504
505 // model data / clear, in order
506 BOOST_FOREACH(const InfoTree::value_type &v, root)
507 {
508 if (v.first == "model")
509 parse_mml_opengl_model(v.second);
510 else if (v.first == "model_clear")
511 parse_mml_opengl_model_clear(v.second);
512 }
513
514 BOOST_FOREACH(InfoTree shader, root.children_named("shader"))
515 {
516 parse_mml_opengl_shader(shader);
517 }
518
519 BOOST_FOREACH(InfoTree fog, root.children_named("fog"))
520 {
521 int16 type = 0;
522 fog.read_indexed("type", type, OGL_NUMBER_OF_FOG_TYPES);
523 OGL_FogData& def = FogData[type];
524
525 fog.read_attr("on", def.IsPresent);
526 fog.read_attr("depth", def.Depth);
527 fog.read_attr("landscapes", def.AffectsLandscapes);
528
529 BOOST_FOREACH(InfoTree color, fog.children_named("color"))
530 {
531 color.read_color(def.Color);
532 }
533 }
534 }
535
536 #ifdef HAVE_OPENGL
537 /* These don't belong here */
SglColor3f(GLfloat r,GLfloat g,GLfloat b)538 void SglColor3f(GLfloat r, GLfloat g, GLfloat b) {
539 GLfloat ov[3] = {sRGB_frob(r), sRGB_frob(g), sRGB_frob(b)};
540 glColor3fv(ov);
541 }
542
SglColor3fv(const GLfloat * iv)543 void SglColor3fv(const GLfloat* iv) {
544 GLfloat ov[3] = {sRGB_frob(iv[0]), sRGB_frob(iv[1]), sRGB_frob(iv[2])};
545 glColor3fv(ov);
546 }
547
SglColor3ub(GLubyte r,GLubyte g,GLubyte b)548 void SglColor3ub(GLubyte r, GLubyte g, GLubyte b) {
549 GLfloat ov[3] = {sRGB_frob(r*(1.f/255.f)), sRGB_frob(g*(1.f/255.f)), sRGB_frob(b*(1.f/255.f))};
550 glColor3fv(ov);
551 }
552
SglColor3us(GLushort r,GLushort g,GLushort b)553 void SglColor3us(GLushort r, GLushort g, GLushort b) {
554 GLfloat ov[3] = {sRGB_frob(r*(1.f/65535.f)), sRGB_frob(g*(1.f/65535.f)), sRGB_frob(b*(1.f/65535.f))};
555 glColor3fv(ov);
556 }
557
SglColor3usv(const GLushort * iv)558 void SglColor3usv(const GLushort* iv) {
559 GLfloat ov[3] = {sRGB_frob(iv[0]*(1.f/65535.f)), sRGB_frob(iv[1]*(1.f/65535.f)), sRGB_frob(iv[2]*(1.f/65535.f))};
560 glColor3fv(ov);
561 }
562
SglColor4f(GLfloat r,GLfloat g,GLfloat b,GLfloat a)563 void SglColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
564 GLfloat ov[4] = {sRGB_frob(r), sRGB_frob(g), sRGB_frob(b), a};
565 glColor4fv(ov);
566 }
567
SglColor4fv(const GLfloat * iv)568 void SglColor4fv(const GLfloat* iv) {
569 GLfloat ov[4] = {sRGB_frob(iv[0]), sRGB_frob(iv[1]), sRGB_frob(iv[2]), iv[3]};
570 glColor4fv(ov);
571 }
572
SglColor4usv(const GLushort * iv)573 void SglColor4usv(const GLushort* iv) {
574 GLfloat ov[4] = {sRGB_frob(iv[0]*(1.f/65535.f)), sRGB_frob(iv[1]*(1.f/65535.f)), sRGB_frob(iv[2]*(1.f/65535.f)), iv[3]*(1.f/65535.f)};
575 glColor4fv(ov);
576 }
577 #endif
578