1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * Palette Allocator for IBM PC.
22  */
23 
24 #include "tinsel/dw.h"		// TBLUE1 definition
25 #include "tinsel/graphics.h"
26 #include "tinsel/handle.h"	// LockMem definition
27 #include "tinsel/palette.h"	// palette allocator structures etc.
28 #include "tinsel/sysvar.h"
29 #include "tinsel/tinsel.h"
30 
31 #include "common/system.h"
32 #include "common/textconsole.h"
33 #include "graphics/palette.h"
34 
35 namespace Tinsel {
36 
37 //----------------- LOCAL DEFINES --------------------
38 
39 /** video DAC transfer Q structure */
40 struct VIDEO_DAC_Q {
41 	union {
42 		SCNHANDLE hRGBarray;	///< handle of palette or
43 		COLORREF *pRGBarray;	///< list of palette colors
44 		COLORREF  singleRGB;
45 	} pal;
46 	bool bHandle;		///< when set - use handle of palette
47 	int destDACindex;	///< start index of palette in video DAC
48 	int numColors;		///< number of colors in "hRGBarray"
49 };
50 
51 
52 //----------------- LOCAL GLOBAL DATA --------------------
53 
54 // FIXME: Avoid non-const global vars
55 
56 /** palette allocator data */
57 static PALQ g_palAllocData[NUM_PALETTES];
58 
59 
60 /** video DAC transfer Q length */
61 #define VDACQLENGTH (NUM_PALETTES+2)
62 
63 /** video DAC transfer Q */
64 static VIDEO_DAC_Q g_vidDACdata[VDACQLENGTH];
65 
66 /** video DAC transfer Q head pointer */
67 static VIDEO_DAC_Q *g_pDAChead;
68 
69 /** color index of the 4 colors used for the translucent palette */
70 #define COL_HILIGHT	TBLUE1
71 
72 /** the translucent palette lookup table */
73 uint8 g_transPalette[MAX_COLORS];	// used in graphics.cpp
74 
75 static int g_translucentIndex	= 228;
76 
77 static int g_talkIndex		= 233;
78 
79 static COLORREF g_talkColRef;
80 
81 static COLORREF g_tagColRef;
82 
83 
84 #ifdef DEBUG
85 // diagnostic palette counters
86 static int numPals = 0;
87 static int maxPals = 0;
88 static int maxDACQ = 0;
89 #endif
90 
91 /**
92  * Map PSX palettes to original palette from resource file
93  */
psxPaletteMapper(PALQ * originalPal,uint8 * psxClut,byte * mapperTable)94 void psxPaletteMapper(PALQ *originalPal, uint8 *psxClut, byte *mapperTable) {
95 	PALETTE *pal = (PALETTE *)LockMem(originalPal->hPal);
96 	bool colorFound = false;
97 	uint16 clutEntry = 0;
98 
99 	// Empty the table with color correspondences
100 	memset(mapperTable, 0, 16);
101 
102 	for (int j = 1; j < 16; j++) {
103 		clutEntry = READ_16(psxClut + (sizeof(uint16) * j));
104 		if (clutEntry) {
105 			if (clutEntry == 0x7EC0) { // This is an already known value, used by the in-game text
106 				mapperTable[j] = 232;
107 				continue;
108 			}
109 
110 			// Check for correspondent color
111 			for (uint i = 0; (i < FROM_32(pal->numColors)) && !colorFound; i++) {
112 				// get R G B values in the same way as psx format converters
113 				uint16 psxEquivalent = TINSEL_PSX_RGB(TINSEL_GetRValue(pal->palRGB[i]) >> 3, TINSEL_GetGValue(pal->palRGB[i]) >> 3, TINSEL_GetBValue(pal->palRGB[i]) >> 3);
114 
115 				if (psxEquivalent == clutEntry) {
116 					mapperTable[j] = i + 1; // Add entry in the table for the found color
117 					colorFound = true;
118 				}
119 			}
120 			colorFound = false;
121 		} else { // The rest of the entries are zeroes
122 			return;
123 		}
124 	}
125 }
126 
127 /**
128  * Transfer palettes in the palette Q to Video DAC.
129  */
PalettesToVideoDAC()130 void PalettesToVideoDAC() {
131 	PALQ *pPalQ;				// palette Q iterator
132 	VIDEO_DAC_Q *pDACtail = g_vidDACdata;	// set tail pointer
133 	byte pal[768];
134 
135 	memset(pal, 0, sizeof(pal));
136 
137 	// while Q is not empty
138 	while (g_pDAChead != pDACtail) {
139 		const PALETTE *pPalette;	// pointer to hardware palette
140 		const COLORREF *pColors;	// pointer to list of RGB triples
141 
142 #ifdef	DEBUG
143 		// make sure palette does not overlap
144 		assert(pDACtail->destDACindex + pDACtail->numColors <= MAX_COLORS);
145 #else
146 		// make sure palette does not overlap
147 		if (pDACtail->destDACindex + pDACtail->numColors > MAX_COLORS)
148 			pDACtail->numColors = MAX_COLORS - pDACtail->destDACindex;
149 #endif
150 
151 		if (pDACtail->bHandle) {
152 			// we are using a palette handle
153 
154 			// get hardware palette pointer
155 			pPalette = (const PALETTE *)LockMem(pDACtail->pal.hRGBarray);
156 
157 			// get RGB pointer
158 			pColors = pPalette->palRGB;
159 		} else if (pDACtail->numColors == 1) {
160 			// we are using a single color palette
161 			pColors = &pDACtail->pal.singleRGB;
162 		} else {
163 			// we are using a palette pointer
164 			pColors = pDACtail->pal.pRGBarray;
165 		}
166 
167 		for (int i = 0; i < pDACtail->numColors; ++i) {
168 			pal[i * 3 + 0] = TINSEL_GetRValue(pColors[i]);
169 			pal[i * 3 + 1] = TINSEL_GetGValue(pColors[i]);
170 			pal[i * 3 + 2] = TINSEL_GetBValue(pColors[i]);
171 		}
172 
173 		// Swap black/white colors in the Mac version.
174 		// We need to swap the current black/white values so that screen fade
175 		// in/out is done correctly.
176 		if (TinselV1Mac) {
177 			byte macWhite = pal[  0 * 3 + 0];
178 			byte macBlack = pal[254 * 3 + 0];
179 			pal[254 * 3 + 0] = pal[254 * 3 + 1] = pal[254 * 3 + 2] = macWhite;
180 			pal[  0 * 3 + 0] = pal[  0 * 3 + 1] = pal[  0 * 3 + 2] = macBlack;
181 		}
182 
183 		// update the system palette
184 		g_system->getPaletteManager()->setPalette(pal, pDACtail->destDACindex, pDACtail->numColors);
185 
186 		// update tail pointer
187 		pDACtail++;
188 
189 	}
190 
191 	// reset video DAC transfer Q head pointer
192 	g_pDAChead = g_vidDACdata;
193 
194 	// clear all palette moved bits
195 	for (pPalQ = g_palAllocData; pPalQ < g_palAllocData + NUM_PALETTES; pPalQ++)
196 		pPalQ->posInDAC &= ~PALETTE_MOVED;
197 }
198 
199 /**
200  * Commpletely reset the palette allocator.
201  */
ResetPalAllocator()202 void ResetPalAllocator() {
203 #ifdef DEBUG
204 	// clear number of palettes in use
205 	numPals = 0;
206 #endif
207 
208 	// wipe out the palette allocator data
209 	memset(g_palAllocData, 0, sizeof(g_palAllocData));
210 
211 	// reset video DAC transfer Q head pointer
212 	g_pDAChead = g_vidDACdata;
213 }
214 
215 #ifdef	DEBUG
216 /**
217  * Shows the maximum number of palettes used at once.
218  */
PaletteStats()219 void PaletteStats() {
220 	debug("%i palettes of %i used", maxPals, NUM_PALETTES);
221 	debug("%i DAC queue entries of %i used", maxDACQ, VDACQLENGTH);
222 }
223 #endif
224 
225 /**
226  * Places a palette in the video DAC queue.
227  * @param posInDAC			Position in video DAC
228  * @param numColors		Number of colors in palette
229  * @param hPalette			Handle to palette
230  */
UpdateDACqueueHandle(int posInDAC,int numColors,SCNHANDLE hPalette)231 void UpdateDACqueueHandle(int posInDAC, int numColors, SCNHANDLE hPalette) {
232 	// check Q overflow
233 	assert(g_pDAChead < g_vidDACdata + VDACQLENGTH);
234 
235 	g_pDAChead->destDACindex = posInDAC & ~PALETTE_MOVED;	// set index in video DAC
236 	g_pDAChead->numColors = numColors;	// set number of colors
237 	g_pDAChead->pal.hRGBarray = hPalette;	// set handle of palette
238 	g_pDAChead->bHandle = true;		// we are using a palette handle
239 
240 	// update head pointer
241 	++g_pDAChead;
242 
243 #ifdef DEBUG
244 	if ((g_pDAChead-g_vidDACdata) > maxDACQ)
245 		maxDACQ = g_pDAChead-g_vidDACdata;
246 #endif
247 }
248 
249 /**
250  * Places a palette in the video DAC queue.
251  * @param posInDAC			Position in video DAC
252  * @param numColors		Number of colors in palette
253  * @param pColors			List of RGB triples
254  */
UpdateDACqueue(int posInDAC,int numColors,COLORREF * pColors)255 void UpdateDACqueue(int posInDAC, int numColors, COLORREF *pColors) {
256 	// check Q overflow
257 	assert(g_pDAChead < g_vidDACdata + NUM_PALETTES);
258 
259 	g_pDAChead->destDACindex = posInDAC & ~PALETTE_MOVED;	// set index in video DAC
260 	g_pDAChead->numColors = numColors;	// set number of colors
261 	if (numColors == 1)
262 		g_pDAChead->pal.singleRGB = *pColors;	// set single color of which the "palette" consists
263 	else
264 		g_pDAChead->pal.pRGBarray = pColors;	// set addr of palette
265 	g_pDAChead->bHandle = false;		// we are not using a palette handle
266 
267 	// update head pointer
268 	++g_pDAChead;
269 
270 #ifdef DEBUG
271 	if ((g_pDAChead-g_vidDACdata) > maxDACQ)
272 		maxDACQ = g_pDAChead-g_vidDACdata;
273 #endif
274 }
275 
276 
277 /**
278  * Places a "palette" consisting of a single color in the video DAC queue.
279  * @param posInDAC			Position in video DAC
280  * @param color				Single RGB triple
281  */
UpdateDACqueue(int posInDAC,COLORREF color)282 void UpdateDACqueue(int posInDAC, COLORREF color) {
283 	// check Q overflow
284 	assert(g_pDAChead < g_vidDACdata + NUM_PALETTES);
285 
286 	g_pDAChead->destDACindex = posInDAC & ~PALETTE_MOVED;	// set index in video DAC
287 	g_pDAChead->numColors = 1;	// set number of colors
288 	g_pDAChead->pal.singleRGB = color;	// set single color of which the "palette" consists
289 	g_pDAChead->bHandle = false;		// we are not using a palette handle
290 
291 	// update head pointer
292 	++g_pDAChead;
293 
294 #ifdef DEBUG
295 	if ((g_pDAChead-g_vidDACdata) > maxDACQ)
296 		maxDACQ = g_pDAChead-g_vidDACdata;
297 #endif
298 }
299 
300 /**
301  * Allocate a palette.
302  * @param hNewPal			Palette to allocate
303  */
AllocPalette(SCNHANDLE hNewPal)304 PALQ *AllocPalette(SCNHANDLE hNewPal) {
305 	PALQ *pPrev, *p;		// walks palAllocData
306 	int iDAC;		// color index in video DAC
307 	PALQ *pNxtPal;		// next PALQ struct in palette allocator
308 	PALETTE *pNewPal;
309 
310 	// get pointer to new palette
311 	pNewPal = (PALETTE *)LockMem(hNewPal);
312 
313 	// search all structs in palette allocator - see if palette already allocated
314 	for (p = g_palAllocData; p < g_palAllocData + NUM_PALETTES; p++) {
315 		if (p->hPal == hNewPal) {
316 			// found the desired palette in palette allocator
317 			p->objCount++;	// update number of objects using palette
318 			return p;	// return palette queue position
319 		}
320 	}
321 
322 	// search all structs in palette allocator - find a free slot
323 	iDAC = FGND_DAC_INDEX;	// init DAC index to first available foreground color
324 
325 	for (p = g_palAllocData; p < g_palAllocData + NUM_PALETTES; p++) {
326 		if (p->hPal == 0) {
327 			// found a free slot in palette allocator
328 			p->objCount = 1;	// init number of objects using palette
329 			p->posInDAC = iDAC;	// set palettes start pos in video DAC
330 			p->hPal = hNewPal;	// set hardware palette data
331 			p->numColors = FROM_32(pNewPal->numColors);	// set number of colors in palette
332 
333 			if (TinselV2)
334 				// Copy all the colors
335 				memcpy(p->palRGB, pNewPal->palRGB, p->numColors * sizeof(COLORREF));
336 
337 #ifdef DEBUG
338 			// one more palette in use
339 			if (++numPals > maxPals)
340 				maxPals = numPals;
341 #endif
342 
343 			// Q the change to the video DAC
344 			if (TinselV2)
345 				UpdateDACqueue(p->posInDAC, p->numColors, p->palRGB);
346 			else
347 				UpdateDACqueueHandle(p->posInDAC, p->numColors, p->hPal);
348 
349 			// move all palettes after this one down (if necessary)
350 			for (pPrev = p, pNxtPal = pPrev + 1; pNxtPal < g_palAllocData + NUM_PALETTES; pNxtPal++) {
351 				if (pNxtPal->hPal != 0) {
352 					// palette slot is in use
353 					if (pNxtPal->posInDAC >= pPrev->posInDAC + pPrev->numColors)
354 						// no need to move palettes down
355 						break;
356 
357 					// move palette down - indicate change
358 					pNxtPal->posInDAC = (pPrev->posInDAC
359 						+ pPrev->numColors) | PALETTE_MOVED;
360 
361 					// Q the palette change in position to the video DAC
362 					if (!TinselV2)
363 						UpdateDACqueueHandle(pNxtPal->posInDAC,
364 							pNxtPal->numColors,
365 							pNxtPal->hPal);
366 					else if (!pNxtPal->bFading)
367 						UpdateDACqueue(pNxtPal->posInDAC,
368 							pNxtPal->numColors,
369 							pNxtPal->palRGB);
370 
371 					// update previous palette to current palette
372 					pPrev = pNxtPal;
373 				}
374 			}
375 
376 			// return palette pointer
377 			return p;
378 		}
379 
380 		// set new DAC index
381 		iDAC = p->posInDAC + p->numColors;
382 	}
383 
384 	// no free palettes
385 	error("AllocPalette(): formally 'assert(0)!'");
386 }
387 
388 /**
389  * Free a palette allocated with "AllocPalette".
390  * @param pFreePal			Palette queue entry to free
391  */
FreePalette(PALQ * pFreePal)392 void FreePalette(PALQ *pFreePal) {
393 	// validate palette Q pointer
394 	assert(pFreePal >= g_palAllocData && pFreePal <= g_palAllocData + NUM_PALETTES - 1);
395 
396 	// reduce the palettes object reference count
397 	pFreePal->objCount--;
398 
399 	// make sure palette has not been deallocated too many times
400 	assert(pFreePal->objCount >= 0);
401 
402 	if (pFreePal->objCount == 0) {
403 		pFreePal->hPal = 0;	// palette is no longer in use
404 
405 #ifdef DEBUG
406 		// one less palette in use
407 		--numPals;
408 		assert(numPals >= 0);
409 #endif
410 	}
411 }
412 
413 /**
414  * Find the specified palette.
415  * @param hSrchPal			Hardware palette to search for
416  */
FindPalette(SCNHANDLE hSrchPal)417 PALQ *FindPalette(SCNHANDLE hSrchPal) {
418 	PALQ *pPal;		// palette allocator iterator
419 
420 	// search all structs in palette allocator
421 	for (pPal = g_palAllocData; pPal < g_palAllocData + NUM_PALETTES; pPal++) {
422 		if (pPal->hPal == hSrchPal)
423 			// found palette in palette allocator
424 			return pPal;
425 	}
426 
427 	// palette not found
428 	return NULL;
429 }
430 
431 /**
432  * Swaps the palettes at the specified palette queue position.
433  * @param pPalQ			Palette queue position
434  * @param hNewPal		New palette
435  */
SwapPalette(PALQ * pPalQ,SCNHANDLE hNewPal)436 void SwapPalette(PALQ *pPalQ, SCNHANDLE hNewPal) {
437 	// convert handle to palette pointer
438 	PALETTE *pNewPal = (PALETTE *)LockMem(hNewPal);
439 
440 	// validate palette Q pointer
441 	assert(pPalQ >= g_palAllocData && pPalQ <= g_palAllocData + NUM_PALETTES - 1);
442 
443 	if (pPalQ->numColors >= (int)FROM_32(pNewPal->numColors)) {
444 		// new palette will fit the slot
445 
446 		// install new palette
447 		pPalQ->hPal = hNewPal;
448 
449 		if (TinselV2) {
450 			pPalQ->numColors = FROM_32(pNewPal->numColors);
451 
452 			// Copy all the colors
453 			memcpy(pPalQ->palRGB, pNewPal->palRGB, FROM_32(pNewPal->numColors) * sizeof(COLORREF));
454 
455 			if (!pPalQ->bFading)
456 				// Q the change to the video DAC
457 				UpdateDACqueue(pPalQ->posInDAC, FROM_32(pNewPal->numColors), pPalQ->palRGB);
458 		} else {
459 			// Q the change to the video DAC
460 			UpdateDACqueueHandle(pPalQ->posInDAC, FROM_32(pNewPal->numColors), hNewPal);
461 		}
462 	} else {
463 		// # colors are different - will have to update all following palette entries
464 		assert(!TinselV2); // Fatal error for Tinsel 2
465 
466 		PALQ *pNxtPalQ;		// next palette queue position
467 
468 		for (pNxtPalQ = pPalQ + 1; pNxtPalQ < g_palAllocData + NUM_PALETTES; pNxtPalQ++) {
469 			if (pNxtPalQ->posInDAC >= pPalQ->posInDAC + pPalQ->numColors)
470 				// no need to move palettes down
471 				break;
472 
473 			// move palette down
474 			pNxtPalQ->posInDAC = (pPalQ->posInDAC
475 				+ pPalQ->numColors) | PALETTE_MOVED;
476 
477 			// Q the palette change in position to the video DAC
478 			UpdateDACqueueHandle(pNxtPalQ->posInDAC,
479 				pNxtPalQ->numColors,
480 				pNxtPalQ->hPal);
481 
482 			// update previous palette to current palette
483 			pPalQ = pNxtPalQ;
484 		}
485 	}
486 }
487 
488 /**
489  * Statless palette iterator. Returns the next palette in the list
490  * @param pStrtPal			Palette to start from - when NULL will start from beginning of list
491  */
GetNextPalette(PALQ * pStrtPal)492 PALQ *GetNextPalette(PALQ *pStrtPal) {
493 	if (pStrtPal == NULL) {
494 		// start of palette iteration - return 1st palette
495 		return (g_palAllocData[0].objCount) ? g_palAllocData : NULL;
496 	}
497 
498 	// validate palette Q pointer
499 	assert(pStrtPal >= g_palAllocData && pStrtPal <= g_palAllocData + NUM_PALETTES - 1);
500 
501 	// return next active palette in list
502 	while (++pStrtPal < g_palAllocData + NUM_PALETTES) {
503 		if (pStrtPal->objCount)
504 			// active palette found
505 			return pStrtPal;
506 	}
507 
508 	// non found
509 	return NULL;
510 }
511 
512 /**
513  * Sets the current background color.
514  * @param color			Color to set the background to
515  */
SetBgndColor(COLORREF color)516 void SetBgndColor(COLORREF color) {
517 	// update background color struct by queuing the change to the video DAC
518 	UpdateDACqueue(BGND_DAC_INDEX, color);
519 }
520 
521 /**
522  * Note whether a palette is being faded.
523  * @param pPalQ			Palette queue position
524  * @param bFading		Whether it is fading
525  */
FadingPalette(PALQ * pPalQ,bool bFading)526 void FadingPalette(PALQ *pPalQ, bool bFading) {
527 	// validate palette Q pointer
528 	assert(pPalQ >= g_palAllocData && pPalQ <= g_palAllocData + NUM_PALETTES - 1);
529 
530 	// validate that this is a change
531 	assert(pPalQ->bFading != bFading);
532 
533 	pPalQ->bFading = bFading;
534 }
535 
536 /**
537  * All fading processes have just been killed, so none of the
538  * palettes are fading.
539  */
NoFadingPalettes()540 void NoFadingPalettes() {
541 	PALQ *pPalQ;
542 
543 	for (pPalQ = g_palAllocData; pPalQ <= g_palAllocData + NUM_PALETTES - 1; pPalQ++) {
544 		pPalQ->bFading = false;
545 	}
546 }
547 
548 /**
549  * Builds the translucent palette from the current backgrounds palette.
550  * @param hPalette			Handle to current background palette
551  */
CreateTranslucentPalette(SCNHANDLE hPalette)552 void CreateTranslucentPalette(SCNHANDLE hPalette) {
553 	// get a pointer to the palette
554 	PALETTE *pPal = (PALETTE *)LockMem(hPalette);
555 
556 	// leave background color alone
557 	g_transPalette[0] = 0;
558 
559 	int32 numColors = FROM_32(pPal->numColors);
560 	for (int32 i = 0; i < numColors; i++) {
561 		// get the RGB color model values
562 		uint8 red   = TINSEL_GetRValue(pPal->palRGB[i]);
563 		uint8 green = TINSEL_GetGValue(pPal->palRGB[i]);
564 		uint8 blue  = TINSEL_GetBValue(pPal->palRGB[i]);
565 
566 		// calculate the Value field of the HSV color model
567 		unsigned val = (red > green) ? red : green;
568 		val = (val > blue) ? val : blue;
569 
570 		// map the Value field to one of the 4 colors reserved for the translucent palette
571 		val /= 63;
572 		byte blackColorIndex = (!TinselV1Mac) ? 0 : 255;
573 		g_transPalette[i + 1] = (uint8)((val == 0) ? blackColorIndex : val +
574 			(TinselV2 ? TranslucentColor() : COL_HILIGHT) - 1);
575 	}
576 }
577 
578 /**
579  * Returns an adjusted color RGB
580  * @param color		Color to scale
581  */
DimColor(COLORREF color,int factor)582 static COLORREF DimColor(COLORREF color, int factor) {
583 	uint32 red, green, blue;
584 
585 	if (factor == 10) {
586 		// No change
587 		return color;
588 	} else if (factor == 0) {
589 		// No brightness
590 		return 0;
591 	} else {
592 		// apply multiplier to RGB components
593 		red   = TINSEL_GetRValue(color) * factor / 10;
594 		green = TINSEL_GetGValue(color) * factor / 10;
595 		blue  = TINSEL_GetBValue(color) * factor / 10;
596 
597 		// return new color
598 		return TINSEL_RGB(red, green, blue);
599 	}
600 }
601 
602 /**
603  * DimPartPalette
604  */
DimPartPalette(SCNHANDLE hDimPal,int startColor,int length,int brightness)605 void DimPartPalette(SCNHANDLE hDimPal, int startColor, int length, int brightness) {
606 	PALQ *pPalQ;
607 	PALETTE *pDimPal;
608 	int iColor;
609 
610 	pPalQ = FindPalette(hDimPal);
611 	assert(pPalQ);
612 
613 	// get pointer to dim palette
614 	pDimPal = (PALETTE *)LockMem(hDimPal);
615 
616 	// Adjust for the fact that palettes don't contain color 0
617 	startColor -= 1;
618 
619 	// Check some other things
620 	if (startColor + length > pPalQ->numColors)
621 		error("DimPartPalette(): color overrun");
622 
623 	for (iColor = startColor; iColor < startColor + length; iColor++) {
624 		pPalQ->palRGB[iColor] = DimColor(pDimPal->palRGB[iColor], brightness);
625 	}
626 
627 	if (!pPalQ->bFading) {
628 		// Q the change to the video DAC
629 		UpdateDACqueue(pPalQ->posInDAC + startColor, length, &pPalQ->palRGB[startColor]);
630 	}
631 }
632 
TranslucentColor()633 int TranslucentColor() {
634 	return g_translucentIndex;
635 }
636 
HighlightColor()637 int HighlightColor() {
638 	UpdateDACqueue(g_talkIndex, (COLORREF)SysVar(SYS_HighlightRGB));
639 
640 	return g_talkIndex;
641 }
642 
TalkColor()643 int TalkColor() {
644 	return TinselV2 ? g_talkIndex : TALKFONT_COL;
645 }
646 
SetTalkColorRef(COLORREF colRef)647 void SetTalkColorRef(COLORREF colRef) {
648 	g_talkColRef = colRef;
649 }
650 
GetTalkColorRef()651 COLORREF GetTalkColorRef() {
652 	return g_talkColRef;
653 }
654 
SetTagColorRef(COLORREF colRef)655 void SetTagColorRef(COLORREF colRef) {
656 	g_tagColRef = colRef;
657 }
658 
GetTagColorRef()659 COLORREF GetTagColorRef() {
660 	return g_tagColRef;
661 }
662 
SetTranslucencyOffset(int offset)663 void SetTranslucencyOffset(int offset) {
664 	g_translucentIndex = offset;
665 }
666 
SetTalkTextOffset(int offset)667 void SetTalkTextOffset(int offset) {
668 	g_talkIndex = offset;
669 }
670 
671 } // End of namespace Tinsel
672