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 = §or[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