mirrors.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 "build.h" 24 #include "compat.h" 25 #ifdef POLYMER 26 #include "polymer.h" 27 #endif 28 #include "common_game.h" 29 #include "blood.h" 30 #include "db.h" 31 #include "gameutil.h" 32 #include "loadsave.h" 33 #include "player.h" 34 #include "sectorfx.h" 35 #include "trig.h" 36 #include "view.h" 37 #include "warp.h" 38 39 bool gMirrorDrawing; 40 41 int mirrorcnt, mirrorsector, mirrorwall[4]; 42 43 typedef struct 44 { 45 int at0; 46 int at4; 47 int at8; 48 int atc; 49 int at10; 50 int at14; 51 } MIRROR; 52 53 MIRROR mirror[16]; 54 55 #ifdef POLYMER 56 void PolymerRORCallback(int16_t sectnum, int16_t wallnum, int8_t rorstat, int16_t* msectnum, int32_t* gx, int32_t* gy, int32_t* gz) 57 { 58 UNREFERENCED_PARAMETER(wallnum); 59 int nMirror; 60 switch (rorstat) 61 { 62 case 1: 63 nMirror = sector[sectnum].ceilingpicnum-4080; 64 *msectnum = mirror[nMirror].at4; 65 *gx += mirror[nMirror].at8; 66 *gy += mirror[nMirror].atc; 67 *gz += mirror[nMirror].at10; 68 break; 69 case 2: 70 nMirror = sector[sectnum].floorpicnum-4080; 71 *msectnum = mirror[nMirror].at4; 72 *gx += mirror[nMirror].at8; 73 *gy += mirror[nMirror].atc; 74 *gz += mirror[nMirror].at10; 75 break; 76 } 77 } 78 #endif 79 80 void InitMirrors(void) 81 { 82 83 #ifdef USE_OPENGL 84 r_rortexture = 4080; 85 r_rortexturerange = 16; 86 #ifdef POLYMER 87 polymer_setrorcallback(PolymerRORCallback); 88 #endif // POLYMER 89 90 #endif 91 gMirrorDrawing = false; 92 mirrorcnt = 0; 93 tilesiz[504].x = 0; 94 tilesiz[504].y = 0; 95 tileDelete(504); 96 97 for(int i = 0; i < 16; i++) 98 tilesiz[4080+i].x = 0, tilesiz[4080+i].y = 0; 99 for (int i = numwalls - 1; i >= 0; i--) 100 { 101 if (mirrorcnt == 16) 102 break; 103 int nTile = 4080+mirrorcnt; 104 if (wall[i].overpicnum == 504) 105 { 106 if (wall[i].extra > 0 && GetWallType(i) == kWallStack) 107 { 108 wall[i].overpicnum = nTile; 109 mirror[mirrorcnt].at14 = i; 110 mirror[mirrorcnt].at0 = 0; 111 wall[i].cstat |= 32; 112 int tmp = xwall[wall[i].extra].data; 113 int j; 114 for (j = numwalls - 1; j >= 0; j--) 115 { 116 if (j == i) 117 continue; 118 if (wall[j].extra > 0 && GetWallType(i) == kWallStack) 119 { 120 if (tmp != xwall[wall[j].extra].data) 121 continue; 122 wall[i].hitag = j; 123 wall[j].hitag = i; 124 mirror[mirrorcnt].at4 = j; 125 break; 126 } 127 } 128 if (j < 0) 129 ThrowError("wall[%d] has no matching wall link! (data=%d)\n", i, tmp); 130 mirrorcnt++; 131 } 132 continue; 133 } 134 if (wall[i].picnum == 504) 135 { 136 mirror[mirrorcnt].at4 = i; 137 mirror[mirrorcnt].at14 = i; 138 wall[i].picnum = nTile; 139 mirror[mirrorcnt].at0 = 0; 140 wall[i].cstat |= 32; 141 mirrorcnt++; 142 continue; 143 } 144 } 145 for (int i = numsectors - 1; i >= 0; i--) 146 { 147 if (mirrorcnt >= 15) 148 break; 149 150 if (sector[i].floorpicnum == 504) 151 { 152 int nLink = gUpperLink[i]; 153 if (nLink < 0) 154 continue; 155 int nLink2 = sprite[nLink].owner; 156 int j = sprite[nLink2].sectnum; 157 if (sector[j].ceilingpicnum != 504) 158 ThrowError("Lower link sector %d doesn't have mirror picnum\n", j); 159 mirror[mirrorcnt].at0 = 2; 160 mirror[mirrorcnt].at8 = sprite[nLink2].x-sprite[nLink].x; 161 mirror[mirrorcnt].atc = sprite[nLink2].y-sprite[nLink].y; 162 mirror[mirrorcnt].at10 = sprite[nLink2].z-sprite[nLink].z; 163 mirror[mirrorcnt].at14 = i; 164 mirror[mirrorcnt].at4 = j; 165 sector[i].floorpicnum = 4080+mirrorcnt; 166 mirrorcnt++; 167 mirror[mirrorcnt].at0 = 1; 168 mirror[mirrorcnt].at8 = sprite[nLink].x-sprite[nLink2].x; 169 mirror[mirrorcnt].atc = sprite[nLink].y-sprite[nLink2].y; 170 mirror[mirrorcnt].at10 = sprite[nLink].z-sprite[nLink2].z; 171 mirror[mirrorcnt].at14 = j; 172 mirror[mirrorcnt].at4 = i; 173 sector[j].ceilingpicnum = 4080+mirrorcnt; 174 mirrorcnt++; 175 } 176 } 177 mirrorsector = numsectors; 178 for (int i = 0; i < 4; i++) 179 { 180 mirrorwall[i] = numwalls+i; 181 wall[mirrorwall[i]].picnum = 504; 182 wall[mirrorwall[i]].overpicnum = 504; 183 wall[mirrorwall[i]].cstat = 0; 184 wall[mirrorwall[i]].nextsector = -1; 185 wall[mirrorwall[i]].nextwall = -1; 186 wall[mirrorwall[i]].point2 = numwalls+i+1; 187 } 188 wall[mirrorwall[3]].point2 = mirrorwall[0]; 189 sector[mirrorsector].ceilingpicnum = 504; 190 sector[mirrorsector].floorpicnum = 504; 191 sector[mirrorsector].wallptr = mirrorwall[0]; 192 sector[mirrorsector].wallnum = 4; 193 } 194 195 void TranslateMirrorColors(int nShade, int nPalette) 196 { 197 if (videoGetRenderMode() != REND_CLASSIC) 198 return; 199 videoBeginDrawing(); 200 nShade = ClipRange(nShade, 0, 63); 201 char *pMap = palookup[nPalette] + (nShade<<8); 202 extern intptr_t frameplace; 203 char *pFrame = (char*)frameplace; 204 unsigned int nPixels = xdim*ydim; 205 for (unsigned int i = 0; i < nPixels; i++, pFrame++) 206 { 207 *pFrame = pMap[*pFrame]; 208 } 209 videoEndDrawing(); 210 } 211 212 void sub_5571C(char mode) 213 { 214 for (int i = mirrorcnt-1; i >= 0; i--) 215 { 216 int nTile = 4080+i; 217 if (TestBitString(gotpic, nTile)) 218 { 219 switch (mirror[i].at0) 220 { 221 case 1: 222 if (mode) 223 sector[mirror[i].at14].ceilingstat |= 1; 224 else 225 sector[mirror[i].at14].ceilingstat &= ~1; 226 break; 227 case 2: 228 if (mode) 229 sector[mirror[i].at14].floorstat |= 1; 230 else 231 sector[mirror[i].at14].floorstat &= ~1; 232 break; 233 } 234 } 235 } 236 } 237 238 void sub_557C4(int x, int y, int interpolation) 239 { 240 if (spritesortcnt == 0) return; 241 int nViewSprites = spritesortcnt; 242 for (int nTSprite = nViewSprites-1; nTSprite >= 0; nTSprite--) 243 { 244 tspritetype *pTSprite = &tsprite[nTSprite]; 245 pTSprite->xrepeat = pTSprite->yrepeat = 0; 246 } 247 for (int i = mirrorcnt-1; i >= 0; i--) 248 { 249 int nTile = 4080+i; 250 if (TestBitString(gotpic, nTile)) 251 { 252 if (mirror[i].at0 == 1 || mirror[i].at0 == 2) 253 { 254 int nSector = mirror[i].at4; 255 int nSector2 = mirror[i].at14; 256 for (int nSprite = headspritesect[nSector]; nSprite >= 0; nSprite = nextspritesect[nSprite]) 257 { 258 spritetype *pSprite = &sprite[nSprite]; 259 if (pSprite == gView->pSprite) 260 continue; 261 int top, bottom; 262 GetSpriteExtents(pSprite, &top, &bottom); 263 int zCeil, zFloor; 264 getzsofslope(nSector, pSprite->x, pSprite->y, &zCeil, &zFloor); 265 if (pSprite->statnum == kStatDude && (top < zCeil || bottom > zFloor)) 266 { 267 int j = i; 268 if (mirror[i].at0 == 2) 269 j++; 270 else 271 j--; 272 int dx = mirror[j].at8; 273 int dy = mirror[j].atc; 274 int dz = mirror[j].at10; 275 if (spritesortcnt < maxspritesonscreen) 276 { 277 tspritetype *pTSprite = &tsprite[spritesortcnt]; 278 memset(pTSprite, 0, sizeof(tspritetype)); 279 pTSprite->type = pSprite->type; 280 pTSprite->index = pSprite->index; 281 pTSprite->sectnum = nSector2; 282 pTSprite->x = pSprite->x+dx; 283 pTSprite->y = pSprite->y+dy; 284 pTSprite->z = pSprite->z+dz; 285 pTSprite->ang = pSprite->ang; 286 pTSprite->picnum = pSprite->picnum; 287 pTSprite->shade = pSprite->shade; 288 pTSprite->pal = pSprite->pal; 289 pTSprite->xrepeat = pSprite->xrepeat; 290 pTSprite->yrepeat = pSprite->yrepeat; 291 pTSprite->xoffset = pSprite->xoffset; 292 pTSprite->yoffset = pSprite->yoffset; 293 pTSprite->cstat = pSprite->cstat; 294 if (!VanillaMode()) 295 { 296 pTSprite->statnum = pSprite->statnum; 297 viewReplacePlayerAsCultist(pTSprite, pSprite->index, pSprite->extra); 298 } 299 pTSprite->statnum = kStatDecoration; 300 pTSprite->owner = pSprite->index; 301 pTSprite->extra = pSprite->extra; 302 pTSprite->flags = pSprite->hitag|0x200; 303 if (gViewInterpolate) 304 { 305 LOCATION *pLocation = &gPrevSpriteLoc[pSprite->index]; 306 pTSprite->x = dx+interpolate(pLocation->x, pSprite->x, interpolation); 307 pTSprite->y = dy+interpolate(pLocation->y, pSprite->y, interpolation); 308 pTSprite->z = dz+interpolate(pLocation->z, pSprite->z, interpolation); 309 pTSprite->ang = pLocation->ang+mulscale16(((pSprite->ang-pLocation->ang+1024)&2047)-1024,interpolation); 310 } 311 spritesortcnt++; 312 } 313 } 314 } 315 } 316 } 317 } 318 for (int nTSprite = spritesortcnt-1; nTSprite >= nViewSprites; nTSprite--) 319 { 320 tspritetype *pTSprite = &tsprite[nTSprite]; 321 int nAnim = 0; 322 switch (picanm[pTSprite->picnum].extra&7) 323 { 324 case 1: 325 { 326 int dX = x - pTSprite->x; 327 int dY = y - pTSprite->y; 328 RotateVector(&dX, &dY, 128 - pTSprite->ang); 329 nAnim = GetOctant(dX, dY); 330 if (nAnim <= 4) 331 { 332 pTSprite->cstat &= ~4; 333 } 334 else 335 { 336 nAnim = 8 - nAnim; 337 pTSprite->cstat |= 4; 338 } 339 break; 340 } 341 case 2: 342 { 343 int dX = x - pTSprite->x; 344 int dY = y - pTSprite->y; 345 RotateVector(&dX, &dY, 128 - pTSprite->ang); 346 nAnim = GetOctant(dX, dY); 347 break; 348 } 349 } 350 while (nAnim > 0) 351 { 352 pTSprite->picnum += picanm[pTSprite->picnum].num+1; 353 nAnim--; 354 } 355 } 356 } 357 358 void DrawMirrors(int x, int y, int z, fix16_t a, fix16_t horiz, int smooth, int viewPlayer) 359 { 360 if (videoGetRenderMode() == REND_POLYMER) 361 return; 362 for (int i = mirrorcnt - 1; i >= 0; i--) 363 { 364 int nTile = 4080+i; 365 if (TestBitString(gotpic, nTile)) 366 { 367 ClearBitString(gotpic, nTile); 368 switch (mirror[i].at0) 369 { 370 case 0: 371 { 372 gMirrorDrawing = true; 373 int nWall = mirror[i].at4; 374 int nSector = sectorofwall(nWall); 375 walltype *pWall = &wall[nWall]; 376 int nNextWall = pWall->nextwall; 377 int nNextSector = pWall->nextsector; 378 pWall->nextwall = mirrorwall[0]; 379 pWall->nextsector = mirrorsector; 380 wall[mirrorwall[0]].nextwall = nWall; 381 wall[mirrorwall[0]].nextsector = nSector; 382 wall[mirrorwall[0]].x = wall[pWall->point2].x; 383 wall[mirrorwall[0]].y = wall[pWall->point2].y; 384 wall[mirrorwall[1]].x = pWall->x; 385 wall[mirrorwall[1]].y = pWall->y; 386 wall[mirrorwall[2]].x = wall[mirrorwall[1]].x+(wall[mirrorwall[1]].x-wall[mirrorwall[0]].x)*16; 387 wall[mirrorwall[2]].y = wall[mirrorwall[1]].y+(wall[mirrorwall[1]].y-wall[mirrorwall[0]].y)*16; 388 wall[mirrorwall[3]].x = wall[mirrorwall[0]].x+(wall[mirrorwall[0]].x-wall[mirrorwall[1]].x)*16; 389 wall[mirrorwall[3]].y = wall[mirrorwall[0]].y+(wall[mirrorwall[0]].y-wall[mirrorwall[1]].y)*16; 390 sector[mirrorsector].floorz = sector[nSector].floorz; 391 sector[mirrorsector].ceilingz = sector[nSector].ceilingz; 392 int cx, cy, ca; 393 if (GetWallType(nWall) == kWallStack) 394 { 395 cx = x - (wall[pWall->hitag].x-wall[pWall->point2].x); 396 cy = y - (wall[pWall->hitag].y-wall[pWall->point2].y); 397 ca = a; 398 } 399 else 400 { 401 //renderPrepareMirror(x,y, fix16_from_int(a),nWall,&cx,&cy,&ca); 402 renderPrepareMirror(x,y,z,a,horiz,nWall,&cx,&cy,&ca); 403 } 404 #ifdef POLYMER 405 if (videoGetRenderMode() == REND_POLYMER) 406 polymer_setanimatesprites(viewProcessSprites, cx, cy, z, fix16_to_int(ca), smooth); 407 #endif 408 yax_preparedrawrooms(); 409 int32_t didmirror = renderDrawRoomsQ16(cx, cy, z, ca,horiz,mirrorsector|MAXSECTORS); 410 UpdateGotSectorSectorFX(); 411 yax_drawrooms(viewProcessSprites, mirrorsector, didmirror, smooth); 412 viewProcessSprites(cx,cy,z,fix16_to_int(ca),smooth); 413 renderDrawMasks(); 414 if (GetWallType(nWall) != kWallStack) 415 renderCompleteMirror(); 416 if (wall[nWall].pal != 0 || wall[nWall].shade != 0) 417 TranslateMirrorColors(wall[nWall].shade, wall[nWall].pal); 418 pWall->nextwall = nNextWall; 419 pWall->nextsector = nNextSector; 420 gMirrorDrawing = false; 421 return; 422 } 423 case 1: 424 { 425 #ifdef USE_OPENGL 426 r_rorphase = 1; 427 #endif 428 int nSector = mirror[i].at4; 429 int bakCstat; 430 if (viewPlayer >= 0) 431 { 432 bakCstat = gPlayer[viewPlayer].pSprite->cstat; 433 if (gViewPos == VIEWPOS_0) 434 { 435 gPlayer[viewPlayer].pSprite->cstat |= CSTAT_SPRITE_INVISIBLE; 436 } 437 else 438 { 439 gPlayer[viewPlayer].pSprite->cstat |= CSTAT_SPRITE_TRANSLUCENT_INVERT | CSTAT_SPRITE_TRANSLUCENT; 440 } 441 } 442 #ifdef POLYMER 443 if (videoGetRenderMode() == REND_POLYMER) 444 polymer_setanimatesprites(viewProcessSprites, x+mirror[i].at8, y+mirror[i].atc, z+mirror[i].at10, fix16_to_int(a), smooth); 445 #endif 446 yax_preparedrawrooms(); 447 renderDrawRoomsQ16(x+mirror[i].at8, y+mirror[i].atc, z+mirror[i].at10, a, horiz, nSector|MAXSECTORS); 448 UpdateGotSectorSectorFX(); 449 yax_drawrooms(viewProcessSprites, nSector, 0, smooth); 450 viewProcessSprites(x+mirror[i].at8, y+mirror[i].atc, z+mirror[i].at10, fix16_to_int(a), smooth); 451 short fstat = sector[nSector].floorstat; 452 sector[nSector].floorstat |= 1; 453 renderDrawMasks(); 454 sector[nSector].floorstat = fstat; 455 for (int i = 0; i < 16; i++) 456 ClearBitString(gotpic, 4080+i); 457 if (viewPlayer >= 0) 458 { 459 gPlayer[viewPlayer].pSprite->cstat = bakCstat; 460 } 461 #ifdef USE_OPENGL 462 r_rorphase = 0; 463 #endif 464 return; 465 } 466 case 2: 467 { 468 #ifdef USE_OPENGL 469 r_rorphase = 1; 470 #endif 471 int nSector = mirror[i].at4; 472 int bakCstat; 473 if (viewPlayer >= 0) 474 { 475 bakCstat = gPlayer[viewPlayer].pSprite->cstat; 476 if (gViewPos == VIEWPOS_0) 477 { 478 gPlayer[viewPlayer].pSprite->cstat |= CSTAT_SPRITE_INVISIBLE; 479 } 480 else 481 { 482 gPlayer[viewPlayer].pSprite->cstat |= CSTAT_SPRITE_TRANSLUCENT_INVERT | CSTAT_SPRITE_TRANSLUCENT; 483 } 484 } 485 #ifdef POLYMER 486 if (videoGetRenderMode() == REND_POLYMER) 487 polymer_setanimatesprites(viewProcessSprites, x+mirror[i].at8, y+mirror[i].atc, z+mirror[i].at10, fix16_to_int(a), smooth); 488 #endif 489 yax_preparedrawrooms(); 490 renderDrawRoomsQ16(x+mirror[i].at8, y+mirror[i].atc, z+mirror[i].at10, a, horiz, nSector|MAXSECTORS); 491 UpdateGotSectorSectorFX(); 492 yax_drawrooms(viewProcessSprites, nSector, 0, smooth); 493 viewProcessSprites(x+mirror[i].at8, y+mirror[i].atc, z+mirror[i].at10, fix16_to_int(a), smooth); 494 short cstat = sector[nSector].ceilingstat; 495 sector[nSector].ceilingstat |= 1; 496 renderDrawMasks(); 497 sector[nSector].ceilingstat = cstat; 498 for (int i = 0; i < 16; i++) 499 ClearBitString(gotpic, 4080+i); 500 if (viewPlayer >= 0) 501 { 502 gPlayer[viewPlayer].pSprite->cstat = bakCstat; 503 } 504 #ifdef USE_OPENGL 505 r_rorphase = 0; 506 #endif 507 return; 508 } 509 } 510 } 511 } 512 } 513 514 class MirrorLoadSave : public LoadSave { 515 public: 516 void Load(void); 517 void Save(void); 518 }; 519 520 static MirrorLoadSave *myLoadSave; 521 522 void MirrorLoadSave::Load(void) 523 { 524 #ifdef USE_OPENGL 525 r_rortexture = 4080; 526 r_rortexturerange = 16; 527 #ifdef POLYMER 528 polymer_setrorcallback(PolymerRORCallback); 529 #endif // POLYMER 530 531 #endif 532 Read(&mirrorcnt,sizeof(mirrorcnt)); 533 Read(&mirrorsector,sizeof(mirrorsector)); 534 Read(mirror, sizeof(mirror)); 535 Read(mirrorwall, sizeof(mirrorwall)); 536 gMirrorDrawing = false; 537 tilesiz[504].x = 0; 538 tilesiz[504].y = 0; 539 540 for (int i = 0; i < 16; i++) 541 tilesiz[4080 + i].x = 0, tilesiz[4080 + i].y = 0; 542 for (int i = 0; i < 4; i++) 543 { 544 wall[mirrorwall[i]].picnum = 504; 545 wall[mirrorwall[i]].overpicnum = 504; 546 wall[mirrorwall[i]].cstat = 0; 547 wall[mirrorwall[i]].nextsector = -1; 548 wall[mirrorwall[i]].nextwall = -1; 549 wall[mirrorwall[i]].point2 = numwalls+i+1; 550 } 551 wall[mirrorwall[3]].point2 = mirrorwall[0]; 552 sector[mirrorsector].ceilingpicnum = 504; 553 sector[mirrorsector].floorpicnum = 504; 554 sector[mirrorsector].wallptr = mirrorwall[0]; 555 sector[mirrorsector].wallnum = 4; 556 } 557 558 void MirrorLoadSave::Save(void) 559 { 560 Write(&mirrorcnt,sizeof(mirrorcnt)); 561 Write(&mirrorsector,sizeof(mirrorsector)); 562 Write(mirror, sizeof(mirror)); 563 Write(mirrorwall, sizeof(mirrorwall)); 564 } 565 566 void MirrorLoadSaveConstruct(void) 567 { 568 myLoadSave = new MirrorLoadSave(); 569 }