2021-03-15 22:46:03 +00:00
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2000-2016 Christoph Oelckers
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
2021-04-02 16:22:54 +00:00
// the Free Software Foundation, either version 2 of the License, or
2021-03-15 22:46:03 +00:00
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
# include "texturemanager.h"
# include "hw_dynlightdata.h"
# include "hw_material.h"
# include "hw_cvars.h"
# include "hw_clock.h"
//#include "hw_lighting.h"
2021-03-18 16:18:03 +00:00
# include "hw_drawinfo.h"
2021-03-21 18:36:55 +00:00
# include "hw_portal.h"
2021-03-15 22:46:03 +00:00
# include "hw_lightbuffer.h"
# include "hw_renderstate.h"
# include "hw_skydome.h"
# include "hw_drawstructs.h"
2021-12-28 16:56:33 +00:00
# include "hw_vertexmap.h"
2022-12-07 16:10:27 +00:00
# include "buildtiles.h"
2021-03-18 11:49:33 +00:00
# include "gamefuncs.h"
2021-03-15 22:46:03 +00:00
# include "cmdlib.h"
2022-12-07 16:10:27 +00:00
# include "texinfo.h"
2021-03-15 22:46:03 +00:00
# include "v_video.h"
# include "flatvertices.h"
2021-12-03 23:34:20 +00:00
DCoreActor * wall_to_sprite_actors [ 8 ] ; // gets updated each frame. Todo: Encapsulate this better without having to permanently store actors in the wall object.
2021-05-20 10:36:35 +00:00
//==========================================================================
//
//
//
//==========================================================================
2021-12-29 17:16:50 +00:00
static walltype * IsOnWall ( tspritetype * tspr , int height , DVector2 & outpos )
2021-05-20 10:36:35 +00:00
{
2022-01-30 13:55:36 +00:00
double maxorthdist = 3 * maptoworld ; // maximum orthogonal distance to be considered an attached sprite.
double maxdistsq = maxorthdist * maxorthdist ;
2022-01-30 07:28:52 +00:00
walltype * best = nullptr ;
2021-05-20 10:36:35 +00:00
2021-12-30 15:58:48 +00:00
auto sect = tspr - > sectp ;
2021-05-20 10:36:35 +00:00
2022-08-10 20:08:41 +00:00
double tx = tspr - > pos . X ;
double ty = tspr - > pos . Y ;
2022-01-30 13:55:36 +00:00
2022-11-15 14:24:17 +00:00
for ( auto & wal : sect - > walls )
2021-05-20 10:36:35 +00:00
{
2021-12-29 17:16:50 +00:00
// Intentionally include two sided walls. Even on them the sprite should be projected onto the wall for better results.
2022-09-07 23:11:54 +00:00
auto d = wal . delta ( ) ;
2022-11-25 12:13:50 +00:00
auto deltaang = absangle ( d . Angle ( ) , tspr - > Angles . Yaw ) ;
2022-10-08 13:19:28 +00:00
const DAngle maxangdelta = DAngle360 / 1024 ;
2021-12-29 17:16:50 +00:00
// angle of the sprite must either be the wall's normal or the negative wall's normal to be aligned.
2022-09-07 23:11:54 +00:00
if ( deltaang > = DAngle90 - maxangdelta & & deltaang < = DAngle90 + maxangdelta )
2021-05-20 10:36:35 +00:00
{
2022-11-25 12:13:50 +00:00
if ( ! ( ( tspr - > Angles . Yaw . Buildang ( ) ) & 510 ) )
2021-05-20 10:36:35 +00:00
{
2022-08-03 12:13:42 +00:00
// orthogonal lines do not check the actual position so that certain off-sector sprites get handled properly.
// In Wanton Destruction's airplane level there's such a sprite assigned to the wrong sector.
if ( d . X = = 0 )
2022-01-01 17:55:42 +00:00
{
2022-08-03 12:13:42 +00:00
double newdist = fabs ( tx - wal . pos . X ) ;
if ( newdist < maxorthdist )
{
maxorthdist = newdist ;
best = & wal ;
}
2022-01-01 17:55:42 +00:00
}
2022-08-03 12:13:42 +00:00
else if ( d . Y = = 0 )
2022-01-01 17:55:42 +00:00
{
2022-08-03 12:13:42 +00:00
double newdist = fabs ( ty - wal . pos . Y ) ;
if ( newdist < maxorthdist )
{
maxorthdist = newdist ;
best = & wal ;
}
2022-01-01 17:55:42 +00:00
}
}
else
{
2022-01-30 13:55:36 +00:00
double wdist = SquareDistToWall ( tx , ty , & wal , & outpos ) ;
2022-01-01 17:55:42 +00:00
if ( wdist < = maxdistsq )
{
2022-01-14 19:20:47 +00:00
return & wal ;
2022-01-01 17:55:42 +00:00
}
2021-05-20 10:36:35 +00:00
}
}
}
2022-01-30 07:28:52 +00:00
return best ;
2021-05-20 10:36:35 +00:00
}
2021-03-15 22:46:03 +00:00
//==========================================================================
//
// General purpose wall rendering function
// everything goes through here
//
//==========================================================================
void HWWall : : RenderWall ( HWDrawInfo * di , FRenderState & state , int textured )
{
assert ( vertcount > 0 ) ;
state . SetLightIndex ( dynlightindex ) ;
state . Draw ( DT_TriangleFan , vertindex , vertcount ) ;
vertexcount + = vertcount ;
}
//==========================================================================
//
//
//
//==========================================================================
void HWWall : : RenderFogBoundary ( HWDrawInfo * di , FRenderState & state )
{
2021-03-21 18:36:55 +00:00
if ( gl_fogmode ) // && !di->isFullbrightScene())
2021-03-15 22:46:03 +00:00
{
state . EnableDrawBufferAttachments ( false ) ;
2022-01-08 11:42:15 +00:00
SetLightAndFog ( di , state , fade , palette , shade , visibility , alpha ) ;
2021-03-15 22:46:03 +00:00
state . SetEffect ( EFF_FOGBOUNDARY ) ;
state . AlphaFunc ( Alpha_GEqual , 0.f ) ;
state . SetDepthBias ( - 1 , - 128 ) ;
RenderWall ( di , state , HWWall : : RWF_BLANK ) ;
state . ClearDepthBias ( ) ;
state . SetEffect ( EFF_NONE ) ;
state . EnableDrawBufferAttachments ( true ) ;
}
}
//==========================================================================
//
//
//
//==========================================================================
void HWWall : : RenderMirrorSurface ( HWDrawInfo * di , FRenderState & state )
{
if ( ! TexMan . mirrorTexture . isValid ( ) ) return ;
state . SetDepthFunc ( DF_LEqual ) ;
// we use texture coordinates and texture matrix to pass the normal stuff to the shader so that the default vertex buffer format can be used as is.
state . EnableTextureMatrix ( true ) ;
// Use sphere mapping for this
state . SetEffect ( EFF_SPHEREMAP ) ;
2022-01-08 11:42:15 +00:00
SetLightAndFog ( di , state , fade , palette , min < int > ( shade , numshades ) , visibility , alpha ) ;
2022-09-25 10:26:37 +00:00
//state.SetColor(PalEntry(25, globalr >> 1, globalg >> 1, globalb >> 1));
state . SetColor ( PalEntry ( 25 , 128 , 128 , 128 ) ) ;
2021-03-23 20:23:49 +00:00
2021-03-15 22:46:03 +00:00
state . SetRenderStyle ( STYLE_Add ) ;
state . AlphaFunc ( Alpha_Greater , 0 ) ;
auto tex = TexMan . GetGameTexture ( TexMan . mirrorTexture , false ) ;
state . SetMaterial ( tex , UF_None , 0 , CLAMP_NONE , 0 , - 1 ) ; // do not upscale the mirror texture.
RenderWall ( di , state , HWWall : : RWF_BLANK ) ;
state . EnableTextureMatrix ( false ) ;
state . SetEffect ( EFF_NONE ) ;
2021-04-08 17:56:18 +00:00
state . AlphaFunc ( Alpha_GEqual , 0.5f ) ;
2021-03-15 22:46:03 +00:00
state . SetDepthFunc ( DF_Less ) ;
state . SetRenderStyle ( STYLE_Translucent ) ;
}
//==========================================================================
//
//
//
//==========================================================================
void HWWall : : RenderTexturedWall ( HWDrawInfo * di , FRenderState & state , int rflags )
{
2022-01-08 11:42:15 +00:00
SetLightAndFog ( di , state , fade , palette , shade , visibility , alpha ) ;
2021-06-01 19:48:39 +00:00
2021-04-20 14:58:18 +00:00
state . SetMaterial ( texture , UF_Texture , 0 , ( flags & ( HWF_CLAMPX | HWF_CLAMPY ) ) , TRANSLATION ( Translation_Remap + curbasepal , palette ) , - 1 ) ;
2021-03-18 16:18:03 +00:00
2021-05-06 22:09:30 +00:00
if ( Sprite = = nullptr )
2021-03-18 16:18:03 +00:00
{
2021-06-01 19:48:39 +00:00
if ( shade > numshades & & ( GlobalMapFog | | ( fade & 0xffffff ) ) )
{
state . SetObjectColor ( fade | 0xff000000 ) ;
state . EnableTexture ( false ) ;
}
2022-12-05 17:32:43 +00:00
if ( ! ( seg - > cstat & CSTAT_WALL_ROTATE_90 ) )
2021-04-20 14:58:18 +00:00
{
2022-12-05 17:32:43 +00:00
int h = ( int ) texture - > GetDisplayHeight ( ) ;
int h2 = 1 < < sizeToBits ( h ) ;
if ( h2 < h ) h2 * = 2 ;
if ( h ! = h2 )
{
float xOffset = 1.f / texture - > GetDisplayWidth ( ) ;
state . SetNpotEmulation ( float ( h2 ) / h , xOffset ) ;
}
2021-04-20 14:58:18 +00:00
}
2021-05-21 17:07:22 +00:00
RenderWall ( di , state , rflags ) ;
2021-03-18 16:18:03 +00:00
}
2021-05-21 10:55:18 +00:00
else if ( ! ( rflags & RWF_TRANS ) )
2021-05-20 10:36:35 +00:00
{
2021-05-21 17:07:22 +00:00
auto oldbias = state . GetDepthBias ( ) ;
2021-12-29 17:16:50 +00:00
if ( walldist ) state . SetDepthBias ( - 1 , - 129 ) ;
2021-05-21 10:55:18 +00:00
else state . ClearDepthBias ( ) ;
2021-05-21 17:07:22 +00:00
RenderWall ( di , state , rflags ) ;
state . SetDepthBias ( oldbias ) ;
2021-03-18 16:18:03 +00:00
2021-05-21 17:07:22 +00:00
}
else
RenderWall ( di , state , rflags ) ;
2021-03-15 22:46:03 +00:00
state . SetNpotEmulation ( 0.f , 0.f ) ;
state . SetObjectColor ( 0xffffffff ) ;
2021-06-01 19:48:39 +00:00
state . EnableTexture ( true ) ;
2021-05-15 08:40:25 +00:00
/* none of these functions is in use.
2021-03-15 22:46:03 +00:00
state . SetObjectColor2 ( 0 ) ;
state . SetAddColor ( 0 ) ;
state . SetTextureMode ( tmode ) ;
state . EnableGlow ( false ) ;
state . EnableGradient ( false ) ;
state . ApplyTextureManipulation ( nullptr ) ;
2021-03-18 16:18:03 +00:00
*/
2021-03-15 22:46:03 +00:00
}
//==========================================================================
//
//
//
//==========================================================================
void HWWall : : RenderTranslucentWall ( HWDrawInfo * di , FRenderState & state )
{
2021-03-27 22:12:41 +00:00
if ( RenderStyle . BlendOp ! = STYLEOP_Add )
{
state . EnableBrightmap ( false ) ;
}
2021-03-15 22:46:03 +00:00
state . SetRenderStyle ( RenderStyle ) ;
2021-03-27 22:12:41 +00:00
state . SetTextureMode ( RenderStyle ) ;
2021-04-11 16:38:26 +00:00
if ( texture & & ! checkTranslucentReplacement ( texture - > GetID ( ) , palette ) ) state . AlphaFunc ( Alpha_GEqual , texture - > alphaThreshold ) ;
2021-03-15 22:46:03 +00:00
else state . AlphaFunc ( Alpha_GEqual , 0.f ) ;
RenderTexturedWall ( di , state , HWWall : : RWF_TEXTURED ) ;
state . SetRenderStyle ( STYLE_Translucent ) ;
2021-03-27 22:12:41 +00:00
state . EnableBrightmap ( true ) ;
2021-03-15 22:46:03 +00:00
}
//==========================================================================
//
//
//
//==========================================================================
void HWWall : : DrawWall ( HWDrawInfo * di , FRenderState & state , bool translucent )
{
2022-01-13 23:49:57 +00:00
rendered_lines + + ;
2021-03-15 22:46:03 +00:00
if ( screen - > BuffersArePersistent ( ) )
{
2021-03-18 16:18:03 +00:00
/*
2021-03-15 22:46:03 +00:00
if ( di - > Level - > HasDynamicLights & & ! di - > isFullbrightScene ( ) & & texture ! = nullptr )
{
SetupLights ( di , lightdata ) ;
}
2021-03-18 16:18:03 +00:00
*/
2021-03-15 22:46:03 +00:00
MakeVertices ( di , ! ! ( flags & HWWall : : HWF_TRANSLUCENT ) ) ;
}
state . SetNormal ( glseg . Normal ( ) ) ;
if ( ! translucent )
{
RenderTexturedWall ( di , state , HWWall : : RWF_TEXTURED ) ;
}
else
{
switch ( type )
{
case RENDERWALL_MIRRORSURFACE :
RenderMirrorSurface ( di , state ) ;
break ;
case RENDERWALL_FOGBOUNDARY :
RenderFogBoundary ( di , state ) ;
break ;
default :
RenderTranslucentWall ( di , state ) ;
break ;
}
}
}
//==========================================================================
//
// Collect lights for shader
//
//==========================================================================
#if 0
void HWWall : : SetupLights ( HWDrawInfo * di , FDynLightData & lightdata )
{
lightdata . Clear ( ) ;
if ( RenderStyle = = STYLE_Add & & ! di - > Level - > lightadditivesurfaces ) return ; // no lights on additively blended surfaces.
// check for wall types which cannot have dynamic lights on them (portal types never get here so they don't need to be checked.)
switch ( type )
{
case RENDERWALL_FOGBOUNDARY :
case RENDERWALL_MIRRORSURFACE :
case RENDERWALL_COLOR :
return ;
}
float vtx [ ] = { glseg . x1 , zbottom [ 0 ] , glseg . y1 , glseg . x1 , ztop [ 0 ] , glseg . y1 , glseg . x2 , ztop [ 1 ] , glseg . y2 , glseg . x2 , zbottom [ 1 ] , glseg . y2 } ;
Plane p ;
auto normal = glseg . Normal ( ) ;
p . Set ( normal , - normal . X * glseg . x1 - normal . Z * glseg . y1 ) ;
FLightNode * node ;
if ( seg - > sidedef = = NULL )
{
node = NULL ;
}
else if ( ! ( seg - > sidedef - > Flags & WALLF_POLYOBJ ) )
{
node = seg - > sidedef - > lighthead ;
}
else if ( sub )
{
// Polobject segs cannot be checked per sidedef so use the subsector instead.
node = sub - > section - > lighthead ;
}
else node = NULL ;
// Iterate through all dynamic lights which touch this wall and render them
while ( node )
{
if ( node - > lightsource - > IsActive ( ) )
{
iter_dlight + + ;
DVector3 posrel = node - > lightsource - > PosRelative ( seg - > frontsector - > PortalGroup ) ;
float x = posrel . X ;
float y = posrel . Y ;
float z = posrel . Z ;
float dist = fabsf ( p . DistToPoint ( x , z , y ) ) ;
float radius = node - > lightsource - > GetRadius ( ) ;
float scale = 1.0f / ( ( 2.f * radius ) - dist ) ;
FVector3 fn , pos ;
if ( radius > 0.f & & dist < radius )
{
FVector3 nearPt , up , right ;
pos = { x , z , y } ;
fn = p . Normal ( ) ;
fn . GetRightUp ( right , up ) ;
FVector3 tmpVec = fn * dist ;
nearPt = pos + tmpVec ;
FVector3 t1 ;
int outcnt [ 4 ] = { 0 , 0 , 0 , 0 } ;
texcoord tcs [ 4 ] ;
// do a quick check whether the light touches this polygon
for ( int i = 0 ; i < 4 ; i + + )
{
t1 = FVector3 ( & vtx [ i * 3 ] ) ;
FVector3 nearToVert = t1 - nearPt ;
tcs [ i ] . u = ( ( nearToVert | right ) * scale ) + 0.5f ;
tcs [ i ] . v = ( ( nearToVert | up ) * scale ) + 0.5f ;
if ( tcs [ i ] . u < 0 ) outcnt [ 0 ] + + ;
if ( tcs [ i ] . u > 1 ) outcnt [ 1 ] + + ;
if ( tcs [ i ] . v < 0 ) outcnt [ 2 ] + + ;
if ( tcs [ i ] . v > 1 ) outcnt [ 3 ] + + ;
}
if ( outcnt [ 0 ] ! = 4 & & outcnt [ 1 ] ! = 4 & & outcnt [ 2 ] ! = 4 & & outcnt [ 3 ] ! = 4 )
{
draw_dlight + = GetLight ( lightdata , seg - > frontsector - > PortalGroup , p , node - > lightsource , true ) ;
}
}
}
node = node - > nextLight ;
}
dynlightindex = screen - > mLights - > UploadLights ( lightdata ) ;
}
# endif
//==========================================================================
//
//
//
//==========================================================================
void HWWall : : PutWall ( HWDrawInfo * di , bool translucent )
{
if ( translucent | | ( texture & & texture - > GetTranslucency ( ) & & type = = RENDERWALL_M2S ) )
{
flags | = HWF_TRANSLUCENT ;
2021-03-27 22:12:41 +00:00
ViewDistance = ( di - > Viewpoint . Pos . XY ( ) - DVector2 ( ( glseg . x1 + glseg . x2 ) * 0.5f , ( glseg . y1 + glseg . y2 ) * 0.5f ) ) . LengthSquared ( ) ;
2021-03-15 22:46:03 +00:00
}
2021-03-28 19:00:24 +00:00
2022-12-05 17:32:43 +00:00
if ( seg & & ( seg - > cstat & CSTAT_WALL_ROTATE_90 ) )
{
float f ;
// rotate 90<39> clockwise. The coordinates have already been set up in rotated space, so all we need to do here is swap u and v and then negate the new v.
f = tcs [ UPLFT ] . u ; tcs [ UPLFT ] . u = tcs [ UPLFT ] . v ; tcs [ UPLFT ] . v = 1.f - f ;
f = tcs [ LOLFT ] . u ; tcs [ LOLFT ] . u = tcs [ LOLFT ] . v ; tcs [ LOLFT ] . v = 1.f - f ;
f = tcs [ UPRGT ] . u ; tcs [ UPRGT ] . u = tcs [ UPRGT ] . v ; tcs [ UPRGT ] . v = 1.f - f ;
f = tcs [ LORGT ] . u ; tcs [ LORGT ] . u = tcs [ LORGT ] . v ; tcs [ LORGT ] . v = 1.f - f ;
}
2021-03-28 19:00:24 +00:00
if ( texture - > isHardwareCanvas ( ) )
{
tcs [ UPLFT ] . v = 1.f - tcs [ UPLFT ] . v ;
tcs [ LOLFT ] . v = 1.f - tcs [ LOLFT ] . v ;
tcs [ UPRGT ] . v = 1.f - tcs [ UPRGT ] . v ;
tcs [ LORGT ] . v = 1.f - tcs [ LORGT ] . v ;
}
2021-12-30 09:30:21 +00:00
2021-03-15 22:46:03 +00:00
if ( ! screen - > BuffersArePersistent ( ) )
{
2021-03-18 16:18:03 +00:00
/*
2021-03-15 22:46:03 +00:00
if ( di - > Level - > HasDynamicLights & & ! di - > isFullbrightScene ( ) & & texture ! = nullptr )
{
SetupLights ( di , lightdata ) ;
}
2021-03-18 16:18:03 +00:00
*/
2021-03-15 22:46:03 +00:00
MakeVertices ( di , translucent ) ;
}
di - > AddWall ( this ) ;
// make sure that following parts of the same linedef do not get this one's vertex and lighting info.
vertcount = 0 ;
dynlightindex = - 1 ;
2021-04-01 17:21:24 +00:00
flags & = ~ ( HWF_TRANSLUCENT | HWF_CLAMPX | HWF_CLAMPY ) ;
2021-03-15 22:46:03 +00:00
}
//==========================================================================
//
// will be done later.
//
//==========================================================================
void HWWall : : PutPortal ( HWDrawInfo * di , int ptype , int plane )
{
HWPortal * portal = nullptr ;
MakeVertices ( di , false ) ;
switch ( ptype )
{
2021-03-21 18:36:55 +00:00
#if 0
2021-03-15 22:46:03 +00:00
// portals don't go into the draw list.
// Instead they are added to the portal manager
case PORTALTYPE_HORIZON :
horizon = portalState . UniqueHorizons . Get ( horizon ) ;
portal = di - > FindPortal ( horizon ) ;
if ( ! portal )
{
portal = new HWHorizonPortal ( & portalState , horizon , di - > Viewpoint ) ;
di - > Portals . Push ( portal ) ;
}
portal - > AddLine ( this ) ;
break ;
case PORTALTYPE_SKYBOX :
portal = di - > FindPortal ( secportal ) ;
if ( ! portal )
{
// either a regular skybox or an Eternity-style horizon
if ( secportal - > mType ! = PORTS_SKYVIEWPOINT ) portal = new HWEEHorizonPortal ( & portalState , secportal ) ;
else
{
portal = new HWSkyboxPortal ( & portalState , secportal ) ;
di - > Portals . Push ( portal ) ;
}
}
portal - > AddLine ( this ) ;
break ;
2021-03-21 18:36:55 +00:00
# endif
2021-03-15 22:46:03 +00:00
case PORTALTYPE_SECTORSTACK :
portal = di - > FindPortal ( this - > portal ) ;
if ( ! portal )
{
portal = new HWSectorStackPortal ( & portalState , this - > portal ) ;
di - > Portals . Push ( portal ) ;
}
portal - > AddLine ( this ) ;
break ;
2021-03-21 18:36:55 +00:00
#if 0
2021-03-15 22:46:03 +00:00
case PORTALTYPE_PLANEMIRROR :
if ( portalState . PlaneMirrorMode * planemirror - > fC ( ) < = 0 )
{
planemirror = portalState . UniquePlaneMirrors . Get ( planemirror ) ;
portal = di - > FindPortal ( planemirror ) ;
if ( ! portal )
{
portal = new HWPlaneMirrorPortal ( & portalState , planemirror ) ;
di - > Portals . Push ( portal ) ;
}
portal - > AddLine ( this ) ;
}
break ;
2021-03-21 18:36:55 +00:00
# endif
2021-03-15 22:46:03 +00:00
case PORTALTYPE_MIRROR :
2021-03-21 18:36:55 +00:00
// These are unique. No need to look existing ones up.
portal = new HWMirrorPortal ( & portalState , seg ) ;
di - > Portals . Push ( portal ) ;
2021-03-15 22:46:03 +00:00
portal - > AddLine ( this ) ;
if ( gl_mirror_envmap )
{
// draw a reflective layer over the mirror
di - > AddMirrorSurface ( this ) ;
}
break ;
case PORTALTYPE_LINETOLINE :
2021-03-21 18:36:55 +00:00
// These are also unique.
portal = new HWLineToLinePortal ( & portalState , seg , & wall [ seg - > portalnum ] ) ;
di - > Portals . Push ( portal ) ;
2021-03-15 22:46:03 +00:00
portal - > AddLine ( this ) ;
break ;
2021-03-24 09:33:50 +00:00
case PORTALTYPE_LINETOSPRITE :
// These are also unique.
2021-12-03 23:34:20 +00:00
assert ( seg - > portalnum > = 0 & & seg - > portalnum < 8 ) ;
2021-12-22 22:41:19 +00:00
portal = new HWLineToSpritePortal ( & portalState , seg , wall_to_sprite_actors [ seg - > portalnum ] ) ;
2021-03-24 09:33:50 +00:00
di - > Portals . Push ( portal ) ;
portal - > AddLine ( this ) ;
break ;
2021-03-15 22:46:03 +00:00
case PORTALTYPE_SKY :
sky = portalState . UniqueSkies . Get ( sky ) ;
portal = di - > FindPortal ( sky ) ;
if ( ! portal )
{
portal = new HWSkyPortal ( screen - > mSkyData , & portalState , sky ) ;
di - > Portals . Push ( portal ) ;
}
portal - > AddLine ( this ) ;
break ;
}
vertcount = 0 ;
if ( plane ! = - 1 & & portal )
{
portal - > planesused | = ( 1 < < plane ) ;
}
}
//==========================================================================
//
// Build does not have horizon effects.
//
//==========================================================================
bool HWWall : : DoHorizon ( HWDrawInfo * di , walltype * seg , sectortype * fs , DVector2 & v1 , DVector2 & v2 )
{
#if 0
HWHorizonInfo hi ;
lightlist_t * light ;
// ZDoom doesn't support slopes in a horizon sector so I won't either!
ztop [ 1 ] = ztop [ 0 ] = fs - > GetPlaneTexZ ( sector_t : : ceiling ) ;
zbottom [ 1 ] = zbottom [ 0 ] = fs - > GetPlaneTexZ ( sector_t : : floor ) ;
auto vpz = di - > Viewpoint . Pos . Z ;
if ( vpz < fs - > GetPlaneTexZ ( sector_t : : ceiling ) )
{
if ( vpz > fs - > GetPlaneTexZ ( sector_t : : floor ) )
zbottom [ 1 ] = zbottom [ 0 ] = vpz ;
if ( fs - > GetTexture ( sector_t : : ceiling ) = = skyflatnum )
{
SkyPlane ( di , fs , sector_t : : ceiling , false ) ;
}
else
{
horizon = & hi ;
PutPortal ( di , PORTALTYPE_HORIZON , - 1 ) ;
}
ztop [ 1 ] = ztop [ 0 ] = zbottom [ 0 ] ;
}
if ( vpz > fs - > GetPlaneTexZ ( sector_t : : floor ) )
{
zbottom [ 1 ] = zbottom [ 0 ] = fs - > GetPlaneTexZ ( sector_t : : floor ) ;
if ( fs - > GetTexture ( sector_t : : floor ) = = skyflatnum )
{
SkyPlane ( di , fs , sector_t : : floor , false ) ;
}
else
{
horizon = & hi ;
PutPortal ( di , PORTALTYPE_HORIZON , - 1 ) ;
}
}
# endif
return true ;
}
//==========================================================================
//
//
//
//==========================================================================
bool HWWall : : SetWallCoordinates ( walltype * seg , float topleft , float topright , float bottomleft , float bottomright )
{
//
//
// set up coordinates for the left side of the polygon
//
// check left side for intersections
if ( topleft > = bottomleft )
{
// normal case
ztop [ 0 ] = topleft ;
zbottom [ 0 ] = bottomleft ;
}
else
{
// ceiling below floor - clip to the visible part of the wall
float dch = topright - topleft ;
float dfh = bottomright - bottomleft ;
float inter_x = ( bottomleft - topleft ) / ( dch - dfh ) ;
float inter_y = topleft + inter_x * dch ;
glseg . x1 = glseg . x1 + inter_x * ( glseg . x2 - glseg . x1 ) ;
glseg . y1 = glseg . y1 + inter_x * ( glseg . y2 - glseg . y1 ) ;
glseg . fracleft = inter_x ;
zbottom [ 0 ] = ztop [ 0 ] = inter_y ;
}
//
//
// set up coordinates for the right side of the polygon
//
// check left side for intersections
if ( topright > = bottomright )
{
// normal case
ztop [ 1 ] = topright ;
zbottom [ 1 ] = bottomright ;
}
else
{
// ceiling below floor - clip to the visible part of the wall
float dch = topright - topleft ;
float dfh = bottomright - bottomleft ;
float inter_x = ( bottomleft - topleft ) / ( dch - dfh ) ;
float inter_y = topleft + inter_x * dch ;
glseg . x2 = glseg . x1 + inter_x * ( glseg . x2 - glseg . x1 ) ;
glseg . y2 = glseg . y1 + inter_x * ( glseg . y2 - glseg . y1 ) ;
glseg . fracright = inter_x ;
zbottom [ 1 ] = ztop [ 1 ] = inter_y ;
}
return true ;
}
//==========================================================================
//
// Do some tweaks with the texture coordinates to reduce visual glitches
//
//==========================================================================
void HWWall : : CheckTexturePosition ( )
{
float sub ;
if ( texture - > isHardwareCanvas ( ) ) return ;
// clamp texture coordinates to a reasonable range.
// Extremely large values can cause visual problems
2021-03-19 09:29:38 +00:00
if ( tcs [ UPLFT ] . v < tcs [ LOLFT ] . v | | tcs [ UPRGT ] . v < tcs [ LORGT ] . v )
2021-03-15 22:46:03 +00:00
{
if ( tcs [ UPLFT ] . v < tcs [ UPRGT ] . v )
{
sub = float ( xs_FloorToInt ( tcs [ UPLFT ] . v ) ) ;
}
else
{
sub = float ( xs_FloorToInt ( tcs [ UPRGT ] . v ) ) ;
}
tcs [ UPLFT ] . v - = sub ;
tcs [ UPRGT ] . v - = sub ;
tcs [ LOLFT ] . v - = sub ;
tcs [ LORGT ] . v - = sub ;
}
else
{
if ( tcs [ LOLFT ] . v < tcs [ LORGT ] . v )
{
sub = float ( xs_FloorToInt ( tcs [ LOLFT ] . v ) ) ;
}
else
{
sub = float ( xs_FloorToInt ( tcs [ LORGT ] . v ) ) ;
}
tcs [ UPLFT ] . v - = sub ;
tcs [ UPRGT ] . v - = sub ;
tcs [ LOLFT ] . v - = sub ;
tcs [ LORGT ] . v - = sub ;
2021-04-01 17:21:24 +00:00
}
if ( tcs [ UPLFT ] . u > = 0.f & & tcs [ UPRGT ] . u > = 0.f & & tcs [ LOLFT ] . u > = 0.f & & tcs [ LORGT ] . u > = 0.f & &
tcs [ UPLFT ] . u < = 1.f & & tcs [ UPRGT ] . u < = 1.f & & tcs [ LOLFT ] . u < = 1.f & & tcs [ LORGT ] . u < = 1.f )
{
flags | = HWF_CLAMPX ;
}
2021-03-15 22:46:03 +00:00
2021-04-01 17:21:24 +00:00
if ( tcs [ UPLFT ] . v > = 0.f & & tcs [ UPRGT ] . v > = 0.f & & tcs [ LOLFT ] . v > = 0.f & & tcs [ LORGT ] . v > = 0.f & &
tcs [ UPLFT ] . v < = 1.f & & tcs [ UPRGT ] . v < = 1.f & & tcs [ LOLFT ] . v < = 1.f & & tcs [ LORGT ] . v < = 1.f )
{
flags | = HWF_CLAMPY ;
2021-03-15 22:46:03 +00:00
}
2021-04-01 17:21:24 +00:00
2021-03-15 22:46:03 +00:00
}
//==========================================================================
//
// Common part of wall drawers
//
//==========================================================================
void HWWall : : DoTexture ( HWDrawInfo * di , walltype * wal , walltype * refwall , float refheight , float topleft , float topright , float bottomleft , float bottomright )
{
auto glsave = glseg ;
SetWallCoordinates ( wal , topleft , topright , bottomleft , bottomright ) ;
bool xflipped = ( wal - > cstat & CSTAT_WALL_XFLIP ) ;
float leftdist = xflipped ? 1.f - glseg . fracleft : glseg . fracleft ;
float rightdist = xflipped ? 1.f - glseg . fracright : glseg . fracright ;
2021-03-28 16:22:30 +00:00
float tw = texture - > GetDisplayWidth ( ) ;
float th = texture - > GetDisplayHeight ( ) ;
2022-12-05 17:32:43 +00:00
if ( wal - > cstat & CSTAT_WALL_ROTATE_90 ) std : : swap ( tw , th ) ;
2021-03-19 09:29:38 +00:00
int pow2size = 1 < < sizeToBits ( th ) ;
if ( pow2size < th ) pow2size * = 2 ;
2021-03-19 10:51:38 +00:00
float ypanning = refwall - > ypan_ ? pow2size * refwall - > ypan_ / ( 256.0f * th ) : 0 ;
2021-03-19 09:29:38 +00:00
2022-10-07 22:02:10 +00:00
tcs [ LOLFT ] . u = tcs [ UPLFT ] . u = ( ( leftdist * 8.f * wal - > xrepeat ) + refwall - > xpan_ ) / tw ;
tcs [ LORGT ] . u = tcs [ UPRGT ] . u = ( ( rightdist * 8.f * wal - > xrepeat ) + refwall - > xpan_ ) / tw ;
2021-12-30 09:30:21 +00:00
2021-03-15 22:46:03 +00:00
auto setv = [ = ] ( float hl , float hr , float frac ) - > float
{
float h = hl + ( hr - hl ) * frac ;
2022-10-07 22:02:10 +00:00
h = ( - ( float ) ( ( refheight + h ) * 256 ) / ( ( th * 2048.0f ) / ( float ) ( wal - > yrepeat ) ) ) + ypanning ;
2021-05-06 22:18:13 +00:00
if ( refwall - > cstat & CSTAT_WALL_YFLIP ) h = - h ;
2021-03-15 22:46:03 +00:00
return h ;
} ;
tcs [ UPLFT ] . v = setv ( topleft , topright , glseg . fracleft ) ;
tcs [ LOLFT ] . v = setv ( bottomleft , bottomright , glseg . fracleft ) ;
tcs [ UPRGT ] . v = setv ( topleft , topright , glseg . fracright ) ;
tcs [ LORGT ] . v = setv ( bottomleft , bottomright , glseg . fracright ) ;
2021-03-19 09:29:38 +00:00
if ( th = = pow2size ) CheckTexturePosition ( ) ; // for NPOT textures this adjustment can break things.
2021-04-08 17:45:18 +00:00
bool trans = type = = RENDERWALL_M2S & & maskWallHasTranslucency ( wal ) ;
2021-03-15 22:46:03 +00:00
if ( trans )
{
2021-03-26 19:28:44 +00:00
RenderStyle = GetRenderStyle ( 0 , ! ! ( wal - > cstat & CSTAT_WALL_TRANS_FLIP ) ) ;
2021-03-15 22:46:03 +00:00
alpha = GetAlphaFromBlend ( ( wal - > cstat & CSTAT_WALL_TRANS_FLIP ) ? DAMETH_TRANS2 : DAMETH_TRANS1 , 0 ) ;
}
PutWall ( di , trans ) ;
2021-03-19 09:29:38 +00:00
flags = 0 ;
2021-03-15 22:46:03 +00:00
glseg = glsave ;
}
//==========================================================================
//
// Handle one sided walls
//
//==========================================================================
void HWWall : : DoOneSidedTexture ( HWDrawInfo * di , walltype * wal , sectortype * frontsector , sectortype * backsector ,
float topleft , float topright , float bottomleft , float bottomright )
{
// get the alignment reference position.
2022-08-20 17:35:24 +00:00
float refheight ;
2021-03-15 22:46:03 +00:00
if ( ( wal - > cstat & CSTAT_WALL_1WAY ) & & backsector )
{
if ( ( ! ( wal - > cstat & CSTAT_WALL_BOTTOM_SWAP ) & & ( wal - > cstat & CSTAT_WALL_1WAY ) ) | |
2021-11-26 19:55:13 +00:00
( ( wal - > cstat & CSTAT_WALL_BOTTOM_SWAP ) & & ( wal - > nextWall ( ) - > cstat & CSTAT_WALL_ALIGN_BOTTOM ) ) )
2022-08-20 17:35:24 +00:00
refheight = frontsector - > ceilingz ;
2021-03-15 22:46:03 +00:00
else
2022-08-20 17:35:24 +00:00
refheight = backsector - > floorz ;
2021-03-15 22:46:03 +00:00
}
else
{
2022-08-20 17:35:24 +00:00
refheight = ( wal - > cstat & CSTAT_WALL_ALIGN_BOTTOM ) ? frontsector - > floorz : frontsector - > ceilingz ;
2021-03-15 22:46:03 +00:00
}
type = RENDERWALL_M1S ;
DoTexture ( di , wal , wal , refheight , topleft , topright , bottomleft , bottomright ) ;
}
//==========================================================================
//
//
//
//==========================================================================
void HWWall : : DoUpperTexture ( HWDrawInfo * di , walltype * wal , sectortype * frontsector , sectortype * backsector ,
float topleft , float topright , float bottomleft , float bottomright )
{
// get the alignment reference position.
2022-08-20 17:35:24 +00:00
float refheight = ( wal - > cstat & CSTAT_WALL_ALIGN_BOTTOM ) ? frontsector - > ceilingz : backsector - > ceilingz ;
2021-03-15 22:46:03 +00:00
2021-03-19 11:02:20 +00:00
type = RENDERWALL_TOP ;
2021-03-15 22:46:03 +00:00
DoTexture ( di , wal , wal , refheight , topleft , topright , bottomleft , bottomright ) ;
}
//==========================================================================
//
//
//
//==========================================================================
void HWWall : : DoLowerTexture ( HWDrawInfo * di , walltype * wal , sectortype * frontsector , sectortype * backsector ,
float topleft , float topright , float bottomleft , float bottomright )
{
// get the alignment reference position.
2021-11-26 19:55:13 +00:00
auto refwall = ( wal - > cstat & CSTAT_WALL_BOTTOM_SWAP ) ? wal - > nextWall ( ) : wal ;
2022-08-20 17:35:24 +00:00
float refheight = ( refwall - > cstat & CSTAT_WALL_ALIGN_BOTTOM ) ? frontsector - > ceilingz : backsector - > floorz ;
2021-03-15 22:46:03 +00:00
2021-04-21 20:31:56 +00:00
shade = refwall - > shade ;
2021-03-15 22:46:03 +00:00
palette = refwall - > pal ;
type = RENDERWALL_BOTTOM ;
DoTexture ( di , wal , refwall , refheight , topleft , topright , bottomleft , bottomright ) ;
}
//==========================================================================
//
//
//
//==========================================================================
void HWWall : : DoMidTexture ( HWDrawInfo * di , walltype * wal ,
sectortype * front , sectortype * back ,
float fch1 , float fch2 , float ffh1 , float ffh2 ,
float bch1 , float bch2 , float bfh1 , float bfh2 )
{
float topleft , bottomleft , topright , bottomright ;
2022-08-20 17:35:24 +00:00
float refheight ;
2021-03-17 22:29:13 +00:00
const int swapit = ( wal - > cstat & CSTAT_WALL_ALIGN_BOTTOM ) ;
if ( wal - > cstat & CSTAT_WALL_1WAY )
{
// 1-sided wall
2022-08-20 17:35:24 +00:00
refheight = swapit ? front - > ceilingz : back - > ceilingz ;
2021-03-17 22:29:13 +00:00
}
else
{
// masked wall
if ( swapit )
2022-08-20 17:35:24 +00:00
refheight = min ( front - > floorz , back - > floorz ) ;
2021-03-17 22:29:13 +00:00
else
2022-08-20 17:35:24 +00:00
refheight = max ( front - > ceilingz , back - > ceilingz ) ;
2021-03-17 22:29:13 +00:00
}
2022-01-30 07:54:11 +00:00
if ( ( bch1 - fch1 ) * ( bch2 - fch2 ) > = 0 )
{
topleft = min ( bch1 , fch1 ) ;
topright = min ( bch2 , fch2 ) ;
}
else
{
// Front ceiling slope obstructs part of the wall
topleft = bch1 ;
topright = bch2 ;
}
if ( ( bfh1 - ffh1 ) * ( bfh2 - ffh2 ) > = 0 )
{
bottomleft = max ( bfh1 , ffh1 ) ;
bottomright = max ( bfh2 , ffh2 ) ;
}
else
{
// Front floor slope obstructs part of the wall
bottomleft = bfh1 ;
bottomright = bfh2 ;
}
2021-03-15 22:46:03 +00:00
if ( topleft < = bottomleft & & topright < = bottomright ) return ;
type = seg - > cstat & CSTAT_WALL_1WAY ? RENDERWALL_M1S : RENDERWALL_M2S ;
// todo: transparency.
DoTexture ( di , wal , wal , refheight , topleft , topright , bottomleft , bottomright ) ;
2021-03-22 11:07:29 +00:00
RenderStyle = STYLE_Translucent ;
2021-03-15 22:46:03 +00:00
alpha = 1.f ;
}
//==========================================================================
//
//
//
//==========================================================================
2021-03-22 15:02:52 +00:00
void HWWall : : Process ( HWDrawInfo * di , walltype * wal , sectortype * frontsector , sectortype * backsector )
2021-03-15 22:46:03 +00:00
{
2021-11-26 19:55:13 +00:00
auto backwall = wal - > twoSided ( ) ? wal - > nextWall ( ) : nullptr ;
auto p2wall = wal - > point2Wall ( ) ;
2021-03-15 22:46:03 +00:00
float fch1 ;
float ffh1 ;
float fch2 ;
float ffh2 ;
2022-09-16 17:37:22 +00:00
FVector2 v1 ( wal - > pos . X , - wal - > pos . Y ) ;
FVector2 v2 ( p2wall - > pos . X , - p2wall - > pos . Y ) ;
2021-03-15 22:46:03 +00:00
2022-01-27 18:27:27 +00:00
PlanesAtPoint ( frontsector , wal - > pos . X , wal - > pos . Y , & fch1 , & ffh1 ) ;
PlanesAtPoint ( frontsector , p2wall - > pos . X , p2wall - > pos . Y , & fch2 , & ffh2 ) ;
2021-03-15 22:46:03 +00:00
2021-03-22 15:02:52 +00:00
2021-03-15 22:46:03 +00:00
# ifdef _DEBUG
2022-11-15 11:03:44 +00:00
if ( wallindex ( wal ) = = 34 )
2021-03-15 22:46:03 +00:00
{
int a = 0 ;
}
# endif
this - > seg = wal ;
this - > frontsector = frontsector ;
this - > backsector = backsector ;
2021-05-06 22:09:30 +00:00
Sprite = nullptr ;
2021-03-15 22:46:03 +00:00
vertindex = 0 ;
vertcount = 0 ;
glseg . x1 = v1 . X ;
glseg . y1 = v1 . Y ;
glseg . x2 = v2 . X ;
glseg . y2 = v2 . Y ;
glseg . fracleft = 0 ;
glseg . fracright = 1 ;
flags = 0 ;
dynlightindex = - 1 ;
2021-04-21 20:31:56 +00:00
shade = wal - > shade ;
2021-03-15 22:46:03 +00:00
palette = wal - > pal ;
2021-05-20 17:17:21 +00:00
fade = lookups . getFade ( wal - > pal ) ;
2021-03-15 22:46:03 +00:00
visibility = sectorVisibility ( frontsector ) ;
alpha = 1.0f ;
2021-03-22 11:07:29 +00:00
RenderStyle = STYLE_Translucent ;
2021-03-15 22:46:03 +00:00
texture = NULL ;
2021-12-28 16:56:33 +00:00
if ( gl_seamless )
{
2022-11-15 11:03:44 +00:00
auto v = & vertices [ vertexMap [ wallindex ( wal ) ] ] ;
2021-12-28 16:56:33 +00:00
if ( v - > dirty ) v - > RecalcVertexHeights ( ) ;
v = & vertices [ vertexMap [ wal - > point2 ] ] ;
if ( v - > dirty ) v - > RecalcVertexHeights ( ) ;
}
2021-03-15 22:46:03 +00:00
/*
if ( wal - > linedef - > special = = Line_Horizon )
{
SkyNormal ( di , frontsector , v1 , v2 ) ;
DoHorizon ( di , wal , frontsector , v1 , v2 ) ;
return ;
}
*/
bool isportal = false ; // wal->linedef->isVisualPortal() && wal->sidedef == wal->linedef->sidedef[0];
2021-03-21 18:36:55 +00:00
if ( seg - > portalflags )
2021-03-15 22:46:03 +00:00
{
2021-03-21 18:36:55 +00:00
int ptype = - 1 ;
if ( seg - > portalflags = = PORTAL_WALL_MIRROR ) ptype = PORTALTYPE_MIRROR ;
else if ( seg - > portalflags = = PORTAL_WALL_VIEW ) ptype = PORTALTYPE_LINETOLINE ;
else if ( seg - > portalflags = = PORTAL_WALL_TO_SPRITE ) ptype = PORTALTYPE_LINETOSPRITE ;
if ( ptype ! = - 1 )
2021-03-15 22:46:03 +00:00
{
2021-03-22 15:02:52 +00:00
ztop [ 0 ] = fch1 ;
ztop [ 1 ] = fch2 ;
zbottom [ 0 ] = ffh1 ;
zbottom [ 1 ] = ffh2 ;
2021-03-21 18:36:55 +00:00
PutPortal ( di , ptype , - 1 ) ;
return ;
2021-03-15 22:46:03 +00:00
}
2021-03-21 18:36:55 +00:00
}
2021-03-15 22:46:03 +00:00
2021-03-21 18:36:55 +00:00
if ( ! backsector | | ! backwall )
{
// sector's sky
2021-03-22 15:02:52 +00:00
SkyNormal ( di , frontsector , v1 , v2 , fch1 , fch2 , ffh1 , ffh2 ) ;
2021-03-21 18:36:55 +00:00
// normal texture
2022-12-06 08:28:00 +00:00
auto tilenum = ( ( wal - > cstat & CSTAT_WALL_1WAY ) & & wal - > nextwall ! = - 1 ) ? wal - > overtexture ( ) : wal - > walltexture ( ) ;
texture = TexMan . GetGameTexture ( tilenum , true ) ;
2021-03-21 18:36:55 +00:00
if ( texture & & texture - > isValid ( ) )
{
DoOneSidedTexture ( di , wal , frontsector , backsector , fch1 , fch2 , ffh1 , ffh2 ) ;
2021-03-15 22:46:03 +00:00
}
}
else // two sided
{
float bfh1 ;
float bfh2 ;
float bch1 ;
float bch2 ;
2022-01-27 18:27:27 +00:00
PlanesAtPoint ( backsector , wal - > pos . X , wal - > pos . Y , & bch1 , & bfh1 ) ;
PlanesAtPoint ( backsector , p2wall - > pos . X , p2wall - > pos . Y , & bch2 , & bfh2 ) ;
2021-03-15 22:46:03 +00:00
2021-04-12 14:31:44 +00:00
SkyTop ( di , wal , frontsector , backsector , v1 , v2 , fch1 , fch2 ) ;
SkyBottom ( di , wal , frontsector , backsector , v1 , v2 , ffh1 , ffh2 ) ;
2021-03-15 22:46:03 +00:00
// upper texture
if ( ! ( frontsector - > ceilingstat & backsector - > ceilingstat & CSTAT_SECTOR_SKY ) )
{
float bch1a = bch1 ;
float bch2a = bch2 ;
2021-04-09 20:48:16 +00:00
if ( ffh1 > bch1 | | ffh2 > bch2 )
2021-03-15 22:46:03 +00:00
{
2021-04-09 20:48:16 +00:00
// the back sector's floor obstructs part of this wall. Todo: Handle the portal case better.
if ( ( ffh1 > bch1 & & ffh2 > bch2 ) | | frontsector - > portalflags = = PORTAL_SECTOR_FLOOR )
{
bch2a = ffh2 ;
bch1a = ffh1 ;
}
2021-03-15 22:46:03 +00:00
}
if ( bch1a < fch1 | | bch2a < fch2 )
{
2022-12-06 08:28:00 +00:00
auto tilenum = wal - > walltexture ( ) ;
texture = TexMan . GetGameTexture ( tilenum , true ) ;
2021-03-15 22:46:03 +00:00
if ( texture & & texture - > isValid ( ) )
{
DoUpperTexture ( di , wal , frontsector , backsector , fch1 , fch2 , bch1a , bch2a ) ;
}
}
}
2021-03-18 08:20:38 +00:00
if ( wal - > cstat & ( CSTAT_WALL_MASKED | CSTAT_WALL_1WAY ) )
2021-03-15 22:46:03 +00:00
{
2022-12-06 08:28:00 +00:00
auto tilenum = wal - > overtexture ( ) ;
texture = TexMan . GetGameTexture ( tilenum , true ) ;
2021-03-15 22:46:03 +00:00
if ( texture & & texture - > isValid ( ) )
{
DoMidTexture ( di , wal , frontsector , backsector , fch1 , fch2 , ffh1 , ffh2 , bch1 , bch2 , bfh1 , bfh2 ) ;
}
}
// lower texture
if ( ! ( frontsector - > floorstat & backsector - > floorstat & CSTAT_SECTOR_SKY ) )
{
2021-04-09 20:48:16 +00:00
if ( fch1 < bfh1 | | fch2 < bfh2 )
2021-03-15 22:46:03 +00:00
{
2021-04-09 20:48:16 +00:00
// the back sector's ceiling obstructs part of this wall. Todo: Handle the portal case better.
if ( ( fch1 < bfh1 & & fch2 < bfh2 ) | | frontsector - > portalflags = = PORTAL_SECTOR_CEILING )
{
bfh1 = fch1 ;
bfh2 = fch2 ;
}
2021-03-15 22:46:03 +00:00
}
if ( bfh1 > ffh1 | | bfh2 > ffh2 )
{
auto w = ( wal - > cstat & CSTAT_WALL_BOTTOM_SWAP ) ? backwall : wal ;
2022-12-06 08:28:00 +00:00
auto tilenum = w - > walltexture ( ) ;
texture = TexMan . GetGameTexture ( tilenum , true ) ;
2021-03-15 22:46:03 +00:00
if ( texture & & texture - > isValid ( ) )
{
DoLowerTexture ( di , wal , frontsector , backsector , bfh1 , bfh2 , ffh1 , ffh2 ) ;
}
}
}
}
}
2022-05-23 22:10:36 +00:00
//==========================================================================
//
// checks if the wall sprite has changed since the last call.
// Returns:
// 0 if identical or only render style changed
// 1 if vertical orientation changed
// 2 if horizontal orientation changed
// 3 if positioning changed
//
//==========================================================================
int HWWall : : CheckWallSprite ( tspritetype * spr , tspritetype * last )
{
// If the position changed we need to recalculate everything.
2022-11-25 12:13:50 +00:00
if ( spr - > pos . XY ( ) ! = last - > pos . XY ( ) | | spr - > sectp ! = last - > sectp | | spr - > Angles . Yaw ! = last - > Angles . Yaw ) return 3 ;
2022-05-23 22:10:36 +00:00
// if the horizontal orientation changes we need to recalculate the walls this attaches to, but not the positioning.
2022-10-07 21:33:37 +00:00
if ( spr - > scale . X ! = last - > scale . X | | spr - > xoffset ! = last - > xoffset | | spr - > picnum ! = last - > picnum | | ( ( spr - > cstat ^ last - > cstat ) & CSTAT_SPRITE_XFLIP ) ) return 2 ;
2022-05-23 22:10:36 +00:00
// only y-positioning changed - we need to re-check the wall tiers this sprite attaches to
2022-10-07 21:33:37 +00:00
if ( spr - > scale . Y ! = last - > scale . Y | | spr - > yoffset ! = last - > yoffset | | ( ( spr - > cstat ^ last - > cstat ) & ( CSTAT_SPRITE_YFLIP | CSTAT_SPRITE_YCENTER ) ) ) return 1 ;
2022-05-23 22:10:36 +00:00
// all remaining properties only affect the render style which is not relevant for positioning a wall sprite
return 0 ;
}
//==========================================================================
//
//
//
//==========================================================================
2021-12-04 18:08:50 +00:00
void HWWall : : ProcessWallSprite ( HWDrawInfo * di , tspritetype * spr , sectortype * sector )
2021-03-27 12:22:34 +00:00
{
2022-12-06 21:30:52 +00:00
auto tex = TexMan . GetGameTexture ( spr - > spritetexture ( ) ) ;
2021-03-27 12:22:34 +00:00
if ( ! tex | | ! tex - > isValid ( ) ) return ;
seg = nullptr ;
2021-05-06 22:09:30 +00:00
Sprite = spr ;
2022-08-17 20:06:39 +00:00
DVector2 pos [ 2 ] ;
2021-03-27 12:22:34 +00:00
2022-08-17 20:06:39 +00:00
GetWallSpritePosition ( spr , spr - > pos . XY ( ) , pos , true ) ;
glseg . x1 = pos [ 0 ] . X ;
glseg . y1 = - pos [ 0 ] . Y ;
glseg . x2 = pos [ 1 ] . X ;
glseg . y2 = - pos [ 1 ] . Y ;
2021-04-02 07:04:13 +00:00
2021-12-17 19:24:48 +00:00
if ( spr - > cstat & CSTAT_SPRITE_ONE_SIDE )
2021-03-27 12:22:34 +00:00
{
2021-04-02 07:04:13 +00:00
if ( PointOnLineSide ( di - > Viewpoint . Pos . X , di - > Viewpoint . Pos . Y , glseg . x1 , glseg . y1 , glseg . x2 - glseg . x1 , glseg . y2 - glseg . y1 ) < = 0 )
{
return ;
}
2021-03-27 12:22:34 +00:00
}
vertindex = 0 ;
vertcount = 0 ;
type = RENDERWALL_M2S ;
frontsector = sector ;
backsector = sector ;
texture = tex ;
2021-04-20 14:58:18 +00:00
flags = HWF_CLAMPX | HWF_CLAMPY ;
2021-03-27 12:22:34 +00:00
dynlightindex = - 1 ;
2021-04-21 20:31:56 +00:00
shade = spr - > shade ;
2021-03-27 12:22:34 +00:00
palette = spr - > pal ;
fade = lookups . getFade ( sector - > floorpal ) ; // fog is per sector.
visibility = sectorVisibility ( sector ) ;
2021-05-06 22:09:30 +00:00
SetSpriteTranslucency ( Sprite , alpha , RenderStyle ) ;
2021-03-27 12:22:34 +00:00
2022-12-07 16:10:27 +00:00
const TileOffs * tofs ;
2021-03-27 12:22:34 +00:00
int height , topofs ;
2022-12-07 14:57:28 +00:00
if ( hw_hightile & & ( tofs = GetHiresOffset ( spr - > spritetexture ( ) ) ) )
2021-03-27 12:22:34 +00:00
{
2022-12-07 14:57:28 +00:00
height = tofs - > ysize ;
topofs = tofs - > yoffs + spr - > yoffset ;
2021-03-27 12:22:34 +00:00
}
else
{
2021-03-28 16:22:30 +00:00
height = ( int ) tex - > GetDisplayHeight ( ) ;
topofs = ( ( int ) tex - > GetDisplayTopOffset ( ) + spr - > yoffset ) ;
2021-03-27 12:22:34 +00:00
}
2021-05-21 10:55:18 +00:00
2022-01-01 09:50:58 +00:00
DVector2 vec { } ;
2021-12-29 17:16:50 +00:00
walldist = IsOnWall ( spr , height , vec ) ;
if ( walldist )
{
// project the sprite right onto the wall.
2022-09-16 17:59:10 +00:00
auto v1 = NearestPointOnWall ( glseg . x1 , - glseg . y1 , walldist , false ) ;
auto v2 = NearestPointOnWall ( glseg . x2 , - glseg . y2 , walldist , false ) ;
2022-01-30 13:55:36 +00:00
glseg . x1 = v1 . X ;
glseg . y1 = - v1 . Y ;
glseg . x2 = v2 . X ;
glseg . y2 = - v2 . Y ;
2021-12-29 17:16:50 +00:00
}
2021-03-27 12:22:34 +00:00
if ( spr - > cstat & CSTAT_SPRITE_YFLIP )
topofs = - topofs ;
2022-08-22 16:18:05 +00:00
2022-10-07 21:33:37 +00:00
float yscale = spr - > scale . Y ;
2022-10-05 22:50:47 +00:00
float sprz = spr - > pos . Z - topofs * yscale ;
2021-03-27 12:22:34 +00:00
if ( spr - > cstat & CSTAT_SPRITE_YCENTER )
{
2022-10-05 22:50:47 +00:00
sprz + = height * yscale * 0.5f ;
if ( height & 1 ) sprz + = yscale * 0.5f ; // Odd yspans
2021-03-27 12:22:34 +00:00
}
glseg . fracleft = 0 ;
glseg . fracright = 1 ;
tcs [ LOLFT ] . u = tcs [ UPLFT ] . u = ( spr - > cstat & CSTAT_SPRITE_XFLIP ) ? 1.f : 0.f ;
tcs [ LORGT ] . u = tcs [ UPRGT ] . u = ( spr - > cstat & CSTAT_SPRITE_XFLIP ) ? 0.f : 1.f ;
2021-03-27 13:18:33 +00:00
tcs [ UPLFT ] . v = tcs [ UPRGT ] . v = ( spr - > cstat & CSTAT_SPRITE_YFLIP ) ? 1.f : 0.f ;
tcs [ LOLFT ] . v = tcs [ LORGT ] . v = ( spr - > cstat & CSTAT_SPRITE_YFLIP ) ? 0.f : 1.f ;
2021-03-28 19:00:24 +00:00
2022-08-22 16:18:05 +00:00
zbottom [ 0 ] = zbottom [ 1 ] = - sprz ;
2022-10-05 22:50:47 +00:00
ztop [ 0 ] = ztop [ 1 ] = - sprz + height * yscale ;
2021-05-16 10:17:26 +00:00
if ( zbottom [ 0 ] > ztop [ 0 ] )
{
// reorder coordinates to make the clipping code below behave.
auto zz = zbottom [ 0 ] ;
zbottom [ 0 ] = zbottom [ 1 ] = ztop [ 0 ] ;
ztop [ 0 ] = ztop [ 1 ] = zz ;
2021-05-16 14:00:00 +00:00
tcs [ UPLFT ] . v = tcs [ UPRGT ] . v = 1.f - tcs [ UPLFT ] . v ;
tcs [ LOLFT ] . v = tcs [ LORGT ] . v = 1.f - tcs [ LOLFT ] . v ;
2021-05-16 10:17:26 +00:00
}
2022-05-29 22:19:32 +00:00
2021-03-27 12:22:34 +00:00
// Clip sprites to ceilings/floors
if ( ! ( sector - > ceilingstat & CSTAT_SECTOR_SKY ) )
{
2021-05-16 14:00:00 +00:00
float polyh = ( ztop [ 0 ] - zbottom [ 0 ] ) ;
2022-08-21 10:19:06 +00:00
float ceilingz = - sector - > ceilingz ;
2022-05-29 22:19:32 +00:00
if ( ceilingz < ztop [ 0 ] & & ceilingz > = zbottom [ 0 ] )
2021-03-27 12:22:34 +00:00
{
2021-05-16 14:00:00 +00:00
float newv = ( ceilingz - zbottom [ 0 ] ) / polyh ;
tcs [ UPLFT ] . v = tcs [ UPRGT ] . v = tcs [ LOLFT ] . v + newv * ( tcs [ UPLFT ] . v - tcs [ LOLFT ] . v ) ;
2021-03-27 12:22:34 +00:00
ztop [ 0 ] = ztop [ 1 ] = ceilingz ;
}
}
if ( ! ( sector - > floorstat & CSTAT_SECTOR_SKY ) )
{
2021-05-16 14:00:00 +00:00
float polyh = ( ztop [ 0 ] - zbottom [ 0 ] ) ;
2022-08-21 10:19:06 +00:00
float floorz = - sector - > floorz ;
2022-05-29 22:19:32 +00:00
if ( floorz < = ztop [ 0 ] & & floorz > zbottom [ 0 ] )
2021-03-27 12:22:34 +00:00
{
2021-05-16 14:00:00 +00:00
float newv = ( floorz - zbottom [ 0 ] ) / polyh ;
tcs [ LOLFT ] . v = tcs [ LORGT ] . v = tcs [ LOLFT ] . v + newv * ( tcs [ UPLFT ] . v - tcs [ LOLFT ] . v ) ;
2021-03-27 12:22:34 +00:00
zbottom [ 0 ] = zbottom [ 1 ] = floorz ;
}
}
2022-05-29 22:19:32 +00:00
if ( zbottom [ 0 ] > = ztop [ 0 ] )
return ; // nothing left to render.
2021-04-19 22:28:52 +00:00
// If the sprite is backward, flip it around so that we have guaranteed orientation when this is about to be sorted.
2022-09-29 14:39:24 +00:00
if ( PointOnLineSide ( di - > Viewpoint . Pos . X , di - > Viewpoint . Pos . Y , glseg . x1 , glseg . y1 , glseg . x2 - glseg . x1 , glseg . y2 - glseg . y1 ) < 0 )
2021-04-19 22:28:52 +00:00
{
std : : swap ( glseg . x1 , glseg . x2 ) ;
std : : swap ( glseg . y1 , glseg . y2 ) ;
// z is always the same on both sides.
std : : swap ( tcs [ LOLFT ] , tcs [ LORGT ] ) ;
std : : swap ( tcs [ UPLFT ] , tcs [ UPRGT ] ) ;
}
2021-05-06 22:09:30 +00:00
PutWall ( di , spriteHasTranslucency ( Sprite ) ) ;
2022-05-23 22:10:36 +00:00
}