diff --git a/src/actor.h b/src/actor.h index 863e4fb46..2199c205e 100644 --- a/src/actor.h +++ b/src/actor.h @@ -401,6 +401,7 @@ enum ActorFlag8 { MF8_FRIGHTENING = 0x00000001, // for those moments when halloween just won't do MF8_INSCROLLSEC = 0x00000002, // actor is partially inside a scrolling sector + MF8_BLOCKASPLAYER = 0x00000004, // actor is blocked by player-blocking lines even if not a player }; // --- mobj.renderflags --- diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index 63c4f9a01..2fe139c62 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -210,44 +210,47 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool processlights, bool auto vcount = flat->sector->ibocount; gl_RenderState.Apply(); + auto iboindex = flat->iboindex; if (gl.legacyMode) { processlights = false; - goto legacy; + iboindex = -1; } - if (vcount > 0 && !gl_RenderState.GetClipLineShouldBeActive()) + if (iboindex >= 0) { - if (processlights) SetupSectorLights(flat, GLPASS_ALL, &dli); - drawcalls.Clock(); - glDrawElements(GL_TRIANGLES, vcount, GL_UNSIGNED_INT, GLRenderer->mVBO->GetIndexPointer() + flat->iboindex); - drawcalls.Unclock(); - flatvertices += vcount; - flatprimitives++; - } - else if (flat->iboindex >= 0) - { - int index = flat->iboindex; - for (int i=0; isector->subsectorcount; i++) + if (vcount > 0 && !gl_RenderState.GetClipLineShouldBeActive()) { - subsector_t * sub = flat->sector->subsectors[i]; - if (sub->numlines <= 2) continue; - - if (ss_renderflags[sub->Index()]& flat->renderflags || istrans) + if (processlights) SetupSectorLights(flat, GLPASS_ALL, &dli); + drawcalls.Clock(); + glDrawElements(GL_TRIANGLES, vcount, GL_UNSIGNED_INT, GLRenderer->mVBO->GetIndexPointer() + iboindex); + drawcalls.Unclock(); + flatvertices += vcount; + flatprimitives++; + } + else + { + int index = iboindex; + for (int i = 0; i < flat->sector->subsectorcount; i++) { - if (processlights) SetupSubsectorLights(flat, GLPASS_ALL, sub, &dli); - drawcalls.Clock(); - glDrawElements(GL_TRIANGLES, (sub->numlines - 2) * 3, GL_UNSIGNED_INT, GLRenderer->mVBO->GetIndexPointer() + index); - drawcalls.Unclock(); - flatvertices += sub->numlines; - flatprimitives++; + subsector_t * sub = flat->sector->subsectors[i]; + if (sub->numlines <= 2) continue; + + if (ss_renderflags[sub->Index()] & flat->renderflags || istrans) + { + if (processlights) SetupSubsectorLights(flat, GLPASS_ALL, sub, &dli); + drawcalls.Clock(); + glDrawElements(GL_TRIANGLES, (sub->numlines - 2) * 3, GL_UNSIGNED_INT, GLRenderer->mVBO->GetIndexPointer() + index); + drawcalls.Unclock(); + flatvertices += sub->numlines; + flatprimitives++; + } + index += (sub->numlines - 2) * 3; } - index += (sub->numlines - 2) * 3; } } else { - legacy: // Draw the subsectors belonging to this sector for (int i=0; isector->subsectorcount; i++) { diff --git a/src/memarena.cpp b/src/memarena.cpp index d19521edf..f5544708d 100644 --- a/src/memarena.cpp +++ b/src/memarena.cpp @@ -46,6 +46,7 @@ struct FMemArena::Block Block *NextBlock; void *Limit; // End of this block void *Avail; // Start of free space in this block + void *alignme; // align to 16 bytes. void Reset(); void *Alloc(size_t size); @@ -94,7 +95,7 @@ FMemArena::~FMemArena() // //========================================================================== -void *FMemArena::Alloc(size_t size) +void *FMemArena::iAlloc(size_t size) { Block *block; @@ -110,6 +111,11 @@ void *FMemArena::Alloc(size_t size) return block->Alloc(size); } +void *FMemArena::Alloc(size_t size) +{ + return iAlloc((size + 15) & ~15); +} + //========================================================================== // // FMemArena :: FreeAll @@ -316,7 +322,7 @@ FString *FSharedStringArena::Alloc(const FString &source) strnode = FindString(source, source.Len(), hash); if (strnode == NULL) { - strnode = (Node *)FMemArena::Alloc(sizeof(Node)); + strnode = (Node *)iAlloc(sizeof(Node)); ::new(&strnode->String) FString(source); strnode->Hash = hash; hash %= countof(Buckets); @@ -351,7 +357,7 @@ FString *FSharedStringArena::Alloc(const char *source, size_t strlen) strnode = FindString(source, strlen, hash); if (strnode == NULL) { - strnode = (Node *)FMemArena::Alloc(sizeof(Node)); + strnode = (Node *)iAlloc(sizeof(Node)); ::new(&strnode->String) FString(source, strlen); strnode->Hash = hash; hash %= countof(Buckets); diff --git a/src/memarena.h b/src/memarena.h index 7b3b34be4..f8a15aefa 100644 --- a/src/memarena.h +++ b/src/memarena.h @@ -54,6 +54,7 @@ protected: Block *AddBlock(size_t size); void FreeBlockChain(Block *&top); + void *iAlloc(size_t size); Block *TopBlock; Block *FreeBlocks; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index db1578d49..5240d91ed 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -714,7 +714,9 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) tics = 1; } } - else + // The following condition is needed to avoid crash when player class has no death states + // Instance of player pawn will be garbage collected on reloading of level + else if (player == nullptr) { Destroy(); } diff --git a/src/p_map.cpp b/src/p_map.cpp index 89eae7859..1aab4fe78 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -930,7 +930,10 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec bool NotBlocked = ((tm.thing->flags3 & MF3_NOBLOCKMONST) || ((i_compatflags & COMPATF_NOBLOCKFRIENDS) && (tm.thing->flags & MF_FRIENDLY))); - if (!(Projectile) || (ld->flags & (ML_BLOCKEVERYTHING | ML_BLOCKPROJECTILE))) + uint32_t ProjectileBlocking = ML_BLOCKEVERYTHING | ML_BLOCKPROJECTILE; + if ( tm.thing->flags8 & MF8_BLOCKASPLAYER ) ProjectileBlocking |= ML_BLOCK_PLAYERS | ML_BLOCKING; + + if (!(Projectile) || (ld->flags & ProjectileBlocking) ) { if (ld->flags & ML_RAILING) { @@ -938,7 +941,7 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec } else if ((ld->flags & (ML_BLOCKING | ML_BLOCKEVERYTHING)) || // explicitly blocking everything (!(NotBlocked) && (ld->flags & ML_BLOCKMONSTERS)) || // block monsters only - (tm.thing->player != NULL && (ld->flags & ML_BLOCK_PLAYERS)) || // block players + (((tm.thing->player != NULL) || (tm.thing->flags8 & MF8_BLOCKASPLAYER)) && (ld->flags & ML_BLOCK_PLAYERS)) || // block players ((Projectile) && (ld->flags & ML_BLOCKPROJECTILE)) || // block projectiles ((tm.thing->flags & MF_FLOAT) && (ld->flags & ML_BLOCK_FLOATERS))) // block floaters { @@ -3100,7 +3103,7 @@ void FSlide::SlideTraverse(const DVector2 &start, const DVector2 &end) { goto isblocking; } - if (li->flags & ML_BLOCK_PLAYERS && slidemo->player != NULL) + if (li->flags & ML_BLOCK_PLAYERS && ((slidemo->player != NULL) || (slidemo->flags8 & MF8_BLOCKASPLAYER))) { goto isblocking; } @@ -4195,11 +4198,38 @@ struct aim_t thingtoppitch = -VecToAngle(dist, th->Top() - shootz); if (thingtoppitch > bottompitch) - continue; // shot over the thing + { + // Check for a hit from above + if (shootz > th->Top()) + { + double exitfrac = ExitPoint(th); + if (exitfrac > 0.) + { + double exitdist = attackrange * exitfrac; + thingtoppitch = -VecToAngle(exitdist, th->Top() - shootz); + if (thingtoppitch > bottompitch) continue; + } + else continue; // shot over the thing + } + else continue; // shot over the thing + } thingbottompitch = -VecToAngle(dist, th->Z() - shootz); if (thingbottompitch < toppitch) + { + // Check for a hit from below + if (shootz < th->Z()) + { + double exitfrac = ExitPoint(th); + if (exitfrac > 0.) + { + double exitdist = attackrange * exitfrac; + thingbottompitch = -VecToAngle(exitdist, th->Z() - shootz); + if (thingbottompitch < toppitch) continue; + } + else continue; // shot over the thing + } continue; // shot under the thing if (crossedffloors) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 5b32b410a..e8dbe8d2f 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -589,7 +589,15 @@ void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornu { actor->player->secretcount++; } - if (cl_showsecretmessage && actor->CheckLocalView(consoleplayer)) + int retval = 1; + IFVIRTUALPTR(actor, AActor, OnGiveSecret) + { + VMValue params[] = { actor, printmessage, playsound }; + VMReturn ret; + ret.IntAt(&retval); + VMCall(func, params, countof(params), &ret, 1); + } + if (retval && cl_showsecretmessage && actor->CheckLocalView(consoleplayer)) { if (printmessage) { @@ -616,6 +624,7 @@ DEFINE_ACTION_FUNCTION(AActor, GiveSecret) return 0; } + DEFINE_ACTION_FUNCTION(FLevelLocals, GiveSecret) { PARAM_PROLOGUE; diff --git a/src/po_man.cpp b/src/po_man.cpp index 76355d4db..ca12120de 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1157,7 +1157,7 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) // [TN] Check wether this actor gets blocked by the line. if (ld->backsector != NULL && !(ld->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING)) - && !(ld->flags & ML_BLOCK_PLAYERS && mobj->player) + && !(ld->flags & ML_BLOCK_PLAYERS && (mobj->player || (mobj->flags8 & MF8_BLOCKASPLAYER))) && !(ld->flags & ML_BLOCKMONSTERS && mobj->flags3 & MF3_ISMONSTER) && !((mobj->flags & MF_FLOAT) && (ld->flags & ML_BLOCK_FLOATERS)) && (!(ld->flags & ML_3DMIDTEX) || diff --git a/src/polyrenderer/drawers/poly_draw_args.cpp b/src/polyrenderer/drawers/poly_draw_args.cpp index 8aa79f70b..86b14bfd8 100644 --- a/src/polyrenderer/drawers/poly_draw_args.cpp +++ b/src/polyrenderer/drawers/poly_draw_args.cpp @@ -106,15 +106,24 @@ void PolyDrawArgs::SetLight(FSWColormap *base_colormap, uint32_t lightlevel, dou mLight = clamp(lightlevel, 0, 255); mFixedLight = fixed; - mLightRed = base_colormap->Color.r * 256 / 255; - mLightGreen = base_colormap->Color.g * 256 / 255; - mLightBlue = base_colormap->Color.b * 256 / 255; - mLightAlpha = base_colormap->Color.a * 256 / 255; + mLightRed = base_colormap->Color.r; + mLightRed += mLightRed >> 7; + mLightGreen = base_colormap->Color.g; + mLightGreen += mLightGreen >> 7; + mLightBlue = base_colormap->Color.b; + mLightBlue += mLightBlue >> 7; + mLightAlpha = base_colormap->Color.a; + mLightAlpha += mLightAlpha >> 7; mFadeRed = base_colormap->Fade.r; + mFadeRed += mFadeRed >> 7; mFadeGreen = base_colormap->Fade.g; + mFadeGreen += mFadeGreen >> 7; mFadeBlue = base_colormap->Fade.b; + mFadeBlue += mFadeBlue >> 7; mFadeAlpha = base_colormap->Fade.a; - mDesaturate = MIN(abs(base_colormap->Desaturate), 255) * 255 / 256; + mFadeAlpha += mFadeAlpha >> 7; + mDesaturate = MIN(abs(base_colormap->Desaturate), 255); + mDesaturate += mDesaturate >> 7; mSimpleShade = (base_colormap->Color.d == 0x00ffffff && base_colormap->Fade.d == 0x00000000 && base_colormap->Desaturate == 0); mColormaps = base_colormap->Maps; } diff --git a/src/polyrenderer/drawers/screen_triangle.cpp b/src/polyrenderer/drawers/screen_triangle.cpp index 4d4894dee..17dfae8b0 100644 --- a/src/polyrenderer/drawers/screen_triangle.cpp +++ b/src/polyrenderer/drawers/screen_triangle.cpp @@ -1315,8 +1315,8 @@ void DrawSpanOpt32(int y, int x0, int x1, const TriDrawTriangleArgs *args) float v1X, v1Y, v1W, v1U, v1V, v1WorldX, v1WorldY, v1WorldZ; float startX, startY; - float stepXW, stepXU, stepXV, stepWorldX, stepWorldY, stepWorldZ; - float posXW, posXU, posXV, posWorldX, posWorldY, posWorldZ; + float stepW, stepU, stepV, stepWorldX, stepWorldY, stepWorldZ; + float posW, posU, posV, posWorldX, posWorldY, posWorldZ; PolyLight *lights; int num_lights; @@ -1340,12 +1340,12 @@ void DrawSpanOpt32(int y, int x0, int x1, const TriDrawTriangleArgs *args) v1V = args->v1->v * v1W; startX = x0 + (0.5f - v1X); startY = y + (0.5f - v1Y); - stepXW = args->gradientX.W; - stepXU = args->gradientX.U; - stepXV = args->gradientX.V; - posXW = v1W + stepXW * startX + args->gradientY.W * startY; - posXU = v1U + stepXU * startX + args->gradientY.U * startY; - posXV = v1V + stepXV * startX + args->gradientY.V * startY; + stepW = args->gradientX.W; + stepU = args->gradientX.U; + stepV = args->gradientX.V; + posW = v1W + stepW * startX + args->gradientY.W * startY; + posU = v1U + stepU * startX + args->gradientY.U * startY; + posV = v1V + stepV * startX + args->gradientY.V * startY; texPixels = (const uint32_t*)args->uniforms->TexturePixels(); translation = (const uint32_t*)args->uniforms->Translation(); @@ -1364,8 +1364,8 @@ void DrawSpanOpt32(int y, int x0, int x1, const TriDrawTriangleArgs *args) float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f); shade = (fixed_t)((2.0f - (light + 12.0f) / 128.0f) * (float)FRACUNIT); - lightpos = (fixed_t)(globVis * posXW * (float)FRACUNIT); - lightstep = (fixed_t)(globVis * stepXW * (float)FRACUNIT); + lightpos = (fixed_t)(globVis * posW * (float)FRACUNIT); + lightstep = (fixed_t)(globVis * stepW * (float)FRACUNIT); int affineOffset = x0 / 16 * 16 - x0; lightpos = lightpos + lightstep * affineOffset; @@ -1411,11 +1411,11 @@ void DrawSpanOpt32(int y, int x0, int x1, const TriDrawTriangleArgs *args) dynlightcolor = args->uniforms->DynLightColor(); int affineOffset = x0 / 16 * 16 - x0; - float posLightW = posXW + stepXW * affineOffset; + float posLightW = posW + stepW * affineOffset; posWorldX = posWorldX + stepWorldX * affineOffset; posWorldY = posWorldY + stepWorldY * affineOffset; posWorldZ = posWorldZ + stepWorldZ * affineOffset; - float stepLightW = stepXW * 16.0f; + float stepLightW = stepW * 16.0f; stepWorldX *= 16.0f; stepWorldY *= 16.0f; stepWorldZ *= 16.0f; @@ -1426,10 +1426,10 @@ void DrawSpanOpt32(int y, int x0, int x1, const TriDrawTriangleArgs *args) uint32_t lit_g = GPART(dynlightcolor); uint32_t lit_b = BPART(dynlightcolor); - float rcp_posXW = 1.0f / posLightW; - float worldposX = posWorldX * rcp_posXW; - float worldposY = posWorldY * rcp_posXW; - float worldposZ = posWorldZ * rcp_posXW; + float rcp_posW = 1.0f / posLightW; + float worldposX = posWorldX * rcp_posW; + float worldposY = posWorldY * rcp_posW; + float worldposZ = posWorldZ * rcp_posW; for (int i = 0; i < num_lights; i++) { float lightposX = lights[i].x; @@ -1516,60 +1516,34 @@ void DrawSpanOpt32(int y, int x0, int x1, const TriDrawTriangleArgs *args) inv_desaturate = 256 - desaturate; } + fixed_t fuzzscale; + int _fuzzpos; + if (ModeT::BlendOp == STYLEOP_Fuzz) + { + fuzzscale = (200 << FRACBITS) / viewheight; + _fuzzpos = swrenderer::fuzzpos; + } + uint32_t *dest = (uint32_t*)args->dest; uint32_t *destLine = dest + args->pitch * y; int x = x0; while (x < x1) { - uint32_t fg = 0; - - if (ModeT::SWFlags & SWSTYLEF_Fill) - { - fg = fillcolor; - } - else if (ModeT::SWFlags & SWSTYLEF_FogBoundary) - { - fg = destLine[x]; - } - else if (ModeT::BlendOp != STYLEOP_Fuzz) - { - float rcpW = 0x01000000 / posXW; - int32_t u = (int32_t)(posXU * rcpW); - int32_t v = (int32_t)(posXV * rcpW); - uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; - uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; - - if (ModeT::SWFlags & SWSTYLEF_Translated) - { - fg = translation[((const uint8_t*)texPixels)[texelX * texHeight + texelY]]; - } - else if (ModeT::Flags & STYLEF_RedIsAlpha) - { - fg = ((const uint8_t*)texPixels)[texelX * texHeight + texelY]; - } - else - { - fg = texPixels[texelX * texHeight + texelY]; - } - } - if (ModeT::BlendOp == STYLEOP_Fuzz) { using namespace swrenderer; - float rcpW = 0x01000000 / posXW; - int32_t u = (int32_t)(posXU * rcpW); - int32_t v = (int32_t)(posXV * rcpW); + float rcpW = 0x01000000 / posW; + int32_t u = (int32_t)(posU * rcpW); + int32_t v = (int32_t)(posV * rcpW); uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; unsigned int sampleshadeout = APART(texPixels[texelX * texHeight + texelY]); sampleshadeout += sampleshadeout >> 7; // 255 -> 256 - fixed_t fuzzscale = (200 << FRACBITS) / viewheight; - int scaled_x = (x * fuzzscale) >> FRACBITS; - int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + fuzzpos; + int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + _fuzzpos; fixed_t fuzzcount = FUZZTABLE << FRACBITS; fixed_t fuzz = ((fuzz_x << FRACBITS) + y * fuzzscale) % fuzzcount; @@ -1587,8 +1561,13 @@ void DrawSpanOpt32(int y, int x0, int x1, const TriDrawTriangleArgs *args) } else if (ModeT::SWFlags & SWSTYLEF_Skycap) { - float rcpW = 0x01000000 / posXW; - int32_t v = (int32_t)(posXV * rcpW); + float rcpW = 0x01000000 / posW; + int32_t u = (int32_t)(posU * rcpW); + int32_t v = (int32_t)(posV * rcpW); + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + + uint32_t fg = texPixels[texelX * texHeight + texelY]; int start_fade = 2; // How fast it should fade out int alpha_top = clamp(v >> (16 - start_fade), 0, 256); @@ -1616,8 +1595,71 @@ void DrawSpanOpt32(int y, int x0, int x1, const TriDrawTriangleArgs *args) destLine[x] = MAKEARGB(255, r, g, b); } } + else if (ModeT::SWFlags & SWSTYLEF_FogBoundary) + { + uint32_t fg = destLine[x]; + + int lightshade; + if (OptT::Flags & SWOPT_FixedLight) + { + lightshade = light; + } + else + { + lightshade = lightpos >> 4; + } + + uint32_t shadedfg_r, shadedfg_g, shadedfg_b; + if (OptT::Flags & SWOPT_ColoredFog) + { + uint32_t fg_r = RPART(fg); + uint32_t fg_g = GPART(fg); + uint32_t fg_b = BPART(fg); + uint32_t intensity = ((fg_r * 77 + fg_g * 143 + fg_b * 37) >> 8) * desaturate; + int inv_light = 256 - lightshade; + shadedfg_r = (((shade_fade_r * inv_light + ((fg_r * inv_desaturate + intensity) >> 8) * lightshade) >> 8) * shade_light_r) >> 8; + shadedfg_g = (((shade_fade_g * inv_light + ((fg_g * inv_desaturate + intensity) >> 8) * lightshade) >> 8) * shade_light_g) >> 8; + shadedfg_b = (((shade_fade_b * inv_light + ((fg_b * inv_desaturate + intensity) >> 8) * lightshade) >> 8) * shade_light_b) >> 8; + } + else + { + shadedfg_r = (RPART(fg) * lightshade) >> 8; + shadedfg_g = (GPART(fg) * lightshade) >> 8; + shadedfg_b = (BPART(fg) * lightshade) >> 8; + } + + destLine[x] = MAKEARGB(255, shadedfg_r, shadedfg_g, shadedfg_b); + } else { + uint32_t fg = 0; + + if (ModeT::SWFlags & SWSTYLEF_Fill) + { + fg = fillcolor; + } + else + { + float rcpW = 0x01000000 / posW; + int32_t u = (int32_t)(posU * rcpW); + int32_t v = (int32_t)(posV * rcpW); + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + + if (ModeT::SWFlags & SWSTYLEF_Translated) + { + fg = translation[((const uint8_t*)texPixels)[texelX * texHeight + texelY]]; + } + else if (ModeT::Flags & STYLEF_RedIsAlpha) + { + fg = ((const uint8_t*)texPixels)[texelX * texHeight + texelY]; + } + else + { + fg = texPixels[texelX * texHeight + texelY]; + } + } + if ((ModeT::Flags & STYLEF_ColorIsFixed) && !(ModeT::SWFlags & SWSTYLEF_Fill)) { if (ModeT::Flags & STYLEF_RedIsAlpha) @@ -1643,14 +1685,6 @@ void DrawSpanOpt32(int y, int x0, int x1, const TriDrawTriangleArgs *args) lightshade = lightpos >> 4; } - uint32_t lit_r = 0, lit_g = 0, lit_b = 0; - if (OptT::Flags & SWOPT_DynLights) - { - lit_r = posdynlight_r >> 4; - lit_g = posdynlight_g >> 4; - lit_b = posdynlight_b >> 4; - } - uint32_t shadedfg_r, shadedfg_g, shadedfg_b; if (OptT::Flags & SWOPT_ColoredFog) { @@ -1658,19 +1692,38 @@ void DrawSpanOpt32(int y, int x0, int x1, const TriDrawTriangleArgs *args) uint32_t fg_g = GPART(fg); uint32_t fg_b = BPART(fg); uint32_t intensity = ((fg_r * 77 + fg_g * 143 + fg_b * 37) >> 8) * desaturate; - shadedfg_r = (((shade_fade_r + ((fg_r * inv_desaturate + intensity) >> 8) * lightshade) >> 8) * shade_light_r) >> 8; - shadedfg_g = (((shade_fade_g + ((fg_g * inv_desaturate + intensity) >> 8) * lightshade) >> 8) * shade_light_g) >> 8; - shadedfg_b = (((shade_fade_b + ((fg_b * inv_desaturate + intensity) >> 8) * lightshade) >> 8) * shade_light_b) >> 8; + int inv_light = 256 - lightshade; + shadedfg_r = (((shade_fade_r * inv_light + ((fg_r * inv_desaturate + intensity) >> 8) * lightshade) >> 8) * shade_light_r) >> 8; + shadedfg_g = (((shade_fade_g * inv_light + ((fg_g * inv_desaturate + intensity) >> 8) * lightshade) >> 8) * shade_light_g) >> 8; + shadedfg_b = (((shade_fade_b * inv_light + ((fg_b * inv_desaturate + intensity) >> 8) * lightshade) >> 8) * shade_light_b) >> 8; - shadedfg_r = MIN(shadedfg_r + ((fg_r * lit_r) >> 8), (uint32_t)255); - shadedfg_g = MIN(shadedfg_g + ((fg_g * lit_g) >> 8), (uint32_t)255); - shadedfg_b = MIN(shadedfg_b + ((fg_b * lit_b) >> 8), (uint32_t)255); + if (OptT::Flags & SWOPT_DynLights) + { + uint32_t lit_r = posdynlight_r >> 4; + uint32_t lit_g = posdynlight_g >> 4; + uint32_t lit_b = posdynlight_b >> 4; + shadedfg_r = MIN(shadedfg_r + ((fg_r * lit_r) >> 8), (uint32_t)255); + shadedfg_g = MIN(shadedfg_g + ((fg_g * lit_g) >> 8), (uint32_t)255); + shadedfg_b = MIN(shadedfg_b + ((fg_b * lit_b) >> 8), (uint32_t)255); + } } else { - shadedfg_r = (RPART(fg) * MIN(lightshade + lit_r, (uint32_t)256)) >> 8; - shadedfg_g = (GPART(fg) * MIN(lightshade + lit_g, (uint32_t)256)) >> 8; - shadedfg_b = (BPART(fg) * MIN(lightshade + lit_b, (uint32_t)256)) >> 8; + if (OptT::Flags & SWOPT_DynLights) + { + uint32_t lit_r = posdynlight_r >> 4; + uint32_t lit_g = posdynlight_g >> 4; + uint32_t lit_b = posdynlight_b >> 4; + shadedfg_r = (RPART(fg) * MIN(lightshade + lit_r, (uint32_t)256)) >> 8; + shadedfg_g = (GPART(fg) * MIN(lightshade + lit_g, (uint32_t)256)) >> 8; + shadedfg_b = (BPART(fg) * MIN(lightshade + lit_b, (uint32_t)256)) >> 8; + } + else + { + shadedfg_r = (RPART(fg) * lightshade) >> 8; + shadedfg_g = (GPART(fg) * lightshade) >> 8; + shadedfg_b = (BPART(fg) * lightshade) >> 8; + } } if (ModeT::BlendSrc == STYLEALPHA_One && ModeT::BlendDest == STYLEALPHA_Zero) @@ -1782,9 +1835,9 @@ void DrawSpanOpt32(int y, int x0, int x1, const TriDrawTriangleArgs *args) } } - posXW += stepXW; - posXU += stepXU; - posXV += stepXV; + posW += stepW; + posU += stepU; + posV += stepV; if (OptT::Flags & SWOPT_DynLights) { posdynlight_r += dynlights_r[x >> 4]; @@ -1802,7 +1855,7 @@ void DrawSpan32(int y, int x0, int x1, const TriDrawTriangleArgs *args) { using namespace TriScreenDrawerModes; - if (args->uniforms->NumLights() == 0) + if (args->uniforms->NumLights() == 0 && args->uniforms->DynLightColor() == 0) { if (!args->uniforms->FixedLight()) { @@ -1845,8 +1898,8 @@ void DrawSpanOpt8(int y, int x0, int x1, const TriDrawTriangleArgs *args) float v1X, v1Y, v1W, v1U, v1V, v1WorldX, v1WorldY, v1WorldZ; float startX, startY; - float stepXW, stepXU, stepXV, stepWorldX, stepWorldY, stepWorldZ; - float posXW, posXU, posXV, posWorldX, posWorldY, posWorldZ; + float stepW, stepU, stepV, stepWorldX, stepWorldY, stepWorldZ; + float posW, posU, posV, posWorldX, posWorldY, posWorldZ; PolyLight *lights; int num_lights; @@ -1869,12 +1922,12 @@ void DrawSpanOpt8(int y, int x0, int x1, const TriDrawTriangleArgs *args) v1V = args->v1->v * v1W; startX = x0 + (0.5f - v1X); startY = y + (0.5f - v1Y); - stepXW = args->gradientX.W; - stepXU = args->gradientX.U; - stepXV = args->gradientX.V; - posXW = v1W + stepXW * startX + args->gradientY.W * startY; - posXU = v1U + stepXU * startX + args->gradientY.U * startY; - posXV = v1V + stepXV * startX + args->gradientY.V * startY; + stepW = args->gradientX.W; + stepU = args->gradientX.U; + stepV = args->gradientX.V; + posW = v1W + stepW * startX + args->gradientY.W * startY; + posU = v1U + stepU * startX + args->gradientY.U * startY; + posV = v1V + stepV * startX + args->gradientY.V * startY; texPixels = args->uniforms->TexturePixels(); translation = args->uniforms->Translation(); @@ -1898,8 +1951,8 @@ void DrawSpanOpt8(int y, int x0, int x1, const TriDrawTriangleArgs *args) float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f); shade = (fixed_t)((2.0f - (light + 12.0f) / 128.0f) * (float)FRACUNIT); - lightpos = (fixed_t)(globVis * posXW * (float)FRACUNIT); - lightstep = (fixed_t)(globVis * stepXW * (float)FRACUNIT); + lightpos = (fixed_t)(globVis * posW * (float)FRACUNIT); + lightstep = (fixed_t)(globVis * stepW * (float)FRACUNIT); int affineOffset = x0 / 16 * 16 - x0; lightpos = lightpos + lightstep * affineOffset; @@ -1945,11 +1998,11 @@ void DrawSpanOpt8(int y, int x0, int x1, const TriDrawTriangleArgs *args) dynlightcolor = args->uniforms->DynLightColor(); int affineOffset = x0 / 16 * 16 - x0; - float posLightW = posXW + stepXW * affineOffset; + float posLightW = posW + stepW * affineOffset; posWorldX = posWorldX + stepWorldX * affineOffset; posWorldY = posWorldY + stepWorldY * affineOffset; posWorldZ = posWorldZ + stepWorldZ * affineOffset; - float stepLightW = stepXW * 16.0f; + float stepLightW = stepW * 16.0f; stepWorldX *= 16.0f; stepWorldY *= 16.0f; stepWorldZ *= 16.0f; @@ -1960,10 +2013,10 @@ void DrawSpanOpt8(int y, int x0, int x1, const TriDrawTriangleArgs *args) uint32_t lit_g = GPART(dynlightcolor); uint32_t lit_b = BPART(dynlightcolor); - float rcp_posXW = 1.0f / posLightW; - float worldposX = posWorldX * rcp_posXW; - float worldposY = posWorldY * rcp_posXW; - float worldposZ = posWorldZ * rcp_posXW; + float rcp_posW = 1.0f / posLightW; + float worldposX = posWorldX * rcp_posW; + float worldposY = posWorldY * rcp_posW; + float worldposZ = posWorldZ * rcp_posW; for (int i = 0; i < num_lights; i++) { float lightposX = lights[i].x; @@ -2038,53 +2091,33 @@ void DrawSpanOpt8(int y, int x0, int x1, const TriDrawTriangleArgs *args) } } + fixed_t fuzzscale; + int _fuzzpos; + if (ModeT::BlendOp == STYLEOP_Fuzz) + { + fuzzscale = (200 << FRACBITS) / viewheight; + _fuzzpos = swrenderer::fuzzpos; + } + uint8_t *dest = (uint8_t*)args->dest; uint8_t *destLine = dest + args->pitch * y; int x = x0; while (x < x1) { - int fg = 0; - int fgalpha = 255; - - if (ModeT::SWFlags & SWSTYLEF_Fill) - { - fg = fillcolor; - } - else if (ModeT::SWFlags & SWSTYLEF_FogBoundary) - { - fg = destLine[x]; - } - else if (ModeT::BlendOp != STYLEOP_Fuzz) - { - float rcpW = 0x01000000 / posXW; - int32_t u = (int32_t)(posXU * rcpW); - int32_t v = (int32_t)(posXV * rcpW); - uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; - uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; - fg = texPixels[texelX * texHeight + texelY]; - - if (ModeT::SWFlags & SWSTYLEF_Translated) - fg = translation[fg]; - - fgalpha = (fg != 0) ? 255 : 0; - } - if (ModeT::BlendOp == STYLEOP_Fuzz) { using namespace swrenderer; - float rcpW = 0x01000000 / posXW; - int32_t u = (int32_t)(posXU * rcpW); - int32_t v = (int32_t)(posXV * rcpW); + float rcpW = 0x01000000 / posW; + int32_t u = (int32_t)(posU * rcpW); + int32_t v = (int32_t)(posV * rcpW); uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; unsigned int sampleshadeout = (texPixels[texelX * texHeight + texelY] != 0) ? 256 : 0; - fixed_t fuzzscale = (200 << FRACBITS) / viewheight; - int scaled_x = (x * fuzzscale) >> FRACBITS; - int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + fuzzpos; + int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + _fuzzpos; fixed_t fuzzcount = FUZZTABLE << FRACBITS; fixed_t fuzz = ((fuzz_x << FRACBITS) + y * fuzzscale) % fuzzcount; @@ -2102,8 +2135,12 @@ void DrawSpanOpt8(int y, int x0, int x1, const TriDrawTriangleArgs *args) } else if (ModeT::SWFlags & SWSTYLEF_Skycap) { - float rcpW = 0x01000000 / posXW; - int32_t v = (int32_t)(posXV * rcpW); + float rcpW = 0x01000000 / posW; + int32_t u = (int32_t)(posU * rcpW); + int32_t v = (int32_t)(posV * rcpW); + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + int fg = texPixels[texelX * texHeight + texelY]; int start_fade = 2; // How fast it should fade out int alpha_top = clamp(v >> (16 - start_fade), 0, 256); @@ -2133,8 +2170,48 @@ void DrawSpanOpt8(int y, int x0, int x1, const TriDrawTriangleArgs *args) destLine[x] = RGB256k.All[((r >> 2) << 12) | ((g >> 2) << 6) | (b >> 2)]; } } + else if (ModeT::SWFlags & SWSTYLEF_FogBoundary) + { + int fg = destLine[x]; + + uint8_t shadedfg; + if (OptT::Flags & SWOPT_FixedLight) + { + shadedfg = colormaps[light + fg]; + } + else + { + int lightshade = (lightpos >> 4) & 0xffffff00; + shadedfg = colormaps[lightshade + fg]; + } + + destLine[x] = shadedfg; + } else { + int fg; + if (ModeT::SWFlags & SWSTYLEF_Fill) + { + fg = fillcolor; + } + else + { + float rcpW = 0x01000000 / posW; + int32_t u = (int32_t)(posU * rcpW); + int32_t v = (int32_t)(posV * rcpW); + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + fg = texPixels[texelX * texHeight + texelY]; + } + + int fgalpha = 255; + + if (ModeT::BlendDest == STYLEALPHA_InvSrc) + { + if (fg == 0) + fgalpha = 0; + } + if ((ModeT::Flags & STYLEF_ColorIsFixed) && !(ModeT::SWFlags & SWSTYLEF_Fill)) { if (ModeT::Flags & STYLEF_RedIsAlpha) @@ -2147,6 +2224,9 @@ void DrawSpanOpt8(int y, int x0, int x1, const TriDrawTriangleArgs *args) fgalpha = (fgalpha * alpha) >> 8; } + if (ModeT::SWFlags & SWSTYLEF_Translated) + fg = translation[fg]; + uint8_t shadedfg; if (OptT::Flags & SWOPT_FixedLight) { @@ -2289,9 +2369,9 @@ void DrawSpanOpt8(int y, int x0, int x1, const TriDrawTriangleArgs *args) } } - posXW += stepXW; - posXU += stepXU; - posXV += stepXV; + posW += stepW; + posU += stepU; + posV += stepV; if (OptT::Flags & SWOPT_DynLights) { posdynlight_r += dynlights_r[x >> 4]; @@ -2309,7 +2389,7 @@ void DrawSpan8(int y, int x0, int x1, const TriDrawTriangleArgs *args) { using namespace TriScreenDrawerModes; - if (args->uniforms->NumLights() == 0) + if (args->uniforms->NumLights() == 0 && args->uniforms->DynLightColor() == 0) { if (!args->uniforms->FixedLight()) DrawSpanOpt8(y, x0, x1, args); @@ -2325,6 +2405,532 @@ void DrawSpan8(int y, int x0, int x1, const TriDrawTriangleArgs *args) } } +template +void DrawRect8(const void *destOrg, int destWidth, int destHeight, int destPitch, const RectDrawArgs *args, PolyTriangleThreadData *thread) +{ + using namespace TriScreenDrawerModes; + + int x0 = clamp((int)(args->X0() + 0.5f), 0, destWidth); + int x1 = clamp((int)(args->X1() + 0.5f), 0, destWidth); + int y0 = clamp((int)(args->Y0() + 0.5f), 0, destHeight); + int y1 = clamp((int)(args->Y1() + 0.5f), 0, destHeight); + + if (x1 <= x0 || y1 <= y0) + return; + + const uint8_t *colormaps, *texPixels, *translation; + int texWidth, texHeight; + uint32_t fillcolor; + int alpha; + uint32_t light; + + texPixels = args->TexturePixels(); + translation = args->Translation(); + texWidth = args->TextureWidth(); + texHeight = args->TextureHeight(); + fillcolor = args->Color(); + alpha = args->Alpha(); + colormaps = args->BaseColormap(); + light = args->Light(); + light += light >> 7; // 255 -> 256 + light = ((256 - light) * NUMCOLORMAPS) & 0xffffff00; + + fixed_t fuzzscale; + int _fuzzpos; + if (ModeT::BlendOp == STYLEOP_Fuzz) + { + fuzzscale = (200 << FRACBITS) / viewheight; + _fuzzpos = swrenderer::fuzzpos; + } + + float fstepU = (args->U1() - args->U0()) / (args->X1() - args->X0()); + float fstepV = (args->V1() - args->V0()) / (args->Y1() - args->Y0()); + uint32_t startU = (int32_t)((args->U0() + (x0 + 0.5f - args->X0()) * fstepU) * 0x1000000); + uint32_t startV = (int32_t)((args->V0() + (y0 + 0.5f - args->Y0()) * fstepV) * 0x1000000); + uint32_t stepU = (int32_t)(fstepU * 0x1000000); + uint32_t stepV = (int32_t)(fstepV * 0x1000000); + + uint32_t posV = startV; + int num_cores = thread->num_cores; + int skip = thread->skipped_by_thread(y0); + posV += skip * stepV; + stepV *= num_cores; + for (int y = y0 + skip; y < y1; y += num_cores, posV += stepV) + { + uint8_t *destLine = ((uint8_t*)destOrg) + y * destPitch; + + uint32_t posU = startU; + for (int x = x0; x < x1; x++) + { + if (ModeT::BlendOp == STYLEOP_Fuzz) + { + using namespace swrenderer; + + uint32_t texelX = (((posU << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = (((posV << 8) >> 16) * texHeight) >> 16; + unsigned int sampleshadeout = (texPixels[texelX * texHeight + texelY] != 0) ? 256 : 0; + + int scaled_x = (x * fuzzscale) >> FRACBITS; + int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + _fuzzpos; + + fixed_t fuzzcount = FUZZTABLE << FRACBITS; + fixed_t fuzz = ((fuzz_x << FRACBITS) + y * fuzzscale) % fuzzcount; + unsigned int alpha = fuzzoffset[fuzz >> FRACBITS]; + + sampleshadeout = (sampleshadeout * alpha) >> 5; + + uint32_t a = 256 - sampleshadeout; + + uint32_t dest = GPalette.BaseColors[destLine[x]].d; + uint32_t r = (RPART(dest) * a) >> 8; + uint32_t g = (GPART(dest) * a) >> 8; + uint32_t b = (BPART(dest) * a) >> 8; + destLine[x] = RGB256k.All[((r >> 2) << 12) | ((g >> 2) << 6) | (b >> 2)]; + } + else + { + int fg = 0; + if (ModeT::SWFlags & SWSTYLEF_Fill) + { + fg = fillcolor; + } + else + { + uint32_t texelX = (((posU << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = (((posV << 8) >> 16) * texHeight) >> 16; + fg = texPixels[texelX * texHeight + texelY]; + } + + int fgalpha = 255; + + if (ModeT::BlendDest == STYLEALPHA_InvSrc) + { + if (fg == 0) + fgalpha = 0; + } + + if ((ModeT::Flags & STYLEF_ColorIsFixed) && !(ModeT::SWFlags & SWSTYLEF_Fill)) + { + if (ModeT::Flags & STYLEF_RedIsAlpha) + fgalpha = fg; + fg = fillcolor; + } + + if (!(ModeT::Flags & STYLEF_Alpha1)) + { + fgalpha = (fgalpha * alpha) >> 8; + } + + if (ModeT::SWFlags & SWSTYLEF_Translated) + fg = translation[fg]; + + uint8_t shadedfg = colormaps[light + fg]; + + if (ModeT::BlendSrc == STYLEALPHA_One && ModeT::BlendDest == STYLEALPHA_Zero) + { + destLine[x] = shadedfg; + } + else if (ModeT::BlendSrc == STYLEALPHA_One && ModeT::BlendDest == STYLEALPHA_One) + { + uint32_t src = GPalette.BaseColors[shadedfg]; + uint32_t dest = GPalette.BaseColors[destLine[x]]; + + if (ModeT::BlendOp == STYLEOP_Add) + { + uint32_t out_r = MIN(RPART(dest) + RPART(src), 255); + uint32_t out_g = MIN(GPART(dest) + GPART(src), 255); + uint32_t out_b = MIN(BPART(dest) + BPART(src), 255); + destLine[x] = RGB256k.All[((out_r >> 2) << 12) | ((out_g >> 2) << 6) | (out_b >> 2)]; + } + else if (ModeT::BlendOp == STYLEOP_RevSub) + { + uint32_t out_r = MAX(RPART(dest) - RPART(src), 0); + uint32_t out_g = MAX(GPART(dest) - GPART(src), 0); + uint32_t out_b = MAX(BPART(dest) - BPART(src), 0); + destLine[x] = RGB256k.All[((out_r >> 2) << 12) | ((out_g >> 2) << 6) | (out_b >> 2)]; + } + else //if (ModeT::BlendOp == STYLEOP_Sub) + { + uint32_t out_r = MAX(RPART(src) - RPART(dest), 0); + uint32_t out_g = MAX(GPART(src) - GPART(dest), 0); + uint32_t out_b = MAX(BPART(src) - BPART(dest), 0); + destLine[x] = RGB256k.All[((out_r >> 2) << 12) | ((out_g >> 2) << 6) | (out_b >> 2)]; + } + } + else if (ModeT::SWFlags & SWSTYLEF_SrcColorOneMinusSrcColor) + { + uint32_t src = GPalette.BaseColors[shadedfg]; + uint32_t dest = GPalette.BaseColors[destLine[x]]; + + uint32_t sfactor_r = RPART(src); sfactor_r += sfactor_r >> 7; // 255 -> 256 + uint32_t sfactor_g = GPART(src); sfactor_g += sfactor_g >> 7; // 255 -> 256 + uint32_t sfactor_b = BPART(src); sfactor_b += sfactor_b >> 7; // 255 -> 256 + uint32_t sfactor_a = fgalpha; sfactor_a += sfactor_a >> 7; // 255 -> 256 + uint32_t dfactor_r = 256 - sfactor_r; + uint32_t dfactor_g = 256 - sfactor_g; + uint32_t dfactor_b = 256 - sfactor_b; + uint32_t out_r = (RPART(dest) * dfactor_r + RPART(src) * sfactor_r + 128) >> 8; + uint32_t out_g = (GPART(dest) * dfactor_g + GPART(src) * sfactor_g + 128) >> 8; + uint32_t out_b = (BPART(dest) * dfactor_b + BPART(src) * sfactor_b + 128) >> 8; + + destLine[x] = RGB256k.All[((out_r >> 2) << 12) | ((out_g >> 2) << 6) | (out_b >> 2)]; + } + else if (ModeT::BlendSrc == STYLEALPHA_Src && ModeT::BlendDest == STYLEALPHA_InvSrc && fgalpha == 255) + { + destLine[x] = shadedfg; + } + else if (ModeT::BlendSrc != STYLEALPHA_Src || ModeT::BlendDest != STYLEALPHA_InvSrc || fgalpha != 0) + { + uint32_t src = GPalette.BaseColors[shadedfg]; + uint32_t dest = GPalette.BaseColors[destLine[x]]; + + uint32_t sfactor = fgalpha; sfactor += sfactor >> 7; // 255 -> 256 + uint32_t dfactor = 256 - sfactor; + uint32_t src_r = RPART(src) * sfactor; + uint32_t src_g = GPART(src) * sfactor; + uint32_t src_b = BPART(src) * sfactor; + uint32_t dest_r = RPART(dest); + uint32_t dest_g = GPART(dest); + uint32_t dest_b = BPART(dest); + if (ModeT::BlendDest == STYLEALPHA_One) + { + dest_r <<= 8; + dest_g <<= 8; + dest_b <<= 8; + } + else + { + uint32_t dfactor = 256 - sfactor; + dest_r *= dfactor; + dest_g *= dfactor; + dest_b *= dfactor; + } + + uint32_t out_r, out_g, out_b; + if (ModeT::BlendOp == STYLEOP_Add) + { + if (ModeT::BlendDest == STYLEALPHA_One) + { + out_r = MIN((dest_r + src_r + 128) >> 8, 255); + out_g = MIN((dest_g + src_g + 128) >> 8, 255); + out_b = MIN((dest_b + src_b + 128) >> 8, 255); + } + else + { + out_r = (dest_r + src_r + 128) >> 8; + out_g = (dest_g + src_g + 128) >> 8; + out_b = (dest_b + src_b + 128) >> 8; + } + } + else if (ModeT::BlendOp == STYLEOP_RevSub) + { + out_r = MAX(static_cast(dest_r - src_r + 128) >> 8, 0); + out_g = MAX(static_cast(dest_g - src_g + 128) >> 8, 0); + out_b = MAX(static_cast(dest_b - src_b + 128) >> 8, 0); + } + else //if (ModeT::BlendOp == STYLEOP_Sub) + { + out_r = MAX(static_cast(src_r - dest_r + 128) >> 8, 0); + out_g = MAX(static_cast(src_g - dest_g + 128) >> 8, 0); + out_b = MAX(static_cast(src_b - dest_b + 128) >> 8, 0); + } + + destLine[x] = RGB256k.All[((out_r >> 2) << 12) | ((out_g >> 2) << 6) | (out_b >> 2)]; + } + } + + posU += stepU; + } + } +} + +template +void DrawRectOpt32(const void *destOrg, int destWidth, int destHeight, int destPitch, const RectDrawArgs *args, PolyTriangleThreadData *thread) +{ + using namespace TriScreenDrawerModes; + + int x0 = clamp((int)(args->X0() + 0.5f), 0, destWidth); + int x1 = clamp((int)(args->X1() + 0.5f), 0, destWidth); + int y0 = clamp((int)(args->Y0() + 0.5f), 0, destHeight); + int y1 = clamp((int)(args->Y1() + 0.5f), 0, destHeight); + + if (x1 <= x0 || y1 <= y0) + return; + + const uint32_t *texPixels, *translation; + int texWidth, texHeight; + uint32_t fillcolor; + int alpha; + uint32_t light; + uint32_t shade_fade_r, shade_fade_g, shade_fade_b, shade_light_r, shade_light_g, shade_light_b, desaturate, inv_desaturate; + + texPixels = (const uint32_t*)args->TexturePixels(); + translation = (const uint32_t*)args->Translation(); + texWidth = args->TextureWidth(); + texHeight = args->TextureHeight(); + fillcolor = args->Color(); + alpha = args->Alpha(); + light = args->Light(); + light += light >> 7; // 255 -> 256 + + if (OptT::Flags & SWOPT_ColoredFog) + { + shade_fade_r = args->ShadeFadeRed(); + shade_fade_g = args->ShadeFadeGreen(); + shade_fade_b = args->ShadeFadeBlue(); + shade_light_r = args->ShadeLightRed(); + shade_light_g = args->ShadeLightGreen(); + shade_light_b = args->ShadeLightBlue(); + desaturate = args->ShadeDesaturate(); + inv_desaturate = 256 - desaturate; + } + + fixed_t fuzzscale; + int _fuzzpos; + if (ModeT::BlendOp == STYLEOP_Fuzz) + { + fuzzscale = (200 << FRACBITS) / viewheight; + _fuzzpos = swrenderer::fuzzpos; + } + + float fstepU = (args->U1() - args->U0()) / (args->X1() - args->X0()); + float fstepV = (args->V1() - args->V0()) / (args->Y1() - args->Y0()); + uint32_t startU = (int32_t)((args->U0() + (x0 + 0.5f - args->X0()) * fstepU) * 0x1000000); + uint32_t startV = (int32_t)((args->V0() + (y0 + 0.5f - args->Y0()) * fstepV) * 0x1000000); + uint32_t stepU = (int32_t)(fstepU * 0x1000000); + uint32_t stepV = (int32_t)(fstepV * 0x1000000); + + uint32_t posV = startV; + int num_cores = thread->num_cores; + int skip = thread->skipped_by_thread(y0); + posV += skip * stepV; + stepV *= num_cores; + for (int y = y0 + skip; y < y1; y += num_cores, posV += stepV) + { + uint32_t *destLine = ((uint32_t*)destOrg) + y * destPitch; + + uint32_t posU = startU; + for (int x = x0; x < x1; x++) + { + if (ModeT::BlendOp == STYLEOP_Fuzz) + { + using namespace swrenderer; + + uint32_t texelX = (((posU << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = (((posV << 8) >> 16) * texHeight) >> 16; + unsigned int sampleshadeout = APART(texPixels[texelX * texHeight + texelY]); + sampleshadeout += sampleshadeout >> 7; // 255 -> 256 + + int scaled_x = (x * fuzzscale) >> FRACBITS; + int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + _fuzzpos; + + fixed_t fuzzcount = FUZZTABLE << FRACBITS; + fixed_t fuzz = ((fuzz_x << FRACBITS) + y * fuzzscale) % fuzzcount; + unsigned int alpha = fuzzoffset[fuzz >> FRACBITS]; + + sampleshadeout = (sampleshadeout * alpha) >> 5; + + uint32_t a = 256 - sampleshadeout; + + uint32_t dest = destLine[x]; + uint32_t out_r = (RPART(dest) * a) >> 8; + uint32_t out_g = (GPART(dest) * a) >> 8; + uint32_t out_b = (BPART(dest) * a) >> 8; + destLine[x] = MAKEARGB(255, out_r, out_g, out_b); + } + else + { + uint32_t fg = 0; + + if (ModeT::SWFlags & SWSTYLEF_Fill) + { + fg = fillcolor; + } + else if (ModeT::SWFlags & SWSTYLEF_FogBoundary) + { + fg = destLine[x]; + } + else + { + uint32_t texelX = (((posU << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = (((posV << 8) >> 16) * texHeight) >> 16; + + if (ModeT::SWFlags & SWSTYLEF_Translated) + { + fg = translation[((const uint8_t*)texPixels)[texelX * texHeight + texelY]]; + } + else if (ModeT::Flags & STYLEF_RedIsAlpha) + { + fg = ((const uint8_t*)texPixels)[texelX * texHeight + texelY]; + } + else + { + fg = texPixels[texelX * texHeight + texelY]; + } + } + + if ((ModeT::Flags & STYLEF_ColorIsFixed) && !(ModeT::SWFlags & SWSTYLEF_Fill)) + { + if (ModeT::Flags & STYLEF_RedIsAlpha) + fg = (fg << 24) | (fillcolor & 0x00ffffff); + else + fg = (fg & 0xff000000) | (fillcolor & 0x00ffffff); + } + + uint32_t fgalpha = fg >> 24; + + if (!(ModeT::Flags & STYLEF_Alpha1)) + { + fgalpha = (fgalpha * alpha) >> 8; + } + + int lightshade = light; + + uint32_t lit_r = 0, lit_g = 0, lit_b = 0; + + uint32_t shadedfg_r, shadedfg_g, shadedfg_b; + if (OptT::Flags & SWOPT_ColoredFog) + { + uint32_t fg_r = RPART(fg); + uint32_t fg_g = GPART(fg); + uint32_t fg_b = BPART(fg); + uint32_t intensity = ((fg_r * 77 + fg_g * 143 + fg_b * 37) >> 8) * desaturate; + shadedfg_r = (((shade_fade_r + ((fg_r * inv_desaturate + intensity) >> 8) * lightshade) >> 8) * shade_light_r) >> 8; + shadedfg_g = (((shade_fade_g + ((fg_g * inv_desaturate + intensity) >> 8) * lightshade) >> 8) * shade_light_g) >> 8; + shadedfg_b = (((shade_fade_b + ((fg_b * inv_desaturate + intensity) >> 8) * lightshade) >> 8) * shade_light_b) >> 8; + } + else + { + shadedfg_r = (RPART(fg) * lightshade) >> 8; + shadedfg_g = (GPART(fg) * lightshade) >> 8; + shadedfg_b = (BPART(fg) * lightshade) >> 8; + } + + if (ModeT::BlendSrc == STYLEALPHA_One && ModeT::BlendDest == STYLEALPHA_Zero) + { + destLine[x] = MAKEARGB(255, shadedfg_r, shadedfg_g, shadedfg_b); + } + else if (ModeT::BlendSrc == STYLEALPHA_One && ModeT::BlendDest == STYLEALPHA_One) + { + uint32_t dest = destLine[x]; + + if (ModeT::BlendOp == STYLEOP_Add) + { + uint32_t out_r = MIN(RPART(dest) + shadedfg_r, 255); + uint32_t out_g = MIN(GPART(dest) + shadedfg_g, 255); + uint32_t out_b = MIN(BPART(dest) + shadedfg_b, 255); + destLine[x] = MAKEARGB(255, out_r, out_g, out_b); + } + else if (ModeT::BlendOp == STYLEOP_RevSub) + { + uint32_t out_r = MAX(RPART(dest) - shadedfg_r, 0); + uint32_t out_g = MAX(GPART(dest) - shadedfg_g, 0); + uint32_t out_b = MAX(BPART(dest) - shadedfg_b, 0); + destLine[x] = MAKEARGB(255, out_r, out_g, out_b); + } + else //if (ModeT::BlendOp == STYLEOP_Sub) + { + uint32_t out_r = MAX(shadedfg_r - RPART(dest), 0); + uint32_t out_g = MAX(shadedfg_g - GPART(dest), 0); + uint32_t out_b = MAX(shadedfg_b - BPART(dest), 0); + destLine[x] = MAKEARGB(255, out_r, out_g, out_b); + } + } + else if (ModeT::SWFlags & SWSTYLEF_SrcColorOneMinusSrcColor) + { + uint32_t dest = destLine[x]; + + uint32_t sfactor_r = shadedfg_r; sfactor_r += sfactor_r >> 7; // 255 -> 256 + uint32_t sfactor_g = shadedfg_g; sfactor_g += sfactor_g >> 7; // 255 -> 256 + uint32_t sfactor_b = shadedfg_b; sfactor_b += sfactor_b >> 7; // 255 -> 256 + uint32_t sfactor_a = fgalpha; sfactor_a += sfactor_a >> 7; // 255 -> 256 + uint32_t dfactor_r = 256 - sfactor_r; + uint32_t dfactor_g = 256 - sfactor_g; + uint32_t dfactor_b = 256 - sfactor_b; + uint32_t out_r = (RPART(dest) * dfactor_r + shadedfg_r * sfactor_r + 128) >> 8; + uint32_t out_g = (GPART(dest) * dfactor_g + shadedfg_g * sfactor_g + 128) >> 8; + uint32_t out_b = (BPART(dest) * dfactor_b + shadedfg_b * sfactor_b + 128) >> 8; + + destLine[x] = MAKEARGB(255, out_r, out_g, out_b); + } + else if (ModeT::BlendSrc == STYLEALPHA_Src && ModeT::BlendDest == STYLEALPHA_InvSrc && fgalpha == 255) + { + destLine[x] = MAKEARGB(255, shadedfg_r, shadedfg_g, shadedfg_b); + } + else if (ModeT::BlendSrc != STYLEALPHA_Src || ModeT::BlendDest != STYLEALPHA_InvSrc || fgalpha != 0) + { + uint32_t dest = destLine[x]; + + uint32_t sfactor = fgalpha; sfactor += sfactor >> 7; // 255 -> 256 + uint32_t src_r = shadedfg_r * sfactor; + uint32_t src_g = shadedfg_g * sfactor; + uint32_t src_b = shadedfg_b * sfactor; + uint32_t dest_r = RPART(dest); + uint32_t dest_g = GPART(dest); + uint32_t dest_b = BPART(dest); + if (ModeT::BlendDest == STYLEALPHA_One) + { + dest_r <<= 8; + dest_g <<= 8; + dest_b <<= 8; + } + else + { + uint32_t dfactor = 256 - sfactor; + dest_r *= dfactor; + dest_g *= dfactor; + dest_b *= dfactor; + } + + uint32_t out_r, out_g, out_b; + if (ModeT::BlendOp == STYLEOP_Add) + { + if (ModeT::BlendDest == STYLEALPHA_One) + { + out_r = MIN((dest_r + src_r + 128) >> 8, 255); + out_g = MIN((dest_g + src_g + 128) >> 8, 255); + out_b = MIN((dest_b + src_b + 128) >> 8, 255); + } + else + { + out_r = (dest_r + src_r + 128) >> 8; + out_g = (dest_g + src_g + 128) >> 8; + out_b = (dest_b + src_b + 128) >> 8; + } + } + else if (ModeT::BlendOp == STYLEOP_RevSub) + { + out_r = MAX(static_cast(dest_r - src_r + 128) >> 8, 0); + out_g = MAX(static_cast(dest_g - src_g + 128) >> 8, 0); + out_b = MAX(static_cast(dest_b - src_b + 128) >> 8, 0); + } + else //if (ModeT::BlendOp == STYLEOP_Sub) + { + out_r = MAX(static_cast(src_r - dest_r + 128) >> 8, 0); + out_g = MAX(static_cast(src_g - dest_g + 128) >> 8, 0); + out_b = MAX(static_cast(src_b - dest_b + 128) >> 8, 0); + } + + destLine[x] = MAKEARGB(255, out_r, out_g, out_b); + } + } + + posU += stepU; + } + } +} + +template +void DrawRect32(const void *destOrg, int destWidth, int destHeight, int destPitch, const RectDrawArgs *args, PolyTriangleThreadData *thread) +{ + using namespace TriScreenDrawerModes; + + if (args->SimpleShade()) + DrawRectOpt32(destOrg, destWidth, destHeight, destPitch, args, thread); + else + DrawRectOpt32(destOrg, destWidth, destHeight, destPitch, args, thread); +} + void(*ScreenTriangle::SpanDrawers8[])(int, int, int, const TriDrawTriangleArgs *) = { &DrawSpan8, diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 9e2830cd9..2f272019e 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -757,8 +757,8 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, { // listener must be reversely offset to calculate the proper sound origin. CalcSectorSoundOrg(listenpos + disp, sector, channum, *pos); - pos->X += (float)disp.X; - pos->Z += (float)disp.Y; + pos->X -= (float)disp.X; + pos->Z -= (float)disp.Y; } else { diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 002c0a81a..1416cbc7a 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -316,6 +316,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF7, FORCEINFIGHTING, AActor, flags7), DEFINE_FLAG(MF8, FRIGHTENING, AActor, flags8), + DEFINE_FLAG(MF8, BLOCKASPLAYER, AActor, flags8), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/src/swrenderer/line/r_walldraw.cpp b/src/swrenderer/line/r_walldraw.cpp index 64f14135f..92235ae34 100644 --- a/src/swrenderer/line/r_walldraw.cpp +++ b/src/swrenderer/line/r_walldraw.cpp @@ -189,7 +189,12 @@ namespace swrenderer { auto viewport = Thread->Viewport.get(); - drawerargs.dc_viewpos.X = (float)((x + 0.5 - viewport->CenterX) / viewport->CenterX * zcol); + int tx = x; + bool mirror = !!(Thread->Portal->MirrorFlags & RF_XFLIP); + if (mirror) + tx = viewwidth - tx - 1; + + drawerargs.dc_viewpos.X = (float)((tx + 0.5 - viewport->CenterX) / viewport->CenterX * zcol); drawerargs.dc_viewpos.Y = zcol; drawerargs.dc_viewpos.Z = (float)((viewport->CenterY - y1 - 0.5) / viewport->InvZtoScale * zcol); drawerargs.dc_viewpos_step.Z = (float)(-zcol / viewport->InvZtoScale); diff --git a/src/swrenderer/plane/r_flatplane.cpp b/src/swrenderer/plane/r_flatplane.cpp index 8d0120559..88b3871a6 100644 --- a/src/swrenderer/plane/r_flatplane.cpp +++ b/src/swrenderer/plane/r_flatplane.cpp @@ -205,13 +205,21 @@ namespace swrenderer if (r_dynlights) { + int tx = x1; + bool mirror = !!(Thread->Portal->MirrorFlags & RF_XFLIP); + if (mirror) + tx = viewwidth - tx - 1; + // Find row position in view space float zspan = (float)(planeheight / (fabs(y + 0.5 - viewport->CenterY) / viewport->InvZtoScale)); - drawerargs.dc_viewpos.X = (float)((x1 + 0.5 - viewport->CenterX) / viewport->CenterX * zspan); + drawerargs.dc_viewpos.X = (float)((tx + 0.5 - viewport->CenterX) / viewport->CenterX * zspan); drawerargs.dc_viewpos.Y = zspan; drawerargs.dc_viewpos.Z = (float)((viewport->CenterY - y - 0.5) / viewport->InvZtoScale * zspan); drawerargs.dc_viewpos_step.X = (float)(zspan / viewport->CenterX); + if (mirror) + drawerargs.dc_viewpos_step.X = -drawerargs.dc_viewpos_step.X; + // Plane normal drawerargs.dc_normal.X = 0.0f; drawerargs.dc_normal.Y = 0.0f; diff --git a/src/swrenderer/scene/r_portal.cpp b/src/swrenderer/scene/r_portal.cpp index 46e6e8357..323480c32 100644 --- a/src/swrenderer/scene/r_portal.cpp +++ b/src/swrenderer/scene/r_portal.cpp @@ -173,6 +173,7 @@ namespace swrenderer Thread->Viewport->viewpoint.sector = port->mDestination; assert(Thread->Viewport->viewpoint.sector != nullptr); R_SetViewAngle(Thread->Viewport->viewpoint, Thread->Viewport->viewwindow); + Thread->Viewport->SetupPolyViewport(Thread); Thread->OpaquePass->ClearSeenSprites(); Thread->Clip3D->ClearFakeFloors(); @@ -239,6 +240,7 @@ namespace swrenderer // Masked textures and planes need the view coordinates restored for proper positioning. viewposStack.Pop(Thread->Viewport->viewpoint.Pos); + Thread->Viewport->SetupPolyViewport(Thread); Thread->TranslucentPass->Render(); VisiblePlane *pl = nullptr; // quiet, GCC! @@ -259,6 +261,7 @@ namespace swrenderer Thread->Viewport->viewpoint.extralight = savedextralight; Thread->Viewport->viewpoint.Angles = savedangles; R_SetViewAngle(Thread->Viewport->viewpoint, Thread->Viewport->viewwindow); + Thread->Viewport->SetupPolyViewport(Thread); CurrentPortalInSkybox = false; Thread->Clip3D->LeaveSkybox(); @@ -426,6 +429,8 @@ namespace swrenderer else MirrorFlags |= RF_XFLIP; } + Thread->Viewport->SetupPolyViewport(Thread); + // some portals have height differences, account for this here Thread->Clip3D->EnterSkybox(); // push 3D floor height map CurrentPortalInSkybox = false; // first portal in a skybox should set this variable to false for proper clipping in skyboxes. @@ -478,6 +483,8 @@ namespace swrenderer viewpoint.Pos = startpos; viewpoint.Path[0] = savedpath[0]; viewpoint.Path[1] = savedpath[1]; + + viewport->SetupPolyViewport(Thread); } #if 0 diff --git a/src/swrenderer/scene/r_scene.cpp b/src/swrenderer/scene/r_scene.cpp index a52d271a3..71ea71652 100644 --- a/src/swrenderer/scene/r_scene.cpp +++ b/src/swrenderer/scene/r_scene.cpp @@ -159,6 +159,8 @@ namespace swrenderer if (r_models) MainThread()->Viewport->SetupPolyViewport(MainThread()); + FRenderViewpoint origviewpoint = MainThread()->Viewport->viewpoint; + ActorRenderFlags savedflags = MainThread()->Viewport->viewpoint.camera->renderflags; // Never draw the player unless in chasecam mode if (!MainThread()->Viewport->viewpoint.showviewer) @@ -167,6 +169,12 @@ namespace swrenderer } RenderThreadSlices(); + + // Mirrors fail to restore the original viewpoint -- we need it for the HUD weapon to draw correctly. + MainThread()->Viewport->viewpoint = origviewpoint; + if (r_models) + MainThread()->Viewport->SetupPolyViewport(MainThread()); + RenderPSprites(); MainThread()->Viewport->viewpoint.camera->renderflags = savedflags; diff --git a/src/swrenderer/things/r_model.cpp b/src/swrenderer/things/r_model.cpp index 025263e34..221170e01 100644 --- a/src/swrenderer/things/r_model.cpp +++ b/src/swrenderer/things/r_model.cpp @@ -47,12 +47,22 @@ namespace swrenderer if (tz < MINZ) return; - // too far off the side? double tx = tr_x * thread->Viewport->viewpoint.Sin - tr_y * thread->Viewport->viewpoint.Cos; + + // Flip for mirrors + if (thread->Portal->MirrorFlags & RF_XFLIP) + { + tx = viewwidth - tx - 1; + } + + // too far off the side? if (fabs(tx / 64) > fabs(tz)) return; RenderModel *vis = thread->FrameMemory->NewObject(x, y, z, smf, actor, float(1 / tz)); + vis->CurrentPortalUniq = thread->Portal->CurrentPortalUniq; + vis->WorldToClip = thread->Viewport->WorldToClip; + vis->MirrorWorldToClip = !!(thread->Portal->MirrorFlags & RF_XFLIP); thread->SpriteList->Push(vis); } @@ -64,7 +74,7 @@ namespace swrenderer void RenderModel::Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) { - SWModelRenderer renderer(thread, clip3DFloor); + SWModelRenderer renderer(thread, clip3DFloor, &WorldToClip, MirrorWorldToClip); renderer.RenderModel(x, y, z, smf, actor); } @@ -72,13 +82,14 @@ namespace swrenderer void RenderHUDModel(RenderThread *thread, DPSprite *psp, float ofsx, float ofsy) { - SWModelRenderer renderer(thread, Fake3DTranslucent()); + SWModelRenderer renderer(thread, Fake3DTranslucent(), &thread->Viewport->WorldToClip, false); renderer.RenderHUDModel(psp, ofsx, ofsy); } ///////////////////////////////////////////////////////////////////////////// - SWModelRenderer::SWModelRenderer(RenderThread *thread, Fake3DTranslucent clip3DFloor) : Thread(thread), Clip3DFloor(clip3DFloor) + SWModelRenderer::SWModelRenderer(RenderThread *thread, Fake3DTranslucent clip3DFloor, Mat4f *worldToClip, bool mirrorWorldToClip) + : Thread(thread), Clip3DFloor(clip3DFloor), WorldToClip(worldToClip), MirrorWorldToClip(mirrorWorldToClip) { } @@ -123,6 +134,7 @@ namespace swrenderer if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] || !!(smf->flags & MDL_DONTCULLBACKFACES)) PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, true); + PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, !(mirrored ^ MirrorWorldToClip)); } void SWModelRenderer::EndDrawModel(AActor *actor, FSpriteModelFrame *smf) @@ -192,6 +204,7 @@ namespace swrenderer if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]) PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, true); + PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, !(mirrored ^ MirrorWorldToClip)); } void SWModelRenderer::EndDrawHUDModel(AActor *actor) @@ -221,7 +234,7 @@ namespace swrenderer swapYZ.Matrix[2 + 1 * 4] = 1.0f; swapYZ.Matrix[3 + 3 * 4] = 1.0f; - PolyTriangleDrawer::SetTransform(Thread->DrawQueue, Thread->FrameMemory->NewObject(Thread->Viewport->WorldToClip * swapYZ * ObjectToWorld)); + PolyTriangleDrawer::SetTransform(Thread->DrawQueue, Thread->FrameMemory->NewObject((*WorldToClip) * swapYZ * ObjectToWorld)); } void SWModelRenderer::DrawArrays(int start, int count) diff --git a/src/swrenderer/things/r_model.h b/src/swrenderer/things/r_model.h index 004636e69..fea1f1117 100644 --- a/src/swrenderer/things/r_model.h +++ b/src/swrenderer/things/r_model.h @@ -47,12 +47,14 @@ namespace swrenderer float x, y, z; FSpriteModelFrame *smf; AActor *actor; + Mat4f WorldToClip; + bool MirrorWorldToClip; }; class SWModelRenderer : public FModelRenderer { public: - SWModelRenderer(RenderThread *thread, Fake3DTranslucent clip3DFloor); + SWModelRenderer(RenderThread *thread, Fake3DTranslucent clip3DFloor, Mat4f *worldToClip, bool mirrorWorldToClip); ModelRendererType GetType() const override { return SWModelRendererType; } @@ -81,6 +83,8 @@ namespace swrenderer unsigned int *IndexBuffer = nullptr; TriVertex *VertexBuffer = nullptr; float InterpolationFactor = 0.0; + Mat4f *WorldToClip = nullptr; + bool MirrorWorldToClip = false; }; class SWModelVertexBuffer : public IModelVertexBuffer diff --git a/src/swrenderer/viewport/r_viewport.cpp b/src/swrenderer/viewport/r_viewport.cpp index 57994d899..e3cfc1548 100644 --- a/src/swrenderer/viewport/r_viewport.cpp +++ b/src/swrenderer/viewport/r_viewport.cpp @@ -62,6 +62,10 @@ namespace swrenderer void RenderViewport::SetupPolyViewport(RenderThread *thread) { WorldToView = SoftwareWorldToView(viewpoint); + + if (thread->Portal->MirrorFlags & RF_XFLIP) + WorldToView = Mat4f::Scale(-1.0f, 1.0f, 1.0f) * WorldToView; + ViewToClip = SoftwareViewToClip(); WorldToClip = ViewToClip * WorldToView; } diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 61afdef0d..48148f23c 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -539,6 +539,9 @@ class Actor : Thinker native { return damage; } + + // called on getting a secret, return false to disable default "secret found" message/sound + virtual bool OnGiveSecret(bool printmsg, bool playsound) { return true; } native virtual bool OkayToSwitchTarget(Actor other); native static class GetReplacement(class cls);