1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010-2019 EDuke32 developers and contributors
4 Copyright (C) 2019 Nuke.YKT
5
6 This file is part of NBlood.
7
8 NBlood is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License version 2
10 as published by the Free Software Foundation.
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.
15
16 See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22 //-------------------------------------------------------------------------
23 #include <string.h>
24 #include "a.h"
25 #include "build.h"
26 #include "colmatch.h"
27 #include "common_game.h"
28
29 #include "globals.h"
30 #include "config.h"
31 #include "gfx.h"
32 #include "resource.h"
33 #include "screen.h"
34
35 RGB StdPal[32] = {
36 { 0, 0, 0 },
37 { 0, 0, 170 },
38 { 0, 170, 170 },
39 { 0, 170, 170 },
40 { 170, 0, 0 },
41 { 170, 0, 170 },
42 { 170, 85, 0 },
43 { 170, 170, 170 },
44 { 85, 85, 85 },
45 { 85, 85, 255 },
46 { 85, 255, 85 },
47 { 85, 255, 255 },
48 { 255, 85, 85 },
49 { 255, 85, 255 },
50 { 255, 255, 85 },
51 { 255, 255, 255 },
52 { 241, 241, 241 },
53 { 226, 226, 226 },
54 { 211, 211, 211 },
55 { 196, 196, 196 },
56 { 181, 181, 181 },
57 { 166, 166, 166 },
58 { 151, 151, 151 },
59 { 136, 136, 136 },
60 { 120, 120, 120 },
61 { 105, 105, 105 },
62 { 90, 90, 90 },
63 { 75, 75, 75 },
64 { 60, 60, 60 },
65 { 45, 45, 45 },
66 { 30, 30, 30 },
67 { 15, 15, 15 }
68 };
69
70 LOADITEM PLU[15] = {
71 { 0, "NORMAL" },
72 { 1, "SATURATE" },
73 { 2, "BEAST" },
74 { 3, "TOMMY" },
75 { 4, "SPIDER3" },
76 { 5, "GRAY" },
77 { 6, "GRAYISH" },
78 { 7, "SPIDER1" },
79 { 8, "SPIDER2" },
80 { 9, "FLAME" },
81 { 10, "COLD" },
82 { 11, "P1" },
83 { 12, "P2" },
84 { 13, "P3" },
85 { 14, "P4" }
86 };
87
88 LOADITEM PAL[5] = {
89 { 0, "BLOOD" },
90 { 1, "WATER" },
91 { 2, "BEAST" },
92 { 3, "SEWER" },
93 { 4, "INVULN1" }
94 };
95
96
97 bool DacInvalid = true;
98 static char(*gammaTable)[256];
99 RGB curDAC[256];
100 RGB baseDAC[256];
101 static RGB fromDAC[256];
102 static RGB toRGB;
103 static RGB *palTable[5];
104 static int curPalette;
105 static int curGamma;
106 int gGammaLevels;
107 bool gFogMode = false;
108 char gStdColor[32];
109 int32_t gBrightness;
110
scrFindClosestColor(int red,int green,int blue)111 char scrFindClosestColor(int red, int green, int blue)
112 {
113 int dist = 0x7fffffff;
114 int best;
115 for (int i = 0; i < 256; i++)
116 {
117 int sum = (palette[i*3+1]-green)*(palette[i*3+1]-green);
118 if (sum >= dist) continue;
119 sum += (palette[i*3+0]-red)*(palette[i*3+0]-red);
120 if (sum >= dist) continue;
121 sum += (palette[i*3+2]-blue)*(palette[i*3+2]-blue);
122 if (sum >= dist) continue;
123 best = i;
124 dist = sum;
125 if (sum == 0)
126 break;
127 }
128 return best;
129 }
130
scrCreateStdColors(void)131 void scrCreateStdColors(void)
132 {
133 for (int i = 0; i < 32; i++)
134 gStdColor[i] = scrFindClosestColor(StdPal[i].red, StdPal[i].green, StdPal[i].blue);
135 }
136
scrResetPalette(void)137 void scrResetPalette(void)
138 {
139 if (palTable[0] == nullptr)
140 return;
141
142 paletteSetColorTable(0, (uint8_t*)palTable[0]);
143 }
144
gSetDacRange(int start,int end,RGB * pPal)145 void gSetDacRange(int start, int end, RGB *pPal)
146 {
147 UNREFERENCED_PARAMETER(start);
148 UNREFERENCED_PARAMETER(end);
149 if (videoGetRenderMode() == REND_CLASSIC)
150 {
151 memcpy(palette, pPal, sizeof(palette));
152 videoSetPalette(gBrightness>>2, 0, 0);
153 }
154 }
155
scrLoadPLUs(void)156 void scrLoadPLUs(void)
157 {
158 if (gFogMode)
159 {
160 DICTNODE *pFog = gSysRes.Lookup("FOG", "FLU");
161 if (!pFog)
162 ThrowError("FOG.FLU not found");
163 palookup[0] = (char*)gSysRes.Lock(pFog);
164 for (int i = 0; i < 15; i++)
165 palookup[PLU[i].id] = palookup[0];
166 parallaxvisibility = 3072;
167 return;
168 }
169
170 // load default palookups
171 for (int i = 0; i < 15; i++) {
172 DICTNODE *pPlu = gSysRes.Lookup(PLU[i].name, "PLU");
173 if (!pPlu)
174 ThrowError("%s.PLU not found", PLU[i].name);
175 if (pPlu->size / 256 != 64)
176 ThrowError("Incorrect PLU size");
177 palookup[PLU[i].id] = (char*)gSysRes.Lock(pPlu);
178 }
179
180 // by NoOne: load user palookups
181 for (int i = kUserPLUStart; i < MAXPALOOKUPS; i++) {
182 DICTNODE* pPlu = gSysRes.Lookup(i, "PLU");
183 if (!pPlu) continue;
184 else if (pPlu->size / 256 != 64) { consoleSysMsg("Incorrect filesize of PLU#%d", i); }
185 else palookup[i] = (char*)gSysRes.Lock(pPlu);
186 }
187
188 #ifdef USE_OPENGL
189 palookupfog[1].r = 255;
190 palookupfog[1].g = 255;
191 palookupfog[1].b = 255;
192 #endif
193 }
194
195 #ifdef USE_OPENGL
196 glblend_t const bloodglblend =
197 {
198 {
199 { 1.f/3.f, BLENDFACTOR_SRC_ALPHA, BLENDFACTOR_ONE_MINUS_SRC_ALPHA, 0 },
200 { 2.f/3.f, BLENDFACTOR_SRC_ALPHA, BLENDFACTOR_ONE_MINUS_SRC_ALPHA, 0 },
201 },
202 };
203 #endif
204
scrLoadPalette(void)205 void scrLoadPalette(void)
206 {
207 paletteInitClosestColorScale(30, 59, 11);
208 paletteInitClosestColorGrid();
209 paletteloaded = 0;
210 initprintf("Loading palettes\n");
211 for (int i = 0; i < 5; i++)
212 {
213 DICTNODE *pPal = gSysRes.Lookup(PAL[i].name, "PAL");
214 if (!pPal)
215 ThrowError("%s.PAL not found (RFF files may be wrong version)", PAL[i].name);
216 palTable[PAL[i].id] = (RGB*)gSysRes.Lock(pPal);
217 paletteSetColorTable(PAL[i].id, (uint8_t*)palTable[PAL[i].id]);
218 }
219 memcpy(palette, palTable[0], sizeof(palette));
220 numshades = 64;
221 paletteloaded |= PALETTE_MAIN;
222 scrLoadPLUs();
223 paletteloaded |= PALETTE_SHADE;
224 initprintf("Loading translucency table\n");
225 DICTNODE *pTrans = gSysRes.Lookup("TRANS", "TLU");
226 if (!pTrans)
227 ThrowError("TRANS.TLU not found");
228 blendtable[0] = (char*)gSysRes.Lock(pTrans);
229 paletteloaded |= PALETTE_TRANSLUC;
230
231 #ifdef USE_OPENGL
232 for (auto & x : glblend)
233 x = bloodglblend;
234
235 for (int i = 0; i < MAXPALOOKUPS; i++)
236 palookupfogfactor[i] = 1.f;
237 #endif
238
239 paletteInitClosestColorMap((uint8_t*)palTable[0]);
240 palettePostLoadTables();
241 // Make color index 255 of palette black.
242 for (int i = 0; i < 5; i++)
243 {
244 if (basepaltable[i] != NULL)
245 Bmemset(&basepaltable[i][255 * 3], 0, 3);
246 }
247 palettePostLoadLookups();
248 }
249
scrSetPalette(int palId)250 void scrSetPalette(int palId)
251 {
252 curPalette = palId;
253 scrSetGamma(0/*curGamma*/);
254 }
255
scrSetGamma(int nGamma)256 void scrSetGamma(int nGamma)
257 {
258 dassert(nGamma < gGammaLevels);
259 curGamma = nGamma;
260 for (int i = 0; i < 256; i++)
261 {
262 baseDAC[i].red = gammaTable[curGamma][palTable[curPalette][i].red];
263 baseDAC[i].green = gammaTable[curGamma][palTable[curPalette][i].green];
264 baseDAC[i].blue = gammaTable[curGamma][palTable[curPalette][i].blue];
265 }
266 DacInvalid = 1;
267 }
268
scrSetupFade(char red,char green,char blue)269 void scrSetupFade(char red, char green, char blue)
270 {
271 memcpy(fromDAC, curDAC, sizeof(fromDAC));
272 toRGB.red = red;
273 toRGB.green = green;
274 toRGB.blue = blue;
275 }
276
scrSetupUnfade(void)277 void scrSetupUnfade(void)
278 {
279 memcpy(fromDAC, baseDAC, sizeof(fromDAC));
280 }
281
scrFadeAmount(int amount)282 void scrFadeAmount(int amount)
283 {
284 for (int i = 0; i < 256; i++)
285 {
286 curDAC[i].red = interpolate(fromDAC[i].red, toRGB.red, amount);
287 curDAC[i].green = interpolate(fromDAC[i].green, toRGB.green, amount);
288 curDAC[i].blue = interpolate(fromDAC[i].blue, toRGB.blue, amount);
289 }
290 gSetDacRange(0, 256, curDAC);
291 }
292
scrSetDac(void)293 void scrSetDac(void)
294 {
295 if (DacInvalid)
296 gSetDacRange(0, 256, baseDAC);
297 DacInvalid = 0;
298 }
299
scrInit(void)300 void scrInit(void)
301 {
302 initprintf("Initializing engine\n");
303 #ifdef USE_OPENGL
304 glrendmode = REND_POLYMOST;
305 #endif
306 engineInit();
307 curPalette = 0;
308 curGamma = 0;
309 initprintf("Loading gamma correction table\n");
310 DICTNODE *pGamma = gSysRes.Lookup("gamma", "DAT");
311 if (!pGamma)
312 ThrowError("Gamma table not found");
313 gGammaLevels = pGamma->size / 256;
314 gammaTable = (char(*)[256])gSysRes.Lock(pGamma);
315 }
316
scrUnInit(void)317 void scrUnInit(void)
318 {
319 memset(palookup, 0, sizeof(palookup));
320 memset(blendtable, 0, sizeof(blendtable));
321 engineUnInit();
322 }
323
324
scrSetGameMode(int vidMode,int XRes,int YRes,int nBits)325 void scrSetGameMode(int vidMode, int XRes, int YRes, int nBits)
326 {
327 videoResetMode();
328 //videoSetGameMode(vidMode, XRes, YRes, nBits, 0);
329 if (videoSetGameMode(vidMode, XRes, YRes, nBits, 0) < 0)
330 {
331 initprintf("Failure setting video mode %dx%dx%d %s! Trying next mode...\n", XRes, YRes,
332 nBits, vidMode ? "fullscreen" : "windowed");
333
334 int resIdx = 0;
335
336 for (int i=0; i < validmodecnt; i++)
337 {
338 if (validmode[i].xdim == XRes && validmode[i].ydim == YRes)
339 {
340 resIdx = i;
341 break;
342 }
343 }
344
345 int const savedIdx = resIdx;
346 int bpp = nBits;
347
348 while (videoSetGameMode(0, validmode[resIdx].xdim, validmode[resIdx].ydim, bpp, 0) < 0)
349 {
350 initprintf("Failure setting video mode %dx%dx%d windowed! Trying next mode...\n",
351 validmode[resIdx].xdim, validmode[resIdx].ydim, bpp);
352
353 if (++resIdx == validmodecnt)
354 {
355 if (bpp == 8)
356 ThrowError("Fatal error: unable to set any video mode!");
357
358 resIdx = savedIdx;
359 bpp = 8;
360 }
361 }
362
363 gSetup.xdim = validmode[resIdx].xdim;
364 gSetup.ydim = validmode[resIdx].ydim;
365 gSetup.bpp = bpp;
366 }
367 videoClearViewableArea(0);
368 scrNextPage();
369 scrSetPalette(curPalette);
370 gfxSetClip(0, 0, xdim, ydim);
371 }
372
scrNextPage(void)373 void scrNextPage(void)
374 {
375 videoNextPage();
376 }
377