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