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 "compat.h"
24 #include "build.h"
25 #include "pragmas.h"
26 #include "common_game.h"
27 
28 #include "blood.h"
29 #include "db.h"
30 #include "gameutil.h"
31 #include "globals.h"
32 #include "trig.h"
33 #include "sectorfx.h"
34 
35 char flicker1[] = {
36     0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0,
37     1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1,
38     0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1,
39     0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1
40 };
41 
42 char flicker2[] = {
43     1, 2, 4, 2, 3, 4, 3, 2, 0, 0, 1, 2, 4, 3, 2, 0,
44     2, 1, 0, 1, 0, 2, 3, 4, 3, 2, 1, 1, 2, 0, 0, 1,
45     1, 2, 3, 4, 4, 3, 2, 1, 2, 3, 4, 4, 2, 1, 0, 1,
46     0, 0, 0, 0, 1, 2, 3, 4, 3, 2, 1, 2, 3, 4, 3, 2
47 };
48 
49 char flicker3[] = {
50     4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 2, 4, 3, 4, 4,
51     4, 4, 2, 1, 3, 3, 3, 4, 3, 4, 4, 4, 4, 4, 2, 4,
52     4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 1, 0, 1,
53     0, 1, 0, 1, 0, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 4
54 };
55 
56 char flicker4[] = {
57     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58     4, 0, 0, 3, 0, 1, 0, 1, 0, 4, 4, 4, 4, 4, 2, 0,
59     0, 0, 0, 4, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1,
60     0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 4, 3, 2,
61     0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0,
62     0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0,
63     0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0,
64     0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0
65 };
66 
67 char strobe[] = {
68     64, 64, 64, 48, 36, 27, 20, 15, 11, 9, 6, 5, 4, 3, 2, 2,
69     1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
72 };
73 
GetWaveValue(int a,int b,int c)74 int GetWaveValue(int a, int b, int c)
75 {
76     b &= 2047;
77     switch (a)
78     {
79     case 0:
80         return c;
81     case 1:
82         return (b>>10)*c;
83     case 2:
84         return (klabs(128-(b>>3))*c)>>7;
85     case 3:
86         return ((b>>3)*c)>>8;
87     case 4:
88         return ((255-(b>>3))*c)>>8;
89     case 5:
90         return (c+mulscale30(c,Sin(b)))>>1;
91     case 6:
92         return flicker1[b>>5]*c;
93     case 7:
94         return (flicker2[b>>5]*c)>>2;
95     case 8:
96         return (flicker3[b>>5]*c)>>2;
97     case 9:
98         return (flicker4[b>>4]*c)>>2;
99     case 10:
100         return (strobe[b>>5]*c)>>6;
101     case 11:
102         if (b*4 > 2048)
103             return 0;
104         return (c-mulscale30(c, Cos(b*4)))>>1;
105     }
106     return 0;
107 }
108 
109 int shadeCount = 0;
110 short shadeList[kMaxXSectors];
111 int panCount = 0;
112 short panList[kMaxXSectors];
113 
DoSectorLighting(void)114 void DoSectorLighting(void)
115 {
116     for (int i = 0; i < shadeCount; i++)
117     {
118         int nXSector = shadeList[i];
119         XSECTOR *pXSector = &xsector[nXSector];
120         int nSector = pXSector->reference;
121         dassert(sector[nSector].extra == nXSector);
122         if (pXSector->shade)
123         {
124             int v4 = pXSector->shade;
125             if (pXSector->shadeFloor)
126             {
127                 sector[nSector].floorshade -= v4;
128                 if (pXSector->color)
129                 {
130                     int nTemp = pXSector->floorpal;
131                     pXSector->floorpal = sector[nSector].floorpal;
132                     sector[nSector].floorpal = nTemp;
133                 }
134             }
135             if (pXSector->shadeCeiling)
136             {
137                 sector[nSector].ceilingshade -= v4;
138                 if (pXSector->color)
139                 {
140                     int nTemp = pXSector->ceilpal;
141                     pXSector->ceilpal = sector[nSector].ceilingpal;
142                     sector[nSector].ceilingpal = nTemp;
143                 }
144             }
145             if (pXSector->shadeWalls)
146             {
147                 int nStartWall = sector[nSector].wallptr;
148                 int nEndWall = nStartWall + sector[nSector].wallnum;
149                 for (int j = nStartWall; j < nEndWall; j++)
150                 {
151                     wall[j].shade -= v4;
152                     if (pXSector->color)
153                     {
154                         wall[j].pal = sector[nSector].floorpal;
155                     }
156                 }
157             }
158             pXSector->shade = 0;
159         }
160         if (pXSector->shadeAlways || pXSector->busy)
161         {
162             int t1 = pXSector->wave;
163             int t2 = pXSector->amplitude;
164             if (!pXSector->shadeAlways && pXSector->busy)
165             {
166                 t2 = mulscale16(t2, pXSector->busy);
167             }
168             int v4 = GetWaveValue(t1, pXSector->phase*8+pXSector->freq*(int)totalclock, t2);
169             if (pXSector->shadeFloor)
170             {
171                 sector[nSector].floorshade = ClipRange(sector[nSector].floorshade+v4, -128, 127);
172                 if (pXSector->color && v4 != 0)
173                 {
174                     int nTemp = pXSector->floorpal;
175                     pXSector->floorpal = sector[nSector].floorpal;
176                     sector[nSector].floorpal = nTemp;
177                 }
178             }
179             if (pXSector->shadeCeiling)
180             {
181                 sector[nSector].ceilingshade = ClipRange(sector[nSector].ceilingshade+v4, -128, 127);
182                 if (pXSector->color && v4 != 0)
183                 {
184                     int nTemp = pXSector->ceilpal;
185                     pXSector->ceilpal = sector[nSector].ceilingpal;
186                     sector[nSector].ceilingpal = nTemp;
187                 }
188             }
189             if (pXSector->shadeWalls)
190             {
191                 int nStartWall = sector[nSector].wallptr;
192                 int nEndWall = nStartWall + sector[nSector].wallnum;
193                 for (int j = nStartWall; j < nEndWall; j++)
194                 {
195                     wall[j].shade = ClipRange(wall[j].shade+v4, -128, 127);
196                     if (pXSector->color && v4 != 0)
197                     {
198                         wall[j].pal = sector[nSector].floorpal;
199                     }
200                 }
201             }
202             pXSector->shade = v4;
203         }
204     }
205 }
206 
UndoSectorLighting(void)207 void UndoSectorLighting(void)
208 {
209     for (int i = 0; i < numsectors; i++)
210     {
211         int nXSprite = sector[i].extra;
212         if (nXSprite > 0)
213         {
214             XSECTOR *pXSector = &xsector[i];
215             if (pXSector->shade)
216             {
217                 int v4 = pXSector->shade;
218                 if (pXSector->shadeFloor)
219                 {
220                     sector[i].floorshade -= v4;
221                     if (pXSector->color)
222                     {
223                         int nTemp = pXSector->floorpal;
224                         pXSector->floorpal = sector[i].floorpal;
225                         sector[i].floorpal = nTemp;
226                     }
227                 }
228                 if (pXSector->shadeCeiling)
229                 {
230                     sector[i].ceilingshade -= v4;
231                     if (pXSector->color)
232                     {
233                         int nTemp = pXSector->ceilpal;
234                         pXSector->ceilpal = sector[i].ceilingpal;
235                         sector[i].ceilingpal = nTemp;
236                     }
237                 }
238                 if (pXSector->shadeWalls)
239                 {
240                     int nStartWall = sector[i].wallptr;
241                     int nEndWall = nStartWall + sector[i].wallnum;
242                     for (int j = nStartWall; j < nEndWall; j++)
243                     {
244                         wall[j].shade -= v4;
245                         if (pXSector->color)
246                         {
247                             wall[j].pal = sector[i].floorpal;
248                         }
249                     }
250                 }
251                 pXSector->shade = 0;
252             }
253         }
254     }
255 }
256 
257 short wallPanList[kMaxXWalls];
258 int wallPanCount;
259 
DoSectorPanning(void)260 void DoSectorPanning(void)
261 {
262     for (int i = 0; i < panCount; i++)
263     {
264         int nXSector = panList[i];
265         XSECTOR *pXSector = &xsector[nXSector];
266         int nSector = pXSector->reference;
267         dassert(nSector >= 0 && nSector < kMaxSectors);
268         sectortype *pSector = &sector[nSector];
269         dassert(pSector->extra == nXSector);
270         if (pXSector->panAlways || pXSector->busy)
271         {
272             int angle = pXSector->panAngle+1024;
273             int speed = pXSector->panVel<<10;
274             if (!pXSector->panAlways && (pXSector->busy&0xffff))
275                 speed = mulscale16(speed, pXSector->busy);
276 
277             if (pXSector->panFloor) // Floor
278             {
279                 int nTile = pSector->floorpicnum;
280                 int px = (pSector->floorxpanning<<8)+pXSector->floorXPanFrac;
281                 int py = (pSector->floorypanning<<8)+pXSector->floorYPanFrac;
282                 if (pSector->floorstat&64)
283                     angle -= 512;
284                 int xBits = (picsiz[nTile]&15)-((pSector->floorstat&8)!=0);
285                 px += mulscale30(speed<<2, Cos(angle))>>xBits;
286                 int yBits = (picsiz[nTile]/16)-((pSector->floorstat&8)!=0);
287                 py -= mulscale30(speed<<2, Sin(angle))>>yBits;
288                 pSector->floorxpanning = px>>8;
289                 pSector->floorypanning = py>>8;
290                 pXSector->floorXPanFrac = px&255;
291                 pXSector->floorYPanFrac = py&255;
292             }
293             if (pXSector->panCeiling) // Ceiling
294             {
295                 int nTile = pSector->ceilingpicnum;
296                 int px = (pSector->ceilingxpanning<<8)+pXSector->ceilXPanFrac;
297                 int py = (pSector->ceilingypanning<<8)+pXSector->ceilYPanFrac;
298                 if (pSector->ceilingstat&64)
299                     angle -= 512;
300                 int xBits = (picsiz[nTile]&15)-((pSector->ceilingstat&8)!=0);
301                 px += mulscale30(speed<<2, Cos(angle))>>xBits;
302                 int yBits = (picsiz[nTile]/16)-((pSector->ceilingstat&8)!=0);
303                 py -= mulscale30(speed<<2, Sin(angle))>>yBits;
304                 pSector->ceilingxpanning = px>>8;
305                 pSector->ceilingypanning = py>>8;
306                 pXSector->ceilXPanFrac = px&255;
307                 pXSector->ceilYPanFrac = py&255;
308             }
309         }
310     }
311     for (int i = 0; i < wallPanCount; i++)
312     {
313         int nXWall = wallPanList[i];
314         XWALL *pXWall = &xwall[nXWall];
315         int nWall = pXWall->reference;
316         dassert(wall[nWall].extra == nXWall);
317         if (pXWall->panAlways || pXWall->busy)
318         {
319             int psx = pXWall->panXVel<<10;
320             int psy = pXWall->panYVel<<10;
321             if (!pXWall->panAlways && (pXWall->busy & 0xffff))
322             {
323                 psx = mulscale16(psx, pXWall->busy);
324                 psy = mulscale16(psy, pXWall->busy);
325             }
326             int nTile = wall[nWall].picnum;
327             int px = (wall[nWall].xpanning<<8)+pXWall->xpanFrac;
328             int py = (wall[nWall].ypanning<<8)+pXWall->ypanFrac;
329             px += (psx<<2)>>((uint8_t)picsiz[nTile]&15);
330             py += (psy<<2)>>((uint8_t)picsiz[nTile]/16);
331             wall[nWall].xpanning = px>>8;
332             wall[nWall].ypanning = py>>8;
333             pXWall->xpanFrac = px&255;
334             pXWall->ypanFrac = py&255;
335         }
336     }
337 }
338 
InitSectorFX(void)339 void InitSectorFX(void)
340 {
341     shadeCount = 0;
342     panCount = 0;
343     wallPanCount = 0;
344     for (int i = 0; i < numsectors; i++)
345     {
346         int nXSector = sector[i].extra;
347         if (nXSector > 0)
348         {
349             XSECTOR *pXSector = &xsector[nXSector];
350             if (pXSector->amplitude)
351                 shadeList[shadeCount++] = nXSector;
352             if (pXSector->panVel)
353                 panList[panCount++] = nXSector;
354         }
355     }
356     for (int i = 0; i < numwalls; i++)
357     {
358         int nXWall = wall[i].extra;
359         if (nXWall > 0)
360         {
361             XWALL *pXWall = &xwall[nXWall];
362             if (pXWall->panXVel || pXWall->panYVel)
363                 wallPanList[wallPanCount++] = nXWall;
364         }
365     }
366 }
367 
368 class CSectorListMgr
369 {
370 public:
371     CSectorListMgr();
372     int CreateList(short);
373     void AddSector(int, short);
374     int GetSectorCount(int);
375     short *GetSectorList(int);
376 private:
377     int nLists;
378     int nListSize[32];
379     int nListStart[32];
380     short nSectors[kMaxSectors];
381 };
382 
CSectorListMgr()383 CSectorListMgr::CSectorListMgr()
384 {
385     nLists = 0;
386 }
387 
CreateList(short nSector)388 int CSectorListMgr::CreateList(short nSector)
389 {
390     int nStart = 0;
391     if (nLists)
392         nStart = nListStart[nLists-1]+nListStart[nLists-1];
393     int nList = nLists;
394     nListStart[nList] = nStart;
395     nListSize[nList] = 1;
396     nLists++;
397     short *pList = GetSectorList(nList);
398     pList[0] = nSector;
399     return nList;
400 }
401 
AddSector(int nList,short nSector)402 void CSectorListMgr::AddSector(int nList, short nSector)
403 {
404     for (int i = nLists; i > nList; i--)
405     {
406         short *pList = GetSectorList(i);
407         int nCount = GetSectorCount(i);
408         memmove(pList+1,pList,nCount*sizeof(short));
409         nListStart[i]++;
410     }
411     short *pList = GetSectorList(nList);
412     int nCount = GetSectorCount(nList);
413     pList[nCount] = nSector;
414     nListSize[nList]++;
415 }
416 
GetSectorCount(int nList)417 int CSectorListMgr::GetSectorCount(int nList)
418 {
419     return nListSize[nList];
420 }
421 
GetSectorList(int nList)422 short * CSectorListMgr::GetSectorList(int nList)
423 {
424     return nSectors+nListStart[nList];
425 }
426