Color in Fallout
The paper describes the color algorithms (Palette => RGB, RGB => Index in the palette, animated color) used in Fallout. Information about them was obtained in the course of reviewing relevant functions in the file Mapper2.exe and Fallout2.exe.
1. Transforming 'palette => RGB'[]
Transforming 'palette => RGB' presented to the following pattern.
+----------------------------------+ | Brightness (currentGamma) (4) | +----------------------------------+ | +--------------+ V | Palette | +----------------------------+ +-------------+ +-------------+ | from | | Translation color | | System | | DirectDraw | | PAL-file (1) | | table (2) | | palette | | palette | +-----+--------+ +----+-----------------------+ +-----+-------+ +-----+-------+ | | Red |-------------------->| 0 | pow (0, currentGamma) | | | Red | | | Red | | +--------+ +----+-----------------------+ | +-------+ | +-------+ | 0 | Green | | 1 | pow (1, currentGamma) |-------->| 0 | Green | | 0 | Green | | +--------+ +----+-----------------------+ | +-------+ | +-------+ | | Blue | | ... | | | Blue | | | Blue | +-----+--------+ +----+-----------------------+ +-----+-------+ Red << 2 +-----+-------+ | | Red | +---->| 63 | pow (63, currentGamma)| | | Red |-- Green << 2 -->| | Red | | +--------+ | +----+-----------------------+ | +-------+ Blue << 2 | +-------+ | 1 | Green | | | 1 | Green | | 1 | Green | | +--------+ | | +-------+ | +-------+ | | Blue | | | | Blue | | | Blue | +-----+--------+ | +-----+-------+ +-----+-------+ | ... | +-----+--------+ +-----+-------+ +-----+-------+ | | Red | Red >> 2 | | Red | | | Red | | +--------+ Green >> 2 | +-------+ | +-------+ | 255 | Green | Blue >> 2 | 255 | Green | | 255 | Green | | +--------+ | +-------+ | +-------+ | | Blue | | | | Blue | | | Blue | +-----+--------+ | +-----+-------+ +-----+-------+ | | | +---------------------------+ | | Animated color (3) |--+ +---------------------------+
- While the loading the PAL file, if the value of a component of a color is not in the range 0 .. 63, the value of all components of that color piled are set to 0.
- If the computed value is less 0, the value of the corresponding table element is set to 0. If the computed value is greater 63, the value of the appropriate element of the table is set to 63. ('pow' is the function for raising a number to a power)
- See 3. Animated color
- In Fallout the currentGamma variable is the type of double and varies from 1.000000 to 1.179993.
It should be noted that changes brightness algorithm used is a zero-defect and the first element of the color conversion table will never change.
Transforming 'RGB => Index in the palette'[]
Transforming 'RGB => index of the palette' presented to the following pattern.
Red Green Blue +---------|-----+ +---------|-----+ +---------|-----+ |7|6|5|4|3|2|1|0| |7|6|5|4|3|2|1|0| |7|6|5|4|3|2|1|0| +---------|-----+ +---------|-----+ +---------|-----+ | | | | | | +-----+ | +-----+ | | | V V V +-|--------------|--------------|--------------+ |0|R7|R6|R5|R4|R3|G7|G6|G5|G4|G3|B7|B6|B5|B4|B3| +-|--------------|--------------|--------------+
The resulting number is used as an index in the PAL file conversion table 'RGB => index of the palette'. Perhaps the tables on the relevant index and the index is desired in the palette.
Animated color[]
In Fallout 'Animated color' has been used to reduce the size of image files, as do allow one frame izmenyayuschimesya with flowers instead of a few static frames with flowers. The user can control the 'Animated color' with two parameters in files fallout2.cfg and mapper2.cfg
[system] color_cycling = 1 cycle_speed_factor = 1
The value color_cycling allowed (1) / prohibited (0) animation colors. Cycle_speed_factor parameter governs the speed of animation, the higher the parameter so less frequently change color. There are six groups Animated in primary colors with different parameters (see Table 3.1).
Table 3.1 - Initial parameters teams' colors Animirovannyh '
Title | Number of colors | Indices in the palette | Color components | Period of cycle | ||
---|---|---|---|---|---|---|
Mucus | 4 | 229 .. 232 | 0 | Red | 0 | 200 ms |
Green | 108 | |||||
Blue | 0 | |||||
1 | Red | 11 | ||||
Green | 115 | |||||
Blue | 7 | |||||
2 | Red | 27 | ||||
Green | 123 | |||||
Blue | 15 | |||||
3 | Red | 43 | ||||
Green | 131 | |||||
Blue | 27 | |||||
Coastline | 6 | 248 .. 253 | 0 | Red | 83 | 200 ms |
Green | 63 | |||||
Blue | 43 | |||||
1 | Red | 75 | ||||
Green | 59 | |||||
Blue | 43 | |||||
2 | Red | 67 | ||||
Green | 55 | |||||
Blue | 39 | |||||
3 | Red | 63 | ||||
Green | 51 | |||||
Blue | 39 | |||||
4 | Red | 55 | ||||
Green | 47 | |||||
Blue | 35 | |||||
5 | Red | 51 | ||||
Green | 43 | |||||
Blue | 35 | |||||
Medlennogoryaschee plyamya | 5 | 238 .. 242 | 0 | Red | 255 | 200 ms |
Green | 0 | |||||
Blue | 0 | |||||
1 | Red 215 | |||||
Green | 0 | |||||
Blue | 0 | |||||
2 | Red | 147 | ||||
Green | 43 | |||||
Blue | 11 | |||||
3 | Red | 255 | ||||
Green | 119 | |||||
Blue | 0 | |||||
4 | Red | 255 | ||||
Green | 59 | |||||
Blue | 0 | |||||
Bystrogoryaschee plyamya | 5 | 243 .. 247 | 0 | Red | 71 | 142 ms |
Green | 0 | |||||
Blue | 0 | |||||
1 | Red | 123 | ||||
Green | 0 | |||||
Blue | 0 | |||||
2 | Red | 179 | ||||
Green | 0 | |||||
Blue | 0 | |||||
3 | Red | 123 | ||||
Green | 0 | |||||
Blue | 0 | |||||
4 | Red | 71 | ||||
Green | 0 | |||||
Blue | 0 | |||||
Monitors | 5 | 233 .. 237 | 0 | Red | 107 | 100 ms |
Green | 107 | |||||
Blue | 111 | |||||
1 | Red | 99 | ||||
Green | 103 | |||||
Blue | 127 | |||||
2 | Red | 87 | ||||
Green | 107 | |||||
Blue | 143 | |||||
3 | Red | 0 | ||||
Green | 147 | |||||
Blue | 163 | |||||
4 | Red | 107 | ||||
Green | 187 | |||||
Blue | 255 | |||||
Alarm | 1 | 254 | 0 | Red | 252 | 33 ms |
Green | 0 | |||||
Blue | 0 |
Note: Periods of changes have been introduced to cycle_speed_factor = 1
Laws change colors appear below in the form of function.
// palette BYTE g_Palette [768] // Start Value color BYTE g_nSlime [] = (0, 108, 0, 11, 115, 7, 27, 123, 15, 43, 131, 27); // Mucus BYTE g_nMonitors [] = (107, 107, 111, 99, 103, 127, 87, 107, 143, 0, 147, 163, 107, 187, 255); // Monitors BYTE g_nFireSlow [] = (255, 0, 0, 215, 0, 0, 147, 43, 11, 255, 119, 0, 255, 59, 0); // Medlennogoryaschy fire BYTE g_nFireFast [] = (71, 0, 0, 123, 0, 0, 179, 0 , 0, 123, 0, 0, 71, 0, 0); // Bystrogoryaschy fire BYTE g_nShoreline [] = (83, 63, 43, 75, 59, 43, 67, 55, 39, 63, 51, 39, 55, 47, 35, 51, 43, 35); // Seaside BYTE g_nBlinkingRed = 252; // Signaling // Current value of the parameter cycle DWORD g_dwSlimeCurrent = 0; DWORD g_dwMonitorsCurrent = 0; DWORD g_dwFireSlowCurrent = 0; DWORD g_dwFireFastCurrent = 0; DWORD g_dwShorelineCurrent = 0; BYTE g_nBlinkingRedCurrent = 0; // Time previous change in color DWORD g_dwLastCycleSlow = 0; DWORD g_dwLastCycleMedium = 0; DWORD g_dwLastCycleFast = 0; DWORD g_dwLastCycleVeryFast = 0; // Current value koeffitsieta speed animation DWORD g_dwCycleSpeedFactor = 1; void AnimatePalette() { BOOL bPaletteChanged = FALSE; DWORD dwCurrentTime = GetTickCount(); if (dwCurrentTime - g_dwLastCycleSlow >= 200 * g_dwCycleSpeedFactor) { // Slime DWORD dwSlimeCurrentWork = g_dwSlimeCurrent; for (int i = 3; i >= 0, i--) { g_Palette[687 + i * 3] = g_nSlime[dwSlimeCurrentWork * 3] >> 2; // Red g_Palette[687 + i * 3 + 1] = g_nSlime[dwSlimeCurrentWork * 3 + 1] >> 2; // Green g_Palette[687 + i * 3 + 2] = g_nSlime[dwSlimeCurrentWork * 3 + 2] >> 2; // Blue if (dwSlimeCurrentWork == 3) dwSlimeCurrentWork = 0; else dwSlimeCurrentWork++; } if (g_dwSlimeCurrent == 3) g_dwSlimeCurrent = 0; else g_dwSlimeCurrent++; // Shoreline DWORD dwShorelineCurrentWork = g_dwShorelineCurrent; for (int i = 5; i >= 0, i--) { g_Palette[744 + i * 3] = g_nShoreline[dwShorelineCurrentWork * 3] >> 2; // Red g_Palette[744 + i * 3 + 1] = g_nShoreline[dwShorelineCurrentWork * 3 + 1] >> 2; // Green g_Palette[744 + i * 3 + 2] = g_nShoreline[dwShorelineCurrentWork * 3 + 2] >> 2; // Blue if (dwShorelineCurrentWork == 5) dwShorelineCurrentWork = 0; else dwShorelineCurrentWork++; } if (g_dwShorelineCurrent == 5) g_dwShorelineCurrent = 0; else g_dwShorelineCurrent++; // Fire_slow DWORD dwFireSlowCurrentWork = g_dwFireSlowCurrent; for (int i = 4; i >= 0, i--) { g_Palette[714 + i * 3] = g_nFireSlow[dwFireSlowCurrentWork * 3] >> 2; // Red g_Palette[714 + i * 3 + 1] = g_nFireSlow[dwFireSlowCurrentWork * 3 + 1] >> 2; // Green g_Palette[714 + i * 3 + 2] = g_nFireSlow[dwFireSlowCurrentWork * 3 + 2] >> 2; // Blue if (dwFireSlowCurrentWork == 4) dwFireSlowCurrentWork = 0; else dwFireSlowCurrentWork++; } if (g_dwFireSlowCurrent == 4) g_dwFireSlowCurrent = 0; else g_dwFireSlowCurrent++; g_dwLastCycleSlow = dwCurrentTime; bPaletteChanged = TRUE; } dwCurrentTime = GetTickCount() if (dwCurrentTime - g_dwLastCycleMedium >= 142 * g_dwCycleSpeedFactor) { // Fire_fast DWORD dwFireFastCurrentWork = g_dwFireFastCurrent; for (int i = 4; i >= 0, i--) { g_Palette[729 + i * 3] = g_nFireFast[dwFireFastCurrentWork * 3] >> 2; // Red g_Palette[729 + i * 3 + 1] = g_nFireFast[dwFireFastCurrentWork * 3 + 1] >> 2; // Green g_Palette[729 + i * 3 + 2] = g_nFireFast[dwFireFastCurrentWork * 3 + 2] >> 2; // Blue if (dwFireFastCurrentWork == 4) dwFireFastCurrentWork = 0; else dwFireFastCurrentWork++; } if (g_dwFireFastCurrent == 4) g_dwFireFastCurrent = 0; else g_dwFireFastCurrent++; g_dwLastCycleMedium = dwCurrentTime; bPaletteChanged = TRUE; } dwCurrentTime = GetTickCount(); if (dwCurrentTime - g_dwLastCycleFast >= 100 * g_dwCycleSpeedFactor) { // Monitors DWORD dwMonitorsCurrentWork = g_dwMonitorsCurrent; for (int i = 4; i >= 0, i--) { g_Palette[699 + i * 3] = g_nMonitors[dwMonitorsCurrentWork * 3] >> 2; // Red g_Palette[699 + i * 3 + 1] = g_nMonitors[dwMonitorsCurrentWork * 3 + 1] >> 2; // Green g_Palette[699 + i * 3 + 2] = g_nMonitors[dwMonitorsCurrentWork * 3 + 2] >> 2; // Blue if (dwMonitorsCurrentWork == 4) dwMonitorsCurrentWork = 0; else dwMonitorsCurrentWork++; } if (g_dwMonitorsCurrent == 4) g_dwMonitorsCurrent = 0; else g_dwMonitorsCurrent++; g_dwLastCycleFast = dwCurrentTime; bPaletteChanged = TRUE; } dwCurrentTime = GetTickCount(); if (dwCurrentTime - g_dwLastCycleVeryFast >= 33 * g_dwCycleSpeedFactor) { // Blinking red if ((g_nBlinkingRedCurrent == 0) || (g_nBlinkingRedCurrent == 60)) g_nBlinkingRed = BYTE(-g_nBlinkingRed); g_Palette [762] = g_nBlinkingRed + g_nBlinkingRedCurrent; // Red g_Palette [763] = 0; // Green g_Palette [764] = 0; // Blue g_nBlinkingRedCurrent = g_nBlinkingRed + g_nBlinkingRedCurrent; g_dwLastCycleVeryFast = dwCurrentTime; bPaletteChanged = TRUE; } if (bPaletteChanged) UpdatePalette (); }