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