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