diff --git a/source/build/src/engine.cpp b/source/build/src/engine.cpp index dbd359661..157076653 100644 --- a/source/build/src/engine.cpp +++ b/source/build/src/engine.cpp @@ -1368,6 +1368,8 @@ static int32_t *swplc, *lplc, *swall, *lwall; static float *swallf; #endif +uint8_t* mirrorBuffer; + static int32_t smostcnt; static int32_t smoststart[MAXWALLSB]; static char smostwalltype[MAXWALLSB]; @@ -1467,7 +1469,7 @@ int16_t searchsector, searchwall, searchstat; //search output // When aiming at a 2-sided wall, 1 if aiming at the bottom part, 0 else int16_t searchbottomwall, searchisbottom; -char inpreparemirror = 0, mirrorrender = 0; +char inpreparemirror = 0; static int32_t mirrorsx1, mirrorsy1, mirrorsx2, mirrorsy2; #define MAXSETVIEW 4 @@ -8025,8 +8027,6 @@ int32_t renderDrawRoomsQ16(int32_t daposx, int32_t daposy, int32_t daposz, int32_t i, j, /*cz, fz,*/ closest; int16_t *shortptr1, *shortptr2; - int32_t didmirror = 0; - beforedrawrooms = 0; set_globalpos(daposx, daposy, daposz); @@ -8183,7 +8183,7 @@ int32_t renderDrawRoomsQ16(int32_t daposx, int32_t daposy, int32_t daposz, polymost_drawrooms(); if (videoGetRenderMode() != REND_CLASSIC) - return 0; + return inpreparemirror; //============================================================================= //POLYMOST ENDS #endif @@ -8236,16 +8236,14 @@ int32_t renderDrawRoomsQ16(int32_t daposx, int32_t daposy, int32_t daposz, // INPREPAREMIRROR_NO_BUNCHES // numbunches==0 can happen if the mirror is far away... the game code decides // to draw it, but scansector gets zero bunches. Result: big screwup! - // Leave inpreparemirror as is, it's restored by completemirror. + // Set inpreparemirror to 0 to indicate that we were unable to render the mirror if (numbunches==0) { + inpreparemirror = 0; videoEndDrawing(); //!!! return 0; } - inpreparemirror = 0; - didmirror = 1; - mirrorsx1 = xdimen-1; mirrorsx2 = 0; for (i=numscans-1; i>=0; i--) { @@ -8301,7 +8299,7 @@ int32_t renderDrawRoomsQ16(int32_t daposx, int32_t daposy, int32_t daposz, videoEndDrawing(); //}}} - return didmirror; + return inpreparemirror; } // UTILITY TYPES AND FUNCTIONS FOR DRAWMASKS OCCLUSION TREE @@ -9962,6 +9960,7 @@ static void videoAllocateBuffers(void) { (void **)&dotp1, clamped_ydim * sizeof(intptr_t) }, { (void **)&dotp2, clamped_ydim * sizeof(intptr_t) }, { (void **)&lastx, clamped_ydim * sizeof(int32_t) }, + { (void **)&mirrorBuffer, (size_t) (xdim * ydim)}, }; for (i = 0; i < (signed)ARRAY_SIZE(dynarray); i++) @@ -11701,7 +11700,6 @@ void squarerotatetile(int16_t tilenume) void renderPrepareMirror(int32_t dax, int32_t day, fix16_t daang, int16_t dawall, int32_t *tposx, int32_t *tposy, fix16_t *tang) { - mirrorrender = 1; const int32_t x = wall[dawall].x, dx = wall[wall[dawall].point2].x-x; const int32_t y = wall[dawall].y, dy = wall[wall[dawall].point2].y-y; @@ -11764,15 +11762,15 @@ void renderPrepareMirrorOld(int32_t dax, int32_t day, int32_t daz, fix16_t daang // void renderCompleteMirror(void) { - mirrorrender = 0; + // Don't try to complete a mirror if we haven't drawn the reflection for one + if (!inpreparemirror) { return; } + inpreparemirror = 0; + #ifdef USE_OPENGL if (videoGetRenderMode() != REND_CLASSIC) return; #endif - // Can't reverse when the world has not yet been drawn from the other side. - if (inpreparemirror) { inpreparemirror = 0; return; } - // The mirroring code maps the rightmost pixel to the right neighbor of the // leftmost one (see copybufreverse() call below). Thus, the leftmost would // be mapped to the right neighbor of the rightmost one, which would be out @@ -11795,22 +11793,21 @@ void renderCompleteMirror(void) int const height = mirrorsy2-mirrorsy1; // Address of the mirror wall's top left corner in the source scene: - intptr_t p = frameplace + ylookup[windowxy1.y+mirrorsy1] + windowxy1.x+mirrorsx1; + intptr_t s = (intptr_t) mirrorBuffer + ylookup[windowxy1.y+mirrorsy1] + windowxy1.x+mirrorsx1; - // Offset (wrt p) of a mirror line's left corner in the destination: - // p+destof == frameplace + ylookup[...] + windowxy2.x-mirrorsx2 - int const destofs = windowxy2.x-mirrorsx2-windowxy1.x-mirrorsx1; + // Pointer to the mirror line's left corner in the destination: + intptr_t d = (intptr_t) frameplace + ylookup[windowxy1.y+mirrorsy1] + windowxy2.x-mirrorsx2; for (bssize_t y=0; y= bytesperline*ydim) + if ((p-mirrorBuffer) + width-1 >= bytesperline*ydim) printf("oob read: mirrorsx1=%d, mirrorsx2=%d\n", mirrorsx1, mirrorsx2); #endif - copybufbyte((void *)p, tempbuf, width); - copybufreverse(&tempbuf[width-1], (void *)(p+destofs+1), width); + copybufreverse((void *)(s+width-1), (void *)(d+1), width); - p += ylookup[1]; + s += ylookup[1]; + d += ylookup[1]; faketimerhandler(); } diff --git a/source/build/src/engine_priv.h b/source/build/src/engine_priv.h index 5910b8a29..3a1470354 100644 --- a/source/build/src/engine_priv.h +++ b/source/build/src/engine_priv.h @@ -209,6 +209,7 @@ extern int16_t thesector[MAXWALLSB], thewall[MAXWALLSB]; extern int16_t bunchfirst[MAXWALLSB], bunchlast[MAXWALLSB]; extern int16_t maskwall[MAXWALLSB], maskwallcnt; extern tspriteptr_t tspriteptr[MAXSPRITESONSCREEN + 1]; +extern uint8_t* mirrorBuffer; extern int32_t xdimen, xdimenrecip, halfxdimen, xdimenscale, xdimscale, ydimen; extern float fxdimen; extern intptr_t frameoffset; @@ -236,7 +237,7 @@ extern int32_t searchx, searchy; extern int16_t searchsector, searchwall, searchstat; extern int16_t searchbottomwall, searchisbottom; -extern char inpreparemirror, mirrorrender; +extern char inpreparemirror; extern char picsiz[MAXTILES]; extern int16_t sectorborder[256]; diff --git a/source/build/src/polymost.cpp b/source/build/src/polymost.cpp index 72a9bdec9..bd0762986 100644 --- a/source/build/src/polymost.cpp +++ b/source/build/src/polymost.cpp @@ -5505,7 +5505,7 @@ void polymost_drawrooms() gctang = (gctang > 0.f) ? 1.f : -1.f; } - if (mirrorrender) + if (inpreparemirror) gstang = -gstang; //Generate viewport trapezoid (for handling screen up/down) @@ -5525,7 +5525,7 @@ void polymost_drawrooms() } #if !SOFTROTMAT - if (mirrorrender) + if (inpreparemirror) gstang = -gstang; #endif @@ -5603,20 +5603,19 @@ void polymost_drawrooms() grhalfxdown10x = grhalfxdown10; - if (mirrorrender) - grhalfxdown10x = -grhalfxdown10; - if (inpreparemirror) { - inpreparemirror = 0; - // see engine.c: INPREPAREMIRROR_NO_BUNCHES if (numbunches > 0) { + grhalfxdown10x = -grhalfxdown10; polymost_drawalls(0); numbunches--; bunchfirst[0] = bunchfirst[numbunches]; bunchlast[0] = bunchlast[numbunches]; + } else + { + inpreparemirror = 0; } } diff --git a/source/build/src/sdlayer.cpp b/source/build/src/sdlayer.cpp index 9c0c3442f..ea854b90a 100644 --- a/source/build/src/sdlayer.cpp +++ b/source/build/src/sdlayer.cpp @@ -1650,21 +1650,22 @@ void videoBeginDrawing(void) if (offscreenrendering) return; + if (inpreparemirror) + { + frameplace = (intptr_t)mirrorBuffer; + } + else #ifdef USE_OPENGL if (!nogl) { frameplace = (intptr_t)glsurface_getBuffer(); - if (modechange) - { - bytesperline = xdim; - calc_ylookup(bytesperline, ydim); - modechange=0; - } - return; } + else #endif + { + frameplace = (intptr_t)softsurface_getBuffer(); + } - frameplace = (intptr_t)softsurface_getBuffer(); if (modechange) { bytesperline = xdim; diff --git a/source/duke3d/src/game.cpp b/source/duke3d/src/game.cpp index 8f86b98d6..2c1508f1a 100644 --- a/source/duke3d/src/game.cpp +++ b/source/duke3d/src/game.cpp @@ -623,17 +623,44 @@ void G_HandleMirror(int32_t x, int32_t y, int32_t z, fix16_t a, fix16_t q16horiz int32_t tposx, tposy; fix16_t tang; + //prepare to render any scripted EVENT_DISPLAYROOMS extras as mirrored renderPrepareMirror(x, y, a, g_mirrorWall[i], &tposx, &tposy, &tang); int32_t j = g_visibility; g_visibility = (j>>1) + (j>>2); + //backup original camera position + int32_t origCamX = CAMERA(pos.x); + int32_t origCamY = CAMERA(pos.y); + int32_t origCamZ = CAMERA(pos.z); + fix16_t origCamq16ang = CAMERA(q16ang); + fix16_t origCamq16horiz = CAMERA(q16horiz); + //set the camera inside the mirror facing out + CAMERA(pos.x) = tposx; + CAMERA(pos.y) = tposy; + CAMERA(pos.z) = z; + CAMERA(q16ang) = tang; + CAMERA(q16horiz) = q16horiz; + display_mirror = 1; + VM_OnEventWithReturn(EVENT_DISPLAYROOMS, g_player[0].ps->i, 0, 0); + display_mirror = 0; + //reset the camera position + CAMERA(pos.x) = origCamX; + CAMERA(pos.y) = origCamY; + CAMERA(pos.z) = origCamZ; + CAMERA(q16ang) = origCamq16ang; + CAMERA(q16horiz) = origCamq16horiz; + + //prepare to render the mirror + renderPrepareMirror(x, y, a, g_mirrorWall[i], &tposx, &tposy, &tang); + if (videoGetRenderMode() != REND_POLYMER) { int32_t didmirror; yax_preparedrawrooms(); didmirror = renderDrawRoomsQ16(tposx,tposy,z,tang,q16horiz,g_mirrorSector[i]+MAXSECTORS); + //POGO: if didmirror == 0, we may simply wish to abort instead of rendering with yax_drawrooms (which may require cleaning yax state) yax_drawrooms(G_DoSpriteAnimations, g_mirrorSector[i], didmirror, smoothratio); } #ifdef USE_OPENGL @@ -649,19 +676,22 @@ void G_HandleMirror(int32_t x, int32_t y, int32_t z, fix16_t a, fix16_t q16horiz renderCompleteMirror(); //Reverse screen x-wise in this function g_visibility = j; } + } +} +static void G_ClearGotMirror() +{ #ifdef SPLITSCREEN_MOD_HACKS - if (!g_fakeMultiMode) + if (!g_fakeMultiMode) #endif - { - // HACK for splitscreen mod: this is so that mirrors will be drawn - // from showview commands. Ugly, because we'll attempt do draw mirrors - // each frame then. But it's better than not drawing them, I guess. - // XXX: fix the sequence of setting/clearing this bit. Right now, - // we always draw one frame without drawing the mirror, after which - // the bit gets set and drawn subsequently. - gotpic[MIRROR>>3] &= ~(1<<(MIRROR&7)); - } + { + // HACK for splitscreen mod: this is so that mirrors will be drawn + // from showview commands. Ugly, because we'll attempt do draw mirrors + // each frame then. But it's better than not drawing them, I guess. + // XXX: fix the sequence of setting/clearing this bit. Right now, + // we always draw one frame without drawing the mirror, after which + // the bit gets set and drawn subsequently. + gotpic[MIRROR>>3] &= ~(1<<(MIRROR&7)); } } @@ -1029,6 +1059,7 @@ void G_DrawRooms(int32_t playerNum, int32_t smoothRatio) #endif G_HandleMirror(CAMERA(pos.x), CAMERA(pos.y), CAMERA(pos.z), CAMERA(q16ang), CAMERA(q16horiz), smoothRatio); + G_ClearGotMirror(); #ifdef LEGACY_ROR G_SE40(smoothRatio); #endif diff --git a/source/duke3d/src/gameexec.cpp b/source/duke3d/src/gameexec.cpp index e697175c3..ed03e8e36 100644 --- a/source/duke3d/src/gameexec.cpp +++ b/source/duke3d/src/gameexec.cpp @@ -1175,6 +1175,7 @@ LUNATIC_EXTERN void G_ShowView(vec3_t vec, fix16_t a, fix16_t horiz, int sect, i if (g_screenCapture) return; + //POGOTODO: check if this has anything to do with cameras not rendering the skybox properly if (offscreenrendering) { videoClearViewableArea(0); @@ -1215,7 +1216,8 @@ LUNATIC_EXTERN void G_ShowView(vec3_t vec, fix16_t a, fix16_t horiz, int sect, i renderSetAspect(viewingRange, yxAspect); int const smoothratio = calc_smoothratio(totalclock, ototalclock); G_DoInterpolations(smoothratio); - G_HandleMirror(vec.x, vec.y, vec.z, a, horiz, smoothratio); + if (!display_mirror) + G_HandleMirror(vec.x, vec.y, vec.z, a, horiz, smoothratio); #ifdef POLYMER if (videoGetRenderMode() == REND_POLYMER) polymer_setanimatesprites(G_DoSpriteAnimations, vec.x, vec.y, fix16_to_int(a), smoothratio);