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