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 Texture Manager,
21 	by Loren Petrich,
22 	March 12, 2000
23 
24 	This implements texture handling for OpenGL.
25 
26 	May 2, 2000:
27 
28 	Fixed silhouette-texture bug: color 0 is now transparent
29 
30 	May 24, 2000:
31 
32 	Added support for setting landscape aspect ratios from outside;
33 	also added more graceful degradation for mis-sized textures.
34 	Walls must be a power of 2 horizontally and vertical;
35 	landscapes must be a power of 2 horizontally
36 	in order for the tiling to work properly.
37 
38 	June 11, 2000:
39 
40 	Added support for opacity shift factor (OpacityShift alongside OpacityScale);
41 	should be good for making dark colors somewhat opaque.
42 
43 Jul 10, 2000:
44 
45 	Fixed crashing bug when OpenGL is inactive with ResetTextures()
46 
47 Sep 9, 2000:
48 
49 	Restored old fix for AppleGL texturing as an option; this fix consists of setting
50 	the minimum size of a texture to be 128.
51 
52 Nov 12, 2000 (Loren Petrich):
53 	Cleaned up some of the code to avoid explicit endianness usage;
54 	also implemented texture substitution.
55 
56 Nov 18, 2000 (Loren Petrich):
57 	Added support for landscape vertical repeats;
58 	also added support for glow mapping of wall textures
59 
60 Dec 16, 2000 (Loren Petrich):
61 	Fixed substitution of landscape textures
62 
63 June 14, 2001 (Loren Petrich):
64 	Changed Width*Height to TxtrWidth*TxtrHeight in some places to ensure that some operations
65 	are done over complete textures
66 
67 Nov 30, 2001 (Alexander Strange):
68 	Added Ian Rickard's texture purging to save VRAM.
69 
70 Jan 25, 2002 (Br'fin (Jeremy Parsons)):
71 	Added TARGET_API_MAC_CARBON for AGL.h
72 
73 May 3, 2003 (Br'fin (Jeremy Parsons))
74 	Added LowLevelShape workaround for passing LowLevelShape info of sprites
75 	instead of abusing/overflowing shape_descriptors
76 */
77 
78 #include <string.h>
79 #include <stdlib.h>
80 #include <stdarg.h>
81 #include <math.h>
82 #include <list>
83 
84 #include "cseries.h"
85 
86 #ifdef HAVE_OPENGL
87 
88 #include "OGL_Headers.h"
89 
90 #include "preferences.h"
91 
92 #include "SDL.h"
93 #include "SDL_endian.h"
94 #include "interface.h"
95 #include "render.h"
96 #include "map.h"
97 #include "collection_definition.h"
98 #include "OGL_Blitter.h"
99 #include "OGL_Setup.h"
100 #include "OGL_Render.h"
101 #include "OGL_Textures.h"
102 #include "screen.h"
103 
104 using std::min;
105 using std::max;
106 
107 OGL_TexturesStats gGLTxStats = {0,0,0,500000,0,0, 0};
108 
109 // Texture mapping
110 struct TxtrTypeInfoData
111 {
112 	GLenum NearFilter;			// OpenGL parameter for near filter (GL_NEAREST, etc.)
113 	GLenum FarFilter;			// OpenGL parameter for far filter (GL_NEAREST, etc.)
114 	int Resolution;				// 0 is full-sized, 1 is half-sized, 2 is fourth-sized
115 	GLenum ColorFormat;			// OpenGL parameter for stored color format (RGBA8, etc.)
116 };
117 
118 
119 static TxtrTypeInfoData TxtrTypeInfoList[OGL_NUMBER_OF_TEXTURE_TYPES];
120 static TxtrTypeInfoData ModelSkinInfo;
121 
122 static bool useSGISMipmaps = false;
123 static bool useMirroredRepeat = false;
124 
125 // Infravision: use algorithm (red + green + blue)/3 to compose intensity,
126 // then shade with these colors, one color for each collection.
127 
128 struct InfravisionData
129 {
130 	GLfloat Red, Green, Blue;	// Infravision tint components: 0 to 1
131 	bool IsTinted;				// whether to use infravision with this collection
132 };
133 
134 struct InfravisionData IVDataList[NUMBER_OF_COLLECTIONS] =
135 {
136 	{1,1,1,false},
137 	{1,1,1,false},
138 	{1,1,1,false},
139 	{1,1,1,false},
140 	{1,1,1,false},
141 	{1,1,1,false},
142 	{1,1,1,false},
143 	{1,1,1,false},
144 	{1,1,1,false},
145 	{1,1,1,false},
146 	{1,1,1,false},
147 	{1,1,1,false},
148 	{1,1,1,false},
149 	{1,1,1,false},
150 	{1,1,1,false},
151 	{1,1,1,false},
152 	{1,1,1,false},
153 	{1,1,1,false},
154 	{1,1,1,false},
155 	{1,1,1,false},
156 	{1,1,1,false},
157 	{1,1,1,false},
158 	{1,1,1,false},
159 	{1,1,1,false},
160 	{1,1,1,false},
161 	{1,1,1,false},
162 	{1,1,1,false},
163 	{1,1,1,false},
164 	{1,1,1,false},
165 	{1,1,1,false},
166 	{1,1,1,false},
167 	{1,1,1,false}
168 };
169 
170 // Is infravision currently active?
171 static bool InfravisionActive = false;
172 
173 static std::list<TextureState*> sgActiveTextureStates;
174 
175 
176 // Allocate some textures and indicate whether an allocation had happened.
Allocate(short txType)177 bool TextureState::Allocate(short txType)
178 {
179 	TextureType = txType;
180 	if (!IsUsed)
181 	{
182 		sgActiveTextureStates.push_front(this);
183 		gGLTxStats.inUse++;
184 		glGenTextures(NUMBER_OF_TEXTURES,IDs);
185 		IsUsed = true;
186 		unusedFrames=0;
187 		return true;
188 	}
189 	return false;
190 }
191 
192 // Use a texture and indicate whether to load it
Use(int Which)193 bool TextureState::Use(int Which)
194 {
195 	glBindTexture(GL_TEXTURE_2D,IDs[Which]);
196 	bool result = !TexGened[Which];
197 	TexGened[Which] = true;
198 	IDUsage[Which]++;
199 	return result;
200 }
201 
202 
203 // Resets the object's texture state
Reset()204 void TextureState::Reset()
205 {
206 	if (IsUsed)
207 	{
208 		sgActiveTextureStates.remove(this);
209 		gGLTxStats.inUse--;
210 		glDeleteTextures(NUMBER_OF_TEXTURES,IDs);
211 	}
212 	IsUsed = IsGlowing = IsBumped = TexGened[Normal] = TexGened[Glowing] = TexGened[Bump] = false;
213 	IDUsage[Normal] = IDUsage[Glowing] = IDUsage[Bump] = unusedFrames = 0;
214 }
215 
FrameTick()216 void TextureState::FrameTick() {
217 	if (!IsUsed) return;
218 
219 	gGLTxStats.totalAge += (TextureType!=OGL_Txtr_Landscape)?unusedFrames:0;
220 
221 	bool used  = false;
222 
223 	for (int i=0 ; i<NUMBER_OF_TEXTURES ; i++)
224 		if (IDUsage[i] != 0) used = true;
225 
226 	if (used) {
227 		IDUsage[Normal] = IDUsage[Glowing] = unusedFrames = 0;
228 
229 	} else {
230 		unusedFrames++;
231 		assert(TextureType != NONE);
232 		switch (TextureType) {
233 		case OGL_Txtr_Wall:
234 				if (unusedFrames > 300) Reset(); // at least 10 seconds till wall textures are released
235 				break;
236 		case OGL_Txtr_Landscape:
237 				// never release landscapes
238 				break;
239 		case OGL_Txtr_Inhabitant:
240 				if (unusedFrames > 450) Reset(); // release unused sprites in 15 seconds
241 				break;
242 		case OGL_Txtr_WeaponsInHand:
243 				if (unusedFrames > 600) Reset(); // release weapons in hand in 20 seconds
244 				break;
245 		}
246 	}
247 }
248 
249 // Will distinguish by texture type as well as by collection;
250 // this is because different rendering modes deserve different treatment.
251 static CollBitmapTextureState* TextureStateSets[OGL_NUMBER_OF_TEXTURE_TYPES][MAXIMUM_COLLECTIONS];
252 
253 static GLuint flatBumpTextureID = 0;
FlatBumpTexture()254 void FlatBumpTexture() {
255 
256 	if (flatBumpTextureID == 0)
257 	{
258 		glGenTextures(1, &flatBumpTextureID);
259 		glBindTexture(GL_TEXTURE_2D, flatBumpTextureID);
260 
261 		GLubyte flatTextureData[4] = {0x80, 0x80, 0xFF, 0x80};
262 
263 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
264 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
265 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
266 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
267 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
268 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, flatTextureData);
269 	}
270 	else
271 		glBindTexture(GL_TEXTURE_2D, flatBumpTextureID);
272 }
273 
274 
275 // Initialize the texture accounting
OGL_StartTextures()276 void OGL_StartTextures()
277 {
278 	// Initialize the texture accounting proper
279 	for (int it=0; it<OGL_NUMBER_OF_TEXTURE_TYPES; it++)
280 		for (int ic=0; ic<MAXIMUM_COLLECTIONS; ic++)
281 		{
282 			bool CollectionPresent = is_collection_present(ic);
283 			short NumberOfBitmaps =
284 				CollectionPresent ? get_number_of_collection_bitmaps(ic) : 0;
285 			TextureStateSets[it][ic] =
286 				(CollectionPresent && NumberOfBitmaps) ?
287 					(new CollBitmapTextureState[NumberOfBitmaps]) : 0;
288 		}
289 
290 	// Initialize the texture-type info
291 	const int NUMBER_OF_NEAR_FILTERS = 2;
292 	const GLenum NearFilterList[NUMBER_OF_NEAR_FILTERS] =
293 	{
294 		GL_NEAREST,
295 		GL_LINEAR
296 	};
297 	const int NUMBER_OF_FAR_FILTERS = 6;
298 	const GLenum FarFilterList[NUMBER_OF_FAR_FILTERS] =
299 	{
300 		GL_NEAREST,
301 		GL_LINEAR,
302 		GL_NEAREST_MIPMAP_NEAREST,
303 		GL_LINEAR_MIPMAP_NEAREST,
304 		GL_NEAREST_MIPMAP_LINEAR,
305 		GL_LINEAR_MIPMAP_LINEAR
306 	};
307 	const int NUMBER_OF_COLOR_FORMATS = 3;
308 	const GLenum ColorFormatList[NUMBER_OF_COLOR_FORMATS] =
309 	{
310 		GL_RGBA8,
311 		GL_RGBA4,
312 		GL_RGBA2
313 	};
314 
315 	OGL_ConfigureData& ConfigureData = Get_OGL_ConfigureData();
316 
317 	for (int k=0; k<OGL_NUMBER_OF_TEXTURE_TYPES; k++)
318 	{
319 		OGL_Texture_Configure& TxtrConfigure = ConfigureData.TxtrConfigList[k];
320 		TxtrTypeInfoData& TxtrTypeInfo = TxtrTypeInfoList[k];
321 
322 		short NearFilter = TxtrConfigure.NearFilter;
323 		if (NearFilter < NUMBER_OF_NEAR_FILTERS)
324 			TxtrTypeInfo.NearFilter = NearFilterList[NearFilter];
325 		else
326 			TxtrTypeInfo.NearFilter = GL_NEAREST;
327 
328 		short FarFilter = TxtrConfigure.FarFilter;
329 		if (FarFilter < NUMBER_OF_FAR_FILTERS)
330 			TxtrTypeInfo.FarFilter = FarFilterList[FarFilter];
331 		else
332 			TxtrTypeInfo.FarFilter = GL_NEAREST;
333 
334 		TxtrTypeInfo.Resolution = TxtrConfigure.Resolution;
335 
336 		short ColorFormat = TxtrConfigure.ColorFormat;
337 		if (ColorFormat < NUMBER_OF_COLOR_FORMATS)
338 			TxtrTypeInfo.ColorFormat = ColorFormatList[ColorFormat];
339 		else
340 			TxtrTypeInfo.ColorFormat = GL_RGBA8;
341 	}
342 
343 	// Model skin
344 	{
345 		OGL_Texture_Configure& TxtrConfigure = ConfigureData.ModelConfig;
346 		TxtrTypeInfoData& TxtrTypeInfo = ModelSkinInfo;
347 
348 		short NearFilter = TxtrConfigure.NearFilter;
349 		if (NearFilter < NUMBER_OF_NEAR_FILTERS)
350 			TxtrTypeInfo.NearFilter = NearFilterList[NearFilter];
351 		else
352 			TxtrTypeInfo.NearFilter = GL_NEAREST;
353 
354 		short FarFilter = TxtrConfigure.FarFilter;
355 		if (FarFilter < NUMBER_OF_FAR_FILTERS)
356 			TxtrTypeInfo.FarFilter = FarFilterList[FarFilter];
357 		else
358 			TxtrTypeInfo.FarFilter = GL_NEAREST;
359 
360 		TxtrTypeInfo.Resolution = TxtrConfigure.Resolution;
361 
362 		short ColorFormat = TxtrConfigure.ColorFormat;
363 		if (ColorFormat < NUMBER_OF_COLOR_FORMATS)
364 			TxtrTypeInfo.ColorFormat = ColorFormatList[ColorFormat];
365 		else
366 			TxtrTypeInfo.ColorFormat = GL_RGBA8;
367 	}
368 
369 #if defined GL_SGIS_generate_mipmap
370 	useSGISMipmaps = OGL_CheckExtension("GL_SGIS_generate_mipmap");
371 #endif
372 #if defined GL_ARB_texture_mirrored_repeat
373 	useMirroredRepeat = OGL_CheckExtension("GL_ARB_texture_mirrored_repeat");
374 #endif
375 }
376 
377 
378 // Done with the texture accounting
OGL_StopTextures()379 void OGL_StopTextures()
380 {
381 	// Clear the texture accounting
382 	for (int it=0; it<OGL_NUMBER_OF_TEXTURE_TYPES; it++)
383 		for (int ic=0; ic<MAXIMUM_COLLECTIONS; ic++)
384 			if (TextureStateSets[it][ic]) delete []TextureStateSets[it][ic];
385 
386 	// clear blitters and fonts
387 	OGL_Blitter::StopTextures();
388 	FontSpecifier::OGL_ResetFonts(false);
389 
390 	glDeleteTextures(1, &flatBumpTextureID);
391 	flatBumpTextureID = 0;
392 
393     // clear leftover infravision
394     InfravisionActive = false;
395 }
396 
OGL_FrameTickTextures()397 void OGL_FrameTickTextures()
398 {
399 	std::list<TextureState*>::iterator i;
400 
401 	for (i=sgActiveTextureStates.begin() ; i!= sgActiveTextureStates.end() ; i++) {
402 		(*i)->FrameTick();
403 	}
404 }
405 
406 // Find an OpenGL-friendly color table from a Marathon shading table
FindOGLColorTable(int NumSrcBytes,byte * OrigColorTable,uint32 * ColorTable)407 static void FindOGLColorTable(int NumSrcBytes, byte *OrigColorTable, uint32 *ColorTable)
408 {
409 	// Stretch the original color table to 4 bytes per value for OpenGL convenience;
410 	// all the intermediate calculations will be done in RGBA 8888 form,
411 	// because that is what OpenGL prefers as a texture input
412 	switch(NumSrcBytes) {
413 	case 2:
414 		for (int k=0; k<MAXIMUM_SHADING_TABLE_INDEXES; k++)
415 		{
416 			byte *OrigPtr = OrigColorTable + NumSrcBytes*k;
417 			uint32 &Color = ColorTable[k];
418 
419 			// Convert from ARGB 5551 to RGBA 8888; make opaque
420 			uint16 Intmd;
421 			uint8 *IntmdPtr = (uint8 *)(&Intmd);
422 			IntmdPtr[0] = OrigPtr[0];
423 			IntmdPtr[1] = OrigPtr[1];
424 			Color = Convert_16to32(Intmd);
425 		}
426 		break;
427 
428 	case 4:
429 		for (int k=0; k<MAXIMUM_SHADING_TABLE_INDEXES; k++)
430 		{
431 			byte *OrigPtr = OrigColorTable + NumSrcBytes*k;
432 			uint32 &Color = ColorTable[k];
433 
434 			// Convert from ARGB 8888 to RGBA 8888; make opaque
435 			uint8 *ColorPtr = (uint8 *)(&Color);
436 			if (PlatformIsLittleEndian()) {
437 				// the compiler will do the right thing and only emit
438 				// code for the correct path. In C++17 we can do constexpr if
439 				// to make that requirement explicit.
440 				ColorPtr[0] = OrigPtr[2];
441 				ColorPtr[1] = OrigPtr[1];
442 				ColorPtr[2] = OrigPtr[0];
443 				ColorPtr[3] = 0xff;
444 			} else {
445 				ColorPtr[0] = OrigPtr[1];
446 				ColorPtr[1] = OrigPtr[2];
447 				ColorPtr[2] = OrigPtr[3];
448 				ColorPtr[3] = 0xff;
449 			}
450 		}
451 		break;
452 	}
453 }
454 
455 
IsLandscapeFlatColored()456 inline bool IsLandscapeFlatColored()
457 {
458 	OGL_ConfigureData& ConfigureData = Get_OGL_ConfigureData();
459 	return TEST_FLAG(ConfigureData.Flags,OGL_Flag_FlatLand);
460 }
461 
462 
463 // Modify color-table index if necessary;
464 // makes it the infravision or silhouette one if necessary
ModifyCLUT(short TransferMode,short CLUT)465 short ModifyCLUT(short TransferMode, short CLUT)
466 {
467 	short CTable;
468 
469 	// Tinted mode is only used for invisibility, and infravision will make objects visible
470 	if (TransferMode == _static_transfer) CTable = SILHOUETTE_BITMAP_CLUTSPECIFIC + CLUT;
471 	else if (TransferMode == _tinted_transfer) CTable = SILHOUETTE_BITMAP_CLUTSPECIFIC + CLUT;
472 	else if (InfravisionActive) CTable = INFRAVISION_BITMAP_CLUTSPECIFIC + CLUT;
473 	else CTable = CLUT;
474 
475 	return CTable;
476 }
477 
478 /*
479 	Routine for using some texture; it will load the texture if necessary.
480 	It parses a shape descriptor and checks on whether the collection's texture type
481 	is one of those given.
482 	It will check for more than one intended texture type,
483 	a convenience for multiple texture types sharing the same handling.
484 
485 	It uses the transfer mode and the transfer data to work out
486 	what transfer modes to use (invisibility is a special case of tinted)
487 */
Setup()488 bool TextureManager::Setup()
489 {
490 
491 	// Parse the shape descriptor and check on whether the texture type
492 	// is the texture's intended type
493 	short CollColor = GET_DESCRIPTOR_COLLECTION(ShapeDesc);
494 	Collection = GET_COLLECTION(CollColor);
495 	CTable = ModifyCLUT(TransferMode,GET_COLLECTION_CLUT(CollColor));
496 	Frame = (LowLevelShape)? LowLevelShape : GET_DESCRIPTOR_SHAPE(ShapeDesc);
497 	Bitmap = get_bitmap_index(Collection,Frame);
498 	if (Bitmap == NONE) return false;
499 
500 	// Get the texture-state info: first, per-collection, then per-bitmap
501 	CollBitmapTextureState *CBTSList = TextureStateSets[TextureType][Collection];
502 	if (CBTSList == NULL) return false;
503 	CollBitmapTextureState& CBTS = CBTSList[Bitmap];
504 
505 	// Get the control info for this texture type:
506 	TxtrTypeInfoData& TxtrTypeInfo = TxtrTypeInfoList[TextureType];
507 
508 	// Get the rendering options for this texture:
509 	TxtrOptsPtr = OGL_GetTextureOptions(Collection,CTable,Bitmap);
510 
511 	// Get the texture-state info: per-color-table -- be sure to preserve this for later
512 	// Set the texture ID, and load the texture if necessary
513 	// If "Use()" is true, then load, otherwise, assume the texture is loaded and skip
514 	TxtrStatePtr = &CBTS.CTStates[CTable];
515 	TextureState &CTState = *TxtrStatePtr;
516 	if (!CTState.IsUsed)
517 	{
518 		// Initial sprite scale/offset
519 		U_Scale = V_Scale = 1;
520 		U_Offset = V_Offset = 0;
521 
522 		// Try to load a substitute texture, and if that fails,
523 		// get the geometry from the shapes bitmap.
524 		bool substitute = LoadSubstituteTexture();
525 		if (!substitute)
526 			if (!SetupTextureGeometry()) return false;
527 
528 		// Store sprite scale/offset
529 		CTState.U_Scale = U_Scale;
530 		CTState.V_Scale = V_Scale;
531 		CTState.U_Offset = U_Offset;
532 		CTState.V_Offset = V_Offset;
533 
534 		// This finding of color tables sets the glow state
535 		if (!substitute)
536 			FindColorTables();
537 		else if (GlowImage.get() && GlowImage.get()->IsPresent()) {
538 			// Override if textures had been substituted;
539 			// if the normal texture had been substituted, it will be assumed to be
540 			// non-glowing unless the glow texture has also been substituted.
541 
542 			IsGlowing = true;
543 		} else {
544 			IsGlowing = false;
545 		}
546 
547 		CTState.IsGlowing = IsGlowing;
548 
549 		if (substitute && OffsetImage.get() && OffsetImage.get()->IsPresent()) {
550 			CTState.IsBumped = true;
551 		} else {
552 			CTState.IsBumped = false;
553 		}
554 
555 		// Load the fake landscape if selected
556 		if (TextureType == OGL_Txtr_Landscape)
557 		{
558 			if (IsLandscapeFlatColored())
559 			{
560 				NormalImage.edit(new ImageDescriptor(TxtrWidth, TxtrHeight, GetFakeLandscape()));
561 			}
562 		}
563 
564 		// If not, then load the expected textures
565 		if (!NormalImage.get() || !NormalImage.get()->IsPresent())
566 			NormalImage.edit(new ImageDescriptor(TxtrWidth, TxtrHeight, GetOGLTexture(NormalColorTable)));
567 		if (IsGlowing && (!GlowImage.get() || !GlowImage.get()->IsPresent()))
568 			GlowImage.edit(new ImageDescriptor(TxtrWidth, TxtrHeight, GetOGLTexture(GlowColorTable)));
569 
570 		// Display size: may be shrunk
571 		int MaxWidth = MAX(TxtrWidth >> TxtrTypeInfo.Resolution, 1);
572 		int MaxHeight = MAX(TxtrHeight >> TxtrTypeInfo.Resolution, 1);
573 
574 		// Fit the image into the maximum size allowed by the OpenGL implementation in use
575 		GLint MaxTextureSize;
576 		glGetIntegerv(GL_MAX_TEXTURE_SIZE,&MaxTextureSize);
577 		while (MaxWidth > MaxTextureSize || MaxHeight > MaxTextureSize)
578 		{
579 			LoadedWidth >>= 1;
580 			LoadedHeight >>= 1;
581 		}
582 
583 		while (NormalImage.get()->GetWidth() > MaxWidth || NormalImage.get()->GetHeight() > MaxHeight)
584 		{
585 			if (!NormalImage.edit()->Minify()) break;
586 			if (GlowImage.get() && GlowImage.get()->IsPresent()) {
587 				if (!GlowImage.edit()->Minify()) break;
588 			}
589 			if (OffsetImage.get() && OffsetImage.get()->IsPresent()) {
590 				if (!OffsetImage.edit()->Minify()) break;
591 			}
592 		}
593 
594 		// Kludge for making top and bottom look flat
595 		/*
596 		if (TextureType == OGL_Txtr_Landscape)
597 		{
598 			MakeAverage(LoadedWidth,NormalBuffer);
599 			MakeAverage(LoadedWidth,NormalBuffer+LoadedWidth*(LoadedHeight-1));
600 		}
601 		*/
602 	}
603 	else
604 	{
605 		// Get sprite scale/offset
606 		U_Scale = CTState.U_Scale;
607 		V_Scale = CTState.V_Scale;
608 		U_Offset = CTState.U_Offset;
609 		V_Offset = CTState.V_Offset;
610 
611 		// Get glow state
612 		IsGlowing = CTState.IsGlowing;
613 
614 		// Populate NormalImage, GlowImage, OffsetImage
615 		NormalImage.set(&TxtrOptsPtr->NormalImg);
616 		GlowImage.set(&TxtrOptsPtr->GlowImg);
617 		OffsetImage.set(&TxtrOptsPtr->OffsetImg);
618 	}
619 
620 	// Done!!!
621 	return true;
622 }
623 
624 
WhetherTextureFix()625 inline bool WhetherTextureFix()
626 {
627 	OGL_ConfigureData& ConfigureData = Get_OGL_ConfigureData();
628 	return TEST_FLAG(ConfigureData.Flags,OGL_Flag_TextureFix);
629 }
630 
631 
632 // Conversion of color data types
633 
MakeEightBit(GLfloat Chan)634 inline int MakeEightBit(GLfloat Chan)
635 {
636 	return int(PIN(int(255*Chan+0.5),0,255));
637 }
638 
MakeIntColor(GLfloat * FloatColor)639 uint32 MakeIntColor(GLfloat *FloatColor)
640 {
641 	uint32 IntColor;
642 	uint8 *ColorPtr = (uint8 *)(&IntColor);
643 	for (int k=0; k<4; k++)
644 		ColorPtr[k] = MakeEightBit(FloatColor[k]);
645 	return IntColor;
646 }
647 
MakeFloatColor(uint32 IntColor,GLfloat * FloatColor)648 void MakeFloatColor(uint32 IntColor, GLfloat *FloatColor)
649 {
650 	uint8 *ColorPtr = (uint8 *)(&IntColor);
651 	for (int k=0; k<4; k++)
652 		FloatColor[k] = float(ColorPtr[k])/float(255);
653 }
654 
LoadSubstituteTexture()655 bool TextureManager::LoadSubstituteTexture()
656 {
657 	// don't load replacements for bitmaps that have been patched
658 	if (Texture->flags & _PATCHED_BIT) return false;
659 
660 	// Is there a texture to be substituted?
661 	ImageDescriptor& NormalImg = TxtrOptsPtr->NormalImg;
662 	if (!NormalImg.IsPresent()) return false;
663 
664 	// Idiot-proofing
665 	if (NormalBuffer)
666 	{
667 		delete []NormalBuffer;
668 		NormalBuffer = NULL;
669 	}
670 	if (GlowBuffer)
671 	{
672 		delete []GlowBuffer;
673 		GlowBuffer = NULL;
674 	}
675 
676 	NormalImage.set(&TxtrOptsPtr->NormalImg);
677 	GlowImage.set(&TxtrOptsPtr->GlowImg);
678 	OffsetImage.set(&TxtrOptsPtr->OffsetImg);
679 
680 	int Width = NormalImg.GetWidth();
681 	int Height = NormalImg.GetHeight();
682 
683 	switch(TextureType)
684 	{
685 	case OGL_Txtr_Wall:
686 		// For tiling to be possible, the width and height must be powers of 2;
687 		// also, be sure to transpose the texture
688 		TxtrHeight = Height;
689 		TxtrWidth = Width;
690 		if (!npotTextures)
691 		{
692 			if (TxtrWidth != NextPowerOfTwo(TxtrWidth)) return false;
693 			if (TxtrHeight != NextPowerOfTwo(TxtrHeight)) return false;
694 		}
695 		TxtrOptsPtr->Substitution = true;
696 		break;
697 
698 	case OGL_Txtr_Landscape:
699 		// For tiling to be possible, the width must be a power of 2;
700 		// the height need not be such a power.
701 		TxtrWidth = Width;
702 		TxtrHeight = (Landscape_AspRatExp >= 0) ?
703 			(TxtrWidth >> Landscape_AspRatExp) :
704 			(TxtrWidth << (-Landscape_AspRatExp));
705 		if (!npotTextures && TxtrWidth != NextPowerOfTwo(TxtrWidth)) return false;
706 
707 		// the renderer doesn't use these,
708 		// so I'll use them to get the texture matrix set up right
709 		U_Scale = (float) TxtrHeight / NormalImg.GetHeight();
710 		U_Offset = -1.0 + ((TxtrHeight - NormalImg.GetHeight()) / 2.0 / TxtrHeight) + (1.0 - NormalImg.GetUScale()) / 2.0;
711 
712 		TxtrOptsPtr->Substitution = true;
713 
714 		GlowImage.set((ImageDescriptor *) NULL);
715 		break;
716 
717 	case OGL_Txtr_Inhabitant:
718 	case OGL_Txtr_WeaponsInHand:
719 		// Much of the code here has been copied from elsewhere.
720 		// Set these for convenience; sprites are transposed, as walls are.
721 		TxtrHeight = Height;
722 		TxtrWidth = Width;
723 
724 		if (!npotTextures)
725 		{
726 			// ImageLoader now stores these as powers of two sized
727 			if (TxtrWidth != NextPowerOfTwo(TxtrWidth)) return false;
728 			if (TxtrHeight != NextPowerOfTwo(TxtrHeight)) return false;
729 		}
730 
731 		// We can calculate the scales and offsets here
732 		V_Scale = NormalImg.GetVScale();
733 		V_Offset = 0;
734 		U_Scale = NormalImg.GetUScale();
735 		U_Offset = 0;
736 
737 		TxtrOptsPtr->Substitution = true;
738 		break;
739 	}
740 
741 	// Use the Tomb Raider opacity hack if selected
742 	SetPixelOpacities(*TxtrOptsPtr, NormalImage);
743 
744 	// Modify if infravision is active
745 	if (IsInfravisionTable(CTable))
746 	{
747 		FindInfravisionVersion(Collection, NormalImage);
748 
749 		// Infravision textures don't glow
750 		GlowImage.set((ImageDescriptor *) NULL);
751 
752 		// FIXME: bump maps don't load properly under infravision
753 		OffsetImage.set((ImageDescriptor *) NULL);
754 	}
755 	else if (IsSilhouetteTable(CTable))
756 	{
757 		FindSilhouetteVersion(NormalImage);
758 		GlowImage.set((ImageDescriptor *) NULL);
759 	}
760 	return true;
761 }
762 
SetupTextureGeometry()763 bool TextureManager::SetupTextureGeometry()
764 {
765 	// How many rows (scanlines) and columns
766 	if (Texture->flags&_COLUMN_ORDER_BIT)
767 	{
768 		BaseTxtrWidth = Texture->height;
769 		BaseTxtrHeight = Texture->width;
770 	}
771 	else
772 	{
773 		BaseTxtrWidth = Texture->width;
774 		BaseTxtrHeight = Texture->height;
775 	}
776 
777 	short RowBytes = Texture->bytes_per_row;
778 	if (RowBytes != NONE)
779 		if (BaseTxtrWidth != RowBytes) return false;
780 
781 	// The default
782 	WidthOffset = HeightOffset = 0;
783 
784 	switch(TextureType)
785 	{
786 	case OGL_Txtr_Wall:
787 		// For tiling to be possible, the width and height must be powers of 2
788 		// Match M1 engine, and truncate larger textures to 128px square
789 		TxtrWidth = std::min(static_cast<int>(BaseTxtrWidth), 128);
790 		TxtrHeight = std::min(static_cast<int>(BaseTxtrHeight), 128);
791 		if (!npotTextures)
792 		{
793 			if (TxtrWidth != NextPowerOfTwo(TxtrWidth)) return false;
794 			if (TxtrHeight != NextPowerOfTwo(TxtrHeight)) return false;
795 		}
796 		break;
797 
798 	case OGL_Txtr_Landscape:
799 		if (IsLandscapeFlatColored())
800 		{
801 			TxtrWidth = 128;
802 			TxtrHeight = 128;
803 		}
804 		else
805 		{
806 			// Width is horizontal direction here
807 			TxtrWidth = BaseTxtrWidth;
808 			if (!npotTextures && TxtrWidth != NextPowerOfTwo(TxtrWidth))
809 				return false;
810 
811 			if (npotTextures)
812 			{
813 				// Use the landscape height here
814 				TxtrHeight = (Landscape_AspRatExp >= 0) ?
815 					(TxtrWidth >> Landscape_AspRatExp) :
816 					(TxtrWidth << (-Landscape_AspRatExp));
817 				U_Scale = (double) TxtrHeight / BaseTxtrHeight;
818 				U_Offset =  -(TxtrHeight - BaseTxtrHeight) / 2.0 / TxtrHeight;
819 				TxtrHeight = BaseTxtrHeight;
820 			}
821 			else
822 			{
823 				// Use the landscape height here
824 				TxtrHeight = (Landscape_AspRatExp >= 0) ?
825 					(TxtrWidth >> Landscape_AspRatExp) :
826 					(TxtrWidth << (-Landscape_AspRatExp));
827 
828 				// Offsets
829 				WidthOffset = (TxtrWidth - BaseTxtrWidth) >> 1;
830 				HeightOffset = (TxtrHeight - BaseTxtrHeight) >> 1;
831 			}
832 		}
833 
834 		break;
835 
836 	case OGL_Txtr_Inhabitant:
837 	case OGL_Txtr_WeaponsInHand:
838 		{
839 			if (npotTextures)
840 			{
841 				TxtrWidth = BaseTxtrWidth;
842 				TxtrHeight = BaseTxtrHeight;
843 			}
844 			else
845 			{
846 				// The 2 here is so that there will be an empty border around a sprite,
847 				// so that the texture can be conveniently mipmapped.
848 				TxtrWidth = NextPowerOfTwo(BaseTxtrWidth+2);
849 				TxtrHeight = NextPowerOfTwo(BaseTxtrHeight+2);
850 
851 				// This kludge no longer necessary
852 				// Restored due to some people still having AppleGL 1.1.2
853 				if (WhetherTextureFix())
854 				{
855 					TxtrWidth = MAX(TxtrWidth,128);
856 					TxtrHeight = MAX(TxtrHeight,128);
857 				}
858 
859 				// Offsets
860 				WidthOffset = (TxtrWidth - BaseTxtrWidth) >> 1;
861 				HeightOffset = (TxtrHeight - BaseTxtrHeight) >> 1;
862 
863 				// We can calculate the scales and offsets here
864 				double TWidRecip = 1/double(TxtrWidth);
865 				double THtRecip = 1/double(TxtrHeight);
866 				U_Scale = TWidRecip*double(BaseTxtrWidth);
867 				U_Offset = TWidRecip*WidthOffset;
868 				V_Scale = THtRecip*double(BaseTxtrHeight);
869 				V_Offset = THtRecip*HeightOffset;
870 			}
871 		}
872 		break;
873 	}
874 
875 	// Success!
876 	return true;
877 }
878 
879 
FindColorTables()880 void TextureManager::FindColorTables()
881 {
882 	// Default
883 	IsGlowing = false;
884 
885 	// The silhouette case is easy
886 	if (IsSilhouetteTable(CTable))
887 	{
888 		NormalColorTable[0] = 0;
889 		for (int k=1; k<MAXIMUM_SHADING_TABLE_INDEXES; k++)
890 			NormalColorTable[k] = 0xffffffff;
891 		return;
892 	}
893 
894 	// Interface collection? Then use the CLUT directly
895 	if (Collection == 0) {
896 		int num_colors;
897 		struct rgb_color_value *q = get_collection_colors(0, 0, num_colors);
898 		uint8 *p = (uint8 *)NormalColorTable;
899 		for (int k=0; k<num_colors; k++) {
900 			int idx = q[k].value;
901 			p[idx * 4 + 0] = q[k].red >> 8;
902 			p[idx * 4 + 1] = q[k].green >> 8;
903 			p[idx * 4 + 2] = q[k].blue >> 8;
904 			p[idx * 4 + 3] = 0xff;
905 		}
906 		SetPixelOpacitiesRGBA(*TxtrOptsPtr, MAXIMUM_SHADING_TABLE_INDEXES, NormalColorTable);
907 		NormalColorTable[0] = 0;
908 		return;
909 	}
910 
911 	// Number of source bytes, for reading off of the shading table
912 	// IR change: dithering
913 	short NumSrcBytes = bit_depth / 8;
914 
915 	// Shadeless polygons use the first, instead of the last, shading table
916 	byte *OrigColorTable = (byte *)ShadingTables;
917 	byte *OrigGlowColorTable = OrigColorTable;
918 	if (!IsShadeless) OrigColorTable +=
919 		NumSrcBytes*(number_of_shading_tables - 1)*MAXIMUM_SHADING_TABLE_INDEXES;
920 
921 	// Find the normal color table,
922 	// and set its opacities as if there was no glow table.
923 	FindOGLColorTable(NumSrcBytes,OrigColorTable,NormalColorTable);
924 	SetPixelOpacitiesRGBA(*TxtrOptsPtr,MAXIMUM_SHADING_TABLE_INDEXES,NormalColorTable);
925 
926 	// Find the glow-map color table;
927 	// only inhabitants are glowmapped.
928 	// Also, it seems that only infravision textures are shadeless.
929 	if (!IsShadeless && (TextureType != OGL_Txtr_Landscape))
930 	{
931 		// Find the glow table from the lowest-illumination color table
932 		FindOGLColorTable(NumSrcBytes,OrigGlowColorTable,GlowColorTable);
933 
934 		// Search for self-luminous colors; ignore the first one as the transparent one
935 		for (int k=1; k<MAXIMUM_SHADING_TABLE_INDEXES; k++)
936 		{
937 			// Check for illumination-independent colors
938 			uint8 *NormalEntry = (uint8 *)(NormalColorTable + k);
939 			uint8 *GlowEntry = (uint8 *)(GlowColorTable + k);
940 
941 			bool EntryIsGlowing = false;
942 			for (int q=0; q<3; q++)
943 				if (GlowEntry[q] >= 0x0f) EntryIsGlowing = true;
944 
945 			// Make the glow color the original color, to get continuity
946 			for (int q=0; q<3; q++)
947 				GlowEntry[q] = NormalEntry[q];
948 
949 			if (EntryIsGlowing && NormalEntry[3])
950 			{
951 				IsGlowing = true;
952 				// Make half-opaque, to get more like the software rendering
953 				float Opacity = NormalEntry[3]/float(0xff);
954 				NormalEntry[3] = MakeEightBit(Opacity/(2-Opacity));
955 				GlowEntry[3] = MakeEightBit(Opacity/2);
956 			}
957 			else
958 			{
959 				// Make transparent, to get appropriate continuity
960 				GlowEntry[3] = 0;
961 			}
962 		}
963 	}
964 
965 	// The first color is always the transparent color,
966 	// except if it is a landscape color
967 	if (TextureType != OGL_Txtr_Landscape)
968 		{NormalColorTable[0] = 0; GlowColorTable[0] = 0;}
969 
970 //	PremultiplyColorTables();
971 }
972 
PremultiplyColorTables()973 void TextureManager::PremultiplyColorTables()
974 {
975 	uint32 alphaMask = PlatformIsLittleEndian() ? 0xff000000 : 0x000000ff;
976 
977 	uint32 *tables[2];
978 	tables[0] = NormalColorTable;
979 	if (!IsShadeless && (TextureType != OGL_Txtr_Landscape))
980 		tables[1] = GlowColorTable;
981 	else
982 		tables[1] = 0;
983 
984 	for (int table = 0; table < 2; table++)
985 	{
986 		if (!tables[table]) continue;
987 		for (int k = 0; k < MAXIMUM_SHADING_TABLE_INDEXES; k++)
988 		{
989 			if ((tables[table][k] & alphaMask) == alphaMask)
990 				continue;
991 			if ((tables[table][k] & alphaMask) == 0) {
992 				tables[table][k] = 0;
993 				continue;
994 			}
995 
996 			short r, g, b, a;
997 			uint8 *PxlPtr = (uint8 *) &tables[table][k];
998 
999 			r = PxlPtr[0];
1000 			g = PxlPtr[1];
1001 			b = PxlPtr[2];
1002 			a = PxlPtr[3];
1003 
1004 			r = (a * r + 127) / 255;
1005 			g = (a * g + 127) / 255;
1006 			b = (a * b + 127) / 255;
1007 
1008 			PxlPtr[0] = (uint8) r;
1009 			PxlPtr[1] = (uint8) g;
1010 			PxlPtr[2] = (uint8) b;
1011 		}
1012 	}
1013 }
1014 
GetOGLTexture(uint32 * ColorTable)1015 uint32 *TextureManager::GetOGLTexture(uint32 *ColorTable)
1016 {
1017 	// Allocate pixel buffer
1018 	int NumPixels = int(TxtrWidth)*int(TxtrHeight);
1019 	uint32 *Buffer = new uint32[NumPixels];
1020 
1021 	// Calculate the rows to move to the OpenGL buffer.
1022 	short OGLHeightOffset, OGLHeightFinish, OrigHeightDiff;
1023 	if (HeightOffset >= 0)
1024 	{
1025 		OGLHeightOffset = HeightOffset;
1026 		OGLHeightFinish = std::min(static_cast<int>(TxtrHeight), HeightOffset + BaseTxtrHeight);
1027 		OrigHeightDiff = -HeightOffset;
1028 	}
1029 	else
1030 	{
1031 		OGLHeightOffset = 0;
1032 		OGLHeightFinish = TxtrHeight;
1033 		OrigHeightDiff = -HeightOffset;
1034 	}
1035 
1036 	// Calculate the pixels within each row to move.
1037 	// If we have a constant row size, we can calculate the
1038 	// offsets once for every row.
1039 	short OrigWidthOffset, OGLWidthOffset, OGLWidthFinish;
1040 	if (Texture->bytes_per_row != NONE)
1041 	{
1042 		if (WidthOffset >= 0)
1043 		{
1044 			OrigWidthOffset = 0;
1045 			OGLWidthOffset = WidthOffset;
1046 			OGLWidthFinish = std::min(static_cast<int>(TxtrWidth), WidthOffset + BaseTxtrWidth);
1047 		}
1048 		else
1049 		{
1050 			OrigWidthOffset = -WidthOffset;
1051 			OGLWidthOffset = 0;
1052 			OGLWidthFinish = TxtrWidth;
1053 		}
1054 	}
1055 	else
1056 	{
1057 		// set later for each row
1058 		OrigWidthOffset = 0;
1059 		OGLWidthOffset = 0;
1060 		OGLWidthFinish = 0;
1061 	}
1062 
1063 	uint32 rgb_mask = PlatformIsLittleEndian() ? 0x00ffffff : 0xffffff00;
1064 
1065 	for (short h = OGLHeightOffset; h < OGLHeightFinish; h++)
1066 	{
1067 		byte *OrigStrip = Texture->row_addresses[h + OrigHeightDiff];
1068 		uint32 *OGLStrip = &Buffer[TxtrWidth * h];
1069 
1070 		if (Texture->bytes_per_row == NONE)
1071 		{
1072 			// Determine the offsets for this row
1073 			// This is the Marathon 2 sprite-interpretation scheme;
1074 			// assumes big-endian data
1075 
1076 			// First destination location
1077 			uint16 First = uint16(*(OrigStrip++)) << 8;
1078 			First |= uint16(*(OrigStrip++));
1079 			// Last destination location (last pixel is just before it)
1080 			uint16 Last = uint16(*(OrigStrip++)) << 8;
1081 			Last |= uint16(*(OrigStrip++));
1082 
1083 			if (WidthOffset + First >= 0)
1084 			{
1085 				OrigWidthOffset = 0;
1086 				OGLWidthOffset = WidthOffset + First;
1087 			}
1088 			else
1089 			{
1090 				OrigWidthOffset = -(WidthOffset + First);
1091 				OGLWidthOffset = 0;
1092 			}
1093 			OGLWidthFinish = std::min(static_cast<int>(TxtrWidth), WidthOffset + Last);
1094 		}
1095 		OrigStrip += OrigWidthOffset;
1096 
1097 		// smear first pixel to left edge
1098 		for (short w = 0; w < OGLWidthOffset; w++)
1099 			*(OGLStrip++) = ColorTable[*OrigStrip] & rgb_mask;
1100 
1101 		for (short w = OGLWidthOffset; w < OGLWidthFinish; w++)
1102 			*(OGLStrip++) = ColorTable[*(OrigStrip++)];
1103 
1104 		// smear last pixel to right edge
1105 		for (short w = OGLWidthFinish; w < TxtrWidth; w++)
1106 			*(OGLStrip++) = ColorTable[*(OrigStrip - 1)] & rgb_mask;
1107 	}
1108 
1109 	// smear first pixel row to top edge
1110 	for (short h = 0; h < OGLHeightOffset; h++)
1111 	{
1112 		uint32 *SrcStrip;
1113 		if (TextureType == OGL_Txtr_Landscape)
1114 		{
1115 			SrcStrip = &Buffer[TxtrWidth * (2 * OGLHeightOffset - h) - 1];
1116 		}
1117 		else
1118 		{
1119 			SrcStrip = &Buffer[TxtrWidth * OGLHeightOffset];
1120 		}
1121 		uint32 *OGLStrip = &Buffer[TxtrWidth * h];
1122 
1123 		for (short w = 0; w < TxtrWidth; w++)
1124 			*(OGLStrip++) = *(SrcStrip++) & rgb_mask;
1125 	}
1126 	// smear last pixel row to bottom edge
1127 	for (short h = OGLHeightFinish; h < TxtrHeight; h++)
1128 	{
1129 		uint32 *SrcStrip;
1130 		if (TextureType == OGL_Txtr_Landscape)
1131 		{
1132 			SrcStrip = &Buffer[TxtrWidth * (2 * OGLHeightFinish - h - 1)];
1133 		}
1134 		else
1135 		{
1136 			SrcStrip = &Buffer[TxtrWidth * (OGLHeightFinish - 1)];
1137 		}
1138 		uint32 *OGLStrip = &Buffer[TxtrWidth * h];
1139 
1140 		for (short w = 0; w < TxtrWidth; w++)
1141 			*(OGLStrip++) = *(SrcStrip++) & rgb_mask;
1142 	}
1143 
1144 	return Buffer;
1145 }
1146 
1147 
GetFakeLandscape()1148 uint32 *TextureManager::GetFakeLandscape()
1149 {
1150 	// Allocate and set to black and transparent
1151 	int NumPixels = int(TxtrWidth)*int(TxtrHeight);
1152 	uint32 *Buffer = new uint32[NumPixels];
1153 	objlist_clear(Buffer,NumPixels);
1154 
1155 	// Set up land and sky colors;
1156 	// be sure to idiot-proof out-of-range ones
1157 	OGL_ConfigureData& ConfigureData = Get_OGL_ConfigureData();
1158 	int LscpIndx = static_world->song_index;
1159 	if (!LandscapesLoaded || (LscpIndx < 0 && LscpIndx >= 4))
1160 	{
1161 		memset(Buffer,0,NumPixels*sizeof(uint32));
1162 		return Buffer;
1163 	}
1164 
1165 	RGBColor OrigLandColor = ConfigureData.LscpColors[LscpIndx][0];
1166 	RGBColor OrigSkyColor = ConfigureData.LscpColors[LscpIndx][1];
1167 
1168 	// Set up floating-point ones, complete with alpha channel
1169 	GLfloat LandColor[4], SkyColor[4];
1170 	MakeFloatColor(OrigLandColor,LandColor);
1171 	LandColor[3] = 1;
1172 	MakeFloatColor(OrigSkyColor,SkyColor);
1173 	SkyColor[3] = 1;
1174 
1175 	// Modify if infravision is active
1176 	if (IsInfravisionTable(CTable))
1177 	{
1178 		FindInfravisionVersionRGBA(Collection,LandColor);
1179 		FindInfravisionVersionRGBA(Collection,SkyColor);
1180 	}
1181 
1182 	uint32 TxtrLandColor = MakeIntColor(LandColor);
1183 	uint32 TxtrSkyColor = MakeIntColor(SkyColor);
1184 
1185 	// Textures' vertical dimension is upward;
1186 	// put in the land after the sky
1187 	uint32 *BufPtr = Buffer;
1188 	for (int h=0; h<TxtrHeight/2; h++)
1189 		for (int w=0; w<TxtrWidth; w++)
1190 			*(BufPtr++) = TxtrLandColor;
1191 	for (int h=0; h<TxtrHeight/2; h++)
1192 		for (int w=0; w<TxtrWidth; w++)
1193 			*(BufPtr++) = TxtrSkyColor;
1194 
1195 	return Buffer;
1196 }
1197 
1198 
Shrink(uint32 * Buffer)1199 uint32 *TextureManager::Shrink(uint32 *Buffer)
1200 {
1201 	int NumPixels = int(LoadedWidth)*int(LoadedHeight);
1202 	GLuint *NewBuffer = new GLuint[NumPixels];
1203 	gluScaleImage(GL_RGBA, TxtrWidth, TxtrHeight, GL_UNSIGNED_BYTE, Buffer,
1204 		LoadedWidth, LoadedHeight, GL_UNSIGNED_BYTE, NewBuffer);
1205 
1206 	return (uint32 *)NewBuffer;
1207 }
1208 
1209 
1210 // This places a texture into the OpenGL software and gives it the right
1211 // mapping attributes
PlaceTexture(const ImageDescriptor * Image,bool normal_map)1212 void TextureManager::PlaceTexture(const ImageDescriptor *Image, bool normal_map)
1213 {
1214 
1215 	bool mipmapsLoaded = false;
1216 
1217 	TxtrTypeInfoData& TxtrTypeInfo = TxtrTypeInfoList[TextureType];
1218 
1219 	GLenum internalFormat = TxtrTypeInfo.ColorFormat;
1220 	// some optimizations here:
1221 	if (TextureType == 1) // landscape
1222 	{
1223 		if (internalFormat == GL_RGBA8)
1224 			internalFormat = GL_RGB8;
1225 		else if (internalFormat == GL_RGBA4)
1226 			internalFormat = GL_RGB5;
1227 	}
1228 	else if (!IsBlended() && internalFormat == GL_RGBA4)
1229 	{
1230 		internalFormat = GL_RGB5_A1;
1231 	}
1232 
1233 	bool load_as_sRGB = (Wanting_sRGB && !normal_map &&
1234 						 Collection != _collection_interface &&
1235 						 Collection != _collection_weapons_in_hand);
1236 
1237 	if(load_as_sRGB) {
1238 	  switch(internalFormat) {
1239 	  case GL_RGB:
1240 	  case GL_R3_G3_B2:
1241 	  case GL_RGB4:
1242 	  case GL_RGB5:
1243 	  case GL_RGB8:
1244 	  case GL_RGB10:
1245 	  case GL_RGB12:
1246 	  case GL_RGB16:
1247 	    internalFormat = GL_SRGB;
1248 	    break;
1249 	  case GL_RGBA:
1250 	  case GL_RGBA2:
1251 	  case GL_RGBA4:
1252 	  case GL_RGB5_A1:
1253 	  case GL_RGBA8:
1254 	  case GL_RGB10_A2:
1255 	  case GL_RGBA12:
1256 	  case GL_RGBA16:
1257 	    internalFormat = GL_SRGB_ALPHA;
1258 	    break;
1259 #if defined(GL_ARB_texture_compression) && defined(GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
1260 	    /* These might not do anything... */
1261 	  case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1262 	    internalFormat = GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
1263 	    break;
1264 	  case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1265 	    internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
1266 	    break;
1267 	  case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
1268 	    internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
1269 	    break;
1270 	  case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1271 	    internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
1272 	    break;
1273 #endif
1274 	  }
1275 	}
1276 
1277 	if (Image->GetFormat() == ImageDescriptor::RGBA8) {
1278 		switch (TxtrTypeInfo.FarFilter)
1279 		{
1280 		case GL_NEAREST:
1281 		case GL_LINEAR:
1282 			glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, Image->GetWidth(), Image->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, Image->GetBuffer());
1283 			break;
1284 		case GL_NEAREST_MIPMAP_NEAREST:
1285 		case GL_LINEAR_MIPMAP_NEAREST:
1286 		case GL_NEAREST_MIPMAP_LINEAR:
1287 		case GL_LINEAR_MIPMAP_LINEAR:
1288 			if (Image->GetMipMapCount() > 1) {
1289 #ifdef GL_SGIS_generate_mipmap
1290 	if (useSGISMipmaps) {
1291 		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
1292 	}
1293 #endif
1294 				int i = 0;
1295 				for (i = 0; i < Image->GetMipMapCount(); i++) {
1296 					glTexImage2D(GL_TEXTURE_2D, i, internalFormat, max(1, Image->GetWidth() >> i), max(1, Image->GetHeight() >> i), 0, GL_RGBA, GL_UNSIGNED_BYTE, Image->GetMipMapPtr(i));
1297 				}
1298 				mipmapsLoaded = true;
1299 			} else {
1300 #ifdef GL_SGIS_generate_mipmap
1301 			if (useSGISMipmaps) {
1302 				glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
1303 				glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, Image->GetWidth(), Image->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, Image->GetBuffer());
1304 			} else
1305 #endif
1306 			{
1307 				gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat, Image->GetWidth(), Image->GetHeight(), GL_RGBA, GL_UNSIGNED_BYTE, Image->GetBuffer());
1308 			}
1309 			mipmapsLoaded = true;
1310 			}
1311 			break;
1312 		default:
1313 			assert(false);
1314 		}
1315 	} else if (Image->GetFormat() == ImageDescriptor::DXTC1 ||
1316 		   Image->GetFormat() == ImageDescriptor::DXTC3 ||
1317 		   Image->GetFormat() == ImageDescriptor::DXTC5)
1318 	{
1319 #if defined(GL_ARB_texture_compression) && defined(GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
1320 		if (Image->GetFormat() == ImageDescriptor::DXTC1)
1321 		  internalFormat = (load_as_sRGB) ? GL_COMPRESSED_SRGB_S3TC_DXT1_EXT : GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
1322 		else if (Image->GetFormat() == ImageDescriptor::DXTC3)
1323 		  internalFormat = (load_as_sRGB) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT : GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
1324 		else if (Image->GetFormat() == ImageDescriptor::DXTC5)
1325 		  internalFormat = (load_as_sRGB) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
1326 
1327 		switch(TxtrTypeInfo.FarFilter)
1328 		{
1329 		case GL_NEAREST:
1330 		case GL_LINEAR:
1331 			glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, internalFormat, Image->GetWidth(), Image->GetHeight(), 0, Image->GetMipMapSize(0), Image->GetBuffer());
1332 			break;
1333 		case GL_NEAREST_MIPMAP_NEAREST:
1334 		case GL_LINEAR_MIPMAP_NEAREST:
1335 		case GL_NEAREST_MIPMAP_LINEAR:
1336 		case GL_LINEAR_MIPMAP_LINEAR:
1337 			if (Image->GetMipMapCount() > 1) {
1338 #ifdef GL_SGIS_generate_mipmap
1339 				if (useSGISMipmaps) {
1340 					glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
1341 				}
1342 #endif
1343 				int i = 0;
1344 				for (i = 0; i < Image->GetMipMapCount(); i++) {
1345 					glCompressedTexImage2DARB(GL_TEXTURE_2D, i, internalFormat, max(1, Image->GetWidth() >> i), max(1, Image->GetHeight() >> i), 0, Image->GetMipMapSize(i), Image->GetMipMapPtr(i));
1346 				}
1347 				mipmapsLoaded = true;
1348 			} else {
1349 #if defined GL_SGIS_generate_mipmap
1350 				if (useSGISMipmaps) {
1351 					glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
1352 					mipmapsLoaded = true;
1353 				}
1354 #endif
1355 				glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, internalFormat, Image->GetWidth(), Image->GetHeight(), 0, Image->GetMipMapSize(0), Image->GetBuffer());
1356 			}
1357 			break;
1358 
1359 		default:
1360 			// Shouldn't happen
1361 			assert(false);
1362 		}
1363 #else
1364 		assert(false);
1365 #endif
1366 	}
1367 
1368 	// Set texture-mapping features
1369 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1370 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TxtrTypeInfo.NearFilter);
1371 	if ((TxtrTypeInfo.FarFilter == GL_NEAREST_MIPMAP_NEAREST || TxtrTypeInfo.FarFilter == GL_LINEAR_MIPMAP_NEAREST || TxtrTypeInfo.FarFilter == GL_NEAREST_MIPMAP_LINEAR || TxtrTypeInfo.FarFilter == GL_LINEAR_MIPMAP_LINEAR) && !mipmapsLoaded)
1372 	{
1373 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1374 	} else {
1375 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TxtrTypeInfo.FarFilter);
1376 	}
1377 
1378 	switch(TextureType)
1379 	{
1380 	case OGL_Txtr_Wall:
1381 		// Walls are tiled in both direction
1382 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1383 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1384 #if defined(GL_TEXTURE_MAX_ANISOTROPY_EXT)
1385                 // enable anisotropic filtering
1386                 {
1387                     float anisoLevel = Get_OGL_ConfigureData().AnisotropyLevel;
1388                     if (anisoLevel > 0.0) {
1389                         GLfloat max_aniso;
1390                         glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_aniso);
1391                         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0F + ((anisoLevel-1.0F)/15.0F)*(max_aniso-1.0F));
1392                     }
1393                 }
1394 #endif
1395 		break;
1396 
1397 	case OGL_Txtr_Landscape:
1398 		// Landscapes repeat horizontally, have vertical limits or repeats vertically
1399 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1400 		if (LandscapeVertRepeat)
1401 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1402 		else
1403 		{
1404 #if defined(GL_ARB_texture_mirrored_repeat)
1405 			if (useMirroredRepeat)
1406 			{
1407 				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT_ARB);
1408 			}
1409 			else
1410 #endif
1411 			{
1412 				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
1413 			}
1414 		}
1415 		break;
1416 
1417 	case OGL_Txtr_Inhabitant:
1418 	case OGL_Txtr_WeaponsInHand:
1419 		// Sprites have both horizontal and vertical limits
1420 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
1421 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
1422 		break;
1423 	}
1424 }
1425 
1426 // What to render:
1427 
1428 // Always call this one and call it first; safe to allocate texture ID's in it
RenderNormal()1429 void TextureManager::RenderNormal()
1430 {
1431 
1432 
1433 	TxtrStatePtr->Allocate(TextureType);
1434 
1435 	if (TxtrStatePtr->UseNormal())
1436 	{
1437 		assert(NormalBuffer || (NormalImage.get() && NormalImage.get()->IsPresent()));
1438 		if (NormalImage.get() && NormalImage.get()->IsPresent()) {
1439 			PlaceTexture(NormalImage.get());
1440 		}
1441 	}
1442 
1443 		gGLTxStats.binds++;
1444 		int time = 0;
1445 		gGLTxStats.totalBind += time;
1446 		if (gGLTxStats.minBind > time) gGLTxStats.minBind = time;
1447 		if (gGLTxStats.maxBind < time) gGLTxStats.maxBind = time;
1448 		if (time>2) gGLTxStats.longNormalSetups++;
1449 }
1450 
1451 // Call this one after RenderNormal()
RenderGlowing()1452 void TextureManager::RenderGlowing()
1453 {
1454 
1455 
1456 	if (TxtrStatePtr->UseGlowing())
1457 	{
1458 		assert(GlowBuffer || (GlowImage.get() && GlowImage.get()->IsPresent()));
1459 		if (GlowImage.get() && GlowImage.get()->IsPresent()) {
1460 			PlaceTexture(GlowImage.get());
1461 		}
1462 	}
1463 
1464 		gGLTxStats.binds++;
1465 		int time = 0;
1466 		gGLTxStats.totalBind += time;
1467 		if (gGLTxStats.minBind > time) gGLTxStats.minBind = time;
1468 		if (gGLTxStats.maxBind < time) gGLTxStats.maxBind = time;
1469 		if (time>2) gGLTxStats.longGlowSetups++;
1470 }
1471 
RenderBump()1472 void TextureManager::RenderBump()
1473 {
1474 	if (TxtrStatePtr->IsBumped) {
1475 		if (TxtrStatePtr->UseBump() && OffsetImage.get() && OffsetImage.get()->IsPresent())
1476 			PlaceTexture(OffsetImage.get(), true);
1477 	} else {
1478 		FlatBumpTexture();
1479 	}
1480 
1481 	gGLTxStats.binds++;
1482 	int time = 0;
1483 	gGLTxStats.totalBind += time;
1484 	if (gGLTxStats.minBind > time) gGLTxStats.minBind = time;
1485 	if (gGLTxStats.maxBind < time) gGLTxStats.maxBind = time;
1486 	if (time>2) gGLTxStats.longBumpSetups++;
1487 }
1488 
SetupTextureMatrix()1489 void TextureManager::SetupTextureMatrix()
1490 {
1491 	// set up the texture matrix
1492 	switch(TextureType)
1493 	{
1494 	case OGL_Txtr_Wall:
1495 	case OGL_Txtr_WeaponsInHand:
1496 	case OGL_Txtr_Inhabitant:
1497 		glMatrixMode(GL_TEXTURE);
1498 		glLoadIdentity();
1499 		if (TxtrOptsPtr->Substitution) {
1500 			// these come in right side up, but the renderer
1501 			// expects them to be upside down and sideways
1502 			glRotatef(90.0, 0.0, 0.0, 1.0);
1503 			glScalef(1.0, -1.0, 1.0);
1504 		}
1505 		glMatrixMode(GL_MODELVIEW);
1506 		break;
1507 	case OGL_Txtr_Landscape:
1508 		glMatrixMode(GL_TEXTURE);
1509 		glLoadIdentity();
1510 		if (TxtrOptsPtr->Substitution) {
1511 			// these come in right side up, and un-centered
1512 			// the renderer expects them upside down, and centered
1513 			glScalef(1.0, -U_Scale, 1.0);
1514 			glTranslatef(0.0, U_Offset, 0.0);
1515 		} else {
1516 			glScalef(1.0, U_Scale, 1.0);
1517 			glTranslatef(0.0, U_Offset, 0.0);
1518 		}
1519 		glMatrixMode(GL_MODELVIEW);
1520 		break;
1521 	}
1522 }
1523 
RestoreTextureMatrix()1524 void TextureManager::RestoreTextureMatrix()
1525 {
1526 	switch(TextureType)
1527 	{
1528 	case OGL_Txtr_Wall:
1529 	case OGL_Txtr_WeaponsInHand:
1530 	case OGL_Txtr_Inhabitant:
1531 	case OGL_Txtr_Landscape:
1532 		glMatrixMode(GL_TEXTURE);
1533 		glLoadIdentity();
1534 		glMatrixMode(GL_MODELVIEW);
1535 	}
1536 }
1537 
1538 
1539 
1540 // Init
TextureManager()1541 TextureManager::TextureManager()
1542 {
1543 	NormalBuffer = 0;
1544 	GlowBuffer = 0;
1545 
1546 	ShadingTables = NULL;
1547 	TransferMode = 0;
1548 	TransferData = 0;
1549 	IsShadeless = false;
1550 	TextureType = 0;
1551 	LandscapeVertRepeat = false;
1552 
1553 	TxtrStatePtr = 0;
1554 	TxtrOptsPtr = 0;
1555 
1556 	FastPath = 0;
1557 
1558 	LowLevelShape = 0;
1559 
1560 	// Marathon default
1561 	Landscape_AspRatExp = 1;
1562 }
1563 
1564 // Cleanup
~TextureManager()1565 TextureManager::~TextureManager()
1566 {
1567 	if (NormalBuffer != 0) delete []NormalBuffer;
1568 	if (GlowBuffer != 0) delete []GlowBuffer;
1569 }
1570 
OGL_ResetTextures()1571 void OGL_ResetTextures()
1572 {
1573 	// Fix for crashing bug when OpenGL is inactive
1574 	if (!OGL_IsActive()) return;
1575 
1576 	// Reset the textures:
1577 	for (int it=0; it<OGL_NUMBER_OF_TEXTURE_TYPES; it++)
1578 		for (int ic=0; ic<MAXIMUM_COLLECTIONS; ic++)
1579 		{
1580 			bool CollectionPresent = is_collection_present(ic);
1581 			short NumberOfBitmaps =
1582 				CollectionPresent ? get_number_of_collection_bitmaps(ic) : 0;
1583 
1584 			CollBitmapTextureState *CBTSSet = TextureStateSets[it][ic];
1585 			for (int ib=0; ib<NumberOfBitmaps; ib++)
1586 			{
1587 				TextureState *TSSet = CBTSSet[ib].CTStates;
1588 				for (int ist=0; ist<NUMBER_OF_OPENGL_BITMAP_SETS; ist++)
1589 					TSSet[ist].Reset();
1590 			}
1591 		}
1592 
1593 	// Reset the surface textures for all the models:
1594 	OGL_ResetModelSkins(OGL_IsActive());
1595 
1596 	// Reset the font textures
1597 	FontSpecifier::OGL_ResetFonts(false);
1598 
1599 	// Reset blitters
1600 	OGL_Blitter::StopTextures();
1601 
1602 	glDeleteTextures(1, &flatBumpTextureID);
1603 	flatBumpTextureID = 0;
1604 }
1605 
1606 
LoadModelSkin(ImageDescriptor & SkinImage,short Collection,short CLUT)1607 void LoadModelSkin(ImageDescriptor& SkinImage, short Collection, short CLUT)
1608 {
1609 	// A lot of this is copies of TextureManager member code
1610 
1611 	ImageDescriptorManager Image;
1612 	Image.set(&SkinImage);
1613 
1614 	int TxtrWidth = Image.get()->GetWidth();
1615 	int TxtrHeight = Image.get()->GetHeight();
1616 
1617 	bool IsInfravision = IsInfravisionTable(CLUT);
1618 	bool IsSilhouette = IsSilhouetteTable(CLUT);
1619 
1620 	if (IsInfravision)
1621 		FindInfravisionVersion(Collection, Image);
1622 	else if (IsSilhouette)
1623 		FindSilhouetteVersion(Image);
1624 
1625 	TxtrTypeInfoData& TxtrTypeInfo = ModelSkinInfo;
1626 
1627 	// Display size: may be shrunk
1628 	int LoadedWidth = MAX(TxtrWidth >> TxtrTypeInfo.Resolution, 1);
1629 	int LoadedHeight = MAX(TxtrHeight >> TxtrTypeInfo.Resolution, 1);
1630 
1631 	// Fit the image into the maximum size allowed by the OpenGL implementation in use
1632 	GLint MaxTextureSize;
1633 	glGetIntegerv(GL_MAX_TEXTURE_SIZE,&MaxTextureSize);
1634 	while (LoadedWidth > MaxTextureSize || LoadedHeight > MaxTextureSize)
1635 	{
1636 		LoadedWidth >>= 1;
1637 		LoadedHeight >>= 1;
1638 	}
1639 
1640 	while (Image.get()->GetWidth() > LoadedWidth || Image.get()->GetHeight() > LoadedHeight)
1641 	{
1642 		if (!Image.edit()->Minify()) break;
1643 	}
1644 
1645 	bool mipmapsLoaded = false;
1646 
1647 	// Load the texture
1648 	GLenum internalFormat = TxtrTypeInfo.ColorFormat;
1649 	if (Image.get()->GetFormat() == ImageDescriptor::RGBA8)
1650 	{
1651 		switch(TxtrTypeInfo.FarFilter)
1652 		{
1653 		case GL_NEAREST:
1654 		case GL_LINEAR:
1655 			glTexImage2D(GL_TEXTURE_2D, 0, TxtrTypeInfo.ColorFormat, LoadedWidth, LoadedHeight,
1656 				     0, GL_RGBA, GL_UNSIGNED_BYTE, Image.get()->GetBuffer());
1657 			break;
1658 		case GL_NEAREST_MIPMAP_NEAREST:
1659 		case GL_LINEAR_MIPMAP_NEAREST:
1660 		case GL_NEAREST_MIPMAP_LINEAR:
1661 		case GL_LINEAR_MIPMAP_LINEAR:
1662 			if (Image.get()->GetMipMapCount() > 1)
1663 			{
1664 #ifdef GL_SGIS_generate_mipmap
1665 				if (useSGISMipmaps) {
1666 					glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
1667 				}
1668 #endif
1669 				int i = 0;
1670 				for (i = 0; i < Image.get()->GetMipMapCount(); i++)
1671 				{
1672 					glTexImage2D(GL_TEXTURE_2D, i, internalFormat, max(1, Image.get()->GetWidth() >> i), max(1, Image.get()->GetHeight() >> i), 0, GL_RGBA, GL_UNSIGNED_BYTE, Image.get()->GetMipMapPtr(i));
1673 				}
1674 				mipmapsLoaded = true;
1675 			}
1676 			else
1677 			{
1678 #ifdef GL_SGIS_generate_mipmap
1679 				if (useSGISMipmaps)
1680 				{
1681 					glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
1682 					glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, Image.get()->GetWidth(), Image.get()->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, Image.get()->GetBuffer());
1683 				}
1684 				else
1685 #endif
1686 				{
1687 					gluBuild2DMipmaps(GL_TEXTURE_2D, TxtrTypeInfo.ColorFormat, LoadedWidth, LoadedHeight,
1688 							  GL_RGBA, GL_UNSIGNED_BYTE, Image.get()->GetBuffer());
1689 				}
1690 				mipmapsLoaded = true;
1691 			}
1692 			break;
1693 
1694 		default:
1695 			// Shouldn't happen
1696 			assert(false);
1697 		}
1698 	}
1699 	else if (Image.get()->GetFormat() == ImageDescriptor::DXTC1 ||
1700 		 Image.get()->GetFormat() == ImageDescriptor::DXTC3 ||
1701 		 Image.get()->GetFormat() == ImageDescriptor::DXTC5)
1702 	{
1703 #if defined (GL_ARB_texture_compression) && defined(GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
1704 		if (Image.get()->GetFormat() == ImageDescriptor::DXTC1)
1705 			internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
1706 		else if (Image.get()->GetFormat() == ImageDescriptor::DXTC3)
1707 			internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
1708 		else if (Image.get()->GetFormat() == ImageDescriptor::DXTC5)
1709 			internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
1710 
1711 		switch (TxtrTypeInfo.FarFilter)
1712 		{
1713 		case GL_NEAREST:
1714 		case GL_LINEAR:
1715 			glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, internalFormat, Image.get()->GetWidth(), Image.get()->GetHeight(), 0, Image.get()->GetMipMapSize(0), Image.get()->GetBuffer());
1716 			break;
1717 		case GL_NEAREST_MIPMAP_NEAREST:
1718 		case GL_LINEAR_MIPMAP_NEAREST:
1719 		case GL_NEAREST_MIPMAP_LINEAR:
1720 		case GL_LINEAR_MIPMAP_LINEAR:
1721 			if (Image.get()->GetMipMapCount() > 1)
1722 			{
1723 #ifdef GL_SGIS_generate_mipmap
1724 				if (useSGISMipmaps)
1725 				{
1726 					glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
1727 				}
1728 #endif
1729 				int i = 0;
1730 				for (i = 0; i < Image.get()->GetMipMapCount(); i++)
1731 				{
1732 					glCompressedTexImage2DARB(GL_TEXTURE_2D, i, internalFormat, max(1, Image.get()->GetWidth() >> i), max(1, Image.get()->GetHeight() >> i), 0, Image.get()->GetMipMapSize(i), Image.get()->GetMipMapPtr(i));
1733 				}
1734 				mipmapsLoaded = true;
1735 			}
1736 			else
1737 			{
1738 #ifdef GL_SGIS_generate_mipmap
1739 				if (useSGISMipmaps)
1740 				{
1741 					glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
1742 					mipmapsLoaded = true;
1743 				}
1744 #endif
1745 				glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, internalFormat, Image.get()->GetWidth(), Image.get()->GetHeight(), 0, Image.get()->GetMipMapSize(0), Image.get()->GetBuffer());
1746 			}
1747 			break;
1748 
1749 		default:
1750 			// Shouldn't happen
1751 			assert(false);
1752 		}
1753 #else
1754 		assert(false);
1755 #endif
1756 	}
1757 
1758 	// Set texture-mapping features
1759 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1760 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TxtrTypeInfo.NearFilter);
1761 	if ((TxtrTypeInfo.FarFilter == GL_NEAREST_MIPMAP_NEAREST || TxtrTypeInfo.FarFilter == GL_LINEAR_MIPMAP_NEAREST || TxtrTypeInfo.FarFilter == GL_NEAREST_MIPMAP_LINEAR || TxtrTypeInfo.FarFilter == GL_LINEAR_MIPMAP_LINEAR) && !mipmapsLoaded)
1762 	{
1763 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1764 	}
1765 	else
1766 	{
1767 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TxtrTypeInfo.FarFilter);
1768 	}
1769 
1770 
1771 	// Like sprites, model textures have both horizontal and vertical limits
1772 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
1773 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
1774 
1775 }
1776 
1777 
1778 // Infravision (I'm blue, are you?)
IsInfravisionActive()1779 bool& IsInfravisionActive() {return InfravisionActive;}
1780 
1781 
1782 // Sets the infravision tinting color for a shapes collection, and whether to use such tinting;
1783 // the color values are from 0 to 1.
SetInfravisionTint(short Collection,bool IsTinted,float Red,float Green,float Blue)1784 bool SetInfravisionTint(short Collection, bool IsTinted, float Red, float Green, float Blue)
1785 {
1786 	assert(Collection >= 0 && Collection < NUMBER_OF_COLLECTIONS);
1787 	InfravisionData& IVData = IVDataList[Collection];
1788 
1789 	IVData.Red = Red;
1790 	IVData.Green = Green;
1791 	IVData.Blue = Blue;
1792 	IVData.IsTinted = IsTinted;
1793 
1794 	return true;
1795 }
1796 
1797 
1798 // Finds the infravision version of a color for some collection set;
1799 // it makes no change if infravision is inactive.
FindInfravisionVersionRGBA(short Collection,GLfloat * Color)1800 void FindInfravisionVersionRGBA(short Collection, GLfloat *Color)
1801 {
1802 	if (!InfravisionActive) return;
1803 
1804 	InfravisionData& IVData = IVDataList[Collection];
1805 	if (!IVData.IsTinted) return;
1806 
1807 	GLfloat AvgColor = (Color[0] + Color[1] + Color[2])/3;
1808 	Color[0] = IVData.Red*AvgColor;
1809 	Color[1] = IVData.Green*AvgColor;
1810 	Color[2] = IVData.Blue*AvgColor;
1811 }
1812 
1813 
1814 // Mass-production version of above; suitable for textures
FindInfravisionVersionRGBA(short Collection,int NumPixels,uint32 * Pixels)1815 void FindInfravisionVersionRGBA(short Collection, int NumPixels, uint32 *Pixels)
1816 {
1817 	if (!InfravisionActive) return;
1818 
1819 	InfravisionData& IVData = IVDataList[Collection];
1820 	if (!IVData.IsTinted) return;
1821 
1822 	// OK to use marching-pointer optimization here;
1823 	// the float-to-int and int-to-float conversions have been simplified,
1824 	// because the infravision-value-finding does not care if the values
1825 	// had been multipled by 255 (int <-> float color-value multiplier/divider)
1826 	for (int k=0; k<NumPixels; k++, Pixels++)
1827 	{
1828 		uint8 *PxlPtr = (uint8 *)Pixels;
1829 		GLfloat AvgColor = GLfloat(int(PxlPtr[0]) + int(PxlPtr[1]) + int(PxlPtr[2]))/3;
1830 		PxlPtr[0] = PIN(int(IVData.Red*AvgColor + 0.5),0,255);
1831 		PxlPtr[1] = PIN(int(IVData.Green*AvgColor + 0.5),0,255);
1832 		PxlPtr[2] = PIN(int(IVData.Blue*AvgColor + 0.5),0,255);
1833 	}
1834 }
1835 
FindInfravisionVersionDXTCColor(SDL_Color tint,uint16 color)1836 static inline uint16 FindInfravisionVersionDXTCColor(SDL_Color tint, uint16 color)
1837 {
1838 	uint16 grayscale = (((color & 0xf800) >> 11) + ((color & 0x7e0) >> 6) + (color & 0x1f)) / 3;
1839 
1840 	uint16 r = (grayscale * tint.r) / 256;
1841 	uint16 g = (grayscale * tint.g) / 256;
1842 	uint16 b = (grayscale * tint.b) / 256;
1843 
1844 	return (r << 11) | (g << 6) | (g > 15 ? 0x20 : 0) | b;
1845 }
1846 
FindInfravisionVersionDXTC1(InfravisionData & IVData,int NumBytes,unsigned char * buffer)1847 void FindInfravisionVersionDXTC1(InfravisionData& IVData, int NumBytes, unsigned char *buffer)
1848 {
1849 	assert(NumBytes % 8 == 0);
1850 
1851 	uint16 *pixels = (uint16 *) buffer;
1852 
1853 	SDL_Color tint;
1854 	tint.r = PIN(int(IVData.Red * 256), 0, 255);
1855 	tint.g = PIN(int(IVData.Green * 256), 0, 255);
1856 	tint.b = PIN(int(IVData.Blue* 256), 0, 255);
1857 	tint.a = 0xff;
1858 
1859 	// the first two uint16s in each block are our colors
1860 	for (int i = 0; i < NumBytes / 4; i++) {
1861 
1862 		uint16 c1 = SDL_SwapLE16(pixels[i * 4]);
1863 		uint16 c2 = SDL_SwapLE16(pixels[i * 4 + 1]);
1864 		uint16 new_c1 = FindInfravisionVersionDXTCColor(tint, c1);
1865 		uint16 new_c2 = FindInfravisionVersionDXTCColor(tint, c2);
1866 
1867 		// DXTC1 uses c1 > c2 to determine whether to make certain
1868 		// pixels transparent
1869 		// if c1 and c2 happen to come out of the infravision algorithm
1870 		// the same, we have to chamge one so that pixels don't become
1871 		// transparent that were opaque, or vice versa
1872 		if (new_c1 == new_c2) {
1873 			if (c1 > c2)
1874 				if (new_c2) new_c2 -= 1;
1875 				else new_c1 += 1;
1876 			else
1877 				if (new_c1) new_c1 -= 1;
1878 				else new_c2 += 1;
1879 		}
1880 		// likewise, in the unlikely state that infravision ends up
1881 		// making one bigger than the other, swap them back
1882 		else if ((new_c1 > new_c2) != (c1 > c2)) {
1883 			SWAP(new_c1, new_c2);
1884 		}
1885 		pixels[i * 4] = SDL_SwapLE16(new_c1);
1886 		pixels[i * 4 + 1] = SDL_SwapLE16(new_c2);
1887 	}
1888 }
1889 
FindInfavisionVersionDXTC35(InfravisionData & IVData,int NumBytes,unsigned char * buffer)1890 void FindInfavisionVersionDXTC35(InfravisionData &IVData, int NumBytes, unsigned char *buffer)
1891 {
1892 	assert(NumBytes % 16 == 0);
1893 
1894 	uint16 *pixels = (uint16 *) buffer;
1895 
1896 	SDL_Color tint;
1897 	tint.r = PIN(int(IVData.Red * 256), 0, 255);
1898 	tint.g = PIN(int(IVData.Green * 256), 0, 255);
1899 	tint.b = PIN(int(IVData.Blue* 256), 0, 255);
1900 	tint.a = 0xff;
1901 
1902 	for (int i = 0; i < NumBytes / 8; i++) {
1903 		uint16 *c1 = &pixels[i * 8 + 4];
1904 		uint16 *c2 = &pixels[i * 8 + 5];
1905 
1906 		uint16 new_c1 = FindInfravisionVersionDXTCColor(tint, SDL_SwapLE16(*c1));
1907 		uint16 new_c2 = FindInfravisionVersionDXTCColor(tint, SDL_SwapLE16(*c2));
1908 
1909 		*c1 = SDL_SwapLE16(new_c1);
1910 		*c2 = SDL_SwapLE16(new_c2);
1911 	}
1912 }
1913 
FindInfravisionVersion(short Collection,ImageDescriptorManager & imageManager)1914 void FindInfravisionVersion(short Collection, ImageDescriptorManager &imageManager)
1915 {
1916 	if (!InfravisionActive) return;
1917 	InfravisionData& IVData = IVDataList[Collection];
1918 	if (!IVData.IsTinted) return;
1919 
1920 	if (!imageManager.get() || !imageManager.get()->IsPresent())
1921 		return;
1922 
1923 	if (imageManager.get()->GetFormat() == ImageDescriptor::RGBA8) {
1924 		FindInfravisionVersionRGBA(Collection, imageManager.edit()->GetBufferSize() / 4, imageManager.edit()->GetBuffer());
1925 	} else if (imageManager.get()->GetFormat() == ImageDescriptor::DXTC1) {
1926 		FindInfravisionVersionDXTC1(IVData, imageManager.edit()->GetBufferSize(), (unsigned char *) imageManager.edit()->GetBuffer());
1927 	} else if (imageManager.get()->GetFormat() == ImageDescriptor::DXTC3 || imageManager.get()->GetFormat() == ImageDescriptor::DXTC5) {
1928 		FindInfavisionVersionDXTC35(IVData, imageManager.edit()->GetBufferSize(), (unsigned char *) imageManager.edit()->GetBuffer());
1929 	}
1930 }
1931 
FindSilhouetteVersionDXTC1(int NumBytes,unsigned char * buffer)1932 void FindSilhouetteVersionDXTC1(int NumBytes, unsigned char *buffer)
1933 {
1934 	uint16 *pixels = (uint16 *) buffer;
1935 
1936 	for (int i = 0; i < NumBytes / 4; i++)
1937 	{
1938 		if (SDL_SwapLE16(pixels[i * 4]) > SDL_SwapLE16(pixels[i * 4 + 1]))
1939 		{
1940 			pixels[i * 4 + 1] = PlatformIsLittleEndian() ? 0xffdf : 0xdfff;
1941 		}
1942 		else
1943 		{
1944 			pixels[i * 4 + 1] = 0xffff;
1945 		}
1946 		pixels[i * 4] = 0xffff;
1947 	}
1948 }
1949 
FindSilhouetteVersionDXTC35(int NumBytes,unsigned char * buffer)1950 void FindSilhouetteVersionDXTC35(int NumBytes, unsigned char *buffer)
1951 {
1952 	uint16 *pixels = (uint16 *) buffer;
1953 
1954 	for (int i = 0; i < NumBytes / 8; i++)
1955 	{
1956 		pixels[i * 8 + 4] = 0xffff;
1957 		pixels[i * 8 + 5] = PlatformIsLittleEndian() ? 0xffdf : 0xdfff;
1958 	}
1959 }
1960 
FindSilhouetteVersionRGBA(int NumPixels,uint32 * Pixels)1961 void FindSilhouetteVersionRGBA(int NumPixels, uint32 *Pixels)
1962 {
1963 	for (int i = 0; i < NumPixels; i++)
1964 	{
1965 		Pixels[i] |= PlatformIsLittleEndian() ? 0x00ffffff : 0xffffff00;
1966 	}
1967 }
1968 
FindSilhouetteVersion(ImageDescriptorManager & imageManager)1969 void FindSilhouetteVersion(ImageDescriptorManager &imageManager)
1970 {
1971 	if (imageManager.get()->GetFormat() == ImageDescriptor::RGBA8)
1972 	{
1973 		FindSilhouetteVersionRGBA(imageManager.edit()->GetBufferSize() / 4, imageManager.edit()->GetBuffer());
1974 	}
1975 	else if (imageManager.get()->GetFormat() == ImageDescriptor::DXTC1)
1976 	{
1977 		FindSilhouetteVersionDXTC1(imageManager.edit()->GetBufferSize(), (unsigned char *) imageManager.edit()->GetBuffer());
1978 	}
1979 	else if (imageManager.get()->GetFormat() == ImageDescriptor::DXTC3 || imageManager.get()->GetFormat() == ImageDescriptor::DXTC5)
1980 	{
1981 		FindSilhouetteVersionDXTC35(imageManager.edit()->GetBufferSize(), (unsigned char *) imageManager.edit()->GetBuffer());
1982 	}
1983 	imageManager.edit()->PremultipliedAlpha = false;
1984 }
1985 
SetPixelOpacitiesDXTC3Row(int scale,int shift,uint16 alpha)1986 static inline uint16 SetPixelOpacitiesDXTC3Row(int scale, int shift, uint16 alpha)
1987 {
1988 	uint16 a1 = (alpha >> 12) & 0xf;
1989 	uint16 a2 = (alpha >> 8) & 0xf;
1990 	uint16 a3 = (alpha >> 4) & 0xf;
1991 	uint16 a4 = alpha & 0xf;
1992 
1993 	a1 = PIN((a1 * scale) / 16 + shift, 0, 15);
1994 	a2 = PIN((a2 * scale) / 16 + shift, 0, 15);
1995 	a3 = PIN((a3 * scale) / 16 + shift, 0, 15);
1996 	a4 = PIN((a4 * scale) / 16 + shift, 0, 15);
1997 
1998 	return ((a1 << 12) | (a2 << 8) | (a3 << 4) | a4);
1999 }
2000 
SetPixelOpacitiesDXTC3(OGL_TextureOptions & Options,int NumBytes,unsigned char * buffer)2001 void SetPixelOpacitiesDXTC3(OGL_TextureOptions& Options, int NumBytes, unsigned char *buffer)
2002 {
2003 	assert(NumBytes % 16 == 0);
2004 
2005 	uint16 *rows = (uint16 *) buffer;
2006 
2007 	int scale = PIN(int(Options.OpacityScale * 16), 0, 16);
2008 	int shift = PIN(int(Options.OpacityShift * 16), -16, 16);
2009 
2010 	for (int i = 0; i < NumBytes / 8; i++) {
2011 		uint16 *a1 = &rows[i * 8];
2012 		uint16 *a2 = &rows[i * 8 + 1];
2013 		uint16 *a3 = &rows[i * 8 + 2];
2014 		uint16 *a4 = &rows[i * 8 + 3];
2015 		*a1 = SetPixelOpacitiesDXTC3Row(scale, shift, *a1);
2016 		*a2 = SetPixelOpacitiesDXTC3Row(scale, shift, *a2);
2017 		*a3 = SetPixelOpacitiesDXTC3Row(scale, shift, *a3);
2018 		*a4 = SetPixelOpacitiesDXTC3Row(scale, shift, *a4);
2019 	}
2020 
2021 }
2022 
SetPixelOpacitiesDXTC5Pair(int scale,int shift,uint16 alpha)2023 static inline uint16 SetPixelOpacitiesDXTC5Pair(int scale, int shift, uint16 alpha)
2024 {
2025 	uint16 a1 = alpha >> 8;
2026 	uint16 a2 = alpha & 0xff;
2027 
2028 	uint16 new_a1 = PIN((a1 * scale) / 256 + shift, 0, 255);
2029 	uint16 new_a2 = PIN((a2 * scale) / 256 + shift, 0, 255);
2030 
2031 	if (new_a1 == new_a2 && a1 != a2)
2032 		if (a1 > a2)
2033 			if (new_a2) new_a2--;
2034 			else new_a1++;
2035 		else
2036 			if (new_a1) new_a1--;
2037 			else new_a2++;
2038 	else if ((new_a1 > new_a2) != (a1 > a2))
2039 		SWAP(new_a1, new_a2);
2040 
2041 	return (new_a1 << 8 | new_a2);
2042 }
2043 
SetPixelOpacitiesDXTC5(OGL_TextureOptions & Options,int NumBytes,unsigned char * buffer)2044 void SetPixelOpacitiesDXTC5(OGL_TextureOptions& Options, int NumBytes, unsigned char *buffer)
2045 {
2046 	assert (NumBytes % 16 == 0);
2047 
2048 	uint16 *pixels = (uint16 *) buffer;
2049 
2050 	int scale = PIN(int(Options.OpacityScale * 256), 0, 256);
2051 	int shift = PIN(int(Options.OpacityShift * 256), -256, 256);
2052 
2053 	for (int i = 0; i < NumBytes / 8; i++) {
2054 		pixels[i * 8] = SDL_SwapLE16(SetPixelOpacitiesDXTC5Pair(scale, shift, SDL_SwapLE16(pixels[i * 8])));
2055 	}
2056 }
2057 
2058 
SetPixelOpacities(OGL_TextureOptions & Options,ImageDescriptorManager & imageManager)2059 void SetPixelOpacities(OGL_TextureOptions& Options, ImageDescriptorManager &imageManager)
2060 {
2061 	if (Options.OpacityType != OGL_OpacType_Avg && Options.OpacityType != OGL_OpacType_Max && Options.OpacityScale == 1.0 && Options.OpacityShift == 0.0)
2062 		return;
2063 
2064 	if (imageManager.get()->GetFormat() == ImageDescriptor::RGBA8) {
2065 
2066 		SetPixelOpacitiesRGBA(Options, imageManager.edit()->GetBufferSize() / 4, imageManager.edit()->GetBuffer());
2067 
2068 	} else if (imageManager.get()->GetFormat() == ImageDescriptor::DXTC3) {
2069 
2070 		// to do opac_type we have to decompress the texture
2071 		if (Options.OpacityType == OGL_OpacType_Avg || Options.OpacityType == OGL_OpacType_Max) {
2072 			if (imageManager.edit()->MakeRGBA()) {
2073 				SetPixelOpacitiesRGBA(Options, imageManager.edit()->GetBufferSize() / 4, imageManager.edit()->GetBuffer());
2074 			} else if (Options.OpacityScale == 1.0 && Options.OpacityShift == 0.0) {
2075 				return;
2076 			} else {
2077 				SetPixelOpacitiesDXTC3(Options, imageManager.edit()->GetBufferSize() / 4, (unsigned char *) imageManager.edit()->GetBuffer());
2078 			}
2079 		} else {
2080 			// if it's just scale/shift, we can do without decompressing
2081 			SetPixelOpacitiesDXTC3(Options, imageManager.edit()->GetBufferSize(), (unsigned char *) imageManager.edit()->GetBuffer());
2082 		}
2083 
2084 	} else if (imageManager.get()->GetFormat() == ImageDescriptor::DXTC5) {
2085 		if (Options.OpacityType == OGL_OpacType_Avg || Options.OpacityType == OGL_OpacType_Max) {
2086 			if (imageManager.edit()->MakeRGBA()) {
2087 				SetPixelOpacitiesRGBA(Options, imageManager.edit()->GetBufferSize() / 4, imageManager.edit()->GetBuffer());
2088 			} else if (Options.OpacityScale == 1.0 && Options.OpacityShift == 0.0) {
2089 				return;
2090 			} else {
2091 				SetPixelOpacitiesDXTC5(Options, imageManager.edit()->GetBufferSize() / 4, (unsigned char *) imageManager.edit()->GetBuffer());
2092 			}
2093 		} else {
2094 			SetPixelOpacitiesDXTC5(Options, imageManager.edit()->GetBufferSize(), (unsigned char *) imageManager.edit()->GetBuffer());
2095 		}
2096 	} else {
2097 		// we have to decompress DXTC1 to do anything
2098 		if (imageManager.edit()->MakeRGBA()) {
2099 			SetPixelOpacitiesRGBA(Options, imageManager.edit()->GetBufferSize() / 4, imageManager.edit()->GetBuffer());
2100 		}
2101 	}
2102 
2103 }
2104 
2105 
2106 // Does this for a set of several pixel values or color-table values;
2107 // the pixels are assumed to be in OpenGL-friendly byte-by-byte RGBA format.
SetPixelOpacitiesRGBA(OGL_TextureOptions & Options,int NumPixels,uint32 * Pixels)2108 void SetPixelOpacitiesRGBA(OGL_TextureOptions& Options, int NumPixels, uint32 *Pixels)
2109 {
2110 	for (int k=0; k<NumPixels; k++)
2111 	{
2112 		uint8 *PxlPtr = (uint8 *)(Pixels + k);
2113 
2114 		// This won't be scaled to (0,1), but will be left at (0,255) here
2115 		float Opacity;
2116 		switch(Options.OpacityType)
2117 		{
2118 		// Two versions of the Tomb Raider texture-opacity hack
2119 		case OGL_OpacType_Avg:
2120 			{
2121 				uint32 Red = uint32(PxlPtr[0]);
2122 				uint32 Green = uint32(PxlPtr[1]);
2123 				uint32 Blue = uint32(PxlPtr[2]);
2124 				Opacity = (Red + Green + Blue)/3.0F;
2125 			}
2126 			break;
2127 
2128 		case OGL_OpacType_Max:
2129 			{
2130 				uint32 Red = uint32(PxlPtr[0]);
2131 				uint32 Green = uint32(PxlPtr[1]);
2132 				uint32 Blue = uint32(PxlPtr[2]);
2133 				Opacity = (float)MAX(MAX(Red,Green),Blue);
2134 			}
2135 			break;
2136 
2137 		// Use pre-existing alpha value; useful if the opacity was loaded from a mask image
2138 		default:
2139 			Opacity = PxlPtr[3];
2140 			break;
2141 		}
2142 
2143 		// Scale, shift, and put back the edited opacity;
2144 		// round off and pin to the appropriate range.
2145 		// The shift has to be scaled to the color-channel range (1 -> 255).
2146 		PxlPtr[3] = PIN(int32(Options.OpacityScale*Opacity + 255*Options.OpacityShift + 0.5),0,255);
2147 	}
2148 }
2149 
2150 /*
2151 // Stuff for doing 16->32 pixel-format conversion, 1555 ARGB to 8888 RGBA
2152 GLuint *ConversionTable_16to32 = NULL;
2153 
2154 void MakeConversion_16to32(int BitDepth)
2155 {
2156 	// This is for allocating a 16->32 conversion table only when necessary
2157 	if (BitDepth == 16 && (!ConversionTable_16to32))
2158 	{
2159 		// Allocate it
2160 		int TableSize = (1 << 15);
2161 		ConversionTable_16to32 = new GLuint[TableSize];
2162 
2163 		// Fill it
2164 		for (word InVal = 0; InVal < TableSize; InVal++)
2165 			ConversionTable_16to32[InVal] = Convert_16to32(InVal);
2166 	}
2167 	else if (ConversionTable_16to32)
2168 	{
2169 		// Get rid of it
2170 		delete []ConversionTable_16to32;
2171 		ConversionTable_16to32 = NULL;
2172 	}
2173 }
2174 */
2175 
2176 #endif // def HAVE_OPENGL
2177