diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 29df810d6..de6c438ee 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1076,6 +1076,7 @@ set (PCH_SOURCES core/rendering/scene/hw_clipper.cpp core/rendering/scene/hw_walls.cpp core/rendering/scene/hw_flats.cpp + core/rendering/scene/hw_sprites.cpp core/rendering/scene/hw_drawlistadd.cpp core/rendering/scene/hw_drawlist.cpp core/rendering/scene/hw_drawinfo.cpp diff --git a/source/build/src/polymost.cpp b/source/build/src/polymost.cpp index 22eb3bdc1..3896fcc36 100644 --- a/source/build/src/polymost.cpp +++ b/source/build/src/polymost.cpp @@ -3329,6 +3329,7 @@ EXTERN_CVAR(Int, gl_fogmode) int32_t renderDrawRoomsQ16(int32_t daposx, int32_t daposy, int32_t daposz, fixed_t daang, fixed_t dahoriz, int16_t dacursectnum) { + spritesortcnt = 0; checkRotatedWalls(); if (gl_fogmode == 1) gl_fogmode = 2; // only radial fog works with Build's screwed up coordinate system. diff --git a/source/core/automap.cpp b/source/core/automap.cpp index 1623a3573..9d79e9067 100644 --- a/source/core/automap.cpp +++ b/source/core/automap.cpp @@ -618,7 +618,7 @@ void renderDrawMapView(int cposx, int cposy, int czoom, int cang) { auto spr = &sprite[sn]; vec2_t pp[4]; - GetFlatSpritePosition(spr, spr->pos.vec2, pp); + GetFlatSpritePosition(spr, spr->pos.vec2, pp, true); for (unsigned j = 0; j < 4; j++) { diff --git a/source/core/gamefuncs.cpp b/source/core/gamefuncs.cpp index a749d1abc..698a7d89d 100644 --- a/source/core/gamefuncs.cpp +++ b/source/core/gamefuncs.cpp @@ -231,11 +231,21 @@ void GetWallSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out) // //========================================================================== -void GetFlatSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out) +void GetFlatSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool render) { auto tex = tileGetTexture(spr->picnum); - int width = tex->GetTexelWidth() * spr->xrepeat; - int height = tex->GetTexelHeight() * spr->yrepeat; + + int width, height; + if (render && hw_hightile && TileFiles.tiledata[spr->picnum].h_xsize) + { + width = TileFiles.tiledata[spr->picnum].h_xsize * spr->xrepeat; + height = TileFiles.tiledata[spr->picnum].h_ysize * spr->yrepeat; + } + else + { + width = tex->GetTexelWidth() * spr->xrepeat; + height = tex->GetTexelHeight() * spr->yrepeat; + } int leftofs = (tex->GetTexelLeftOffset() + spr->xoffset) * spr->xrepeat; int topofs = (tex->GetTexelTopOffset() + spr->yoffset) * spr->yrepeat; diff --git a/source/core/gamefuncs.h b/source/core/gamefuncs.h index 75266b643..7cd485c3b 100644 --- a/source/core/gamefuncs.h +++ b/source/core/gamefuncs.h @@ -11,7 +11,7 @@ bool spriteIsModelOrVoxel(const spritetype* tspr); void PlanesAtPoint(const sectortype* sec, float dax, float day, float* ceilz, float* florz); void setWallSectors(); void GetWallSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out); -void GetFlatSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out); +void GetFlatSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool render = false); void checkRotatedWalls(); // y is negated so that the orientation is the same as in GZDoom, in order to use its utilities. diff --git a/source/core/rendering/scene/hw_drawinfo.cpp b/source/core/rendering/scene/hw_drawinfo.cpp index a84c88648..0bae0019c 100644 --- a/source/core/rendering/scene/hw_drawinfo.cpp +++ b/source/core/rendering/scene/hw_drawinfo.cpp @@ -283,6 +283,84 @@ HWDecal* HWDrawInfo::AddDecal(bool onmirror) #endif } +void HWDrawInfo::DispatchSprites() +{ + for (int i = 0; i < spritesortcnt; i++) + { + auto tspr = &tsprite[i]; + int tilenum = tspr->picnum; + int spritenum = tspr->owner; + + if (spritenum < 0 || (unsigned)tilenum >= MAXTILES) + continue; + + setgotpic(tilenum); + + if ((tspr->cstat & CSTAT_SPRITE_ALIGNMENT) != CSTAT_SPRITE_ALIGNMENT_SLAB) + tileUpdatePicnum(&tilenum, spritenum + 32768, 0); + + + while (!(spriteext[spritenum].flags & SPREXT_NOTMD)) + { + int pt = Ptile2tile(tspr->picnum, tspr->pal); + if (hw_models && tile2model[pt].modelid >= 0 && tile2model[pt].framenum >= 0) + { + //HWSprite hwsprite; + //if (hwsprite.ProcessModel(pt, tspr)) return; + break; + } + + if (r_voxels) + { + if ((tspr->cstat & CSTAT_SPRITE_ALIGNMENT) != CSTAT_SPRITE_ALIGNMENT_SLAB && tiletovox[tspr->picnum] >= 0 && voxmodels[tiletovox[tspr->picnum]]) + { + //HWSprite hwsprite; + //if (hwsprite.ProcessVoxel(voxmodels[tiletovox[tspr->picnum]], tspr)) return; + break; + } + else if ((tspr->cstat & CSTAT_SPRITE_ALIGNMENT) == CSTAT_SPRITE_ALIGNMENT_SLAB && tspr->picnum < MAXVOXELS && voxmodels[tspr->picnum]) + { + //HWSprite hwsprite; + //hwsprite.ProcessVoxel(voxmodels[tspr->picnum], tspr); + return; + } + } + break; + } + + if (spriteext[spritenum].flags & SPREXT_AWAY1) + { + tspr->pos.x += bcos(tspr->ang, -13); + tspr->pos.y += bsin(tspr->ang, -13); + } + else if (spriteext[spritenum].flags & SPREXT_AWAY2) + { + tspr->pos.x -= bcos(tspr->ang, -13); + tspr->pos.y -= bsin(tspr->ang, -13); + } + + switch (tspr->cstat & CSTAT_SPRITE_ALIGNMENT) + { + case CSTAT_SPRITE_ALIGNMENT_FACING: + // face sprite + break; + + case CSTAT_SPRITE_ALIGNMENT_WALL: + // wall sprite + break; + + case CSTAT_SPRITE_ALIGNMENT_FLOOR: + { + HWFlat flat; + flat.ProcessFlatSprite(this, tspr, §or[tspr->sectnum]); + break; + } + + default: + break; + } + } +} //----------------------------------------------------------------------------- // // CreateScene @@ -318,6 +396,7 @@ void HWDrawInfo::CreateScene() SetupSprite.Clock(); gi->processSprites(view.x, view.y, vp.Pos.Z * -256, bamang(vp.RotAngle), vp.TicFrac * 65536); + DispatchSprites(); SetupSprite.Unclock(); screen->mLights->Unmap(); @@ -345,14 +424,6 @@ void HWDrawInfo::RenderScene(FRenderState &state) state.EnableFog(true); state.SetRenderStyle(STYLE_Source); - if (gl_sort_textures) - { - drawlists[GLDL_PLAINWALLS].SortWalls(); - drawlists[GLDL_PLAINFLATS].SortFlats(); - drawlists[GLDL_MASKEDWALLS].SortWalls(); - drawlists[GLDL_MASKEDFLATS].SortFlats(); - drawlists[GLDL_MASKEDWALLSOFS].SortWalls(); - } // Part 1: solid geometry. This is set up so that there are no transparent parts state.SetDepthFunc(DF_Less); @@ -362,21 +433,35 @@ void HWDrawInfo::RenderScene(FRenderState &state) state.EnableTexture(gl_texture); state.EnableBrightmap(true); drawlists[GLDL_PLAINWALLS].DrawWalls(this, state, false); + drawlists[GLDL_PLAINFLATS].DrawFlats(this, state, false); // Part 2: masked geometry. This is set up so that only pixels with alpha>gl_mask_threshold will show state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); - drawlists[GLDL_MASKEDWALLS].DrawWalls(this, state, false); - drawlists[GLDL_MASKEDFLATS].DrawFlats(this, state, false); - // Part 3: masked geometry with polygon offset. This list is empty most of the time so only waste time on it when in use. - if (drawlists[GLDL_MASKEDWALLSOFS].Size() > 0) - { - state.SetDepthBias(-1, -128); - drawlists[GLDL_MASKEDWALLSOFS].DrawWalls(this, state, false); - state.ClearDepthBias(); - } + // This list is masked, non-translucent walls. + drawlists[GLDL_MASKEDWALLS].DrawWalls(this, state, false); + + // These lists must be drawn in two passes for color and depth to avoid depth fighting with overlapping entries + drawlists[GLDL_MASKEDFLATS].SortFlats(this); + //drawlists[GLDL_MASKEDWALLSV].SortWalls(this); + //drawlists[GLDL_MASKEDWALLSH].SortWalls(this); + + // these lists are only wall and floor sprites - often attached to walls and floors - so they need to be offset from the plane they may be attached to. + drawlists[GLDL_MASKEDWALLSS].DrawWalls(this, state, false); + state.SetDepthBias(-1, -128); + state.SetDepthMask(false); + drawlists[GLDL_MASKEDWALLSV].DrawWalls(this, state, false); + drawlists[GLDL_MASKEDWALLSH].DrawWalls(this, state, false); + drawlists[GLDL_MASKEDFLATS].DrawFlats(this, state, false); + state.SetDepthMask(true); + state.SetColorMask(false); + drawlists[GLDL_MASKEDWALLSV].DrawWalls(this, state, false); + drawlists[GLDL_MASKEDWALLSH].DrawWalls(this, state, false); + drawlists[GLDL_MASKEDFLATS].DrawFlats(this, state, false); + state.SetColorMask(true); + state.ClearDepthBias(); drawlists[GLDL_MODELS].Draw(this, state, false); diff --git a/source/core/rendering/scene/hw_drawinfo.h b/source/core/rendering/scene/hw_drawinfo.h index 62d38b603..70bea1fa9 100644 --- a/source/core/rendering/scene/hw_drawinfo.h +++ b/source/core/rendering/scene/hw_drawinfo.h @@ -72,6 +72,9 @@ enum DrawListType GLDL_PLAINWALLS, GLDL_PLAINFLATS, GLDL_MASKEDWALLS, + GLDL_MASKEDWALLSS, // arbitrary wall sprites. + GLDL_MASKEDWALLSV, // vertical wall sprites + GLDL_MASKEDWALLSH, // horizontal wall sprites. These two lists merely exist for easier sorting. GLDL_MASKEDFLATS, GLDL_MASKEDWALLSOFS, GLDL_MODELS, @@ -154,6 +157,7 @@ public: void DrawScene(int drawmode); void CreateScene(); + void DispatchSprites(); void RenderScene(FRenderState &state); void RenderTranslucent(FRenderState &state); void RenderPortal(HWPortal *p, FRenderState &state, bool usestencil); diff --git a/source/core/rendering/scene/hw_drawlist.cpp b/source/core/rendering/scene/hw_drawlist.cpp index 207726b59..a2c0bb116 100644 --- a/source/core/rendering/scene/hw_drawlist.cpp +++ b/source/core/rendering/scene/hw_drawlist.cpp @@ -330,7 +330,7 @@ void HWDrawList::SortSpriteIntoPlane(SortNode * head, SortNode * sort) auto hiz = ss->z1 > ss->z2 ? ss->z1 : ss->z2; auto loz = ss->z1 < ss->z2 ? ss->z1 : ss->z2; - if ((hiz > fh->z && loz < fh->z) || ss->modelframe) + if ((hiz > fh->z && loz < fh->z))// || ss->modelframe) { // We have to split this sprite HWSprite *s = NewSprite(); @@ -723,16 +723,44 @@ void HWDrawList::SortWalls() } } -void HWDrawList::SortFlats() +void HWDrawList::SortFlats(HWDrawInfo* di) { + auto viewz = di->Viewpoint.Pos.Z; if (drawitems.Size() > 1) { - std::sort(drawitems.begin(), drawitems.end(), [=](const HWDrawItem &a, const HWDrawItem &b) + TArray list1(drawitems.Size(), false); + TArray list2(drawitems.Size(), false); + + for (auto& item : drawitems) { - HWFlat * w1 = flats[a.index]; + HWFlat* w1 = flats[item.index]; + if (w1->z < viewz) list1.Push(item); + else list2.Push(item); + } + + std::sort(list1.begin(), list1.end(), [=](const HWDrawItem &a, const HWDrawItem &b) + { + HWFlat* w1 = flats[a.index]; HWFlat* w2 = flats[b.index]; - return w1->texture < w2->texture; + if (w1->z != w2->z) return w1->z < w2->z; + int time1 = w1->sprite ? w1->sprite->time : -1; + int time2 = w2->sprite ? w2->sprite->time : -1; + return time1 < time2; }); + + std::sort(list2.begin(), list2.end(), [=](const HWDrawItem& a, const HWDrawItem& b) + { + HWFlat* w1 = flats[a.index]; + HWFlat* w2 = flats[b.index]; + if (w1->z != w2->z) return w2->z < w1->z; + int time1 = w1->sprite ? w1->sprite->time : -1; + int time2 = w2->sprite ? w2->sprite->time : -1; + return time1 < time2; + }); + + drawitems.Clear(); + drawitems.Append(list1); + drawitems.Append(list2); } } diff --git a/source/core/rendering/scene/hw_drawlist.h b/source/core/rendering/scene/hw_drawlist.h index eaa0c471c..e8913d904 100644 --- a/source/core/rendering/scene/hw_drawlist.h +++ b/source/core/rendering/scene/hw_drawlist.h @@ -31,6 +31,7 @@ struct HWDrawItem HWDrawItemType rendertype; int index; + HWDrawItem() = default; // we need this for dynamic arrays. HWDrawItem(HWDrawItemType _rendertype,int _index) : rendertype(_rendertype),index(_index) {} }; @@ -92,7 +93,7 @@ public: HWSprite *NewSprite(); void Reset(); void SortWalls(); - void SortFlats(); + void SortFlats(HWDrawInfo* di); void MakeSortList(); diff --git a/source/core/rendering/scene/hw_drawlistadd.cpp b/source/core/rendering/scene/hw_drawlistadd.cpp index 22958c07c..a1c8f53d0 100644 --- a/source/core/rendering/scene/hw_drawlistadd.cpp +++ b/source/core/rendering/scene/hw_drawlistadd.cpp @@ -106,33 +106,17 @@ void HWDrawInfo::AddMirrorSurface(HWWall *w) void HWDrawInfo::AddFlat(HWFlat *flat) { - int list = GLDL_PLAINFLATS; + int list;; -#if 0 - if (flat->renderstyle != STYLE_Translucent || flat->alpha < 1.f - FLT_EPSILON) + if (flat->RenderStyle != LegacyRenderStyles[STYLE_Translucent] || flat->alpha < 1.f - FLT_EPSILON) // flat->texture->GetTranslucency() - fixme { // translucent portals go into the translucent border list. - list = GLDL_TRANSLUCENTBORDER; + list = flat->sprite? GLDL_TRANSLUCENT : GLDL_TRANSLUCENTBORDER; } - else if (flat->texture->GetTranslucency()) + else { - /* - if (flat->stack) - { - list = GLDL_TRANSLUCENTBORDER; - } - else - */ - { - list = GLDL_PLAINFLATS; - } + list = flat->sprite ? GLDL_MASKEDFLATS : GLDL_PLAINFLATS; } - else //if (flat->hacktype != SSRF_FLOODHACK) // The flood hack may later need different treatment but with the current setup can go into the existing render list. - { - bool masked = flat->texture->isMasked() && flat->stack; - list = masked ? GLDL_MASKEDFLATS : GLDL_PLAINFLATS; - } -#endif auto newflat = drawlists[list].NewFlat(); *newflat = *flat; } diff --git a/source/core/rendering/scene/hw_drawstructs.h b/source/core/rendering/scene/hw_drawstructs.h index 47500ad69..f5acc25dc 100644 --- a/source/core/rendering/scene/hw_drawstructs.h +++ b/source/core/rendering/scene/hw_drawstructs.h @@ -153,7 +153,7 @@ public: texcoord tcs[4]; float alpha; - ERenderStyle RenderStyle; + FRenderStyle RenderStyle; float ViewDistance; float visibility; @@ -181,8 +181,9 @@ public: unsigned int vertcount; public: - walltype * seg; - sectortype *frontsector, *backsector; + walltype* seg; + spritetype* sprite; + sectortype* frontsector, * backsector; //private: void PutWall(HWDrawInfo *di, bool translucent); @@ -229,6 +230,7 @@ public: public: void Process(HWDrawInfo* di, walltype* seg, sectortype* frontsector, sectortype* backsector); + void ProcessWallSprite(HWDrawInfo* di, walltype* seg, sectortype* frontsector, sectortype* backsector); float PointOnSide(float x,float y) { @@ -249,15 +251,16 @@ class HWFlat { public: sectortype * sec; + spritetype* sprite; // for flat sprites. FGameTexture *texture; float z; // the z position of the flat (only valid for non-sloped planes) FColormap Colormap; // light and fog - ERenderStyle renderstyle; PalEntry fade; int shade, palette, visibility; float alpha; + FRenderStyle RenderStyle; int iboindex; //int vboheight; @@ -272,6 +275,7 @@ public: void PutFlat(HWDrawInfo* di, int whichplane); void ProcessSector(HWDrawInfo *di, sectortype * frontsector, int which = 7 /*SSRF_RENDERALL*/); // cannot use constant due to circular dependencies. + void ProcessFlatSprite(HWDrawInfo* di, spritetype* sprite, sectortype* sector); void DrawSubsectors(HWDrawInfo *di, FRenderState &state); void DrawFlat(HWDrawInfo* di, FRenderState& state, bool translucent); @@ -293,7 +297,7 @@ public: bool fullbright; bool polyoffset; FColormap Colormap; - FSpriteModelFrame * modelframe; + int modeltype; FRenderStyle RenderStyle; int OverrideShader; diff --git a/source/core/rendering/scene/hw_flats.cpp b/source/core/rendering/scene/hw_flats.cpp index f0e8c1003..6ef51f281 100644 --- a/source/core/rendering/scene/hw_flats.cpp +++ b/source/core/rendering/scene/hw_flats.cpp @@ -97,20 +97,44 @@ void HWFlat::SetupLights(HWDrawInfo *di, FLightNode * node, FDynLightData &light void HWFlat::MakeVertices() { - auto mesh = sectorGeometry.get(sec - sector, plane); - if (!mesh) return; - auto ret = screen->mVertexData->AllocVertices(mesh->vertices.Size()); - auto vp = ret.first; - for (unsigned i = 0; i < mesh->vertices.Size(); i++) + if (vertcount > 0) return; + if (sprite == nullptr) { - auto& pt = mesh->vertices[i]; - auto& uv = mesh->texcoords[i]; - vp->SetVertex(pt.X, pt.Z, pt.Y); - vp->SetTexCoord(uv.X, uv.Y); - vp++; + auto mesh = sectorGeometry.get(sec - sector, plane); + if (!mesh) return; + auto ret = screen->mVertexData->AllocVertices(mesh->vertices.Size()); + auto vp = ret.first; + for (unsigned i = 0; i < mesh->vertices.Size(); i++) + { + auto& pt = mesh->vertices[i]; + auto& uv = mesh->texcoords[i]; + vp->SetVertex(pt.X, pt.Z, pt.Y); + vp->SetTexCoord(uv.X, uv.Y); + vp++; + } + vertindex = ret.second; + vertcount = mesh->vertices.Size(); + } + else + { + vec2_t pos[4]; + GetFlatSpritePosition(sprite, sprite->pos.vec2, pos, true); + + auto ret = screen->mVertexData->AllocVertices(6); + auto vp = ret.first; + float x = !(sprite->cstat & CSTAT_SECTOR_XFLIP) ? 0.f : 1.f; + float y = !(sprite->cstat & CSTAT_SECTOR_YFLIP) ? 0.f : 1.f; + for (unsigned i = 0; i < 6; i++) + { + const static unsigned indices[] = { 0, 1, 2, 0, 2, 3 }; + int j = indices[i]; + vp->SetVertex(pos[j].x * (1 / 16.f), z, pos[j].y * (1 / -16.f)); + vp->SetTexCoord(j == 1 || j == 2 ? 1.f - x : x, j == 2 || j == 3 ? 1.f - x : x); + vp++; + } + vertindex = ret.second; + vertcount = 6; } - vertindex = ret.second; - vertcount = mesh->vertices.Size(); } //========================================================================== @@ -132,8 +156,16 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent) } #endif - auto mesh = sectorGeometry.get(sec - sector, plane); - state.SetNormal(mesh->normal); + if (!sprite) + { + auto mesh = sectorGeometry.get(sec - sector, plane); + state.SetNormal(mesh->normal); + } + else + { + if (z < di->Viewpoint.Pos.Z) state.SetNormal({ 0,1,0 }); + else state.SetNormal({ 0, -1, 0 }); + } // Fog must be done before the texture so that the texture selector can override it. bool foggy = (GlobalMapFog || (fade & 0xffffff)); @@ -160,7 +192,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent) if (translucent) { - state.SetRenderStyle(renderstyle); + state.SetRenderStyle(RenderStyle); if (!texture->GetTranslucency()) state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); else state.AlphaFunc(Alpha_GEqual, 0.f); } @@ -186,6 +218,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent) void HWFlat::PutFlat(HWDrawInfo *di, int whichplane) { + vertcount = 0; plane = whichplane; if (!screen->BuffersArePersistent()) // should be made static buffer content later (when the logic is working) { @@ -228,6 +261,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sectortype * frontsector, int which) fade = lookups.getFade(frontsector->floorpal); // fog is per sector. visibility = sectorVisibility(frontsector); sec = frontsector; + sprite = nullptr; // // @@ -262,7 +296,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sectortype * frontsector, int which) if (texture && texture->isValid()) { //iboindex = frontsector->iboindex[sector_t::floor]; - renderstyle = STYLE_Translucent; + RenderStyle = STYLE_Translucent; PutFlat(di, 0); } } @@ -303,10 +337,45 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sectortype * frontsector, int which) if (texture && texture->isValid()) { //iboindex = frontsector->iboindex[sector_t::floor]; - renderstyle = STYLE_Translucent; + RenderStyle = STYLE_Translucent; PutFlat(di, 1); } } } } +void HWFlat::ProcessFlatSprite(HWDrawInfo* di, spritetype* sprite, sectortype* sector) +{ + int tilenum = sprite->picnum; + texture = tileGetTexture(tilenum); + z = sprite->z * (1 / -256.f); + if (z == di->Viewpoint.Pos.Z) return; // looking right at the edge. + + visibility = sectorVisibility(§or[sprite->sectnum]);// *(4.f / 5.f); // The factor comes directly from Polymost. No idea why this uses a different visibility setting. Bad projection math? + + // Weird Build logic that really makes no sense. + if ((sprite->cstat & CSTAT_SPRITE_ONE_SIDED) != 0 && (di->Viewpoint.Pos.Z < z) == ((sprite->cstat & CSTAT_SPRITE_YFLIP) == 0)) + return; + + if (texture && texture->isValid()) + { + this->sprite = sprite; + sec = sector; + shade = sprite->shade; + palette = sprite->pal; + fade = lookups.getFade(sector[sprite->sectnum].floorpal); // fog is per sector. + + bool trans = (sprite->cstat & CSTAT_SPRITE_TRANSLUCENT); + if (trans) + { + RenderStyle = GetRenderStyle(0, !!(sprite->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT)); + alpha = GetAlphaFromBlend((sprite->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT) ? DAMETH_TRANS2 : DAMETH_TRANS1, 0); + } + else + { + RenderStyle = LegacyRenderStyles[STYLE_Translucent]; + alpha = 1.f; + } + PutFlat(di, 0); + } +} diff --git a/source/core/rendering/scene/hw_sprites.cpp b/source/core/rendering/scene/hw_sprites.cpp new file mode 100644 index 000000000..e9302ab03 --- /dev/null +++ b/source/core/rendering/scene/hw_sprites.cpp @@ -0,0 +1,315 @@ + +#if 0 +void polymost_drawsprite(int32_t snum) +{ + + vec2_t off = { 0, 0 }; + + if ((globalorientation & 48) != 48) // only non-voxel sprites should do this + { + int const flag = hw_hightile && TileFiles.tiledata[globalpicnum].h_xsize; + off = { (int32_t)tspr->xoffset + (flag ? TileFiles.tiledata[globalpicnum].h_xoffs : tileLeftOffset(globalpicnum)), + (int32_t)tspr->yoffset + (flag ? TileFiles.tiledata[globalpicnum].h_yoffs : tileTopOffset(globalpicnum)) }; + } + + int32_t method = DAMETH_MASK | DAMETH_CLAMPED; + + if (tspr->cstat & 2) + method = DAMETH_CLAMPED | ((tspr->cstat & 512) ? DAMETH_TRANS2 : DAMETH_TRANS1); + + SetRenderStyleFromBlend(!!(tspr->cstat & 2), tspr->blend, !!(tspr->cstat & 512)); + + drawpoly_alpha = spriteext[spritenum].alpha; + drawpoly_blend = tspr->blend; + + sec = (usectorptr_t)§or[tspr->sectnum]; + + + vec3_t pos = tspr->pos; + + + vec2_t tsiz; + + if (hw_hightile && TileFiles.tiledata[globalpicnum].h_xsize) + tsiz = { TileFiles.tiledata[globalpicnum].h_xsize, TileFiles.tiledata[globalpicnum].h_ysize }; + else + tsiz = { tileWidth(globalpicnum), tileHeight(globalpicnum) }; + + if (tsiz.x <= 0 || tsiz.y <= 0) + return; + + vec2f_t const ftsiz = { (float) tsiz.x, (float) tsiz.y }; + + switch ((globalorientation >> 4) & 3) + { + case 0: // Face sprite + { + // Project 3D to 2D + if (globalorientation & 4) + off.x = -off.x; + // NOTE: yoff not negated not for y flipping, unlike wall and floor + // aligned sprites. + + int const ang = (getangle(tspr->x - globalposx, tspr->y - globalposy) + 1024) & 2047; + + float foffs = TSPR_OFFSET(tspr); + float foffs2 = TSPR_OFFSET(tspr); + if (fabs(foffs2) < fabs(foffs)) foffs = foffs2; + + vec2f_t const offs = { float(bcosf(ang, -6) * foffs), float(bsinf(ang, -6) * foffs) }; + + vec2f_t s0 = { (float)(tspr->x - globalposx) + offs.x, + (float)(tspr->y - globalposy) + offs.y}; + + vec2f_t p0 = { s0.y * gcosang - s0.x * gsinang, s0.x * gcosang2 + s0.y * gsinang2 }; + + if (p0.y <= SCISDIST) + goto _drawsprite_return; + + float const ryp0 = 1.f / p0.y; + s0 = { ghalfx * p0.x * ryp0 + ghalfx, ((float)(pos.z - globalposz)) * gyxscale * ryp0 + ghoriz }; + + float const f = ryp0 * fxdimen * (1.0f / 160.f); + + vec2f_t ff = { ((float)tspr->xrepeat) * f, + ((float)tspr->yrepeat) * f * ((float)yxaspect * (1.0f / 65536.f)) }; + + if (tsiz.x & 1) + s0.x += ff.x * 0.5f; + if (globalorientation & 128 && tsiz.y & 1) + s0.y += ff.y * 0.5f; + + s0.x -= ff.x * (float) off.x; + s0.y -= ff.y * (float) off.y; + + ff.x *= ftsiz.x; + ff.y *= ftsiz.y; + + vec2f_t pxy[4]; + + pxy[0].x = pxy[3].x = s0.x - ff.x * 0.5f; + pxy[1].x = pxy[2].x = s0.x + ff.x * 0.5f; + if (!(globalorientation & 128)) + { + pxy[0].y = pxy[1].y = s0.y - ff.y; + pxy[2].y = pxy[3].y = s0.y; + } + else + { + pxy[0].y = pxy[1].y = s0.y - ff.y * 0.5f; + pxy[2].y = pxy[3].y = s0.y + ff.y * 0.5f; + } + + xtex.d = ytex.d = ytex.u = xtex.v = 0; + otex.d = ryp0 * gviewxrange; + + if (!(globalorientation & 4)) + { + xtex.u = ftsiz.x * otex.d / (pxy[1].x - pxy[0].x + .002f); + otex.u = -xtex.u * (pxy[0].x - .001f); + } + else + { + xtex.u = ftsiz.x * otex.d / (pxy[0].x - pxy[1].x - .002f); + otex.u = -xtex.u * (pxy[1].x + .001f); + } + + if (!(globalorientation & 8)) + { + ytex.v = ftsiz.y * otex.d / (pxy[3].y - pxy[0].y + .002f); + otex.v = -ytex.v * (pxy[0].y - .001f); + } + else + { + ytex.v = ftsiz.y * otex.d / (pxy[0].y - pxy[3].y - .002f); + otex.v = -ytex.v * (pxy[3].y + .001f); + } + + // Clip sprites to ceilings/floors when no parallaxing and not sloped + if (!(sector[tspr->sectnum].ceilingstat & 3)) + { + s0.y = ((float) (sector[tspr->sectnum].ceilingz - globalposz)) * gyxscale * ryp0 + ghoriz; + if (pxy[0].y < s0.y) + pxy[0].y = pxy[1].y = s0.y; + } + + if (!(sector[tspr->sectnum].floorstat & 3)) + { + s0.y = ((float) (sector[tspr->sectnum].floorz - globalposz)) * gyxscale * ryp0 + ghoriz; + if (pxy[2].y > s0.y) + pxy[2].y = pxy[3].y = s0.y; + } + + vec2_16_t tempsiz = { (int16_t)tsiz.x, (int16_t)tsiz.y }; + pow2xsplit = 0; + polymost_drawpoly(pxy, 4, method, tempsiz); + + drawpoly_srepeat = 0; + drawpoly_trepeat = 0; + } + break; + + case 1: // Wall sprite + { + // Project 3D to 2D + if (globalorientation & 4) + off.x = -off.x; + + if (globalorientation & 8) + off.y = -off.y; + + vec2f_t const extent = { float(tspr->xrepeat * bsinf(tspr->ang, -16)), + float(tspr->xrepeat * -bcosf(tspr->ang, -16)) }; + + float f = (float)(tsiz.x >> 1) + (float)off.x; + + vec2f_t const vf = { extent.x * f, extent.y * f }; + + vec2f_t vec0 = { (float)(pos.x - globalposx) - vf.x, + (float)(pos.y - globalposy) - vf.y }; + + int32_t const s = tspr->owner; + int32_t walldist = 1; + int32_t w = (s == -1) ? -1 : wsprinfo[s].wall; + + vec2f_t p0 = { vec0.y * gcosang - vec0.x * gsinang, + vec0.x * gcosang2 + vec0.y * gsinang2 }; + + vec2f_t const pp = { extent.x * ftsiz.x + vec0.x, + extent.y * ftsiz.x + vec0.y }; + + vec2f_t p1 = { pp.y * gcosang - pp.x * gsinang, + pp.x * gcosang2 + pp.y * gsinang2 }; + + if ((p0.y <= SCISDIST) && (p1.y <= SCISDIST)) + goto _drawsprite_return; + + // Clip to close parallel-screen plane + vec2f_t const op0 = p0; + + float t0 = 0.f, t1 = 1.f; + + if (p0.y < SCISDIST) + { + t0 = (SCISDIST - p0.y) / (p1.y - p0.y); + p0 = { (p1.x - p0.x) * t0 + p0.x, SCISDIST }; + } + + if (p1.y < SCISDIST) + { + t1 = (SCISDIST - op0.y) / (p1.y - op0.y); + p1 = { (p1.x - op0.x) * t1 + op0.x, SCISDIST }; + } + + f = 1.f / p0.y; + const float ryp0 = f * gyxscale; + float sx0 = ghalfx * p0.x * f + ghalfx; + + f = 1.f / p1.y; + const float ryp1 = f * gyxscale; + float sx1 = ghalfx * p1.x * f + ghalfx; + + pos.z -= ((off.y * tspr->yrepeat) << 2); + + if (globalorientation & 128) + { + pos.z += ((tsiz.y * tspr->yrepeat) << 1); + + if (tsiz.y & 1) + pos.z += (tspr->yrepeat << 1); // Odd yspans + } + + xtex.d = (ryp0 - ryp1) * gxyaspect / (sx0 - sx1); + ytex.d = 0; + otex.d = ryp0 * gxyaspect - xtex.d * sx0; + + if (globalorientation & 4) + { + t0 = 1.f - t0; + t1 = 1.f - t1; + } + + xtex.u = (t0 * ryp0 - t1 * ryp1) * gxyaspect * ftsiz.x / (sx0 - sx1); + ytex.u = 0; + otex.u = t0 * ryp0 * gxyaspect * ftsiz.x - xtex.u * sx0; + + f = ((float) tspr->yrepeat) * ftsiz.y * 4; + + float sc0 = ((float) (pos.z - globalposz - f)) * ryp0 + ghoriz; + float sc1 = ((float) (pos.z - globalposz - f)) * ryp1 + ghoriz; + float sf0 = ((float) (pos.z - globalposz)) * ryp0 + ghoriz; + float sf1 = ((float) (pos.z - globalposz)) * ryp1 + ghoriz; + + // gvx*sx0 + gvy*sc0 + gvo = 0 + // gvx*sx1 + gvy*sc1 + gvo = 0 + // gvx*sx0 + gvy*sf0 + gvo = tsizy*(gdx*sx0 + gdo) + f = ftsiz.y * (xtex.d * sx0 + otex.d) / ((sx0 - sx1) * (sc0 - sf0)); + + if (!(globalorientation & 8)) + { + xtex.v = (sc0 - sc1) * f; + ytex.v = (sx1 - sx0) * f; + otex.v = -xtex.v * sx0 - ytex.v * sc0; + } + else + { + xtex.v = (sf1 - sf0) * f; + ytex.v = (sx0 - sx1) * f; + otex.v = -xtex.v * sx0 - ytex.v * sf0; + } + + // Clip sprites to ceilings/floors when no parallaxing + if (!(sector[tspr->sectnum].ceilingstat & 1)) + { + if (sector[tspr->sectnum].ceilingz > pos.z - (float)((tspr->yrepeat * tsiz.y) << 2)) + { + sc0 = (float)(sector[tspr->sectnum].ceilingz - globalposz) * ryp0 + ghoriz; + sc1 = (float)(sector[tspr->sectnum].ceilingz - globalposz) * ryp1 + ghoriz; + } + } + if (!(sector[tspr->sectnum].floorstat & 1)) + { + if (sector[tspr->sectnum].floorz < pos.z) + { + sf0 = (float)(sector[tspr->sectnum].floorz - globalposz) * ryp0 + ghoriz; + sf1 = (float)(sector[tspr->sectnum].floorz - globalposz) * ryp1 + ghoriz; + } + } + + if (sx0 > sx1) + { + if (globalorientation & 64) + goto _drawsprite_return; // 1-sided sprite + + std::swap(sx0, sx1); + std::swap(sc0, sc1); + std::swap(sf0, sf1); + } + + vec2f_t const pxy[4] = { { sx0, sc0 }, { sx1, sc1 }, { sx1, sf1 }, { sx0, sf0 } }; + + vec2_16_t tempsiz = { (int16_t)tsiz.x, (int16_t)tsiz.y }; + pow2xsplit = 0; + polymost_drawpoly(pxy, 4, method, tempsiz); + + drawpoly_srepeat = 0; + drawpoly_trepeat = 0; + } + break; + + case 2: // Floor sprite + else + + break; + + case 3: // Voxel sprite + break; + } + + if (automapping == 1 && (unsigned)spritenum < MAXSPRITES) + show2dsprite.Set(spritenum); + +_drawsprite_return: + ; +} +#endif diff --git a/source/core/rendering/scene/hw_walls.cpp b/source/core/rendering/scene/hw_walls.cpp index b54846262..5b2a80499 100644 --- a/source/core/rendering/scene/hw_walls.cpp +++ b/source/core/rendering/scene/hw_walls.cpp @@ -766,7 +766,7 @@ void HWWall::DoTexture(HWDrawInfo* di, walltype* wal, walltype* refwall, float r bool trans = type == RENDERWALL_M2S && (wal->cstat & CSTAT_WALL_TRANSLUCENT); if (trans) { - SetRenderStyleFromBlend(!!(wal->cstat & CSTAT_WALL_TRANSLUCENT), 0, !!(wal->cstat & CSTAT_WALL_TRANS_FLIP)); + RenderStyle = GetRenderStyle(0, !!(wal->cstat & CSTAT_WALL_TRANS_FLIP)); alpha = GetAlphaFromBlend((wal->cstat & CSTAT_WALL_TRANS_FLIP) ? DAMETH_TRANS2 : DAMETH_TRANS1, 0); } PutWall(di, trans);