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