/ source / blood / src / mirrors.cpp
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  }