#pragma once //========================================================================== // // One wall segment in the draw list // //========================================================================== #include "renderstyle.h" #include "textures.h" #include "fcolormap.h" #include "build.h" #include "gamefuncs.h" #include "render.h" #include "matrix.h" #include "gamecontrol.h" #include "hw_renderstate.h" #include "hw_cvars.h" #include "coreactor.h" #ifdef _MSC_VER #pragma warning(disable:4244) // this gets a bit annoying in the renderer... #endif struct HWHorizonInfo; struct HWSkyInfo; class FMaterial; struct FTexCoordInfo; struct FSectorPortalGroup; struct FFlatVertex; struct FDynLightData; class VSMatrix; struct FSpriteModelFrame; class FRenderState; struct voxmodel_t; struct Section; struct HWSectorPlane { FTextureID texture; //secplane_t plane; float Texheight; float Angle; FVector2 Offs; FVector2 Scale; void GetFromSector(sectortype* sec, int ceiling) { /* Offs.X = (float)sec->GetXOffset(ceiling); Offs.Y = (float)sec->GetYOffset(ceiling); Scale.X = (float)sec->GetXScale(ceiling); Scale.Y = (float)sec->GetYScale(ceiling); Angle = (float)sec->GetAngle(ceiling).Degrees; texture = sec->GetTexture(ceiling); plane = sec->GetSecPlane(ceiling); Texheight = (float)((ceiling == sector_t::ceiling) ? plane.fD() : -plane.fD()); */ } }; enum HWRenderStyle { STYLEHW_Normal, // default STYLEHW_Solid, // drawn solid (needs special treatment for sprites) STYLEHW_NoAlphaTest, // disable alpha test }; enum WallTypes { RENDERWALL_NONE, RENDERWALL_TOP, RENDERWALL_M1S, RENDERWALL_M2S, RENDERWALL_BOTTOM, RENDERWALL_FOGBOUNDARY, RENDERWALL_MIRRORSURFACE, RENDERWALL_M2SNF, RENDERWALL_COLOR, // Insert new types at the end! }; enum PortalTypes { PORTALTYPE_SKY, PORTALTYPE_HORIZON, PORTALTYPE_SKYBOX, PORTALTYPE_SECTORSTACK, PORTALTYPE_PLANEMIRROR, PORTALTYPE_MIRROR, PORTALTYPE_LINETOLINE, PORTALTYPE_LINETOSPRITE, }; //========================================================================== // // One sector plane, still in fixed point // //========================================================================== struct HWSeg { float x1,x2; float y1,y2; float fracleft, fracright; FVector3 Normal() const { // we do not use the vector math inlines here because they are not optimized for speed but accuracy in the playsim and this is called quite frequently. float x = y2 - y1; float y = x1 - x2; float ilength = 1.f / sqrtf(x*x + y*y); return FVector3(x * ilength, 0, y * ilength); } }; struct texcoord { float u,v; }; struct HWDrawInfo; class HWWall { public: static const char passflag[]; enum { HWF_CLAMPX=1, HWF_CLAMPY=2, HWF_SKYHACK=4, HWF_NOSPLIT=64, HWF_TRANSLUCENT = 128, }; enum { RWF_BLANK = 0, RWF_TEXTURED = 1, // actually not being used anymore because with buffers it's even less efficient not writing the texture coordinates - but leave it here RWF_TRANS = 2, RWF_NORENDER = 8, }; enum { LOLFT, UPLFT, UPRGT, LORGT, }; friend struct HWDrawList; friend class HWPortal; FGameTexture *texture; HWSeg glseg; float ztop[2],zbottom[2]; texcoord tcs[4]; float alpha; FRenderStyle RenderStyle; float ViewDistance; float visibility; walltype* walldist; FVector2 wallpoint; short shade, palette; PalEntry fade; uint16_t flags; uint8_t type; int dynlightindex; union { // it's either one of them but never more! //FSectorPortal *secportal; // sector portal (formerly skybox) HWSkyInfo * sky; // for normal sky //HWHorizonInfo * horizon; // for horizon information PortalDesc * portal; // stacked sector portals const int * planemirror; // for plane mirrors }; unsigned int vertindex; unsigned int vertcount; public: walltype* seg; tspritetype* Sprite; sectortype* frontsector, * backsector; //private: void PutWall(HWDrawInfo *di, bool translucent); void PutPortal(HWDrawInfo *di, int ptype, int plane); void CheckTexturePosition(); void SetupLights(HWDrawInfo *di, FDynLightData &lightdata); void MakeVertices(HWDrawInfo *di, bool nosplit); void SkyPlane(HWDrawInfo *di, sectortype *sector, int plane, bool allowmirror); void SkyLine(HWDrawInfo *di, sectortype *sec, walltype *line); void SkyNormal(HWDrawInfo* di, sectortype* fs, FVector2& v1, FVector2& v2, float fch1, float fch2, float ffh1, float ffh2); void SkyTop(HWDrawInfo* di, walltype* seg, sectortype* fs, sectortype* bs, FVector2& v1, FVector2& v2, float fch1, float fch2); void SkyBottom(HWDrawInfo* di, walltype* seg, sectortype* fs, sectortype* bs, FVector2& v1, FVector2& v2, float ffh1, float ffh2); bool DoHorizon(HWDrawInfo *di, walltype * seg,sectortype * fs, DVector2& v1, DVector2& v2); bool SetWallCoordinates(walltype* seg, float topleft, float topright, float bottomleft, float bottomright); void DoTexture(HWDrawInfo* di, walltype* wal, walltype* refwall, float yref, float topleft, float topright, float bottomleft, float bottomright); void DoOneSidedTexture(HWDrawInfo *di, walltype * seg, sectortype* frontsector, sectortype* backsector, float topleft,float topright, float bottomleft,float bottomright); void DoUpperTexture(HWDrawInfo* di, walltype* seg, sectortype* frontsector, sectortype* backsector, float topleft, float topright, float bottomleft, float bottomright); void DoLowerTexture(HWDrawInfo* di, walltype* seg, sectortype* frontsector, sectortype* backsector, float topleft, float topright, float bottomleft, float bottomright); void DoMidTexture(HWDrawInfo *di, walltype * seg, sectortype * front, sectortype * back, float fch1, float fch2, float ffh1, float ffh2, float bch1, float bch2, float bfh1, float bfh2); int CreateVertices(FFlatVertex *&ptr, bool nosplit); int CountVertices(); void SplitLeftEdge(FFlatVertex*& ptr); void SplitRightEdge(FFlatVertex*& ptr); void CountLeftEdge(unsigned& ptr); void CountRightEdge(unsigned& ptr); void RenderWall(HWDrawInfo *di, FRenderState &state, int textured); void RenderFogBoundary(HWDrawInfo *di, FRenderState &state); void RenderMirrorSurface(HWDrawInfo *di, FRenderState &state); void RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags); void RenderTranslucentWall(HWDrawInfo *di, FRenderState &state); public: void Process(HWDrawInfo* di, walltype* seg, sectortype* frontsector, sectortype* backsector); void ProcessWallSprite(HWDrawInfo* di, tspritetype* spr, sectortype* frontsector); float PointOnSide(float x,float y) { return -((y-glseg.y1)*(glseg.x2-glseg.x1)-(x-glseg.x1)*(glseg.y2-glseg.y1)); } void DrawWall(HWDrawInfo *di, FRenderState &state, bool translucent); }; //========================================================================== // // Common fields needed by the sprite sorter. // //========================================================================== class HWFlatOrSprite { public: float depth; tspritetype* Sprite; // for flat sprites. }; //========================================================================== // // One flat plane in the draw list // //========================================================================== class HWFlat : public HWFlatOrSprite { public: sectortype* sec; FGameTexture* texture; int section; float z; // the z position of the flat (only valid for non-sloped planes) PalEntry fade; int shade, palette; float visibility; float alpha; FRenderStyle RenderStyle; int iboindex; bool stack; uint8_t plane; short slopecount; FVector2 geoofs; //int vboheight; int slopeindex; int vertindex, vertcount; // this should later use a static vertex buffer, but that'd hinder the development phase, so for now vertex data gets created on the fly. void MakeVertices(HWDrawInfo* di); int dynlightindex; void CreateSkyboxVertices(FFlatVertex *buffer); //void SetupLights(HWDrawInfo *di, FLightNode *head, FDynLightData &lightdata, int portalgroup); void PutFlat(HWDrawInfo* di, int whichplane); void ProcessSector(HWDrawInfo *di, sectortype * frontsector, int sectionnum, int which = 7 /*SSRF_RENDERALL*/); // cannot use constant due to circular dependencies. void ProcessFlatSprite(HWDrawInfo* di, tspritetype* sprite, sectortype* sector); void DrawSubsectors(HWDrawInfo *di, FRenderState &state); void DrawFlat(HWDrawInfo* di, FRenderState& state, bool translucent); }; //========================================================================== // // One sprite in the draw list // //========================================================================== class HWSprite : public HWFlatOrSprite { public: PalEntry fade; int shade, palette; float visibility; float alpha; FRenderStyle RenderStyle; int modelframe; // : sprite, 1: model, -1:voxel voxmodel_t* voxel; int index; int vertexindex; float x,y,z; // needed for sorting! union { struct { float ul, ur; float vt, vb; float x1, y1, z1; float x2, y2, z2; }; VSMatrix rotmat; }; int dynlightindex; FGameTexture *texture; DRotator Angles; void CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp); public: void CreateVertices(HWDrawInfo* di); void PutSprite(HWDrawInfo *di, bool translucent); void Process(HWDrawInfo *di, tspritetype* thing,sectortype * sector, int thruportal = false); bool ProcessVoxel(HWDrawInfo* di, voxmodel_t* voxel, tspritetype* tspr, sectortype* sector, bool rotate); void DrawSprite(HWDrawInfo* di, FRenderState& state, bool translucent); }; inline float Dist2(float x1,float y1,float x2,float y2) { return sqrtf((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } void hw_GetDynModelLight(AActor *self, FDynLightData &modellightdata); extern const float LARGE_VALUE; struct FDynLightData; struct FDynamicLight; bool GetLight(FDynLightData& dld, int group, Plane& p, FDynamicLight* light, bool checkside); void AddLightToList(FDynLightData &dld, int group, FDynamicLight* light, bool forceAttenuate); inline float sectorVisibility(sectortype* sec) { // Beware of wraparound madness... int v = sec->visibility; return v ? ((uint8_t)(v + 16)) / 16.f : 1.f; } inline const float hw_density = 0.35f; int checkTranslucentReplacement(FTextureID picnum, int pal); inline bool maskWallHasTranslucency(const walltype* wall) { return (wall->cstat & CSTAT_WALL_TRANSLUCENT) || checkTranslucentReplacement(tileGetTexture(wall->picnum)->GetID(), wall->pal); } inline bool spriteHasTranslucency(const tspritetype* tspr) { if ((tspr->cstat & CSTAT_SPRITE_TRANSLUCENT) || //(tspr->clipdist & TSPR_FLAGS_DRAW_LAST) || (tspr->ownerActor->sprext.alpha)) return true; return checkTranslucentReplacement(tileGetTexture(tspr->picnum)->GetID(), tspr->pal); } inline void SetSpriteTranslucency(const tspritetype* sprite, float& alpha, FRenderStyle& RenderStyle) { bool trans = (sprite->cstat & CSTAT_SPRITE_TRANSLUCENT); if (trans) { RenderStyle = GetRenderStyle(0, !!(sprite->cstat & CSTAT_SPRITE_TRANS_FLIP)); alpha = GetAlphaFromBlend((sprite->cstat & CSTAT_SPRITE_TRANS_FLIP) ? DAMETH_TRANS2 : DAMETH_TRANS1, 0); } else { RenderStyle = LegacyRenderStyles[STYLE_Translucent]; alpha = 1.f; } alpha *= 1.f - sprite->ownerActor->sprext.alpha; } //========================================================================== // // // //========================================================================== extern PalEntry GlobalMapFog; extern float GlobalFogDensity; __forceinline void SetLightAndFog(FRenderState& state, PalEntry fade, int palette, int shade, float visibility, float alpha) { // Fog must be done before the texture so that the texture selector can override it. bool foggy = (GlobalMapFog || (fade & 0xffffff)); auto ShadeDiv = lookups.tables[palette].ShadeFactor; if (shade == 127) state.SetObjectColor(0xff000000); // 127 is generally used for shadow objects that must be black, even in foggy areas. // Disable brightmaps if non-black fog is used. if (ShadeDiv >= 1 / 1000.f && foggy) { state.EnableFog(1); float density = GlobalMapFog ? GlobalFogDensity : 350.f - Scale(numshades - shade, 150, numshades); state.SetFog((GlobalMapFog) ? GlobalMapFog : fade, density * hw_density); state.SetSoftLightLevel(255); state.SetLightParms(128.f, 1 / 1000.f); } else { state.EnableFog(0); state.SetFog(0, 0); state.SetSoftLightLevel(gl_fogmode != 0 && ShadeDiv >= 1 / 1000.f ? max(0, 255 - Scale(shade, 255, numshades)) : 255); state.SetLightParms(visibility, ShadeDiv / (numshades - 2)); } // The shade rgb from the tint is ignored here. state.SetColor(globalr * (1 / 255.f), globalg * (1 / 255.f), globalb * (1 / 255.f), alpha); }