mirror of
https://github.com/ZDoom/Raze.git
synced 2025-02-20 18:42:26 +00:00
Merge commit '9406e6d2adc4a8a70e28fd4167ca6f0bac33a7ce' into whaven
This commit is contained in:
commit
df85d3277d
37 changed files with 6161 additions and 771 deletions
|
@ -638,6 +638,8 @@ file( GLOB HEADER_FILES
|
|||
core/music/*.h
|
||||
core/menu/*.h
|
||||
core/input/*.h
|
||||
core/rendering/*.h
|
||||
core/rendering/scene/*.h
|
||||
|
||||
common/audio/sound/thirdparty/*.h
|
||||
common/audio/sound/*.h
|
||||
|
@ -1122,6 +1124,15 @@ set (PCH_SOURCES
|
|||
core/statusbar2.cpp
|
||||
core/gi.cpp
|
||||
|
||||
core/rendering/hw_entrypoint.cpp
|
||||
core/rendering/scene/hw_clipper.cpp
|
||||
core/rendering/scene/hw_walls.cpp
|
||||
core/rendering/scene/hw_flats.cpp
|
||||
core/rendering/scene/hw_drawlistadd.cpp
|
||||
core/rendering/scene/hw_drawlist.cpp
|
||||
core/rendering/scene/hw_drawinfo.cpp
|
||||
core/rendering/scene/hw_bunchdrawer.cpp
|
||||
|
||||
core/console/c_notifybuffer.cpp
|
||||
core/console/d_event.cpp
|
||||
|
||||
|
@ -1415,6 +1426,8 @@ include_directories(
|
|||
core/dobject
|
||||
core/menu
|
||||
core/input
|
||||
core/rendering
|
||||
core/rendering/scene
|
||||
platform
|
||||
common/audio/sound
|
||||
common/audio/music
|
||||
|
@ -1567,6 +1580,8 @@ source_group("Core\\2D" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/2d
|
|||
source_group("Core\\Console" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/console/.+")
|
||||
source_group("Core\\DObject" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/dobject/.+")
|
||||
source_group("Core\\Menu" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/menu/.+")
|
||||
source_group("Core\\Rendering" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/rendering/.+")
|
||||
source_group("Core\\Rendering\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/rendering/scene/.+")
|
||||
source_group("Rendering" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/glbackend/.+")
|
||||
source_group("Platform" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/platform/.+")
|
||||
source_group("Platform\\Win32" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/platform/win32/.+")
|
||||
|
|
|
@ -529,7 +529,11 @@ static FORCE_INLINE int32_t krand(void)
|
|||
int32_t krand(void);
|
||||
#endif
|
||||
|
||||
int32_t ksqrt(uint32_t num);
|
||||
inline int32_t ksqrt(uint32_t num)
|
||||
{
|
||||
return int(sqrt((float)num));
|
||||
}
|
||||
|
||||
int32_t getangle(int32_t xvect, int32_t yvect);
|
||||
fixed_t gethiq16angle(int32_t xvect, int32_t yvect);
|
||||
|
||||
|
@ -883,6 +887,19 @@ enum EHitBits
|
|||
|
||||
void updateModelInterpolation();
|
||||
|
||||
int32_t renderAddTsprite(int16_t z, int16_t sectnum);
|
||||
|
||||
inline void tileUpdatePicnum(int* const tileptr, int const obj, int stat)
|
||||
{
|
||||
auto& tile = *tileptr;
|
||||
|
||||
if (picanm[tile].sf & PICANM_ANIMTYPE_MASK)
|
||||
tile += animateoffs(tile, obj);
|
||||
|
||||
if (((obj & 16384) == 16384) && (stat & CSTAT_WALL_ROTATE_90) && RotTile(tile).newtile != -1)
|
||||
tile = RotTile(tile).newtile;
|
||||
}
|
||||
|
||||
|
||||
#include "iterators.h"
|
||||
|
||||
|
|
|
@ -20,6 +20,17 @@
|
|||
// bits 12-15: reserved
|
||||
|
||||
//////////////////// Version 7 map format ////////////////////
|
||||
enum
|
||||
{
|
||||
CSTAT_SECTOR_SKY = 1,
|
||||
CSTAT_SECTOR_SLOPE = 2,
|
||||
CSTAT_SECTOR_SWAPXY = 4,
|
||||
CSTAT_SECTOR_TEXHALF = 8,
|
||||
CSTAT_SECTOR_XFLIP = 16,
|
||||
CSTAT_SECTOR_YFLIP = 32,
|
||||
CSTAT_SECTOR_ALIGN = 64,
|
||||
CSTAT_SECTOR_METHOD = 384
|
||||
};
|
||||
|
||||
//40 bytes
|
||||
struct sectortype
|
||||
|
@ -91,6 +102,7 @@ struct walltype
|
|||
int16_t hitag;
|
||||
int16_t extra;
|
||||
float xpan_, ypan_;
|
||||
angle_t clipangle;
|
||||
|
||||
int xpan() const { return int(xpan_); }
|
||||
int ypan() const { return int(ypan_); }
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
|
||||
#include "mdsprite.h"
|
||||
|
||||
typedef struct { uint8_t r, g, b, a; } coltype;
|
||||
typedef struct { float r, g, b, a; } coltypef;
|
||||
|
||||
namespace Polymost
|
||||
{
|
||||
extern float gtang;
|
||||
extern double gxyaspect;
|
||||
extern float grhalfxdown10x;
|
||||
|
@ -14,7 +13,6 @@ extern float gcosang, gsinang, gcosang2, gsinang2;
|
|||
|
||||
extern void Polymost_prepare_loadboard(void);
|
||||
|
||||
void polymost_outputGLDebugMessage(uint8_t severity, const char* format, ...);
|
||||
|
||||
//void phex(char v, char *s);
|
||||
void polymost_drawsprite(int32_t snum);
|
||||
|
@ -24,57 +22,25 @@ void polymost_initosdfuncs(void);
|
|||
void polymost_drawrooms(void);
|
||||
void polymost_prepareMirror(int32_t dax, int32_t day, int32_t daz, fixed_t daang, fixed_t dahoriz, int16_t mirrorWall);
|
||||
void polymost_completeMirror();
|
||||
void polymost_precache(int32_t dapicnum, int32_t dapalnum, int32_t datype);
|
||||
void polymost_deletesprite(int num);
|
||||
|
||||
int32_t polymost_maskWallHasTranslucency(uwalltype const * const wall);
|
||||
int32_t polymost_spriteHasTranslucency(tspritetype const * const tspr);
|
||||
int32_t polymost_spriteIsModelOrVoxel(tspritetype const * const tspr);
|
||||
|
||||
void polymost_glreset(void);
|
||||
|
||||
enum {
|
||||
INVALIDATE_ALL,
|
||||
INVALIDATE_ART,
|
||||
INVALIDATE_ALL_NON_INDEXED,
|
||||
INVALIDATE_ART_NON_INDEXED
|
||||
};
|
||||
|
||||
void polymost_scansector(int32_t sectnum);
|
||||
|
||||
extern float curpolygonoffset;
|
||||
|
||||
}
|
||||
|
||||
// these are defined in engine.cpp.
|
||||
extern int16_t globalpicnum;
|
||||
|
||||
#define POLYMOST_CHOOSE_FOG_PAL(fogpal, pal) \
|
||||
((fogpal) ? (fogpal) : (pal))
|
||||
static FORCE_INLINE int32_t get_floor_fogpal(usectorptr_t const sec)
|
||||
{
|
||||
return POLYMOST_CHOOSE_FOG_PAL(sec->fogpal, sec->floorpal);
|
||||
}
|
||||
static FORCE_INLINE int32_t get_ceiling_fogpal(usectorptr_t const sec)
|
||||
{
|
||||
return POLYMOST_CHOOSE_FOG_PAL(sec->fogpal, sec->ceilingpal);
|
||||
}
|
||||
static FORCE_INLINE int32_t fogshade(int32_t const shade, int32_t const pal)
|
||||
{
|
||||
return (globalflags & GLOBAL_NO_GL_FOGSHADE) ? 0 : shade;
|
||||
}
|
||||
|
||||
static constexpr inline int check_nonpow2(int32_t const x)
|
||||
{
|
||||
return (x > 1 && (x&(x-1)));
|
||||
}
|
||||
|
||||
static inline float polymost_invsqrt_approximation(float x)
|
||||
{
|
||||
#if !B_BIG_ENDIAN
|
||||
float const haf = x * .5f;
|
||||
union { float f; uint32_t i; } n = { x };
|
||||
n.i = 0x5f375a86 - (n.i >> 1);
|
||||
return n.f * (1.5f - haf * (n.f * n.f));
|
||||
#else
|
||||
// this is the comment
|
||||
return 1.f / sqrtf(x);
|
||||
#endif
|
||||
}
|
||||
extern float fcosglobalang, fsinglobalang;
|
||||
extern float fydimen, fviewingrange;
|
||||
extern int32_t viewingrangerecip;
|
||||
|
||||
// Flags of the <dameth> argument of various functions
|
||||
enum {
|
||||
|
@ -95,11 +61,4 @@ enum {
|
|||
DAMETH_BACKFACECULL = -1,
|
||||
};
|
||||
|
||||
#define DAMETH_NARROW_MASKPROPS(dameth) (((dameth)&(~DAMETH_TRANS1))|(((dameth)&DAMETH_TRANS1)>>1))
|
||||
static_assert(DAMETH_NARROW_MASKPROPS(DAMETH_MASKPROPS) == DAMETH_MASK);
|
||||
|
||||
extern float fcosglobalang, fsinglobalang;
|
||||
extern float fydimen, fviewingrange;
|
||||
extern int32_t viewingrangerecip;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -175,34 +175,6 @@ static FORCE_INLINE void clipmove_tweak_pos(const vec3_t *pos, int32_t gx, int32
|
|||
}
|
||||
}
|
||||
|
||||
int32_t getceilzofslope_old(int32_t sectnum, int32_t dax, int32_t day)
|
||||
{
|
||||
int32_t dx, dy, i, j;
|
||||
|
||||
if (!(sector[sectnum].ceilingstat&2)) return sector[sectnum].ceilingz;
|
||||
j = sector[sectnum].wallptr;
|
||||
dx = wall[wall[j].point2].x-wall[j].x;
|
||||
dy = wall[wall[j].point2].y-wall[j].y;
|
||||
i = (ksqrtasm_old(dx*dx+dy*dy)); if (i == 0) return(sector[sectnum].ceilingz);
|
||||
i = DivScale(sector[sectnum].ceilingheinum,i, 15);
|
||||
dx *= i; dy *= i;
|
||||
return sector[sectnum].ceilingz+DMulScale(dx,day-wall[j].y,-dy,dax-wall[j].x, 23);
|
||||
}
|
||||
|
||||
int32_t getflorzofslope_old(int32_t sectnum, int32_t dax, int32_t day)
|
||||
{
|
||||
int32_t dx, dy, i, j;
|
||||
|
||||
if (!(sector[sectnum].floorstat&2)) return sector[sectnum].floorz;
|
||||
j = sector[sectnum].wallptr;
|
||||
dx = wall[wall[j].point2].x-wall[j].x;
|
||||
dy = wall[wall[j].point2].y-wall[j].y;
|
||||
i = (ksqrtasm_old(dx*dx+dy*dy)); if (i == 0) return sector[sectnum].floorz;
|
||||
i = DivScale(sector[sectnum].floorheinum,i, 15);
|
||||
dx *= i; dy *= i;
|
||||
return sector[sectnum].floorz+DMulScale(dx,day-wall[j].y,-dy,dax-wall[j].x, 23);
|
||||
}
|
||||
|
||||
// Returns: should clip?
|
||||
static int cliptestsector(int const dasect, int const nextsect, int32_t const flordist, int32_t const ceildist, vec2_t const pos, int32_t const posz)
|
||||
{
|
||||
|
@ -214,20 +186,6 @@ static int cliptestsector(int const dasect, int const nextsect, int32_t const fl
|
|||
{
|
||||
case ENGINECOMPATIBILITY_NONE:
|
||||
break;
|
||||
case ENGINECOMPATIBILITY_19950829:
|
||||
{
|
||||
int32_t daz = getflorzofslope_old(dasect, pos.x, pos.y);
|
||||
int32_t daz2 = getflorzofslope_old(nextsect, pos.x, pos.y);
|
||||
|
||||
if (daz2 < daz && (sec2->floorstat&1) == 0)
|
||||
if (posz >= daz2-(flordist-1)) return 1;
|
||||
daz = getceilzofslope_old(dasect, pos.x, pos.y);
|
||||
daz2 = getceilzofslope_old(nextsect, pos.x, pos.y);
|
||||
if (daz2 > daz && (sec2->ceilingstat&1) == 0)
|
||||
if (posz <= daz2+(ceildist-1)) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
{
|
||||
int32_t daz = getflorzofslope(dasect, pos.x, pos.y);
|
||||
|
@ -491,7 +449,7 @@ int32_t clipmove(vec3_t * const pos, int16_t * const sectnum, int32_t xvect, int
|
|||
|
||||
//Extra walldist for sprites on sector lines
|
||||
vec2_t const diff = { goal.x - (pos->x), goal.y - (pos->y) };
|
||||
int32_t const rad = clip_nsqrtasm(compat_maybe_truncate_to_int32(uhypsq(diff.x, diff.y))) + MAXCLIPDIST + walldist + 8;
|
||||
int32_t const rad = ksqrt(compat_maybe_truncate_to_int32(uhypsq(diff.x, diff.y))) + MAXCLIPDIST + walldist + 8;
|
||||
vec2_t const clipMin = { cent.x - rad, cent.y - rad };
|
||||
vec2_t const clipMax = { cent.x + rad, cent.y + rad };
|
||||
|
||||
|
@ -989,11 +947,6 @@ void getzrange(const vec3_t *pos, int16_t sectnum,
|
|||
vec2_t closest = pos->vec2;
|
||||
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
||||
getsectordist(closest, sectnum, &closest);
|
||||
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
||||
{
|
||||
*ceilz = getceilzofslope_old(sectnum,closest.x,closest.y);
|
||||
*florz = getflorzofslope_old(sectnum,closest.x,closest.y);
|
||||
}
|
||||
else
|
||||
getzsofslope(sectnum,closest.x,closest.y,ceilz,florz);
|
||||
*ceilhit = sectnum+16384; *florhit = sectnum+16384;
|
||||
|
@ -1061,11 +1014,6 @@ void getzrange(const vec3_t *pos, int16_t sectnum,
|
|||
closest = pos->vec2;
|
||||
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
||||
getsectordist(closest, k, &closest);
|
||||
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
||||
{
|
||||
daz = getceilzofslope_old(k, closest.x,closest.y);
|
||||
daz2 = getflorzofslope_old(k, closest.x,closest.y);
|
||||
}
|
||||
else
|
||||
getzsofslope(k, closest.x,closest.y, &daz,&daz2);
|
||||
|
||||
|
@ -1240,7 +1188,7 @@ static int32_t hitscan_trysector(const vec3_t *sv, usectorptr_t sec, hitdata_t *
|
|||
auto const wal2 = (uwallptr_t)&wall[wal->point2];
|
||||
int32_t j, dax=wal2->x-wal->x, day=wal2->y-wal->y;
|
||||
|
||||
i = nsqrtasm(compat_maybe_truncate_to_int32(uhypsq(dax,day))); if (i == 0) return 1; //continue;
|
||||
i = ksqrt(compat_maybe_truncate_to_int32(uhypsq(dax,day))); if (i == 0) return 1; //continue;
|
||||
i = DivScale(heinum,i, 15);
|
||||
dax *= i; day *= i;
|
||||
|
||||
|
@ -1471,7 +1419,7 @@ int32_t hitscan(const vec3_t *sv, int16_t sectnum, int32_t vx, int32_t vy, int32
|
|||
{
|
||||
if (picanm[tilenum].sf&PICANM_TEXHITSCAN_BIT)
|
||||
{
|
||||
tileUpdatePicnum(&tilenum, 0);
|
||||
tileUpdatePicnum(&tilenum, 0, 0);
|
||||
|
||||
if (tileLoad(tilenum))
|
||||
{
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include "inputstate.h"
|
||||
#include "printf.h"
|
||||
#include "gamecontrol.h"
|
||||
#include "render.h"
|
||||
#include "gamefuncs.h"
|
||||
|
||||
#ifdef USE_OPENGL
|
||||
# include "mdsprite.h"
|
||||
|
@ -38,6 +40,7 @@
|
|||
#include "gl_renderer.h"
|
||||
#endif
|
||||
|
||||
float rollang;
|
||||
|
||||
int32_t r_rortexture = 0;
|
||||
int32_t r_rortexturerange = 0;
|
||||
|
@ -55,9 +58,7 @@ int16_t pskybits_override = -1;
|
|||
static TArray<TArray<uint8_t>> voxelmemory;
|
||||
|
||||
int16_t tiletovox[MAXTILES];
|
||||
#ifdef USE_OPENGL
|
||||
char *voxfilenames[MAXVOXELS];
|
||||
#endif
|
||||
char g_haveVoxels;
|
||||
//#define kloadvoxel loadvoxel
|
||||
|
||||
|
@ -80,8 +81,6 @@ static int32_t no_radarang2 = 0;
|
|||
static int16_t radarang[1280];
|
||||
static int32_t qradarang[10240];
|
||||
|
||||
uint16_t ATTRIBUTE((used)) sqrtable[4096], ATTRIBUTE((used)) shlookup[4096+256], ATTRIBUTE((used)) sqrtable_old[2048];
|
||||
|
||||
const char *engineerrstr = "No error";
|
||||
|
||||
int32_t showfirstwall=0;
|
||||
|
@ -299,7 +298,7 @@ int32_t animateoffs(int const tilenum, int fakevar)
|
|||
|
||||
static void renderDrawSprite(int32_t snum)
|
||||
{
|
||||
polymost_drawsprite(snum);
|
||||
Polymost::polymost_drawsprite(snum);
|
||||
}
|
||||
|
||||
|
||||
|
@ -308,74 +307,10 @@ static void renderDrawSprite(int32_t snum)
|
|||
//
|
||||
static void renderDrawMaskedWall(int16_t damaskwallcnt)
|
||||
{
|
||||
polymost_drawmaskwall(damaskwallcnt); return;
|
||||
Polymost::polymost_drawmaskwall(damaskwallcnt); return;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t msqrtasm(uint32_t c)
|
||||
{
|
||||
uint32_t a = 0x40000000l, b = 0x20000000l;
|
||||
|
||||
do
|
||||
{
|
||||
if (c >= a)
|
||||
{
|
||||
c -= a;
|
||||
a += b*4;
|
||||
}
|
||||
a -= b;
|
||||
a >>= 1;
|
||||
b >>= 2;
|
||||
} while (b);
|
||||
|
||||
if (c >= a)
|
||||
a++;
|
||||
|
||||
return a >> 1;
|
||||
}
|
||||
|
||||
//
|
||||
// initksqrt (internal)
|
||||
//
|
||||
static inline void initksqrt(void)
|
||||
{
|
||||
int32_t i, j, k;
|
||||
uint32_t root, num;
|
||||
int32_t temp;
|
||||
|
||||
j = 1; k = 0;
|
||||
for (i=0; i<4096; i++)
|
||||
{
|
||||
if (i >= j) { j <<= 2; k++; }
|
||||
sqrtable[i] = (uint16_t)(msqrtasm((i<<18)+131072)<<1);
|
||||
shlookup[i] = (k<<1)+((10-k)<<8);
|
||||
if (i < 256) shlookup[i+4096] = ((k+6)<<1)+((10-(k+6))<<8);
|
||||
}
|
||||
|
||||
for(i=0;i<2048;i++)
|
||||
{
|
||||
root = 128;
|
||||
num = i<<20;
|
||||
do
|
||||
{
|
||||
temp = root;
|
||||
root = (root+num/root)>>1;
|
||||
} while((temp-root+1) > 2);
|
||||
temp = root*root-num;
|
||||
while (abs(int32_t(temp-2*root+1)) < abs(temp))
|
||||
{
|
||||
temp += 1-int(2*root);
|
||||
root--;
|
||||
}
|
||||
while (abs(int32_t(temp+2*root+1)) < abs(temp))
|
||||
{
|
||||
temp += 2*root+1;
|
||||
root++;
|
||||
}
|
||||
sqrtable_old[i] = root;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t engineLoadTables(void)
|
||||
{
|
||||
static char tablesloaded = 0;
|
||||
|
@ -384,8 +319,6 @@ static int32_t engineLoadTables(void)
|
|||
{
|
||||
int32_t i;
|
||||
|
||||
initksqrt();
|
||||
|
||||
for (i=0; i<2048; i++)
|
||||
reciptable[i] = DivScale(2048, i+2048, 30);
|
||||
|
||||
|
@ -532,10 +465,9 @@ int32_t insertsprite(int16_t sectnum, int16_t statnum)
|
|||
// deletesprite
|
||||
//
|
||||
int32_t (*deletesprite_replace)(int16_t spritenum) = NULL;
|
||||
void polymost_deletesprite(int num);
|
||||
int32_t deletesprite(int16_t spritenum)
|
||||
{
|
||||
polymost_deletesprite(spritenum);
|
||||
Polymost::polymost_deletesprite(spritenum);
|
||||
if (deletesprite_replace)
|
||||
return deletesprite_replace(spritenum);
|
||||
assert((sprite[spritenum].statnum == MAXSTATUS)
|
||||
|
@ -890,7 +822,7 @@ int32_t engineInit(void)
|
|||
|
||||
void engineUnInit(void)
|
||||
{
|
||||
polymost_glreset();
|
||||
Polymost::polymost_glreset();
|
||||
freeallmodels();
|
||||
# ifdef POLYMER
|
||||
polymer_uninit();
|
||||
|
@ -980,9 +912,33 @@ void set_globalang(fixed_t const ang)
|
|||
// drawrooms
|
||||
//
|
||||
EXTERN_CVAR(Int, gl_fogmode)
|
||||
CVAR(Bool, testnewrenderer, true, 0)
|
||||
CVAR(Bool, testnewinterface, true, 0)
|
||||
|
||||
int32_t renderDrawRoomsQ16(int32_t daposx, int32_t daposy, int32_t daposz,
|
||||
fixed_t daang, fixed_t dahoriz, int16_t dacursectnum)
|
||||
{
|
||||
for (int i = 0; i < numwalls; ++i)
|
||||
{
|
||||
if (wall[i].cstat & CSTAT_WALL_ROTATE_90)
|
||||
{
|
||||
auto& w = wall[i];
|
||||
auto& tile = RotTile(w.picnum + animateoffs(w.picnum, 16384));
|
||||
|
||||
if (tile.newtile == -1 && tile.owner == -1)
|
||||
{
|
||||
auto owner = w.picnum + animateoffs(w.picnum, 16384);
|
||||
|
||||
tile.newtile = TileFiles.tileCreateRotated(owner);
|
||||
assert(tile.newtile != -1);
|
||||
|
||||
RotTile(tile.newtile).owner = w.picnum + animateoffs(w.picnum, 16384);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32_t i;
|
||||
|
||||
if (gl_fogmode == 1) gl_fogmode = 2; // only radial fog works with Build's screwed up coordinate system.
|
||||
|
@ -1002,26 +958,6 @@ int32_t renderDrawRoomsQ16(int32_t daposx, int32_t daposy, int32_t daposz,
|
|||
|
||||
i = xdimen-1;
|
||||
|
||||
for (int i = 0; i < numwalls; ++i)
|
||||
{
|
||||
if (wall[i].cstat & CSTAT_WALL_ROTATE_90)
|
||||
{
|
||||
auto &w = wall[i];
|
||||
auto &tile = RotTile(w.picnum+animateoffs(w.picnum,16384));
|
||||
|
||||
if (tile.newtile == -1 && tile.owner == -1)
|
||||
{
|
||||
auto owner = w.picnum + animateoffs(w.picnum, 16384);
|
||||
|
||||
tile.newtile = TileFiles.tileCreateRotated(owner);
|
||||
assert(tile.newtile != -1);
|
||||
|
||||
RotTile(tile.newtile).owner = w.picnum+animateoffs(w.picnum,16384);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update starting sector number (common to classic and Polymost).
|
||||
// ADJUST_GLOBALCURSECTNUM.
|
||||
if (globalcursectnum >= MAXSECTORS)
|
||||
|
@ -1038,7 +974,16 @@ int32_t renderDrawRoomsQ16(int32_t daposx, int32_t daposy, int32_t daposz,
|
|||
return 0;
|
||||
}
|
||||
|
||||
polymost_drawrooms();
|
||||
if (!testnewrenderer)
|
||||
{
|
||||
Polymost::polymost_drawrooms();
|
||||
}
|
||||
else
|
||||
{
|
||||
vec3_t pos = { daposx, daposy, daposz };
|
||||
//if (!testnewinterface) render_drawrooms_(pos, globalcursectnum, daang, dahoriz, rollang, r_fov, false, false);
|
||||
/*else*/ render_drawrooms(pos, globalcursectnum, daang, dahoriz, rollang, false, false);
|
||||
}
|
||||
|
||||
return inpreparemirror;
|
||||
}
|
||||
|
@ -1180,7 +1125,7 @@ void renderDrawMasks(void)
|
|||
int32_t back = i;
|
||||
for (; i >= 0; --i)
|
||||
{
|
||||
if (polymost_spriteHasTranslucency(&tsprite[i]))
|
||||
if (Polymost::polymost_spriteHasTranslucency(&tsprite[i]))
|
||||
{
|
||||
tspriteptr[spritesortcnt] = &tsprite[i];
|
||||
++spritesortcnt;
|
||||
|
@ -1195,7 +1140,7 @@ void renderDrawMasks(void)
|
|||
{
|
||||
const int32_t xs = tspriteptr[i]->x-globalposx, ys = tspriteptr[i]->y-globalposy;
|
||||
const int32_t yp = DMulScale(xs,cosviewingrangeglobalang,ys,sinviewingrangeglobalang, 6);
|
||||
const int32_t modelp = polymost_spriteIsModelOrVoxel(tspriteptr[i]);
|
||||
const int32_t modelp = spriteIsModelOrVoxel(tspriteptr[i]);
|
||||
|
||||
if (yp > (4<<8))
|
||||
{
|
||||
|
@ -1259,10 +1204,10 @@ killsprite:
|
|||
int32_t pcstat = tspriteptr[i]->cstat & 48;
|
||||
int32_t pangle = tspriteptr[i]->ang;
|
||||
int j = i + 1;
|
||||
if (!polymost_spriteIsModelOrVoxel(tspriteptr[i]))
|
||||
if (!spriteIsModelOrVoxel(tspriteptr[i]))
|
||||
{
|
||||
while (j < numSprites && py == spritesxyz[j].y && pcstat == (tspriteptr[j]->cstat & 48) && (pcstat != 16 || pangle == tspriteptr[j]->ang)
|
||||
&& !polymost_spriteIsModelOrVoxel(tspriteptr[j]))
|
||||
&& !spriteIsModelOrVoxel(tspriteptr[j]))
|
||||
{
|
||||
j++;
|
||||
}
|
||||
|
@ -1304,7 +1249,7 @@ killsprite:
|
|||
maskwallcnt = 0;
|
||||
for (i = 0; i < numMaskWalls; i++)
|
||||
{
|
||||
if (polymost_maskWallHasTranslucency((uwalltype *) &wall[thewall[maskwall[i]]]))
|
||||
if (Polymost::polymost_maskWallHasTranslucency((uwalltype *) &wall[thewall[maskwall[i]]]))
|
||||
{
|
||||
maskwall[maskwallcnt] = maskwall[i];
|
||||
maskwallcnt++;
|
||||
|
@ -1893,9 +1838,11 @@ void renderDrawMapView(int32_t dax, int32_t day, int32_t zoome, int16_t ang)
|
|||
|
||||
globalfloorpal = globalpal = sec->floorpal;
|
||||
|
||||
globalpicnum = sec->floorpicnum;
|
||||
if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0;
|
||||
tileUpdatePicnum(&globalpicnum, s);
|
||||
int _globalpicnum = sec->floorpicnum;
|
||||
if ((unsigned)_globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0;
|
||||
tileUpdatePicnum(&_globalpicnum, s, 0);
|
||||
globalpicnum = _globalpicnum;
|
||||
|
||||
setgotpic(globalpicnum);
|
||||
if ((tileWidth(globalpicnum) <= 0) || (tileHeight(globalpicnum) <= 0)) continue;
|
||||
|
||||
|
@ -1910,7 +1857,7 @@ void renderDrawMapView(int32_t dax, int32_t day, int32_t zoome, int16_t ang)
|
|||
{
|
||||
ox = wall[wall[startwall].point2].x - wall[startwall].x;
|
||||
oy = wall[wall[startwall].point2].y - wall[startwall].y;
|
||||
i = nsqrtasm(uhypsq(ox,oy)); if (i == 0) continue;
|
||||
i = ksqrt(uhypsq(ox,oy)); if (i == 0) continue;
|
||||
i = 1048576/i;
|
||||
globalx1 = MulScale(DMulScale(ox,bakgvect.x,oy,bakgvect.y, 10),i, 10);
|
||||
globaly1 = MulScale(DMulScale(ox,bakgvect.y,-oy,bakgvect.x, 10),i, 10);
|
||||
|
@ -1921,7 +1868,7 @@ void renderDrawMapView(int32_t dax, int32_t day, int32_t zoome, int16_t ang)
|
|||
globaly2 = -globaly1;
|
||||
|
||||
int32_t const daslope = sector[s].floorheinum;
|
||||
i = nsqrtasm(daslope*daslope+16777216);
|
||||
i = ksqrt(daslope*daslope+16777216);
|
||||
set_globalpos(globalposx, MulScale(globalposy,i, 12), globalposz);
|
||||
globalx2 = MulScale(globalx2,i, 12);
|
||||
globaly2 = MulScale(globaly2,i, 12);
|
||||
|
@ -2012,8 +1959,12 @@ void renderDrawMapView(int32_t dax, int32_t day, int32_t zoome, int16_t ang)
|
|||
|
||||
globalpicnum = spr->picnum;
|
||||
globalpal = spr->pal; // GL needs this, software doesn't
|
||||
if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0;
|
||||
tileUpdatePicnum(&globalpicnum, s);
|
||||
|
||||
int _globalpicnum = sec->floorpicnum;
|
||||
if ((unsigned)_globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0;
|
||||
tileUpdatePicnum(&_globalpicnum, s, 0);
|
||||
globalpicnum = _globalpicnum;
|
||||
|
||||
setgotpic(globalpicnum);
|
||||
if ((tileWidth(globalpicnum) <= 0) || (tileHeight(globalpicnum) <= 0)) continue;
|
||||
|
||||
|
@ -2311,16 +2262,6 @@ fixed_t gethiq16angle(int32_t xvect, int32_t yvect)
|
|||
return rv;
|
||||
}
|
||||
|
||||
//
|
||||
// ksqrt
|
||||
//
|
||||
int32_t ksqrt(uint32_t num)
|
||||
{
|
||||
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
||||
return ksqrtasm_old(num);
|
||||
return nsqrtasm(num);
|
||||
}
|
||||
|
||||
// Gets the BUILD unit height and z offset of a sprite.
|
||||
// Returns the z offset, 'height' may be NULL.
|
||||
int32_t spriteheightofsptr(uspriteptr_t spr, int32_t *height, int32_t alsotileyofs)
|
||||
|
@ -3169,7 +3110,7 @@ void renderPrepareMirror(int32_t dax, int32_t day, int32_t daz, fixed_t daang, f
|
|||
|
||||
inpreparemirror = 1;
|
||||
|
||||
polymost_prepareMirror(dax, day, daz, daang, dahoriz, dawall);
|
||||
Polymost::polymost_prepareMirror(dax, day, daz, daang, dahoriz, dawall);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3178,7 +3119,7 @@ void renderPrepareMirror(int32_t dax, int32_t day, int32_t daz, fixed_t daang, f
|
|||
//
|
||||
void renderCompleteMirror(void)
|
||||
{
|
||||
polymost_completeMirror();
|
||||
Polymost::polymost_completeMirror();
|
||||
inpreparemirror = 0;
|
||||
}
|
||||
|
||||
|
@ -3224,7 +3165,7 @@ int32_t getceilzofslopeptr(usectorptr_t sec, int32_t dax, int32_t day)
|
|||
vec2_t const w = *(vec2_t const *)wal;
|
||||
vec2_t const d = { wal2->x - w.x, wal2->y - w.y };
|
||||
|
||||
int const i = nsqrtasm(uhypsq(d.x,d.y))<<5;
|
||||
int const i = ksqrt(uhypsq(d.x,d.y))<<5;
|
||||
if (i == 0) return sec->ceilingz;
|
||||
|
||||
int const j = DMulScale(d.x, day-w.y, -d.y, dax-w.x, 3);
|
||||
|
@ -3243,7 +3184,7 @@ int32_t getflorzofslopeptr(usectorptr_t sec, int32_t dax, int32_t day)
|
|||
vec2_t const w = *(vec2_t const *)wal;
|
||||
vec2_t const d = { wal2->x - w.x, wal2->y - w.y };
|
||||
|
||||
int const i = nsqrtasm(uhypsq(d.x,d.y))<<5;
|
||||
int const i = ksqrt(uhypsq(d.x,d.y))<<5;
|
||||
if (i == 0) return sec->floorz;
|
||||
|
||||
int const j = DMulScale(d.x, day-w.y, -d.y, dax-w.x, 3);
|
||||
|
@ -3263,7 +3204,7 @@ void getzsofslopeptr(usectorptr_t sec, int32_t dax, int32_t day, int32_t *ceilz,
|
|||
|
||||
vec2_t const d = { wal2->x - wal->x, wal2->y - wal->y };
|
||||
|
||||
int const i = nsqrtasm(uhypsq(d.x,d.y))<<5;
|
||||
int const i = ksqrt(uhypsq(d.x,d.y))<<5;
|
||||
if (i == 0) return;
|
||||
|
||||
int const j = DMulScale(d.x,day-wal->y, -d.y,dax-wal->x, 3);
|
||||
|
@ -3288,7 +3229,7 @@ void alignceilslope(int16_t dasect, int32_t x, int32_t y, int32_t z)
|
|||
return;
|
||||
|
||||
sector[dasect].ceilingheinum = Scale((z-sector[dasect].ceilingz)<<8,
|
||||
nsqrtasm(uhypsq(dax,day)), i);
|
||||
ksqrt(uhypsq(dax,day)), i);
|
||||
if (sector[dasect].ceilingheinum == 0)
|
||||
sector[dasect].ceilingstat &= ~2;
|
||||
else sector[dasect].ceilingstat |= 2;
|
||||
|
@ -3309,7 +3250,7 @@ void alignflorslope(int16_t dasect, int32_t x, int32_t y, int32_t z)
|
|||
return;
|
||||
|
||||
sector[dasect].floorheinum = Scale((z-sector[dasect].floorz)<<8,
|
||||
nsqrtasm(uhypsq(dax,day)), i);
|
||||
ksqrt(uhypsq(dax,day)), i);
|
||||
if (sector[dasect].floorheinum == 0)
|
||||
sector[dasect].floorstat &= ~2;
|
||||
else sector[dasect].floorstat |= 2;
|
||||
|
@ -3323,7 +3264,8 @@ void alignflorslope(int16_t dasect, int32_t x, int32_t y, int32_t z)
|
|||
#ifdef USE_OPENGL
|
||||
void renderSetRollAngle(float rolla)
|
||||
{
|
||||
gtang = rolla * BAngRadian;
|
||||
Polymost::gtang = rolla * BAngRadian;
|
||||
rollang = rolla * (BAngRadian * 180 / pi::pif());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "cmdlib.h"
|
||||
|
||||
#ifndef ENGINE_PRIV_H
|
||||
#define ENGINE_PRIV_H
|
||||
|
||||
|
@ -23,63 +25,15 @@
|
|||
extern int32_t globalx1, globaly2;
|
||||
|
||||
|
||||
extern uint16_t sqrtable[4096], shlookup[4096+256],sqrtable_old[2048];
|
||||
|
||||
|
||||
static inline int32_t nsqrtasm(uint32_t a)
|
||||
{
|
||||
// JBF 20030901: This was a damn lot simpler to reverse engineer than
|
||||
// msqrtasm was. Really, it was just like simplifying an algebra equation.
|
||||
uint16_t c;
|
||||
|
||||
if (a & 0xff000000) // test eax, 0xff000000 / jnz short over24
|
||||
{
|
||||
c = shlookup[(a >> 24) + 4096]; // mov ebx, eax
|
||||
// over24: shr ebx, 24
|
||||
// mov cx, word ptr shlookup[ebx*2+8192]
|
||||
}
|
||||
else
|
||||
{
|
||||
c = shlookup[a >> 12]; // mov ebx, eax
|
||||
// shr ebx, 12
|
||||
// mov cx, word ptr shlookup[ebx*2]
|
||||
// jmp short under24
|
||||
}
|
||||
a >>= c&0xff; // under24: shr eax, cl
|
||||
a = (a&0xffff0000)|(sqrtable[a]); // mov ax, word ptr sqrtable[eax*2]
|
||||
a >>= ((c&0xff00) >> 8); // mov cl, ch
|
||||
// shr eax, cl
|
||||
return a;
|
||||
}
|
||||
|
||||
static inline int32_t getclipmask(int32_t a, int32_t b, int32_t c, int32_t d)
|
||||
{
|
||||
// Ken did this
|
||||
d = ((a<0)<<3) + ((b<0)<<2) + ((c<0)<<1) + (d<0);
|
||||
return (((d<<4)^0xf0)|d);
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline int32_t ksqrtasm_old(int32_t n)
|
||||
static inline int32_t getclipmask(int32_t a, int32_t b, int32_t c, int32_t d)
|
||||
{
|
||||
uint32_t shift = 0;
|
||||
n = abs((int32_t)n);
|
||||
while (n >= 2048)
|
||||
{
|
||||
n >>= 2;
|
||||
++shift;
|
||||
}
|
||||
uint32_t const s = sqrtable_old[n];
|
||||
return (s << shift) >> 10;
|
||||
// Ken did this
|
||||
d = ((a<0)<<3) + ((b<0)<<2) + ((c<0)<<1) + (d<0);
|
||||
return (((d<<4)^0xf0)|d);
|
||||
}
|
||||
|
||||
inline int32_t clip_nsqrtasm(int32_t n)
|
||||
{
|
||||
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
||||
return ksqrtasm_old(n);
|
||||
return nsqrtasm(n);
|
||||
}
|
||||
|
||||
|
||||
extern int16_t thesector[MAXWALLSB], thewall[MAXWALLSB];
|
||||
extern int16_t bunchfirst[MAXWALLSB], bunchlast[MAXWALLSB];
|
||||
|
@ -142,13 +96,6 @@ static FORCE_INLINE int32_t getpalookup(int32_t davis, int32_t dashade)
|
|||
|
||||
static FORCE_INLINE int32_t getpalookupsh(int32_t davis) { return getpalookup(davis, globalshade) << 8; }
|
||||
|
||||
////// yax'y stuff //////
|
||||
#ifdef USE_OPENGL
|
||||
extern void polymost_scansector(int32_t sectnum);
|
||||
#endif
|
||||
int32_t renderAddTsprite(int16_t z, int16_t sectnum);
|
||||
|
||||
|
||||
static FORCE_INLINE void setgotpic(int32_t tilenume)
|
||||
{
|
||||
gotpic[tilenume>>3] |= pow2char[tilenume&7];
|
||||
|
@ -166,16 +113,6 @@ static FORCE_INLINE void set_globalpos(int32_t const x, int32_t const y, int32_t
|
|||
globalposz = z, fglobalposz = (float)z;
|
||||
}
|
||||
|
||||
template <typename T> static FORCE_INLINE void tileUpdatePicnum(T * const tileptr, int const obj)
|
||||
{
|
||||
auto &tile = *tileptr;
|
||||
|
||||
if (picanm[tile].sf & PICANM_ANIMTYPE_MASK)
|
||||
tile += animateoffs(tile, obj);
|
||||
|
||||
if (((obj & 16384) == 16384) && (globalorientation & CSTAT_WALL_ROTATE_90) && RotTile(tile).newtile != -1)
|
||||
tile = RotTile(tile).newtile;
|
||||
}
|
||||
|
||||
// x1, y1: in/out
|
||||
// rest x/y: out
|
||||
|
@ -245,22 +182,12 @@ static inline void get_floorspr_points(T const * const spr, int32_t px, int32_t
|
|||
|
||||
inline int widthBits(int num)
|
||||
{
|
||||
int w = tileWidth(num);
|
||||
int j = 15;
|
||||
|
||||
while ((j > 1) && ((1 << j) > w))
|
||||
j--;
|
||||
return j;
|
||||
return sizeToBits(tileWidth(num));
|
||||
}
|
||||
|
||||
inline int heightBits(int num)
|
||||
{
|
||||
int w = tileHeight(num);
|
||||
int j = 15;
|
||||
|
||||
while ((j > 1) && ((1 << j) > w))
|
||||
j--;
|
||||
return j;
|
||||
return sizeToBits(tileHeight(num));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ static int32_t curextra=MAXTILES;
|
|||
|
||||
#define MIN_CACHETIME_PRINT 10
|
||||
|
||||
using namespace Polymost;
|
||||
|
||||
static int32_t addtileP(int32_t model,int32_t tile,int32_t pallet)
|
||||
{
|
||||
|
@ -1261,9 +1262,6 @@ static int32_t polymost_md3draw(md3model_t *m, tspriteptr_t tspr)
|
|||
const uint8_t lpal = ((unsigned)owner < MAXSPRITES) ? sprite[tspr->owner].pal : tspr->pal;
|
||||
const int32_t sizyrep = tileHeight(tspr->picnum) * tspr->yrepeat;
|
||||
|
||||
polymost_outputGLDebugMessage(3, "polymost_md3draw(m:%p, tspr:%p)", m, tspr);
|
||||
// if ((tspr->cstat&48) == 32) return 0;
|
||||
|
||||
updateanimation((md2model_t *)m, tspr, lpal);
|
||||
|
||||
//create current&next frame's vertex list from whole list
|
||||
|
|
|
@ -23,18 +23,15 @@ Ken Silverman's official web site: http://www.advsys.net/ken
|
|||
#include "hw_renderstate.h"
|
||||
#include "printf.h"
|
||||
|
||||
int skiptile = -1;
|
||||
FGameTexture* GetSkyTexture(int basetile, int lognumtiles, const int16_t* tilemap);
|
||||
|
||||
int checkTranslucentReplacement(FTextureID picnum, int pal);
|
||||
|
||||
CVARD(Bool, hw_animsmoothing, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable model animation smoothing")
|
||||
CVARD(Bool, hw_hightile, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable hightile texture rendering")
|
||||
CVARD(Bool, hw_models, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable model rendering")
|
||||
CVARD(Bool, hw_parallaxskypanning, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable parallaxed floor/ceiling panning when drawing a parallaxing sky")
|
||||
CVARD(Float, hw_shadescale, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "multiplier for shading")
|
||||
bool hw_int_useindexedcolortextures;
|
||||
CUSTOM_CVARD(Bool, hw_useindexedcolortextures, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable indexed color texture rendering")
|
||||
{
|
||||
if (screen) screen->SetTextureFilterMode();
|
||||
}
|
||||
|
||||
|
||||
//{ "r_yshearing", "enable/disable y-shearing", (void*)&r_yshearing, CVAR_BOOL, 0, 1 }, disabled because not fully functional
|
||||
|
@ -42,6 +39,10 @@ CUSTOM_CVARD(Bool, hw_useindexedcolortextures, false, CVAR_ARCHIVE | CVAR_GLOBAL
|
|||
// For testing - will be removed later.
|
||||
CVAR(Int, skytile, 0, 0)
|
||||
|
||||
namespace Polymost
|
||||
{
|
||||
|
||||
|
||||
typedef struct { float x, cy[2], fy[2]; int32_t tag; int16_t n, p, ctag, ftag; } vsptyp;
|
||||
#define VSPMAX 2048 //<- careful!
|
||||
static vsptyp vsp[VSPMAX];
|
||||
|
@ -102,19 +103,35 @@ static int32_t hicprecaching = 0;
|
|||
static hitdata_t polymost_hitdata;
|
||||
|
||||
FGameTexture* globalskytex = nullptr;
|
||||
FGameTexture* GetSkyTexture(int basetile, int lognumtiles, const int16_t* tilemap);
|
||||
|
||||
void polymost_outputGLDebugMessage(uint8_t severity, const char* format, ...)
|
||||
{
|
||||
}
|
||||
|
||||
float sectorVisibility(int sectnum)
|
||||
static inline float polymost_invsqrt_approximation(float x)
|
||||
{
|
||||
// this is the comment
|
||||
return 1.f / sqrtf(x);
|
||||
}
|
||||
|
||||
static float sectorVisibility(int sectnum)
|
||||
{
|
||||
// Beware of wraparound madness...
|
||||
int v = sector[sectnum].visibility;
|
||||
return v? ((uint8_t)(v + 16)) / 16.f : 1.f;
|
||||
}
|
||||
|
||||
template <typename T> static FORCE_INLINE void tileUpdatePicnum(T* const tileptr, int const obj)
|
||||
{
|
||||
auto& tile = *tileptr;
|
||||
|
||||
if (picanm[tile].sf & PICANM_ANIMTYPE_MASK)
|
||||
tile += animateoffs(tile, obj);
|
||||
|
||||
if (((obj & 16384) == 16384) && (globalorientation & CSTAT_WALL_ROTATE_90) && RotTile(tile).newtile != -1)
|
||||
tile = RotTile(tile).newtile;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
//Use this for both initialization and uninitialization of OpenGL.
|
||||
|
@ -216,25 +233,6 @@ int32_t polymost_spriteHasTranslucency(tspritetype const * const tspr)
|
|||
return checkTranslucentReplacement(tileGetTexture(tspr->picnum)->GetID(), tspr->pal);
|
||||
}
|
||||
|
||||
int32_t polymost_spriteIsModelOrVoxel(tspritetype const * const tspr)
|
||||
{
|
||||
if ((unsigned)tspr->owner < MAXSPRITES && spriteext[tspr->owner].flags&SPREXT_NOTMD)
|
||||
return false;
|
||||
|
||||
|
||||
if (hw_models && tile2model[Ptile2tile(tspr->picnum, tspr->pal)].modelid >= 0 &&
|
||||
tile2model[Ptile2tile(tspr->picnum, tspr->pal)].framenum >= 0)
|
||||
return true;
|
||||
|
||||
if (r_voxels && (tspr->cstat & CSTAT_SPRITE_ALIGNMENT) != CSTAT_SPRITE_ALIGNMENT_SLAB && tiletovox[tspr->picnum] >= 0 && voxmodels[tiletovox[tspr->picnum]])
|
||||
return true;
|
||||
|
||||
if ((tspr->cstat & CSTAT_SPRITE_ALIGNMENT) == CSTAT_SPRITE_ALIGNMENT_SLAB && voxmodels[tspr->picnum])
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void polymost_updaterotmat(void)
|
||||
{
|
||||
//Up/down rotation
|
||||
|
@ -253,7 +251,8 @@ static void polymost_updaterotmat(void)
|
|||
};
|
||||
multiplyMatrix4f(matrix, tiltmatrix);
|
||||
renderSetViewMatrix(matrix);
|
||||
renderSetVisibility(MulScale(g_visibility, MulScale(xdimenscale, viewingrangerecip, 16), 16) * fviewingrange * (1.f / (65536.f * 65536.f)) / r_ambientlight);
|
||||
float fxdimen = FixedToFloat(xdimenscale);
|
||||
renderSetVisibility(g_visibility * fxdimen * (1.f / (65536.f)) / r_ambientlight);
|
||||
}
|
||||
|
||||
const vec2_16_t tileSize(size_t index)
|
||||
|
@ -265,7 +264,6 @@ const vec2_16_t tileSize(size_t index)
|
|||
static void polymost_flatskyrender(vec2f_t const* const dpxy, int32_t const n, int32_t method, const vec2_16_t& tilesize);
|
||||
|
||||
// Hack for Duke's camera until I can find out why this behaves erratically.
|
||||
int skiptile = -1;
|
||||
|
||||
static void polymost_drawpoly(vec2f_t const * const dpxy, int32_t const n, int32_t method, const vec2_16_t &tilesize)
|
||||
{
|
||||
|
@ -333,8 +331,6 @@ static void polymost_drawpoly(vec2f_t const * const dpxy, int32_t const n, int32
|
|||
float usub = 0;
|
||||
float vsub = 0;
|
||||
|
||||
polymost_outputGLDebugMessage(3, "polymost_drawpoly(dpxy:%p, n:%d, method_:%X), method: %X", dpxy, n, method_, method);
|
||||
|
||||
// This only takes effect for textures with their default set to SamplerClampXY.
|
||||
int sampleroverride = CLAMP_NONE;
|
||||
if (method & DAMETH_CLAMPED)
|
||||
|
@ -962,12 +958,12 @@ static void polymost_internal_nonparallaxed(vec2f_t n0, vec2f_t n1, float ryp0,
|
|||
|
||||
if (globalorientation & 2)
|
||||
{
|
||||
int i = krecipasm(nsqrtasm(uhypsq(xy.x,xy.y)));
|
||||
int i = krecipasm(ksqrt(uhypsq(xy.x,xy.y)));
|
||||
r = i * (1.f/1073741824.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = nsqrtasm(uhypsq(xy.x,xy.y)); if (i == 0) i = 1024; else i = 1048576 / i;
|
||||
int i = ksqrt(uhypsq(xy.x,xy.y)); if (i == 0) i = 1024; else i = 1048576 / i;
|
||||
r = i * (1.f/1048576.f);
|
||||
}
|
||||
|
||||
|
@ -1210,7 +1206,7 @@ static float fgetceilzofslope(usectorptr_t sec, float dax, float day)
|
|||
vec2_t const w = *(vec2_t const *)wal;
|
||||
vec2_t const d = { wal2->x - w.x, wal2->y - w.y };
|
||||
|
||||
int const i = nsqrtasm(uhypsq(d.x,d.y))<<5;
|
||||
int const i = ksqrt(uhypsq(d.x,d.y))<<5;
|
||||
if (i == 0) return sec->ceilingz;
|
||||
|
||||
float const j = (d.x*(day-w.y)-d.y*(dax-w.x))*(1.f/8.f);
|
||||
|
@ -1228,7 +1224,7 @@ static float fgetflorzofslope(usectorptr_t sec, float dax, float day)
|
|||
vec2_t const w = *(vec2_t const *)wal;
|
||||
vec2_t const d = { wal2->x - w.x, wal2->y - w.y };
|
||||
|
||||
int const i = nsqrtasm(uhypsq(d.x,d.y))<<5;
|
||||
int const i = ksqrt(uhypsq(d.x,d.y))<<5;
|
||||
if (i == 0) return sec->floorz;
|
||||
|
||||
float const j = (d.x*(day-w.y)-d.y*(dax-w.x))*(1.f/8.f);
|
||||
|
@ -1247,7 +1243,7 @@ static void fgetzsofslope(usectorptr_t sec, float dax, float day, float* ceilz,
|
|||
|
||||
vec2_t const d = { wal2->x - wal->x, wal2->y - wal->y };
|
||||
|
||||
int const i = nsqrtasm(uhypsq(d.x,d.y))<<5;
|
||||
int const i = ksqrt(uhypsq(d.x,d.y))<<5;
|
||||
if (i == 0) return;
|
||||
|
||||
float const j = (d.x*(day-wal->y)-d.y*(dax-wal->x))*(1.f/8.f);
|
||||
|
@ -1590,184 +1586,6 @@ static void polymost_drawalls(int32_t const bunch)
|
|||
flatskyrender = 0;
|
||||
ghoriz = ghorizbak;
|
||||
}
|
||||
#if 0
|
||||
else //NOTE: code copied from ceiling code... lots of duplicated stuff :/
|
||||
{
|
||||
//Skybox code for parallax floor!
|
||||
float sky_t0, sky_t1; // _nx0, _ny0, _nx1, _ny1;
|
||||
float sky_ryp0, sky_ryp1, sky_x0, sky_x1, sky_cy0, sky_fy0, sky_cy1, sky_fy1, sky_ox0, sky_ox1;
|
||||
static vec2f_t const skywal[4] = { { -512, -512 }, { 512, -512 }, { 512, 512 }, { -512, 512 } };
|
||||
|
||||
pow2xsplit = 0;
|
||||
|
||||
for (bssize_t i=0; i<4; i++)
|
||||
{
|
||||
walpos = skywal[i&3];
|
||||
vec2f_t skyp0 = { walpos.y * gcosang - walpos.x * gsinang,
|
||||
walpos.x * gcosang2 + walpos.y * gsinang2 };
|
||||
|
||||
walpos = skywal[(i + 1) & 3];
|
||||
vec2f_t skyp1 = { walpos.y * gcosang - walpos.x * gsinang,
|
||||
walpos.x * gcosang2 + walpos.y * gsinang2 };
|
||||
|
||||
vec2f_t const oskyp0 = skyp0;
|
||||
|
||||
//Clip to close parallel-screen plane
|
||||
if (skyp0.y < SCISDIST)
|
||||
{
|
||||
if (skyp1.y < SCISDIST) continue;
|
||||
sky_t0 = (SCISDIST - skyp0.y) / (skyp1.y - skyp0.y);
|
||||
skyp0 = { (skyp1.x - skyp0.x) * sky_t0 + skyp0.x, SCISDIST };
|
||||
}
|
||||
else { sky_t0 = 0.f; }
|
||||
|
||||
if (skyp1.y < SCISDIST)
|
||||
{
|
||||
sky_t1 = (SCISDIST - oskyp0.y) / (skyp1.y - oskyp0.y);
|
||||
skyp1 = { (skyp1.x - oskyp0.x) * sky_t1 + oskyp0.x, SCISDIST };
|
||||
}
|
||||
else { sky_t1 = 1.f; }
|
||||
|
||||
sky_ryp0 = 1.f/skyp0.y; sky_ryp1 = 1.f/skyp1.y;
|
||||
|
||||
//Generate screen coordinates for front side of wall
|
||||
sky_x0 = ghalfx*skyp0.x*sky_ryp0 + ghalfx;
|
||||
sky_x1 = ghalfx*skyp1.x*sky_ryp1 + ghalfx;
|
||||
if ((sky_x1 <= sky_x0) || (sky_x0 >= x1) || (x0 >= sky_x1)) continue;
|
||||
|
||||
sky_ryp0 *= gyxscale; sky_ryp1 *= gyxscale;
|
||||
|
||||
sky_cy0 = -8192.f*sky_ryp0 + ghoriz;
|
||||
sky_fy0 = 8192.f*sky_ryp0 + ghoriz;
|
||||
sky_cy1 = -8192.f*sky_ryp1 + ghoriz;
|
||||
sky_fy1 = 8192.f*sky_ryp1 + ghoriz;
|
||||
|
||||
sky_ox0 = sky_x0; sky_ox1 = sky_x1;
|
||||
|
||||
//Make sure: x0<=_x0<_x1<=x1
|
||||
float nfy[2] = { fy0, fy1 };
|
||||
|
||||
if (sky_x0 < x0)
|
||||
{
|
||||
float const t = (x0-sky_x0)/(sky_x1-sky_x0);
|
||||
sky_cy0 += (sky_cy1-sky_cy0)*t;
|
||||
sky_fy0 += (sky_fy1-sky_fy0)*t;
|
||||
sky_x0 = x0;
|
||||
}
|
||||
else if (sky_x0 > x0) nfy[0] += (sky_x0-x0)*(fy1-fy0)/(x1-x0);
|
||||
|
||||
if (sky_x1 > x1)
|
||||
{
|
||||
float const t = (x1-sky_x1)/(sky_x1-sky_x0);
|
||||
sky_cy1 += (sky_cy1-sky_cy0)*t;
|
||||
sky_fy1 += (sky_fy1-sky_fy0)*t;
|
||||
sky_x1 = x1;
|
||||
}
|
||||
else if (sky_x1 < x1) nfy[1] += (sky_x1-x1)*(fy1-fy0)/(x1-x0);
|
||||
|
||||
// (skybox floor)
|
||||
//(_x0,_fy0)-(_x1,_fy1)
|
||||
// (skybox wall)
|
||||
//(_x0,_cy0)-(_x1,_cy1)
|
||||
// (skybox ceiling)
|
||||
//(_x0,nfy0)-(_x1,nfy1)
|
||||
|
||||
//floor of skybox
|
||||
drawingskybox = 6; //floor/6th texture/index 5 of skybox
|
||||
float const ft[4] = { 512 / 16, 512 / -16, fcosglobalang * (1.f / 2147483648.f),
|
||||
fsinglobalang * (1.f / 2147483648.f) };
|
||||
|
||||
xtex.d = 0;
|
||||
ytex.d = gxyaspect*(1.0/4194304.0);
|
||||
otex.d = -ghoriz*ytex.d;
|
||||
xtex.u = ft[3]*fviewingrange*(-1.0/65536.0);
|
||||
xtex.v = ft[2]*fviewingrange*(-1.0/65536.0);
|
||||
ytex.u = ft[0]*ytex.d; ytex.v = ft[1]*ytex.d;
|
||||
otex.u = ft[0]*otex.d; otex.v = ft[1]*otex.d;
|
||||
otex.u += (ft[2]-xtex.u)*ghalfx;
|
||||
otex.v -= (ft[3]+xtex.v)*ghalfx;
|
||||
xtex.v = -xtex.v; ytex.v = -ytex.v; otex.v = -otex.v; //y-flip skybox floor
|
||||
|
||||
if ((sky_fy0 > nfy[0]) && (sky_fy1 > nfy[1]))
|
||||
polymost_domost(sky_x0,sky_fy0,sky_x1,sky_fy1);
|
||||
else if ((sky_fy0 > nfy[0]) != (sky_fy1 > nfy[1]))
|
||||
{
|
||||
//(ox,oy) is intersection of: (_x0,_fy0)-(_x1,_fy1)
|
||||
// (_x0,nfy0)-(_x1,nfy1)
|
||||
float const t = (sky_fy0-nfy[0])/(nfy[1]-nfy[0]-sky_fy1+sky_fy0);
|
||||
vec2f_t const o = { sky_x0 + (sky_x1-sky_x0)*t, sky_fy0 + (sky_fy1-sky_fy0)*t };
|
||||
if (nfy[0] > sky_fy0)
|
||||
{
|
||||
polymost_domost(sky_x0,nfy[0],o.x,o.y);
|
||||
polymost_domost(o.x,o.y,sky_x1,sky_fy1);
|
||||
}
|
||||
else
|
||||
{
|
||||
polymost_domost(sky_x0,sky_fy0,o.x,o.y);
|
||||
polymost_domost(o.x,o.y,sky_x1,nfy[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
polymost_domost(sky_x0,nfy[0],sky_x1,nfy[1]);
|
||||
|
||||
//wall of skybox
|
||||
drawingskybox = i+1; //i+1th texture/index i of skybox
|
||||
xtex.d = (sky_ryp0-sky_ryp1)*gxyaspect*(1.0/512.0) / (sky_ox0-sky_ox1);
|
||||
ytex.d = 0;
|
||||
otex.d = sky_ryp0*gxyaspect*(1.0/512.0) - xtex.d*sky_ox0;
|
||||
xtex.u = (sky_t0*sky_ryp0 - sky_t1*sky_ryp1)*gxyaspect*(64.0/512.0) / (sky_ox0-sky_ox1);
|
||||
otex.u = sky_t0*sky_ryp0*gxyaspect*(64.0/512.0) - xtex.u*sky_ox0;
|
||||
ytex.u = 0;
|
||||
sky_t0 = -8192.f*sky_ryp0 + ghoriz;
|
||||
sky_t1 = -8192.f*sky_ryp1 + ghoriz;
|
||||
float const t = ((xtex.d*sky_ox0 + otex.d)*8.f) / ((sky_ox1-sky_ox0) * sky_ryp0 * 2048.f);
|
||||
xtex.v = (sky_t0-sky_t1)*t;
|
||||
ytex.v = (sky_ox1-sky_ox0)*t;
|
||||
otex.v = -xtex.v*sky_ox0 - ytex.v*sky_t0;
|
||||
|
||||
if ((sky_cy0 > nfy[0]) && (sky_cy1 > nfy[1]))
|
||||
polymost_domost(sky_x0,sky_cy0,sky_x1,sky_cy1);
|
||||
else if ((sky_cy0 > nfy[0]) != (sky_cy1 > nfy[1]))
|
||||
{
|
||||
//(ox,oy) is intersection of: (_x0,_fy0)-(_x1,_fy1)
|
||||
// (_x0,nfy0)-(_x1,nfy1)
|
||||
float const t = (sky_cy0-nfy[0])/(nfy[1]-nfy[0]-sky_cy1+sky_cy0);
|
||||
vec2f_t const o = { sky_x0 + (sky_x1 - sky_x0) * t, sky_cy0 + (sky_cy1 - sky_cy0) * t };
|
||||
if (nfy[0] > sky_cy0)
|
||||
{
|
||||
polymost_domost(sky_x0,nfy[0],o.x,o.y);
|
||||
polymost_domost(o.x,o.y,sky_x1,sky_cy1);
|
||||
}
|
||||
else
|
||||
{
|
||||
polymost_domost(sky_x0,sky_cy0,o.x,o.y);
|
||||
polymost_domost(o.x,o.y,sky_x1,nfy[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
polymost_domost(sky_x0,nfy[0],sky_x1,nfy[1]);
|
||||
}
|
||||
|
||||
//Ceiling of skybox
|
||||
drawingskybox = 5; //ceiling/5th texture/index 4 of skybox
|
||||
float const ft[4] = { 512 / 16, -512 / -16, fcosglobalang * (1.f / 2147483648.f),
|
||||
fsinglobalang * (1.f / 2147483648.f) };
|
||||
|
||||
xtex.d = 0;
|
||||
ytex.d = gxyaspect*(-1.0/4194304.0);
|
||||
otex.d = -ghoriz*ytex.d;
|
||||
xtex.u = ft[3]*fviewingrange*(-1.0/65536.0);
|
||||
xtex.v = ft[2]*fviewingrange*(-1.0/65536.0);
|
||||
ytex.u = ft[0]*ytex.d; ytex.v = ft[1]*ytex.d;
|
||||
otex.u = ft[0]*otex.d; otex.v = ft[1]*otex.d;
|
||||
otex.u += (ft[2]-xtex.u)*ghalfx;
|
||||
otex.v -= (ft[3]+xtex.v)*ghalfx;
|
||||
|
||||
polymost_domost(x0,fy0,x1,fy1);
|
||||
|
||||
drawingskybox = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
@ -1821,184 +1639,6 @@ static void polymost_drawalls(int32_t const bunch)
|
|||
flatskyrender = 0;
|
||||
ghoriz = ghorizbak;
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
//Skybox code for parallax ceiling!
|
||||
float sky_t0, sky_t1; // _nx0, _ny0, _nx1, _ny1;
|
||||
float sky_ryp0, sky_ryp1, sky_x0, sky_x1, sky_cy0, sky_fy0, sky_cy1, sky_fy1, sky_ox0, sky_ox1;
|
||||
static vec2f_t const skywal[4] = { { -512, -512 }, { 512, -512 }, { 512, 512 }, { -512, 512 } };
|
||||
|
||||
pow2xsplit = 0;
|
||||
|
||||
for (bssize_t i=0; i<4; i++)
|
||||
{
|
||||
walpos = skywal[i&3];
|
||||
vec2f_t skyp0 = { walpos.y * gcosang - walpos.x * gsinang,
|
||||
walpos.x * gcosang2 + walpos.y * gsinang2 };
|
||||
|
||||
walpos = skywal[(i + 1) & 3];
|
||||
vec2f_t skyp1 = { walpos.y * gcosang - walpos.x * gsinang,
|
||||
walpos.x * gcosang2 + walpos.y * gsinang2 };
|
||||
|
||||
vec2f_t const oskyp0 = skyp0;
|
||||
|
||||
//Clip to close parallel-screen plane
|
||||
if (skyp0.y < SCISDIST)
|
||||
{
|
||||
if (skyp1.y < SCISDIST) continue;
|
||||
sky_t0 = (SCISDIST - skyp0.y) / (skyp1.y - skyp0.y);
|
||||
skyp0 = { (skyp1.x - skyp0.x) * sky_t0 + skyp0.x, SCISDIST };
|
||||
}
|
||||
else { sky_t0 = 0.f; }
|
||||
|
||||
if (skyp1.y < SCISDIST)
|
||||
{
|
||||
sky_t1 = (SCISDIST - oskyp0.y) / (skyp1.y - oskyp0.y);
|
||||
skyp1 = { (skyp1.x - oskyp0.x) * sky_t1 + oskyp0.x, SCISDIST };
|
||||
}
|
||||
else { sky_t1 = 1.f; }
|
||||
|
||||
sky_ryp0 = 1.f/skyp0.y; sky_ryp1 = 1.f/skyp1.y;
|
||||
|
||||
//Generate screen coordinates for front side of wall
|
||||
sky_x0 = ghalfx*skyp0.x*sky_ryp0 + ghalfx;
|
||||
sky_x1 = ghalfx*skyp1.x*sky_ryp1 + ghalfx;
|
||||
if ((sky_x1 <= sky_x0) || (sky_x0 >= x1) || (x0 >= sky_x1)) continue;
|
||||
|
||||
sky_ryp0 *= gyxscale; sky_ryp1 *= gyxscale;
|
||||
|
||||
sky_cy0 = -8192.f*sky_ryp0 + ghoriz;
|
||||
sky_fy0 = 8192.f*sky_ryp0 + ghoriz;
|
||||
sky_cy1 = -8192.f*sky_ryp1 + ghoriz;
|
||||
sky_fy1 = 8192.f*sky_ryp1 + ghoriz;
|
||||
|
||||
sky_ox0 = sky_x0; sky_ox1 = sky_x1;
|
||||
|
||||
//Make sure: x0<=_x0<_x1<=x1
|
||||
float ncy[2] = { cy0, cy1 };
|
||||
|
||||
if (sky_x0 < x0)
|
||||
{
|
||||
float const t = (x0-sky_x0)/(sky_x1-sky_x0);
|
||||
sky_cy0 += (sky_cy1-sky_cy0)*t;
|
||||
sky_fy0 += (sky_fy1-sky_fy0)*t;
|
||||
sky_x0 = x0;
|
||||
}
|
||||
else if (sky_x0 > x0) ncy[0] += (sky_x0-x0)*(cy1-cy0)/(x1-x0);
|
||||
|
||||
if (sky_x1 > x1)
|
||||
{
|
||||
float const t = (x1-sky_x1)/(sky_x1-sky_x0);
|
||||
sky_cy1 += (sky_cy1-sky_cy0)*t;
|
||||
sky_fy1 += (sky_fy1-sky_fy0)*t;
|
||||
sky_x1 = x1;
|
||||
}
|
||||
else if (sky_x1 < x1) ncy[1] += (sky_x1-x1)*(cy1-cy0)/(x1-x0);
|
||||
|
||||
// (skybox ceiling)
|
||||
//(_x0,_cy0)-(_x1,_cy1)
|
||||
// (skybox wall)
|
||||
//(_x0,_fy0)-(_x1,_fy1)
|
||||
// (skybox floor)
|
||||
//(_x0,ncy0)-(_x1,ncy1)
|
||||
|
||||
//ceiling of skybox
|
||||
drawingskybox = 5; //ceiling/5th texture/index 4 of skybox
|
||||
float const ft[4] = { 512 / 16, -512 / -16, fcosglobalang * (1.f / 2147483648.f),
|
||||
fsinglobalang * (1.f / 2147483648.f) };
|
||||
|
||||
xtex.d = 0;
|
||||
ytex.d = gxyaspect*(-1.0/4194304.0);
|
||||
otex.d = -ghoriz*ytex.d;
|
||||
xtex.u = ft[3]*fviewingrange*(-1.0/65536.0);
|
||||
xtex.v = ft[2]*fviewingrange*(-1.0/65536.0);
|
||||
ytex.u = ft[0]*ytex.d; ytex.v = ft[1]*ytex.d;
|
||||
otex.u = ft[0]*otex.d; otex.v = ft[1]*otex.d;
|
||||
otex.u += (ft[2]-xtex.u)*ghalfx;
|
||||
otex.v -= (ft[3]+xtex.v)*ghalfx;
|
||||
|
||||
|
||||
if ((sky_cy0 < ncy[0]) && (sky_cy1 < ncy[1]))
|
||||
polymost_domost(sky_x1,sky_cy1,sky_x0,sky_cy0);
|
||||
else if ((sky_cy0 < ncy[0]) != (sky_cy1 < ncy[1]))
|
||||
{
|
||||
//(ox,oy) is intersection of: (_x0,_cy0)-(_x1,_cy1)
|
||||
// (_x0,ncy0)-(_x1,ncy1)
|
||||
float const t = (sky_cy0-ncy[0])/(ncy[1]-ncy[0]-sky_cy1+sky_cy0);
|
||||
vec2f_t const o = { sky_x0 + (sky_x1-sky_x0)*t, sky_cy0 + (sky_cy1-sky_cy0)*t };
|
||||
if (ncy[0] < sky_cy0)
|
||||
{
|
||||
polymost_domost(o.x,o.y,sky_x0,ncy[0]);
|
||||
polymost_domost(sky_x1,sky_cy1,o.x,o.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
polymost_domost(o.x,o.y,sky_x0,sky_cy0);
|
||||
polymost_domost(sky_x1,ncy[1],o.x,o.y);
|
||||
}
|
||||
}
|
||||
else
|
||||
polymost_domost(sky_x1,ncy[1],sky_x0,ncy[0]);
|
||||
|
||||
//wall of skybox
|
||||
drawingskybox = i+1; //i+1th texture/index i of skybox
|
||||
xtex.d = (sky_ryp0-sky_ryp1)*gxyaspect*(1.0/512.0) / (sky_ox0-sky_ox1);
|
||||
ytex.d = 0;
|
||||
otex.d = sky_ryp0*gxyaspect*(1.0/512.0) - xtex.d*sky_ox0;
|
||||
xtex.u = (sky_t0*sky_ryp0 - sky_t1*sky_ryp1)*gxyaspect*(64.0/512.0) / (sky_ox0-sky_ox1);
|
||||
otex.u = sky_t0*sky_ryp0*gxyaspect*(64.0/512.0) - xtex.u*sky_ox0;
|
||||
ytex.u = 0;
|
||||
sky_t0 = -8192.f*sky_ryp0 + ghoriz;
|
||||
sky_t1 = -8192.f*sky_ryp1 + ghoriz;
|
||||
float const t = ((xtex.d*sky_ox0 + otex.d)*8.f) / ((sky_ox1-sky_ox0) * sky_ryp0 * 2048.f);
|
||||
xtex.v = (sky_t0-sky_t1)*t;
|
||||
ytex.v = (sky_ox1-sky_ox0)*t;
|
||||
otex.v = -xtex.v*sky_ox0 - ytex.v*sky_t0;
|
||||
|
||||
if ((sky_fy0 < ncy[0]) && (sky_fy1 < ncy[1]))
|
||||
polymost_domost(sky_x1,sky_fy1,sky_x0,sky_fy0);
|
||||
else if ((sky_fy0 < ncy[0]) != (sky_fy1 < ncy[1]))
|
||||
{
|
||||
//(ox,oy) is intersection of: (_x0,_fy0)-(_x1,_fy1)
|
||||
// (_x0,ncy0)-(_x1,ncy1)
|
||||
float const t = (sky_fy0-ncy[0])/(ncy[1]-ncy[0]-sky_fy1+sky_fy0);
|
||||
vec2f_t const o = { sky_x0 + (sky_x1 - sky_x0) * t, sky_fy0 + (sky_fy1 - sky_fy0) * t };
|
||||
if (ncy[0] < sky_fy0)
|
||||
{
|
||||
polymost_domost(o.x,o.y,sky_x0,ncy[0]);
|
||||
polymost_domost(sky_x1,sky_fy1,o.x,o.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
polymost_domost(o.x,o.y,sky_x0,sky_fy0);
|
||||
polymost_domost(sky_x1,ncy[1],o.x,o.y);
|
||||
}
|
||||
}
|
||||
else
|
||||
polymost_domost(sky_x1,ncy[1],sky_x0,ncy[0]);
|
||||
}
|
||||
|
||||
//Floor of skybox
|
||||
drawingskybox = 6; //floor/6th texture/index 5 of skybox
|
||||
float const ft[4] = { 512 / 16, 512 / -16, fcosglobalang * (1.f / 2147483648.f),
|
||||
fsinglobalang * (1.f / 2147483648.f) };
|
||||
|
||||
xtex.d = 0;
|
||||
ytex.d = gxyaspect*(1.0/4194304.0);
|
||||
otex.d = -ghoriz*ytex.d;
|
||||
xtex.u = ft[3]*fviewingrange*(-1.0/65536.0);
|
||||
xtex.v = ft[2]*fviewingrange*(-1.0/65536.0);
|
||||
ytex.u = ft[0]*ytex.d; ytex.v = ft[1]*ytex.d;
|
||||
otex.u = ft[0]*otex.d; otex.v = ft[1]*otex.d;
|
||||
otex.u += (ft[2]-xtex.u)*ghalfx;
|
||||
otex.v -= (ft[3]+xtex.v)*ghalfx;
|
||||
xtex.v = -xtex.v; ytex.v = -ytex.v; otex.v = -otex.v; //y-flip skybox floor
|
||||
polymost_domost(x1,cy1,x0,cy0);
|
||||
|
||||
drawingskybox = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
skyzbufferhack = 0;
|
||||
}
|
||||
|
@ -2416,6 +2056,7 @@ void polymost_drawrooms()
|
|||
GLInterface.EnableDepthTest(true);
|
||||
GLInterface.SetDepthFunc(DF_LEqual);
|
||||
GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Translucent]);
|
||||
renderSetViewpoint(0, 0, 0);
|
||||
|
||||
gvrcorrection = viewingrange*(1.f/65536.f);
|
||||
//if (glprojectionhacks == 2)
|
||||
|
@ -2985,8 +2626,6 @@ void polymost_drawsprite(int32_t snum)
|
|||
|
||||
int32_t spritenum = tspr->owner;
|
||||
|
||||
polymost_outputGLDebugMessage(3, "polymost_drawsprite(snum:%d)", snum);
|
||||
|
||||
if ((tspr->cstat&48) != 48)
|
||||
tileUpdatePicnum(&tspr->picnum, spritenum + 32768);
|
||||
|
||||
|
@ -3570,39 +3209,12 @@ void polymost_precache(int32_t dapicnum, int32_t dapalnum, int32_t datype)
|
|||
if (tex) GLInterface.SetTexture(tex, palid, CLAMP_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrecacheHardwareTextures(int nTile)
|
||||
{
|
||||
// PRECACHE
|
||||
// This really *really* needs improvement on the game side - the entire precaching logic has no clue about the different needs of a hardware renderer.
|
||||
polymost_precache(nTile, 0, 1);
|
||||
Polymost::polymost_precache(nTile, 0, 1);
|
||||
}
|
||||
|
||||
extern char* voxfilenames[MAXVOXELS];
|
||||
void (*PolymostProcessVoxels_Callback)(void) = NULL;
|
||||
void PolymostProcessVoxels(void)
|
||||
{
|
||||
if (PolymostProcessVoxels_Callback)
|
||||
PolymostProcessVoxels_Callback();
|
||||
|
||||
if (g_haveVoxels != 1)
|
||||
return;
|
||||
|
||||
g_haveVoxels = 2;
|
||||
|
||||
Printf(PRINT_NONOTIFY, "Generating voxel models for Polymost. This may take a while...\n");
|
||||
|
||||
for (bssize_t i = 0; i < MAXVOXELS; i++)
|
||||
{
|
||||
if (voxfilenames[i])
|
||||
{
|
||||
int lumpnum = fileSystem.FindFile(voxfilenames[i]);
|
||||
if (lumpnum >= 0)
|
||||
{
|
||||
voxmodels[i] = voxload(lumpnum);
|
||||
voxmodels[i]->scale = voxscale[i] * (1.f / 65536.f);
|
||||
}
|
||||
DO_FREE_AND_NULL(voxfilenames[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,10 +13,13 @@
|
|||
#include "texturemanager.h"
|
||||
#include "voxels.h"
|
||||
#include "glbackend/gl_models.h"
|
||||
#include "printf.h"
|
||||
|
||||
#include "palette.h"
|
||||
#include "../../glbackend/glbackend.h"
|
||||
|
||||
using namespace Polymost;
|
||||
|
||||
void voxfree(voxmodel_t *m)
|
||||
{
|
||||
if (!m)
|
||||
|
@ -61,10 +64,6 @@ int32_t polymost_voxdraw(voxmodel_t* m, tspriteptr_t const tspr)
|
|||
if ((tspr->cstat & 48) == 32)
|
||||
return 0;
|
||||
|
||||
polymost_outputGLDebugMessage(3, "polymost_voxdraw(m:%p, tspr:%p)", m, tspr);
|
||||
|
||||
//updateanimation((md2model *)m,tspr);
|
||||
|
||||
vec3f_t m0 = { m->scale, m->scale, m->scale };
|
||||
vec3f_t a0 = { 0, 0, m->zadd*m->scale };
|
||||
|
||||
|
@ -191,9 +190,38 @@ int32_t polymost_voxdraw(voxmodel_t* m, tspriteptr_t const tspr)
|
|||
GLInterface.SetDepthFunc(DF_Less);
|
||||
}
|
||||
GLInterface.SetIdentityMatrix(Matrix_Model);
|
||||
GLInterface.SetFadeDisable(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern char* voxfilenames[MAXVOXELS];
|
||||
void (*PolymostProcessVoxels_Callback)(void) = NULL;
|
||||
void PolymostProcessVoxels(void)
|
||||
{
|
||||
if (PolymostProcessVoxels_Callback)
|
||||
PolymostProcessVoxels_Callback();
|
||||
|
||||
if (g_haveVoxels != 1)
|
||||
return;
|
||||
|
||||
g_haveVoxels = 2;
|
||||
|
||||
Printf(PRINT_NONOTIFY, "Generating voxel models for Polymost. This may take a while...\n");
|
||||
|
||||
for (bssize_t i = 0; i < MAXVOXELS; i++)
|
||||
{
|
||||
if (voxfilenames[i])
|
||||
{
|
||||
int lumpnum = fileSystem.FindFile(voxfilenames[i]);
|
||||
if (lumpnum >= 0)
|
||||
{
|
||||
voxmodels[i] = voxload(lumpnum);
|
||||
voxmodels[i]->scale = voxscale[i] * (1.f / 65536.f);
|
||||
}
|
||||
DO_FREE_AND_NULL(voxfilenames[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//---------------------------------------- VOX LIBRARY ENDS ----------------------------------------
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
class FRenderState;
|
||||
struct secplane_t;
|
||||
struct subsector_t;
|
||||
|
||||
struct FFlatVertex
|
||||
{
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
#include "tarray.h"
|
||||
#include "vectors.h"
|
||||
|
||||
struct FLevelLocals;
|
||||
|
||||
namespace hwrenderer
|
||||
{
|
||||
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "hw_shadowmap.h"
|
||||
|
||||
|
||||
struct sector_t;
|
||||
struct FPortalSceneState;
|
||||
class FSkyVertexBuffer;
|
||||
class IIndexBuffer;
|
||||
|
|
|
@ -103,4 +103,14 @@ inline void fillshort(void* buff, size_t count, uint16_t clear)
|
|||
template<typename T> inline constexpr T Sgn(const T& val) { return (val > 0) - (val < 0); }
|
||||
|
||||
|
||||
inline int sizeToBits(int w)
|
||||
{
|
||||
int j = 15;
|
||||
|
||||
while ((j > 1) && ((1 << j) > w))
|
||||
j--;
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -146,3 +146,79 @@ bool calcChaseCamPos(int* px, int* py, int* pz, spritetype* pspr, short *psectnu
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool spriteIsModelOrVoxel(const spritetype * tspr)
|
||||
{
|
||||
if ((unsigned)tspr->owner < MAXSPRITES && spriteext[tspr->owner].flags & SPREXT_NOTMD)
|
||||
return false;
|
||||
|
||||
if (hw_models)
|
||||
{
|
||||
auto& mdinfo = tile2model[Ptile2tile(tspr->picnum, tspr->pal)];
|
||||
if (mdinfo.modelid >= 0 && mdinfo.framenum >= 0) return true;
|
||||
}
|
||||
|
||||
auto slabalign = (tspr->cstat & CSTAT_SPRITE_ALIGNMENT) == CSTAT_SPRITE_ALIGNMENT_SLAB;
|
||||
if (r_voxels && !slabalign && tiletovox[tspr->picnum] >= 0 && voxmodels[tiletovox[tspr->picnum]]) return true;
|
||||
return (slabalign && voxmodels[tspr->picnum]);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// note that this returns values in renderer coordinate space with inverted sign!
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PlanesAtPoint(usectorptr_t sec, float dax, float day, float* pceilz, float* pflorz)
|
||||
{
|
||||
float ceilz = float(sec->ceilingz);
|
||||
float florz = float(sec->floorz);
|
||||
|
||||
if (((sec->ceilingstat | sec->floorstat) & CSTAT_SECTOR_SLOPE) == CSTAT_SECTOR_SLOPE)
|
||||
{
|
||||
auto wal = &wall[sec->wallptr];
|
||||
auto wal2 = &wall[wal->point2];
|
||||
|
||||
float dx = wal2->x - wal->x;
|
||||
float dy = wal2->y - wal->y;
|
||||
|
||||
int i = (int)sqrt(dx * dx + dy * dy) << 5; // length of sector's first wall.
|
||||
if (i != 0)
|
||||
{
|
||||
float const j = (dx * (day - wal->y) - dy * (dax - wal->x)) * (1.f / 8.f);
|
||||
if (sec->ceilingstat & CSTAT_SECTOR_SLOPE) ceilz += (sec->ceilingheinum * j) / i;
|
||||
if (sec->floorstat & CSTAT_SECTOR_SLOPE) florz += (sec->floorheinum * j) / i;
|
||||
}
|
||||
}
|
||||
// Scale to render coordinates.
|
||||
if (pceilz) *pceilz = ceilz * -(1.f / 256.f);
|
||||
if (pflorz) *pflorz = florz * -(1.f / 256.f);
|
||||
}
|
||||
|
||||
// variant that allows to pass precalculated info for the first line in. For cases where multiple points in a sector need to be checked.
|
||||
void PlanesAtPoint(usectorptr_t sec, PlaneParam *pp, float dax, float day, float* pceilz, float* pflorz)
|
||||
{
|
||||
float ceilz = float(sec->ceilingz);
|
||||
float florz = float(sec->floorz);
|
||||
|
||||
if (((sec->ceilingstat | sec->floorstat) & CSTAT_SECTOR_SLOPE) == CSTAT_SECTOR_SLOPE)
|
||||
{
|
||||
if (pp->length != 0)
|
||||
{
|
||||
auto wal = &wall[sec->wallptr];
|
||||
float const j = (pp->dx * (day - wal->y) - pp->dy * (dax - wal->x)) * (1.f / 8.f);
|
||||
if (sec->ceilingstat & CSTAT_SECTOR_SLOPE) ceilz += (sec->ceilingheinum * j) / pp->length;
|
||||
if (sec->floorstat & CSTAT_SECTOR_SLOPE) florz += (sec->floorheinum * j) / pp->length;
|
||||
}
|
||||
}
|
||||
// Scale to render coordinates.
|
||||
if (pceilz) *pceilz = ceilz * -(1.f / 256.f);
|
||||
if (pflorz) *pflorz = florz * -(1.f / 256.f);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,4 +6,73 @@
|
|||
|
||||
extern int cameradist, cameraclock;
|
||||
|
||||
bool calcChaseCamPos(int* px, int* py, int* pz, spritetype* pspr, short *psectnum, binangle ang, fixedhoriz horiz, double const smoothratio);
|
||||
bool calcChaseCamPos(int* px, int* py, int* pz, spritetype* pspr, short *psectnum, binangle ang, fixedhoriz horiz, double const smoothratio);
|
||||
bool spriteIsModelOrVoxel(const spritetype* tspr);
|
||||
void PlanesAtPoint(usectorptr_t sec, float dax, float day, float* ceilz, float* florz);
|
||||
|
||||
struct PlaneParam
|
||||
{
|
||||
float dx, dy;
|
||||
int length;
|
||||
};
|
||||
|
||||
void PlanesAtPoint(usectorptr_t sec, PlaneParam* pp, float dax, float day, float* ceilz, float* florz);
|
||||
|
||||
// y is negated so that the orientation is the same as in GZDoom, in order to use its utilities.
|
||||
// The render code should NOT use Build coordinates for anything!
|
||||
|
||||
inline double WallStartX(int wallnum)
|
||||
{
|
||||
return wall[wallnum].x * (1 / 16.);
|
||||
}
|
||||
|
||||
inline double WallStartY(int wallnum)
|
||||
{
|
||||
return wall[wallnum].y * (1 / -16.);
|
||||
}
|
||||
|
||||
inline double WallEndX(int wallnum)
|
||||
{
|
||||
return wall[wall[wallnum].point2].x * (1 / 16.);
|
||||
}
|
||||
|
||||
inline double WallEndY(int wallnum)
|
||||
{
|
||||
return wall[wall[wallnum].point2].y * (1 / -16.);
|
||||
}
|
||||
|
||||
inline double WallStartX(const walltype* wallnum)
|
||||
{
|
||||
return wallnum->x * (1 / 16.);
|
||||
}
|
||||
|
||||
inline double WallStartY(const walltype* wallnum)
|
||||
{
|
||||
return wallnum->y * (1 / -16.);
|
||||
}
|
||||
|
||||
inline double WallEndX(const walltype* wallnum)
|
||||
{
|
||||
return wall[wallnum->point2].x * (1 / 16.);
|
||||
}
|
||||
|
||||
inline double WallEndY(const walltype* wallnum)
|
||||
{
|
||||
return wall[wallnum->point2].y * (1 / -16.);
|
||||
}
|
||||
|
||||
inline double SpriteX(int wallnum)
|
||||
{
|
||||
return sprite[wallnum].x * (1 / 16.);
|
||||
}
|
||||
|
||||
inline double SpriteY(int wallnum)
|
||||
{
|
||||
return sprite[wallnum].y * (1 / -16.);
|
||||
}
|
||||
|
||||
inline double PointOnLineSide(double x, double y, double linex, double liney, double deltax, double deltay)
|
||||
{
|
||||
return (x - linex) * deltay - (y - liney) * deltax;
|
||||
}
|
||||
|
||||
|
|
|
@ -385,7 +385,7 @@ void engineLoadBoard(const char* filename, int flags, vec3_t* pos, int16_t* ang,
|
|||
memset(spritesmooth, 0, sizeof(spritesmooth_t) * (MAXSPRITES + MAXUNIQHUDID));
|
||||
initspritelists();
|
||||
ClearAutomap();
|
||||
Polymost_prepare_loadboard();
|
||||
Polymost::Polymost_prepare_loadboard();
|
||||
|
||||
pos->x = fr.ReadInt32();
|
||||
pos->y = fr.ReadInt32();
|
||||
|
|
331
source/core/rendering/hw_entrypoint.cpp
Normal file
331
source/core/rendering/hw_entrypoint.cpp
Normal file
|
@ -0,0 +1,331 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2004-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
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (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/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_scene.cpp
|
||||
** manages the rendering of the player's view
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gi.h"
|
||||
#include "build.h"
|
||||
#include "v_draw.h"
|
||||
//#include "a_dynlight.h"
|
||||
#include "v_video.h"
|
||||
#include "m_png.h"
|
||||
//#include "doomstat.h"
|
||||
//#include "r_data/r_interpolate.h"
|
||||
//#include "r_utility.h"
|
||||
//#include "d_player.h"
|
||||
#include "i_time.h"
|
||||
#include "hw_dynlightdata.h"
|
||||
#include "hw_clock.h"
|
||||
#include "flatvertices.h"
|
||||
//#include "v_palette.h"
|
||||
//#include "d_main.h"
|
||||
|
||||
#include "hw_renderstate.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "hw_viewpointbuffer.h"
|
||||
#include "hw_clipper.h"
|
||||
//#include "hwrenderer/scene/hw_portal.h"
|
||||
#include "hw_vrmodes.h"
|
||||
//#include "g_levellocals.h"
|
||||
|
||||
#include "hw_drawstructs.h"
|
||||
#include "hw_drawlist.h"
|
||||
#include "hw_drawinfo.h"
|
||||
#include "gamecvars.h"
|
||||
|
||||
EXTERN_CVAR(Bool, cl_capfps)
|
||||
bool NoInterpolateView;
|
||||
|
||||
|
||||
PalEntry GlobalMapFog;
|
||||
float GlobalFogDensity;
|
||||
|
||||
|
||||
#if 0
|
||||
void CollectLights(FLevelLocals* Level)
|
||||
{
|
||||
IShadowMap* sm = &screen->mShadowMap;
|
||||
int lightindex = 0;
|
||||
|
||||
// Todo: this should go through the blockmap in a spiral pattern around the player so that closer lights are preferred.
|
||||
for (auto light = Level->lights; light; light = light->next)
|
||||
{
|
||||
IShadowMap::LightsProcessed++;
|
||||
if (light->shadowmapped && light->IsActive() && lightindex < 1024)
|
||||
{
|
||||
IShadowMap::LightsShadowmapped++;
|
||||
|
||||
light->mShadowmapIndex = lightindex;
|
||||
sm->SetLight(lightindex, (float)light->X(), (float)light->Y(), (float)light->Z(), light->GetRadius());
|
||||
lightindex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
light->mShadowmapIndex = 1024;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (; lightindex < 1024; lightindex++)
|
||||
{
|
||||
sm->SetLight(lightindex, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Renders one viewpoint in a scene
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void RenderViewpoint(FRenderViewpoint& mainvp, IntRect* bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen)
|
||||
{
|
||||
auto& RenderState = *screen->RenderState();
|
||||
|
||||
/*
|
||||
if (mainview && toscreen)
|
||||
{
|
||||
screen->SetAABBTree(camera->Level->aabbTree);
|
||||
screen->mShadowMap.SetCollectLights([=] {
|
||||
CollectLights(camera->Level);
|
||||
});
|
||||
screen->UpdateShadowMap();
|
||||
}
|
||||
*/
|
||||
|
||||
// Render (potentially) multiple views for stereo 3d
|
||||
// Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode.
|
||||
auto vrmode = VRMode::GetVRMode(mainview && toscreen);
|
||||
const int eyeCount = vrmode->mEyeCount;
|
||||
screen->FirstEye();
|
||||
for (int eye_ix = 0; eye_ix < eyeCount; ++eye_ix)
|
||||
{
|
||||
const auto& eye = vrmode->mEyes[eye_ix];
|
||||
screen->SetViewportRects(bounds);
|
||||
|
||||
if (mainview) // Bind the scene frame buffer and turn on draw buffers used by ssao
|
||||
{
|
||||
bool useSSAO = (gl_ssao != 0);
|
||||
screen->SetSceneRenderTarget(useSSAO);
|
||||
RenderState.SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS);
|
||||
RenderState.EnableDrawBuffers(RenderState.GetPassDrawBufferCount(), true);
|
||||
}
|
||||
|
||||
auto di = HWDrawInfo::StartDrawInfo(nullptr, mainvp, nullptr);
|
||||
auto& vp = di->Viewpoint;
|
||||
vp = mainvp;
|
||||
|
||||
di->Set3DViewport(RenderState);
|
||||
float flash = 1.f;
|
||||
di->Viewpoint.FieldOfView = fov; // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint)
|
||||
|
||||
// Stereo mode specific perspective projection
|
||||
di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio);
|
||||
// Stereo mode specific viewpoint adjustment
|
||||
vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees);
|
||||
di->SetupView(RenderState, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false);
|
||||
|
||||
di->ProcessScene(toscreen);
|
||||
|
||||
if (mainview)
|
||||
{
|
||||
PostProcess.Clock();
|
||||
if (toscreen) di->EndDrawScene(RenderState); // do not call this for camera textures.
|
||||
|
||||
if (RenderState.GetPassType() == GBUFFER_PASS) // Turn off ssao draw buffers
|
||||
{
|
||||
RenderState.SetPassType(NORMAL_PASS);
|
||||
RenderState.EnableDrawBuffers(1);
|
||||
}
|
||||
|
||||
screen->PostProcessScene(false, CM_DEFAULT, flash, [&]() { });
|
||||
PostProcess.Unclock();
|
||||
}
|
||||
di->EndDrawInfo();
|
||||
if (eyeCount - eye_ix > 1)
|
||||
screen->NextEye(eyeCount);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Set up the view point.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FRenderViewpoint SetupView(vec3_t& position, int sectnum, fixed_t q16angle, fixed_t q16horizon, float rollang)
|
||||
{
|
||||
FRenderViewpoint r_viewpoint{};
|
||||
r_viewpoint.SectNum = sectnum;
|
||||
r_viewpoint.Pos = { position.x / 16.f, position.y / -16.f, position.z / -256.f };
|
||||
r_viewpoint.HWAngles.Yaw = -90.f + q16ang(q16angle).asdeg();
|
||||
r_viewpoint.HWAngles.Pitch = -HorizToPitch(q16horizon);
|
||||
r_viewpoint.HWAngles.Roll = rollang;
|
||||
r_viewpoint.FieldOfView = (float)r_fov;
|
||||
r_viewpoint.RotAngle = q16ang(q16angle).asbam();
|
||||
return r_viewpoint;
|
||||
}
|
||||
|
||||
|
||||
void DoWriteSavePic(FileWriter* file, uint8_t* scr, int width, int height, bool upsidedown)
|
||||
{
|
||||
int pixelsize = 1;
|
||||
|
||||
int pitch = width * pixelsize;
|
||||
if (upsidedown)
|
||||
{
|
||||
scr += ((height - 1) * width * pixelsize);
|
||||
pitch *= -1;
|
||||
}
|
||||
|
||||
M_CreatePNG(file, scr, nullptr, SS_RGB, width, height, pitch, vid_gamma);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Render the view to a savegame picture
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
#if 0
|
||||
void WriteSavePic(player_t* player, FileWriter* file, int width, int height)
|
||||
{
|
||||
IntRect bounds;
|
||||
bounds.left = 0;
|
||||
bounds.top = 0;
|
||||
bounds.width = width;
|
||||
bounds.height = height;
|
||||
auto& RenderState = *screen->RenderState();
|
||||
|
||||
// we must be sure the GPU finished reading from the buffer before we fill it with new data.
|
||||
screen->WaitForCommands(false);
|
||||
|
||||
// Switch to render buffers dimensioned for the savepic
|
||||
screen->SetSaveBuffers(true);
|
||||
screen->ImageTransitionScene(true);
|
||||
|
||||
hw_ClearFakeFlat();
|
||||
RenderState.SetVertexBuffer(screen->mVertexData);
|
||||
screen->mVertexData->Reset();
|
||||
screen->mLights->Clear();
|
||||
screen->mViewpoints->Clear();
|
||||
|
||||
// This shouldn't overwrite the global viewpoint even for a short time.
|
||||
FRenderViewpoint savevp;
|
||||
sector_t* viewsector = RenderViewpoint(savevp, players[consoleplayer].camera, &bounds, r_viewpoint.FieldOfView.Degrees, 1.6f, 1.6f, true, false);
|
||||
RenderState.EnableStencil(false);
|
||||
RenderState.SetNoSoftLightLevel();
|
||||
|
||||
int numpixels = width * height;
|
||||
uint8_t* scr = (uint8_t*)M_Malloc(numpixels * 3);
|
||||
screen->CopyScreenToBuffer(width, height, scr);
|
||||
|
||||
DoWriteSavePic(file, SS_RGB, scr, width, height, viewsector, screen->FlipSavePic());
|
||||
M_Free(scr);
|
||||
|
||||
// Switch back the screen render buffers
|
||||
screen->SetViewportRects(nullptr);
|
||||
screen->SetSaveBuffers(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Renders the main view
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
static void CheckTimer(FRenderState &state, uint64_t ShaderStartTime)
|
||||
{
|
||||
// if firstFrame is not yet initialized, initialize it to current time
|
||||
// if we're going to overflow a float (after ~4.6 hours, or 24 bits), re-init to regain precision
|
||||
if ((state.firstFrame == 0) || (screen->FrameTime - state.firstFrame >= 1 << 24) || ShaderStartTime >= state.firstFrame)
|
||||
state.firstFrame = screen->FrameTime;
|
||||
}
|
||||
|
||||
|
||||
void render_drawrooms(vec3_t& position, int sectnum, fixed_t q16angle, fixed_t q16horizon, float rollang, bool mirror, bool planemirror)
|
||||
{
|
||||
auto RenderState = screen->RenderState();
|
||||
RenderState->SetVertexBuffer(screen->mVertexData);
|
||||
screen->mVertexData->Reset();
|
||||
|
||||
FRenderViewpoint r_viewpoint = SetupView(position, sectnum, q16angle, q16horizon, rollang);
|
||||
iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0;
|
||||
|
||||
checkBenchActive();
|
||||
|
||||
// reset statistics counters
|
||||
ResetProfilingData();
|
||||
|
||||
// Get this before everything else
|
||||
if (cl_capfps) r_viewpoint.TicFrac = 1.;
|
||||
else r_viewpoint.TicFrac = I_GetTimeFrac();
|
||||
|
||||
screen->mLights->Clear();
|
||||
screen->mViewpoints->Clear();
|
||||
|
||||
// NoInterpolateView should have no bearing on camera textures, but needs to be preserved for the main view below.
|
||||
bool saved_niv = NoInterpolateView;
|
||||
NoInterpolateView = false;
|
||||
|
||||
// Shader start time does not need to be handled per level. Just use the one from the camera to render from.
|
||||
CheckTimer(*RenderState, 0/*ShaderStartTime*/);
|
||||
// prepare all camera textures that have been used in the last frame.
|
||||
// This must be done for all levels, not just the primary one!
|
||||
/*
|
||||
Level->canvasTextureInfo.UpdateAll([&](AActor* camera, FCanvasTexture* camtex, double fov)
|
||||
{
|
||||
screen->RenderTextureView(camtex, [=](IntRect& bounds)
|
||||
{
|
||||
FRenderViewpoint texvp;
|
||||
float ratio = camtex->aspectRatio;
|
||||
RenderViewpoint(texvp, camera, &bounds, fov, ratio, ratio, false, false);
|
||||
});
|
||||
});
|
||||
}
|
||||
*/
|
||||
NoInterpolateView = saved_niv;
|
||||
|
||||
// now render the main view
|
||||
float fovratio;
|
||||
float ratio = ActiveRatio(windowxy2.x - windowxy1.x + 1, windowxy2.y - windowxy1.y + 1);
|
||||
if (ratio >= 1.33f)
|
||||
{
|
||||
fovratio = 1.33f;
|
||||
}
|
||||
else
|
||||
{
|
||||
fovratio = ratio;
|
||||
}
|
||||
|
||||
screen->ImageTransitionScene(true); // Only relevant for Vulkan.
|
||||
|
||||
RenderViewpoint(r_viewpoint, NULL, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true);
|
||||
All.Unclock();
|
||||
}
|
4
source/core/rendering/render.h
Normal file
4
source/core/rendering/render.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
#include "build.h"
|
||||
|
||||
void render_drawrooms(vec3_t& position, int sectnum, fixed_t q16angle, fixed_t q16horizon, float rollang, bool mirror, bool planemirror);
|
494
source/core/rendering/scene/hw_bunchdrawer.cpp
Normal file
494
source/core/rendering/scene/hw_bunchdrawer.cpp
Normal file
|
@ -0,0 +1,494 @@
|
|||
/*
|
||||
** hw_bunchdrawer.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2008-2021 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "hw_drawinfo.h"
|
||||
#include "hw_bunchdrawer.h"
|
||||
#include "hw_clipper.h"
|
||||
#include "hw_clock.h"
|
||||
#include "hw_drawstructs.h"
|
||||
#include "automap.h"
|
||||
#include "gamefuncs.h"
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BunchDrawer::Init(HWDrawInfo *_di, Clipper* c, vec2_t& view)
|
||||
{
|
||||
di = _di;
|
||||
clipper = c;
|
||||
viewx = view.x * (1/ 16.f);
|
||||
viewy = view.y * -(1/ 16.f);
|
||||
StartScene();
|
||||
clipper->SetViewpoint(DVector2(viewx, viewy));
|
||||
for (int i = 0; i < numwalls; i++)
|
||||
{
|
||||
// Precalculate the clip angles to avoid doing this repeatedly during level traversal.
|
||||
// Reverse the orientation so that startangle and endangle are properly ordered.
|
||||
wall[i].clipangle = 0 - clipper->PointToPseudoAngle(wall[i].x * (1 / 16.f), wall[i].y * (-1 / 16.f));
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BunchDrawer::StartScene()
|
||||
{
|
||||
LastBunch = 0;
|
||||
StartTime = I_msTime();
|
||||
Bunches.Clear();
|
||||
CompareData.Clear();
|
||||
gotsector.Zero();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BunchDrawer::StartBunch(int sectnum, int linenum, angle_t startan, angle_t endan)
|
||||
{
|
||||
FBunch* bunch = &Bunches[LastBunch = Bunches.Reserve(1)];
|
||||
|
||||
bunch->sectnum = sectnum;
|
||||
bunch->startline = bunch->endline = linenum;
|
||||
bunch->startangle = startan;
|
||||
bunch->endangle = endan;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BunchDrawer::AddLineToBunch(int line, int newan)
|
||||
{
|
||||
Bunches[LastBunch].endline++;
|
||||
Bunches[LastBunch].endangle = newan;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BunchDrawer::DeleteBunch(int index)
|
||||
{
|
||||
Bunches[index] = Bunches.Last();
|
||||
Bunches.Pop();
|
||||
}
|
||||
|
||||
bool BunchDrawer::CheckClip(walltype* wal)
|
||||
{
|
||||
auto pt2 = &wall[wal->point2];
|
||||
sectortype* backsector = §or[wal->nextsector];
|
||||
sectortype* frontsector = §or[wall[wal->nextwall].nextsector];
|
||||
float bs_floorheight1;
|
||||
float bs_floorheight2;
|
||||
float bs_ceilingheight1;
|
||||
float bs_ceilingheight2;
|
||||
float fs_floorheight1;
|
||||
float fs_floorheight2;
|
||||
float fs_ceilingheight1;
|
||||
float fs_ceilingheight2;
|
||||
|
||||
// Mirrors and horizons always block the view
|
||||
//if (linedef->special==Line_Mirror || linedef->special==Line_Horizon) return true;
|
||||
|
||||
PlanesAtPoint(frontsector, wal->x, wal->y, &fs_ceilingheight1, &fs_floorheight1);
|
||||
PlanesAtPoint(frontsector, pt2->x, pt2->y, &fs_ceilingheight2, &fs_floorheight2);
|
||||
|
||||
PlanesAtPoint(backsector, wal->x, wal->y, &bs_ceilingheight1, &bs_floorheight1);
|
||||
PlanesAtPoint(backsector, pt2->x, pt2->y, &bs_ceilingheight2, &bs_floorheight2);
|
||||
|
||||
// now check for closed sectors! No idea if we really need the sky checks. We'll see.
|
||||
if (bs_ceilingheight1 <= fs_floorheight1 && bs_ceilingheight2 <= fs_floorheight2)
|
||||
{
|
||||
// backsector's ceiling is below frontsector's floor.
|
||||
if (frontsector->ceilingstat & backsector->ceilingstat & CSTAT_SECTOR_SKY) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fs_ceilingheight1 <= bs_floorheight1 && fs_ceilingheight2 <= bs_floorheight2)
|
||||
{
|
||||
// backsector's floor is above frontsector's ceiling
|
||||
if (frontsector->floorstat & backsector->floorstat & CSTAT_SECTOR_SKY) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bs_ceilingheight1 <= bs_floorheight1 && bs_ceilingheight2 <= bs_floorheight2)
|
||||
{
|
||||
// backsector is closed
|
||||
if (frontsector->ceilingstat & backsector->ceilingstat & CSTAT_SECTOR_SKY) return false;
|
||||
if (frontsector->floorstat & backsector->floorstat & CSTAT_SECTOR_SKY) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ClipLine
|
||||
// Clips the given segment
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int BunchDrawer::ClipLine(int line)
|
||||
{
|
||||
angle_t startAngle, endAngle;
|
||||
auto wal = &wall[line];
|
||||
|
||||
startAngle = wal->clipangle;
|
||||
endAngle = wall[wal->point2].clipangle;
|
||||
|
||||
// Back side, i.e. backface culling - read: endAngle >= startAngle!
|
||||
if (startAngle - endAngle < ANGLE_180)
|
||||
{
|
||||
return CL_Skip;
|
||||
}
|
||||
|
||||
if (!clipper->SafeCheckRange(startAngle, endAngle))
|
||||
{
|
||||
return CL_Skip;
|
||||
}
|
||||
|
||||
if (wal->nextwall == -1 || (wal->cstat & CSTAT_WALL_1WAY) || CheckClip(wal))
|
||||
{
|
||||
// one-sided
|
||||
clipper->SafeAddClipRange(startAngle, endAngle);
|
||||
return CL_Draw;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CL_Draw | CL_Pass;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BunchDrawer::ProcessBunch(int bnch)
|
||||
{
|
||||
FBunch* bunch = &Bunches[bnch];
|
||||
|
||||
ClipWall.Clock();
|
||||
for (int i = bunch->startline; i <= bunch->endline; i++)
|
||||
{
|
||||
int clipped = ClipLine(i);
|
||||
|
||||
if (clipped & CL_Draw)
|
||||
{
|
||||
show2dwall.Set(i);
|
||||
|
||||
//if (gl_render_walls)
|
||||
{
|
||||
SetupWall.Clock();
|
||||
|
||||
HWWall hwwall;
|
||||
//Printf("Rendering wall %d\n", i);
|
||||
hwwall.Process(di, &wall[i], §or[bunch->sectnum], wall[i].nextsector<0? nullptr : §or[wall[i].nextsector]);
|
||||
rendered_lines++;
|
||||
|
||||
SetupWall.Unclock();
|
||||
}
|
||||
}
|
||||
|
||||
if (clipped & CL_Pass)
|
||||
{
|
||||
ClipWall.Unclock();
|
||||
ProcessSector(wall[i].nextsector);
|
||||
ClipWall.Clock();
|
||||
}
|
||||
}
|
||||
ClipWall.Unclock();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int BunchDrawer::WallInFront(int wall1, int wall2)
|
||||
{
|
||||
double x1s = WallStartX(wall1);
|
||||
double y1s = WallStartY(wall1);
|
||||
double x1e = WallEndX(wall1);
|
||||
double y1e = WallEndY(wall1);
|
||||
double x2s = WallStartX(wall2);
|
||||
double y2s = WallStartY(wall2);
|
||||
double x2e = WallEndX(wall2);
|
||||
double y2e = WallEndY(wall2);
|
||||
|
||||
double dx = x1e - x1s;
|
||||
double dy = y1e - y1s;
|
||||
|
||||
double t1 = PointOnLineSide(x2s, y2s, x1s, y1s, dx, dy);
|
||||
double t2 = PointOnLineSide(x2e, y2e, x1s, y1s, dx, dy);
|
||||
if (t1 == 0)
|
||||
{
|
||||
if (t2 == 0) return(-1);
|
||||
t1 = t2;
|
||||
}
|
||||
if (t2 == 0) t2 = t1;
|
||||
|
||||
if ((t1 * t2) >= 0)
|
||||
{
|
||||
t2 = PointOnLineSide(viewx, viewy, x1s, y1s, dx, dy);
|
||||
return((t2 * t1) < 0);
|
||||
}
|
||||
|
||||
dx = x2e - x2s;
|
||||
dy = y2e - y2s;
|
||||
t1 = PointOnLineSide(x1s, y1s, x2s, y2s, dx, dy);
|
||||
t2 = PointOnLineSide(x1e, y1e, x2s, y2s, dx, dy);
|
||||
if (t1 == 0)
|
||||
{
|
||||
if (t2 == 0) return(-1);
|
||||
t1 = t2;
|
||||
}
|
||||
if (t2 == 0) t2 = t1;
|
||||
if ((t1 * t2) >= 0)
|
||||
{
|
||||
t2 = PointOnLineSide(viewx, viewy, x2s, y2s, dx, dy);
|
||||
return((t2 * t1) >= 0);
|
||||
}
|
||||
return(-2);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// This is a bit more complicated than it looks because angles can wrap
|
||||
// around so we can only compare angle differences.
|
||||
//
|
||||
// Rules:
|
||||
// 1. Any bunch can span at most 180°.
|
||||
// 2. 2 bunches can never overlap at both ends
|
||||
// 3. if there is an overlap one of the 2 starting points must be in the
|
||||
// overlapping area.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int BunchDrawer::BunchInFront(FBunch* b1, FBunch* b2)
|
||||
{
|
||||
angle_t anglecheck, endang;
|
||||
|
||||
if (b2->startangle - b1->startangle < b1->endangle - b1->startangle)
|
||||
{
|
||||
// we have an overlap at b2->startangle
|
||||
anglecheck = b2->startangle - b1->startangle;
|
||||
|
||||
// Find the wall in b1 that overlaps b2->startangle
|
||||
for (int i = b1->startline; i <= b1->endline; i++)
|
||||
{
|
||||
endang = wall[wall[i].point2].clipangle - b1->startangle;
|
||||
if (endang > anglecheck)
|
||||
{
|
||||
// found a line
|
||||
int ret = WallInFront(b2->startline, i);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (b1->startangle - b2->startangle < b2->endangle - b2->startangle)
|
||||
{
|
||||
// we have an overlap at b1->startangle
|
||||
anglecheck = b1->startangle - b2->startangle;
|
||||
|
||||
// Find the wall in b2 that overlaps b1->startangle
|
||||
for (int i = b2->startline; i <= b2->endline; i++)
|
||||
{
|
||||
endang = wall[wall[i].point2].clipangle - b2->startangle;
|
||||
if (endang > anglecheck)
|
||||
{
|
||||
// found a line
|
||||
int ret = WallInFront(i, b1->startline);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
// we have no overlap
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int BunchDrawer::FindClosestBunch()
|
||||
{
|
||||
int closest = 0; //Almost works, but not quite :(
|
||||
|
||||
CompareData.Clear();
|
||||
for (unsigned i = 1; i < Bunches.Size(); i++)
|
||||
{
|
||||
switch (BunchInFront(&Bunches[i], &Bunches[closest]))
|
||||
{
|
||||
case 0: // i is in front
|
||||
closest = i;
|
||||
continue;
|
||||
|
||||
case 1: // i is behind
|
||||
continue;
|
||||
|
||||
default: // can't determine
|
||||
CompareData.Push(i); // mark for later comparison
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// we need to do a second pass to see how the marked bunches relate to the currently closest one.
|
||||
for (unsigned i = 0; i < CompareData.Size(); i++)
|
||||
{
|
||||
switch (BunchInFront(&Bunches[CompareData[i]], &Bunches[closest]))
|
||||
{
|
||||
case 0: // is in front
|
||||
closest = CompareData[i];
|
||||
CompareData[i] = CompareData.Last();
|
||||
CompareData.Pop();
|
||||
i = 0; // we need to recheck everything that's still marked.
|
||||
continue;
|
||||
|
||||
case 1: // is behind
|
||||
CompareData[i] = CompareData.Last();
|
||||
CompareData.Pop();
|
||||
i--;
|
||||
continue;
|
||||
|
||||
default:
|
||||
continue;
|
||||
|
||||
}
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BunchDrawer::ProcessSector(int sectnum)
|
||||
{
|
||||
if (gotsector[sectnum]) return;
|
||||
gotsector.Set(sectnum);
|
||||
|
||||
Bsp.Clock();
|
||||
|
||||
auto sect = §or[sectnum];
|
||||
bool inbunch;
|
||||
angle_t startangle;
|
||||
|
||||
SetupFlat.Clock();
|
||||
HWFlat flat;
|
||||
flat.ProcessSector(di, §or[sectnum]);
|
||||
SetupFlat.Unclock();
|
||||
|
||||
//Todo: process subsectors
|
||||
inbunch = false;
|
||||
for (int i = 0; i < sect->wallnum; i++)
|
||||
{
|
||||
auto thiswall = &wall[sect->wallptr + i];
|
||||
|
||||
#ifdef _DEBUG
|
||||
// For displaying positions in debugger
|
||||
DVector2 start = { WallStartX(thiswall), WallStartY(thiswall) };
|
||||
DVector2 end = { WallStartX(thiswall->point2), WallStartY(thiswall->point2) };
|
||||
#endif
|
||||
angle_t ang1 = thiswall->clipangle;
|
||||
angle_t ang2 = wall[thiswall->point2].clipangle;
|
||||
|
||||
if (ang1 - ang2 < ANGLE_180)
|
||||
{
|
||||
// Backside
|
||||
inbunch = false;
|
||||
}
|
||||
else if (!clipper->SafeCheckRange(ang1, ang2))
|
||||
{
|
||||
// is it visible?
|
||||
inbunch = false;
|
||||
}
|
||||
else if (!inbunch || ang2 - startangle >= ANGLE_180)
|
||||
{
|
||||
// don't let a bunch span more than 180° to avoid problems.
|
||||
// This limitation ensures that the combined range of 2
|
||||
// bunches will always be less than 360° which simplifies
|
||||
// the distance comparison code because it prevents a
|
||||
// situation where 2 bunches may overlap at both ends.
|
||||
|
||||
startangle = ang1;
|
||||
StartBunch(sectnum, sect->wallptr + i, ang1, ang2);
|
||||
inbunch = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddLineToBunch(sect->wallptr + i, ang2);
|
||||
}
|
||||
if (thiswall->point2 != sect->wallptr + i + 1) inbunch = false;
|
||||
}
|
||||
Bsp.Unclock();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BunchDrawer::RenderScene(int viewsector)
|
||||
{
|
||||
ProcessSector(viewsector);
|
||||
while (Bunches.Size() > 0)
|
||||
{
|
||||
int closest = FindClosestBunch();
|
||||
ProcessBunch(closest);
|
||||
DeleteBunch(closest);
|
||||
}
|
||||
}
|
54
source/core/rendering/scene/hw_bunchdrawer.h
Normal file
54
source/core/rendering/scene/hw_bunchdrawer.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
#include "tarray.h"
|
||||
#include "basics.h"
|
||||
|
||||
struct HWDrawInfo;
|
||||
class Clipper;
|
||||
|
||||
struct FBunch
|
||||
{
|
||||
int sectnum;
|
||||
int startline;
|
||||
int endline;
|
||||
angle_t startangle; // in pseudo angles for the clipper
|
||||
angle_t endangle;
|
||||
};
|
||||
|
||||
class BunchDrawer
|
||||
{
|
||||
HWDrawInfo *di;
|
||||
Clipper *clipper;
|
||||
int LastBunch;
|
||||
int StartTime;
|
||||
TArray<FBunch> Bunches;
|
||||
TArray<int> CompareData;
|
||||
double viewx, viewy;
|
||||
FixedBitArray<MAXSECTORS> gotsector;
|
||||
|
||||
private:
|
||||
|
||||
enum
|
||||
{
|
||||
CL_Skip = 0,
|
||||
CL_Draw = 1,
|
||||
CL_Pass = 2,
|
||||
};
|
||||
|
||||
|
||||
void StartScene();
|
||||
void StartBunch(int sectnum, int linenum, angle_t startan, angle_t endan);
|
||||
void AddLineToBunch(int line, int newan);
|
||||
void DeleteBunch(int index);
|
||||
bool CheckClip(walltype* wal);
|
||||
int ClipLine(int line);
|
||||
void ProcessBunch(int bnch);
|
||||
int WallInFront(int wall1, int wall2);
|
||||
int BunchInFront(FBunch* b1, FBunch* b2);
|
||||
int FindClosestBunch();
|
||||
void ProcessSector(int sectnum);
|
||||
|
||||
public:
|
||||
void Init(HWDrawInfo* _di, Clipper* c, vec2_t& view);
|
||||
void RenderScene(int viewsector);
|
||||
};
|
397
source/core/rendering/scene/hw_clipper.cpp
Normal file
397
source/core/rendering/scene/hw_clipper.cpp
Normal file
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
*
|
||||
** gl_clipper.cpp
|
||||
**
|
||||
** Handles visibility checks.
|
||||
** Loosely based on the JDoom clipper.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2003 Tim Stump
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "hw_clipper.h"
|
||||
#include "basics.h"
|
||||
|
||||
unsigned Clipper::starttime;
|
||||
|
||||
Clipper::Clipper()
|
||||
{
|
||||
starttime++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RemoveRange
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::RemoveRange(ClipNode * range)
|
||||
{
|
||||
if (range == cliphead)
|
||||
{
|
||||
cliphead = cliphead->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (range->prev) range->prev->next = range->next;
|
||||
if (range->next) range->next->prev = range->prev;
|
||||
}
|
||||
|
||||
Free(range);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Clear
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::Clear()
|
||||
{
|
||||
ClipNode *node = cliphead;
|
||||
ClipNode *temp;
|
||||
|
||||
blocked = false;
|
||||
while (node != NULL)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
Free(temp);
|
||||
}
|
||||
node = silhouette;
|
||||
|
||||
while (node != NULL)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
Free(temp);
|
||||
}
|
||||
|
||||
cliphead = NULL;
|
||||
silhouette = NULL;
|
||||
starttime++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// SetSilhouette
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::SetSilhouette()
|
||||
{
|
||||
ClipNode *node = cliphead;
|
||||
ClipNode *last = NULL;
|
||||
|
||||
while (node != NULL)
|
||||
{
|
||||
ClipNode *snode = NewRange(node->start, node->end);
|
||||
if (silhouette == NULL) silhouette = snode;
|
||||
snode->prev = last;
|
||||
if (last != NULL) last->next = snode;
|
||||
last = snode;
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// IsRangeVisible
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool Clipper::IsRangeVisible(angle_t startAngle, angle_t endAngle)
|
||||
{
|
||||
ClipNode *ci;
|
||||
ci = cliphead;
|
||||
|
||||
if (endAngle==0 && ci && ci->start==0) return false;
|
||||
|
||||
while (ci != NULL && ci->start < endAngle)
|
||||
{
|
||||
if (startAngle >= ci->start && endAngle <= ci->end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ci = ci->next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// AddClipRange
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::AddClipRange(angle_t start, angle_t end)
|
||||
{
|
||||
ClipNode *node, *temp, *prevNode;
|
||||
|
||||
if (cliphead)
|
||||
{
|
||||
//check to see if range contains any old ranges
|
||||
node = cliphead;
|
||||
while (node != NULL && node->start < end)
|
||||
{
|
||||
if (node->start >= start && node->end <= end)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
RemoveRange(temp);
|
||||
}
|
||||
else if (node->start<=start && node->end>=end)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
//check to see if range overlaps a range (or possibly 2)
|
||||
node = cliphead;
|
||||
while (node != NULL && node->start <= end)
|
||||
{
|
||||
if (node->end >= start)
|
||||
{
|
||||
// we found the first overlapping node
|
||||
if (node->start > start)
|
||||
{
|
||||
// the new range overlaps with this node's start point
|
||||
node->start = start;
|
||||
}
|
||||
|
||||
if (node->end < end)
|
||||
{
|
||||
node->end = end;
|
||||
}
|
||||
|
||||
ClipNode *node2 = node->next;
|
||||
while (node2 && node2->start <= node->end)
|
||||
{
|
||||
if (node2->end > node->end) node->end = node2->end;
|
||||
ClipNode *delnode = node2;
|
||||
node2 = node2->next;
|
||||
RemoveRange(delnode);
|
||||
}
|
||||
return;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
//just add range
|
||||
node = cliphead;
|
||||
prevNode = NULL;
|
||||
temp = NewRange(start, end);
|
||||
|
||||
while (node != NULL && node->start < end)
|
||||
{
|
||||
prevNode = node;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
temp->next = node;
|
||||
if (node == NULL)
|
||||
{
|
||||
temp->prev = prevNode;
|
||||
if (prevNode) prevNode->next = temp;
|
||||
if (!cliphead) cliphead = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node == cliphead)
|
||||
{
|
||||
cliphead->prev = temp;
|
||||
cliphead = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp->prev = prevNode;
|
||||
prevNode->next = temp;
|
||||
node->prev = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = NewRange(start, end);
|
||||
cliphead = temp;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RemoveClipRange
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::RemoveClipRange(angle_t start, angle_t end)
|
||||
{
|
||||
ClipNode *node;
|
||||
|
||||
if (silhouette)
|
||||
{
|
||||
node = silhouette;
|
||||
while (node != NULL && node->end <= start)
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
if (node != NULL && node->start <= start)
|
||||
{
|
||||
if (node->end >= end) return;
|
||||
start = node->end;
|
||||
node = node->next;
|
||||
}
|
||||
while (node != NULL && node->start < end)
|
||||
{
|
||||
DoRemoveClipRange(start, node->start);
|
||||
start = node->end;
|
||||
node = node->next;
|
||||
}
|
||||
if (start >= end) return;
|
||||
}
|
||||
DoRemoveClipRange(start, end);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RemoveClipRange worker function
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::DoRemoveClipRange(angle_t start, angle_t end)
|
||||
{
|
||||
ClipNode *node, *temp;
|
||||
|
||||
if (cliphead)
|
||||
{
|
||||
//check to see if range contains any old ranges
|
||||
node = cliphead;
|
||||
while (node != NULL && node->start < end)
|
||||
{
|
||||
if (node->start >= start && node->end <= end)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
RemoveRange(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
//check to see if range overlaps a range (or possibly 2)
|
||||
node = cliphead;
|
||||
while (node != NULL)
|
||||
{
|
||||
if (node->start >= start && node->start <= end)
|
||||
{
|
||||
node->start = end;
|
||||
break;
|
||||
}
|
||||
else if (node->end >= start && node->end <= end)
|
||||
{
|
||||
node->end=start;
|
||||
}
|
||||
else if (node->start < start && node->end > end)
|
||||
{
|
||||
temp = NewRange(end, node->end);
|
||||
node->end=start;
|
||||
temp->next=node->next;
|
||||
temp->prev=node;
|
||||
node->next=temp;
|
||||
if (temp->next) temp->next->prev=temp;
|
||||
break;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
angle_t Clipper::AngleToPseudo(angle_t ang)
|
||||
{
|
||||
double vecx = cos(ang * M_PI / ANGLE_180);
|
||||
double vecy = sin(ang * M_PI / ANGLE_180);
|
||||
|
||||
double result = vecy / (fabs(vecx) + fabs(vecy));
|
||||
if (vecx < 0)
|
||||
{
|
||||
result = 2.f - result;
|
||||
}
|
||||
return xs_Fix<30>::ToFix(result);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ! Returns the pseudoangle between the line p1 to (infinity, p1.y) and the
|
||||
// line from p1 to p2. The pseudoangle has the property that the ordering of
|
||||
// points by true angle around p1 and ordering of points by pseudoangle are the
|
||||
// same.
|
||||
//
|
||||
// For clipping exact angles are not needed. Only the ordering matters.
|
||||
// This is about as fast as the fixed point R_PointToAngle2 but without
|
||||
// the precision issues associated with that function.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
angle_t Clipper::PointToPseudoAngle(double x, double y)
|
||||
{
|
||||
double vecx = x - viewpoint.X;
|
||||
double vecy = y - viewpoint.Y;
|
||||
|
||||
if (vecx == 0 && vecy == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double result = vecy / (fabs(vecx) + fabs(vecy));
|
||||
if (vecx < 0)
|
||||
{
|
||||
result = 2. - result;
|
||||
}
|
||||
return xs_Fix<30>::ToFix(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
159
source/core/rendering/scene/hw_clipper.h
Normal file
159
source/core/rendering/scene/hw_clipper.h
Normal file
|
@ -0,0 +1,159 @@
|
|||
#ifndef __GL_CLIPPER
|
||||
#define __GL_CLIPPER
|
||||
|
||||
#include "xs_Float.h"
|
||||
#include "memarena.h"
|
||||
#include "basics.h"
|
||||
#include "vectors.h"
|
||||
|
||||
class ClipNode
|
||||
{
|
||||
friend class Clipper;
|
||||
|
||||
ClipNode *prev, *next;
|
||||
angle_t start, end;
|
||||
|
||||
bool operator== (const ClipNode &other)
|
||||
{
|
||||
return other.start == start && other.end == end;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Clipper
|
||||
{
|
||||
static unsigned starttime;
|
||||
FMemArena nodearena;
|
||||
ClipNode * freelist = nullptr;
|
||||
|
||||
ClipNode * clipnodes = nullptr;
|
||||
ClipNode * cliphead = nullptr;
|
||||
ClipNode * silhouette = nullptr; // will be preserved even when RemoveClipRange is called
|
||||
DVector2 viewpoint;
|
||||
bool blocked = false;
|
||||
|
||||
bool IsRangeVisible(angle_t startangle, angle_t endangle);
|
||||
void RemoveRange(ClipNode * cn);
|
||||
void AddClipRange(angle_t startangle, angle_t endangle);
|
||||
void RemoveClipRange(angle_t startangle, angle_t endangle);
|
||||
void DoRemoveClipRange(angle_t start, angle_t end);
|
||||
|
||||
public:
|
||||
|
||||
Clipper();
|
||||
|
||||
void Clear();
|
||||
static angle_t AngleToPseudo(angle_t ang);
|
||||
|
||||
void Free(ClipNode *node)
|
||||
{
|
||||
node->next = freelist;
|
||||
freelist = node;
|
||||
}
|
||||
|
||||
ClipNode * GetNew()
|
||||
{
|
||||
if (freelist)
|
||||
{
|
||||
ClipNode * p = freelist;
|
||||
freelist = p->next;
|
||||
return p;
|
||||
}
|
||||
else return (ClipNode*)nodearena.Alloc(sizeof(ClipNode));
|
||||
}
|
||||
|
||||
ClipNode * NewRange(angle_t start, angle_t end)
|
||||
{
|
||||
ClipNode * c = GetNew();
|
||||
|
||||
c->start = start;
|
||||
c->end = end;
|
||||
c->next = c->prev = NULL;
|
||||
return c;
|
||||
}
|
||||
|
||||
void SetViewpoint(const DVector2 &vp)
|
||||
{
|
||||
viewpoint = vp;
|
||||
}
|
||||
|
||||
void SetSilhouette();
|
||||
|
||||
bool SafeCheckRange(angle_t startAngle, angle_t endAngle)
|
||||
{
|
||||
if(startAngle > endAngle)
|
||||
{
|
||||
return (IsRangeVisible(startAngle, ANGLE_MAX) || IsRangeVisible(0, endAngle));
|
||||
}
|
||||
|
||||
return IsRangeVisible(startAngle, endAngle);
|
||||
}
|
||||
|
||||
void SafeAddClipRange(angle_t startangle, angle_t endangle)
|
||||
{
|
||||
if(startangle > endangle)
|
||||
{
|
||||
// The range has to added in two parts.
|
||||
AddClipRange(startangle, ANGLE_MAX);
|
||||
AddClipRange(0, endangle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the range as usual.
|
||||
AddClipRange(startangle, endangle);
|
||||
}
|
||||
}
|
||||
|
||||
void SafeAddClipRange(const DVector2& v1, const DVector2& v2)
|
||||
{
|
||||
angle_t a2 = PointToPseudoAngle(v1.X, v1.Y);
|
||||
angle_t a1 = PointToPseudoAngle(v2.X, v2.Y);
|
||||
SafeAddClipRange(a1,a2);
|
||||
}
|
||||
|
||||
void SafeAddClipRangeRealAngles(angle_t startangle, angle_t endangle)
|
||||
{
|
||||
SafeAddClipRange(AngleToPseudo(startangle), AngleToPseudo(endangle));
|
||||
}
|
||||
|
||||
|
||||
void SafeRemoveClipRange(angle_t startangle, angle_t endangle)
|
||||
{
|
||||
if(startangle > endangle)
|
||||
{
|
||||
// The range has to added in two parts.
|
||||
RemoveClipRange(startangle, ANGLE_MAX);
|
||||
RemoveClipRange(0, endangle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the range as usual.
|
||||
RemoveClipRange(startangle, endangle);
|
||||
}
|
||||
}
|
||||
|
||||
void SafeRemoveClipRangeRealAngles(angle_t startangle, angle_t endangle)
|
||||
{
|
||||
SafeRemoveClipRange(AngleToPseudo(startangle), AngleToPseudo(endangle));
|
||||
}
|
||||
|
||||
void SetBlocked(bool on)
|
||||
{
|
||||
blocked = on;
|
||||
}
|
||||
|
||||
bool IsBlocked() const
|
||||
{
|
||||
return blocked;
|
||||
}
|
||||
|
||||
angle_t PointToPseudoAngle(double x, double y);
|
||||
|
||||
inline angle_t GetClipAngle(const DVector2& v)
|
||||
{
|
||||
return PointToPseudoAngle(v.X, v.Y);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
586
source/core/rendering/scene/hw_drawinfo.cpp
Normal file
586
source/core/rendering/scene/hw_drawinfo.cpp
Normal file
|
@ -0,0 +1,586 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2000-2018 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
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (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/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_drawinfo.cpp
|
||||
** Basic scene draw info management class
|
||||
**
|
||||
*/
|
||||
|
||||
#include "hw_portal.h"
|
||||
#include "build.h"
|
||||
#include "hw_renderstate.h"
|
||||
#include "hw_drawinfo.h"
|
||||
//#include "models.h"
|
||||
#include "hw_clock.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "hw_viewpointbuffer.h"
|
||||
#include "flatvertices.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "hw_vrmodes.h"
|
||||
#include "hw_clipper.h"
|
||||
#include "v_draw.h"
|
||||
#include "gamecvars.h"
|
||||
|
||||
EXTERN_CVAR(Float, r_visibility)
|
||||
CVAR(Bool, gl_bandedswlight, false, CVAR_ARCHIVE)
|
||||
CVAR(Bool, gl_sort_textures, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Bool, gl_no_skyclear, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Int, gl_enhanced_nv_stealth, 3, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
CVAR(Bool, gl_texture, true, 0)
|
||||
CVAR(Float, gl_mask_threshold, 0.5f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Float, gl_mask_sprite_threshold, 0.5f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FDrawInfoList
|
||||
{
|
||||
public:
|
||||
TDeletingArray<HWDrawInfo *> mList;
|
||||
|
||||
HWDrawInfo * GetNew();
|
||||
void Release(HWDrawInfo *);
|
||||
};
|
||||
|
||||
|
||||
FDrawInfoList di_list;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Try to reuse the lists as often as possible as they contain resources that
|
||||
// are expensive to create and delete.
|
||||
//
|
||||
// Note: If multithreading gets used, this class needs synchronization.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
HWDrawInfo *FDrawInfoList::GetNew()
|
||||
{
|
||||
if (mList.Size() > 0)
|
||||
{
|
||||
HWDrawInfo *di;
|
||||
mList.Pop(di);
|
||||
return di;
|
||||
}
|
||||
return new HWDrawInfo();
|
||||
}
|
||||
|
||||
void FDrawInfoList::Release(HWDrawInfo * di)
|
||||
{
|
||||
di->ClearBuffers();
|
||||
mList.Push(di);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sets up a new drawinfo struct
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
HWDrawInfo *HWDrawInfo::StartDrawInfo(HWDrawInfo *parent, FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms)
|
||||
{
|
||||
HWDrawInfo *di = di_list.GetNew();
|
||||
di->StartScene(parentvp, uniforms);
|
||||
return di;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static Clipper staticClipper; // Since all scenes are processed sequentially we only need one clipper.
|
||||
static HWDrawInfo * gl_drawinfo; // This is a linked list of all active DrawInfos and needed to free the memory arena after the last one goes out of scope.
|
||||
|
||||
void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms)
|
||||
{
|
||||
staticClipper.Clear();
|
||||
mClipper = &staticClipper;
|
||||
|
||||
Viewpoint = parentvp;
|
||||
//lightmode = Level->lightMode;
|
||||
if (uniforms)
|
||||
{
|
||||
VPUniforms = *uniforms;
|
||||
// The clip planes will never be inherited from the parent drawinfo.
|
||||
VPUniforms.mClipLine.X = -1000001.f;
|
||||
VPUniforms.mClipHeight = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
VPUniforms.mProjectionMatrix.loadIdentity();
|
||||
VPUniforms.mViewMatrix.loadIdentity();
|
||||
VPUniforms.mNormalViewMatrix.loadIdentity();
|
||||
//VPUniforms.mViewHeight = viewheight;
|
||||
VPUniforms.mGlobVis = (2 / 65536.f) * g_visibility / r_ambientlight;
|
||||
VPUniforms.mPalLightLevels = numshades | (static_cast<int>(gl_fogmode) << 8) | (5 << 16);
|
||||
|
||||
VPUniforms.mClipLine.X = -10000000.0f;
|
||||
VPUniforms.mShadowmapFilter = gl_shadowmap_filter;
|
||||
}
|
||||
mClipper->SetViewpoint(Viewpoint.Pos.XY());
|
||||
|
||||
ClearBuffers();
|
||||
|
||||
for (int i = 0; i < GLDL_TYPES; i++) drawlists[i].Reset();
|
||||
vpIndex = 0;
|
||||
|
||||
// Fullbright information needs to be propagated from the main view.
|
||||
if (outer != nullptr) FullbrightFlags = outer->FullbrightFlags;
|
||||
else FullbrightFlags = 0;
|
||||
|
||||
outer = gl_drawinfo;
|
||||
gl_drawinfo = this;
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
HWDrawInfo *HWDrawInfo::EndDrawInfo()
|
||||
{
|
||||
assert(this == gl_drawinfo);
|
||||
for (int i = 0; i < GLDL_TYPES; i++) drawlists[i].Reset();
|
||||
gl_drawinfo = outer;
|
||||
di_list.Release(this);
|
||||
if (gl_drawinfo == nullptr)
|
||||
ResetRenderDataAllocator();
|
||||
return gl_drawinfo;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void HWDrawInfo::ClearBuffers()
|
||||
{
|
||||
spriteindex = 0;
|
||||
Decals[0].Clear();
|
||||
Decals[1].Clear();
|
||||
mClipPortal = nullptr;
|
||||
mCurrentPortal = nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// R_FrustumAngle
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
angle_t HWDrawInfo::FrustumAngle()
|
||||
{
|
||||
float WidescreenRatio = 1.6666f; // fixme - this is a placeholder.
|
||||
float tilt = fabs(Viewpoint.HWAngles.Pitch.Degrees);
|
||||
|
||||
// If the pitch is larger than this you can look all around at a FOV of 90°
|
||||
if (tilt > 46.0f) return 0xffffffff;
|
||||
|
||||
// ok, this is a gross hack that barely works...
|
||||
// but at least it doesn't overestimate too much...
|
||||
double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*Viewpoint.FieldOfView.Degrees*48.0 / AspectMultiplier(WidescreenRatio) / 90.0;
|
||||
angle_t a1 = DAngle(floatangle).BAMs();
|
||||
if (a1 >= ANGLE_180) return 0xffffffff;
|
||||
return a1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Setup the modelview matrix
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror)
|
||||
{
|
||||
float mult = mirror ? -1.f : 1.f;
|
||||
float planemult = planemirror ? -1 : 1;// Level->info->pixelstretch : Level->info->pixelstretch;
|
||||
|
||||
VPUniforms.mViewMatrix.loadIdentity();
|
||||
VPUniforms.mViewMatrix.rotate(angles.Roll.Degrees, 0.0f, 0.0f, 1.0f);
|
||||
VPUniforms.mViewMatrix.rotate(angles.Pitch.Degrees, 1.0f, 0.0f, 0.0f);
|
||||
VPUniforms.mViewMatrix.rotate(angles.Yaw.Degrees, 0.0f, mult, 0.0f);
|
||||
VPUniforms.mViewMatrix.translate(vx * mult, -vz * planemult, -vy);
|
||||
VPUniforms.mViewMatrix.scale(-mult, planemult, 1);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// SetupView
|
||||
// Setup the view rotation matrix for the given viewpoint
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void HWDrawInfo::SetupView(FRenderState &state, float vx, float vy, float vz, bool mirror, bool planemirror)
|
||||
{
|
||||
auto &vp = Viewpoint;
|
||||
//vp.SetViewAngle(r_viewwindow); // todo: need to pass in.
|
||||
SetViewMatrix(vp.HWAngles, vx, vy, vz, mirror, planemirror);
|
||||
SetCameraPos(vp.Pos);
|
||||
VPUniforms.CalcDependencies();
|
||||
vpIndex = screen->mViewpoints->SetViewpoint(state, &VPUniforms);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
HWPortal * HWDrawInfo::FindPortal(const void * src)
|
||||
{
|
||||
int i = Portals.Size() - 1;
|
||||
|
||||
while (i >= 0 && Portals[i] && Portals[i]->GetSource() != src) i--;
|
||||
return i >= 0 ? Portals[i] : nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
HWDecal* HWDrawInfo::AddDecal(bool onmirror)
|
||||
{
|
||||
#if 0
|
||||
auto decal = (HWDecal*)RenderDataAllocator.Alloc(sizeof(HWDecal));
|
||||
Decals[onmirror ? 1 : 0].Push(decal);
|
||||
return decal;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// CreateScene
|
||||
//
|
||||
// creates the draw lists for the current scene
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::CreateScene()
|
||||
{
|
||||
const auto& vp = Viewpoint;
|
||||
|
||||
angle_t a1 = FrustumAngle();
|
||||
mClipper->SafeAddClipRangeRealAngles(vp.RotAngle + a1, vp.RotAngle - a1);
|
||||
|
||||
#if 0
|
||||
// reset the portal manager
|
||||
portalState.StartFrame();
|
||||
#endif
|
||||
|
||||
ProcessAll.Clock();
|
||||
|
||||
// clip the scene and fill the drawlists
|
||||
screen->mVertexData->Map();
|
||||
screen->mLights->Map();
|
||||
|
||||
vec2_t view = { int(vp.Pos.X * 16), int(vp.Pos.Y * -16) };
|
||||
mDrawer.Init(this, mClipper, view);
|
||||
mDrawer.RenderScene(vp.SectNum);
|
||||
|
||||
// And now the crappy hacks that have to be done to avoid rendering anomalies.
|
||||
// These cannot be multithreaded when the time comes because all these depend
|
||||
// on the global 'validcount' variable.
|
||||
|
||||
screen->mLights->Unmap();
|
||||
screen->mVertexData->Unmap();
|
||||
|
||||
ProcessAll.Unclock();
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RenderScene
|
||||
//
|
||||
// Draws the current draw lists for the non GLSL renderer
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::RenderScene(FRenderState &state)
|
||||
{
|
||||
const auto &vp = Viewpoint;
|
||||
RenderAll.Clock();
|
||||
|
||||
state.SetDepthMask(true);
|
||||
|
||||
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);
|
||||
state.AlphaFunc(Alpha_GEqual, 0.f);
|
||||
state.ClearDepthBias();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
drawlists[GLDL_MODELS].Draw(this, state, false);
|
||||
|
||||
state.SetRenderStyle(STYLE_Translucent);
|
||||
|
||||
// Part 4: Draw decals (not a real pass)
|
||||
state.SetDepthFunc(DF_LEqual);
|
||||
#if 0
|
||||
DrawDecals(state, Decals[0]);
|
||||
#endif
|
||||
|
||||
RenderAll.Unclock();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RenderTranslucent
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::RenderTranslucent(FRenderState &state)
|
||||
{
|
||||
RenderAll.Clock();
|
||||
|
||||
// final pass: translucent stuff
|
||||
state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold);
|
||||
state.SetRenderStyle(STYLE_Translucent);
|
||||
|
||||
state.EnableBrightmap(true);
|
||||
drawlists[GLDL_TRANSLUCENTBORDER].Draw(this, state, true);
|
||||
state.SetDepthMask(false);
|
||||
|
||||
drawlists[GLDL_TRANSLUCENT].DrawSorted(this, state);
|
||||
state.EnableBrightmap(false);
|
||||
|
||||
|
||||
state.AlphaFunc(Alpha_GEqual, 0.5f);
|
||||
state.SetDepthMask(true);
|
||||
|
||||
RenderAll.Unclock();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RenderTranslucent
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::RenderPortal(HWPortal *p, FRenderState &state, bool usestencil)
|
||||
{
|
||||
#if 0
|
||||
auto gp = static_cast<HWPortal *>(p);
|
||||
gp->SetupStencil(this, state, usestencil);
|
||||
auto new_di = StartDrawInfo(this, Viewpoint, &VPUniforms);
|
||||
new_di->mCurrentPortal = gp;
|
||||
state.SetLightIndex(-1);
|
||||
gp->DrawContents(new_di, state);
|
||||
new_di->EndDrawInfo();
|
||||
state.SetVertexBuffer(screen->mVertexData);
|
||||
screen->mViewpoints->Bind(state, vpIndex);
|
||||
gp->RemoveStencil(this, state, usestencil);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Draws player sprites and color blend
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
void HWDrawInfo::EndDrawScene(FRenderState &state)
|
||||
{
|
||||
state.EnableFog(false);
|
||||
|
||||
#if 0
|
||||
// [BB] HUD models need to be rendered here.
|
||||
const bool renderHUDModel = IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player);
|
||||
if (renderHUDModel)
|
||||
{
|
||||
// [BB] The HUD model should be drawn over everything else already drawn.
|
||||
state.Clear(CT_Depth);
|
||||
DrawPlayerSprites(true, state);
|
||||
}
|
||||
#endif
|
||||
|
||||
state.EnableStencil(false);
|
||||
state.SetViewport(screen->mScreenViewport.left, screen->mScreenViewport.top, screen->mScreenViewport.width, screen->mScreenViewport.height);
|
||||
|
||||
// Restore standard rendering state
|
||||
state.SetRenderStyle(STYLE_Translucent);
|
||||
state.ResetColor();
|
||||
state.EnableTexture(true);
|
||||
state.SetScissor(0, 0, -1, -1);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// sets 3D viewport and initial state
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::Set3DViewport(FRenderState &state)
|
||||
{
|
||||
// Always clear all buffers with scissor test disabled.
|
||||
// This is faster on newer hardware because it allows the GPU to skip
|
||||
// reading from slower memory where the full buffers are stored.
|
||||
state.SetScissor(0, 0, -1, -1);
|
||||
state.Clear(CT_Color | CT_Depth | CT_Stencil);
|
||||
|
||||
const auto &bounds = screen->mSceneViewport;
|
||||
state.SetViewport(bounds.left, bounds.top, bounds.width, bounds.height);
|
||||
state.SetScissor(bounds.left, bounds.top, bounds.width, bounds.height);
|
||||
state.EnableMultisampling(true);
|
||||
state.EnableDepthTest(true);
|
||||
state.EnableStencil(true);
|
||||
state.SetStencil(0, SOP_Keep, SF_AllOn);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// gl_drawscene - this function renders the scene from the current
|
||||
// viewpoint, including mirrors and skyboxes and other portals
|
||||
// It is assumed that the HWPortal::EndFrame returns with the
|
||||
// stencil, z-buffer and the projection matrix intact!
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::DrawScene(int drawmode)
|
||||
{
|
||||
static int recursion = 0;
|
||||
static int ssao_portals_available = 0;
|
||||
const auto& vp = Viewpoint;
|
||||
|
||||
bool applySSAO = false;
|
||||
if (drawmode == DM_MAINVIEW)
|
||||
{
|
||||
ssao_portals_available = gl_ssao_portals;
|
||||
applySSAO = true;
|
||||
}
|
||||
else if (drawmode == DM_OFFSCREEN)
|
||||
{
|
||||
ssao_portals_available = 0;
|
||||
}
|
||||
else if (drawmode == DM_PORTAL && ssao_portals_available > 0)
|
||||
{
|
||||
applySSAO = (mCurrentPortal->AllowSSAO()/* || Level->flags3&LEVEL3_SKYBOXAO*/);
|
||||
ssao_portals_available--;
|
||||
}
|
||||
|
||||
CreateScene();
|
||||
auto& RenderState = *screen->RenderState();
|
||||
|
||||
RenderState.SetDepthMask(true);
|
||||
#if 0
|
||||
if (!gl_no_skyclear) portalState.RenderFirstSkyPortal(recursion, this, RenderState);
|
||||
#endif
|
||||
|
||||
RenderScene(RenderState);
|
||||
|
||||
if (applySSAO && RenderState.GetPassType() == GBUFFER_PASS)
|
||||
{
|
||||
screen->AmbientOccludeScene(VPUniforms.mProjectionMatrix.get()[5]);
|
||||
screen->mViewpoints->Bind(RenderState, vpIndex);
|
||||
}
|
||||
|
||||
// Handle all portals after rendering the opaque objects but before
|
||||
// doing all translucent stuff
|
||||
recursion++;
|
||||
#if 0
|
||||
portalState.EndFrame(this, RenderState);
|
||||
#endif
|
||||
recursion--;
|
||||
RenderTranslucent(RenderState);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// R_RenderView - renders one view - either the screen or a camera texture
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::ProcessScene(bool toscreen)
|
||||
{
|
||||
#if 0
|
||||
portalState.BeginScene();
|
||||
#endif
|
||||
DrawScene(toscreen ? DM_MAINVIEW : DM_OFFSCREEN);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
/*
|
||||
void HWDrawInfo::AddSubsectorToPortal(FSectorPortalGroup *ptg, subsector_t *sub)
|
||||
{
|
||||
auto portal = FindPortal(ptg);
|
||||
if (!portal)
|
||||
{
|
||||
portal = new HWSectorStackPortal(&portalState, ptg);
|
||||
Portals.Push(portal);
|
||||
}
|
||||
auto ptl = static_cast<HWSectorStackPortal*>(portal);
|
||||
ptl->AddSubsector(sub);
|
||||
}
|
||||
*/
|
||||
|
215
source/core/rendering/scene/hw_drawinfo.h
Normal file
215
source/core/rendering/scene/hw_drawinfo.h
Normal file
|
@ -0,0 +1,215 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include "build.h"
|
||||
#include "vectors.h"
|
||||
#include "hw_viewpointuniforms.h"
|
||||
#include "v_video.h"
|
||||
#include "hw_drawlist.h"
|
||||
#include "hw_bunchdrawer.h"
|
||||
//#include "r_viewpoint.h"
|
||||
|
||||
enum EDrawMode
|
||||
{
|
||||
DM_MAINVIEW,
|
||||
DM_OFFSCREEN,
|
||||
DM_PORTAL,
|
||||
DM_SKYPORTAL
|
||||
};
|
||||
|
||||
struct FSectorPortalGroup;
|
||||
struct FFlatVertex;
|
||||
class HWWall;
|
||||
class HWFlat;
|
||||
class HWSprite;
|
||||
struct HWDecal;
|
||||
class IShadowMap;
|
||||
struct FDynLightData;
|
||||
class Clipper;
|
||||
class HWPortal;
|
||||
class FFlatVertexBuffer;
|
||||
class IRenderQueue;
|
||||
class HWScenePortalBase;
|
||||
class FRenderState;
|
||||
|
||||
struct FRenderViewpoint
|
||||
{
|
||||
DVector3 Pos;
|
||||
FRotator HWAngles;
|
||||
FAngle FieldOfView;
|
||||
angle_t RotAngle;
|
||||
int SectNum;
|
||||
double TicFrac;
|
||||
};
|
||||
//==========================================================================
|
||||
//
|
||||
// these are used to link faked planes due to missing textures to a sector
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
enum SectorRenderFlags
|
||||
{
|
||||
// This is used to merge several subsectors into a single draw item
|
||||
SSRF_RENDERFLOOR = 1,
|
||||
SSRF_RENDERCEILING = 2,
|
||||
SSRF_RENDERALL = 7,
|
||||
SSRF_PROCESSED = 8,
|
||||
SSRF_SEEN = 16,
|
||||
};
|
||||
|
||||
enum EPortalClip
|
||||
{
|
||||
PClip_InFront,
|
||||
PClip_Inside,
|
||||
PClip_Behind,
|
||||
};
|
||||
|
||||
enum DrawListType
|
||||
{
|
||||
GLDL_PLAINWALLS,
|
||||
GLDL_PLAINFLATS,
|
||||
GLDL_MASKEDWALLS,
|
||||
GLDL_MASKEDFLATS,
|
||||
GLDL_MASKEDWALLSOFS,
|
||||
GLDL_MODELS,
|
||||
|
||||
GLDL_TRANSLUCENT,
|
||||
GLDL_TRANSLUCENTBORDER,
|
||||
|
||||
GLDL_TYPES,
|
||||
};
|
||||
|
||||
|
||||
struct HWDrawInfo
|
||||
{
|
||||
struct wallseg
|
||||
{
|
||||
float x1, y1, z1, x2, y2, z2;
|
||||
};
|
||||
|
||||
HWDrawList drawlists[GLDL_TYPES];
|
||||
int vpIndex;
|
||||
//ELightMode lightmode;
|
||||
|
||||
HWDrawInfo * outer = nullptr;
|
||||
int FullbrightFlags;
|
||||
std::atomic<int> spriteindex;
|
||||
HWPortal *mClipPortal;
|
||||
HWPortal *mCurrentPortal;
|
||||
//FRotator mAngles;
|
||||
BunchDrawer mDrawer;
|
||||
Clipper *mClipper;
|
||||
FRenderViewpoint Viewpoint;
|
||||
HWViewpointUniforms VPUniforms; // per-viewpoint uniform state
|
||||
TArray<HWPortal *> Portals;
|
||||
TArray<HWDecal *> Decals[2]; // the second slot is for mirrors which get rendered in a separate pass.
|
||||
|
||||
// This is needed by the BSP traverser.
|
||||
fixed_t viewx, viewy; // since the nodes are still fixed point, keeping the view position also fixed point for node traversal is faster.
|
||||
bool multithread;
|
||||
|
||||
private:
|
||||
bool inview;
|
||||
sectortype *currentsector;
|
||||
|
||||
void WorkerThread();
|
||||
|
||||
void UnclipSubsector(sectortype *sub);
|
||||
|
||||
void AddLine(walltype *seg, bool portalclip);
|
||||
void AddLines(sectortype* sector);
|
||||
void AddSpecialPortalLines(sectortype * sector, walltype* line);
|
||||
public:
|
||||
//void RenderThings(sectortype * sub, sectortype * sector);
|
||||
//void RenderParticles(sectortype *sub, sectortype *front);
|
||||
void SetColor(FRenderState &state, int sectorlightlevel, int rellight, bool fullbright, const FColormap &cm, float alpha, bool weapon = false);
|
||||
public:
|
||||
|
||||
void SetCameraPos(const DVector3 &pos)
|
||||
{
|
||||
VPUniforms.mCameraPos = { (float)pos.X, (float)pos.Z, (float)pos.Y, 0.f };
|
||||
}
|
||||
|
||||
void SetClipHeight(float h, float d)
|
||||
{
|
||||
VPUniforms.mClipHeight = h;
|
||||
VPUniforms.mClipHeightDirection = d;
|
||||
VPUniforms.mClipLine.X = -1000001.f;
|
||||
}
|
||||
|
||||
void SetClipLine(walltype *line)
|
||||
{
|
||||
//VPUniforms.mClipLine = { (float)line->v1->fX(), (float)line->v1->fY(), (float)line->Delta().X, (float)line->Delta().Y };
|
||||
VPUniforms.mClipHeight = 0;
|
||||
}
|
||||
|
||||
HWPortal * FindPortal(const void * src);
|
||||
|
||||
static HWDrawInfo *StartDrawInfo(HWDrawInfo *parent, FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms);
|
||||
void StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms);
|
||||
void ClearBuffers();
|
||||
HWDrawInfo *EndDrawInfo();
|
||||
|
||||
void DrawScene(int drawmode);
|
||||
void CreateScene();
|
||||
void RenderScene(FRenderState &state);
|
||||
void RenderTranslucent(FRenderState &state);
|
||||
void RenderPortal(HWPortal *p, FRenderState &state, bool usestencil);
|
||||
void EndDrawScene(FRenderState &state);
|
||||
void Set3DViewport(FRenderState &state);
|
||||
void ProcessScene(bool toscreen);
|
||||
|
||||
//void GetDynSpriteLight(AActor *self, float x, float y, float z, FLightNode *node, int portalgroup, float *out);
|
||||
//void GetDynSpriteLight(AActor *thing, particle_t *particle, float *out);
|
||||
|
||||
void SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror);
|
||||
void SetupView(FRenderState &state, float vx, float vy, float vz, bool mirror, bool planemirror);
|
||||
angle_t FrustumAngle();
|
||||
|
||||
void DrawDecals(FRenderState &state, TArray<HWDecal *> &decals);
|
||||
void DrawPlayerSprites(bool hudModelStep, FRenderState &state);
|
||||
|
||||
//void AddSubsectorToPortal(FSectorPortalGroup *portal, sectortype *sub);
|
||||
|
||||
void AddWall(HWWall *w);
|
||||
void AddMirrorSurface(HWWall *w);
|
||||
void AddFlat(HWFlat *flat);
|
||||
void AddSprite(HWSprite *sprite, bool translucent);
|
||||
|
||||
|
||||
HWDecal *AddDecal(bool onmirror);
|
||||
|
||||
bool isSoftwareLighting() const
|
||||
{
|
||||
return true;// lightmode == ELightMode::ZDoomSoftware || lightmode == ELightMode::DoomSoftware || lightmode == ELightMode::Build;
|
||||
}
|
||||
|
||||
bool isBuildSoftwareLighting() const
|
||||
{
|
||||
return true;// lightmode == ELightMode::Build;
|
||||
}
|
||||
|
||||
bool isDoomSoftwareLighting() const
|
||||
{
|
||||
return false;// lightmode == ELightMode::ZDoomSoftware || lightmode == ELightMode::DoomSoftware;
|
||||
}
|
||||
|
||||
bool isDarkLightMode() const
|
||||
{
|
||||
return false;// lightmode == ELightMode::Doom || lightmode == ELightMode::DoomDark;
|
||||
}
|
||||
|
||||
void SetFallbackLightMode()
|
||||
{
|
||||
//lightmode = ELightMode::Doom;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void CleanSWDrawer();
|
||||
//sectortype* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen);
|
||||
//void WriteSavePic(player_t* player, FileWriter* file, int width, int height);
|
||||
//sectortype* RenderView(player_t* player);
|
||||
|
||||
|
941
source/core/rendering/scene/hw_drawlist.cpp
Normal file
941
source/core/rendering/scene/hw_drawlist.cpp
Normal file
|
@ -0,0 +1,941 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2002-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
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (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/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** hw_drawlist.cpp
|
||||
** The main container type for draw items.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "hw_drawstructs.h"
|
||||
#include "hw_drawlist.h"
|
||||
#include "flatvertices.h"
|
||||
#include "hw_clock.h"
|
||||
#include "hw_renderstate.h"
|
||||
#include "hw_drawinfo.h"
|
||||
|
||||
FMemArena RenderDataAllocator(1024*1024); // Use large blocks to reduce allocation time.
|
||||
|
||||
void ResetRenderDataAllocator()
|
||||
{
|
||||
RenderDataAllocator.FreeAll();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
class StaticSortNodeArray : public TDeletingArray<SortNode*>
|
||||
{
|
||||
unsigned usecount;
|
||||
public:
|
||||
unsigned Size() { return usecount; }
|
||||
void Clear() { usecount=0; }
|
||||
void Release(int start) { usecount=start; }
|
||||
SortNode * GetNew();
|
||||
};
|
||||
|
||||
|
||||
SortNode * StaticSortNodeArray::GetNew()
|
||||
{
|
||||
if (usecount==TArray<SortNode*>::Size())
|
||||
{
|
||||
Push(new SortNode);
|
||||
}
|
||||
return operator[](usecount++);
|
||||
}
|
||||
|
||||
|
||||
static StaticSortNodeArray SortNodes;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void HWDrawList::Reset()
|
||||
{
|
||||
if (sorted) SortNodes.Release(SortNodeStart);
|
||||
sorted=NULL;
|
||||
walls.Clear();
|
||||
flats.Clear();
|
||||
sprites.Clear();
|
||||
drawitems.Clear();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
inline void SortNode::UnlinkFromChain()
|
||||
{
|
||||
if (parent) parent->next=next;
|
||||
if (next) next->parent=parent;
|
||||
parent=next=NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
inline void SortNode::Link(SortNode * hook)
|
||||
{
|
||||
if (hook)
|
||||
{
|
||||
parent=hook->parent;
|
||||
hook->parent=this;
|
||||
}
|
||||
next=hook;
|
||||
if (parent) parent->next=this;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
inline void SortNode::AddToEqual(SortNode *child)
|
||||
{
|
||||
child->UnlinkFromChain();
|
||||
child->equal=equal;
|
||||
equal=child;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
inline void SortNode::AddToLeft(SortNode * child)
|
||||
{
|
||||
child->UnlinkFromChain();
|
||||
child->Link(left);
|
||||
left=child;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
inline void SortNode::AddToRight(SortNode * child)
|
||||
{
|
||||
child->UnlinkFromChain();
|
||||
child->Link(right);
|
||||
right=child;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void HWDrawList::MakeSortList()
|
||||
{
|
||||
SortNode * p, * n, * c;
|
||||
unsigned i;
|
||||
|
||||
SortNodeStart=SortNodes.Size();
|
||||
p=NULL;
|
||||
n=SortNodes.GetNew();
|
||||
for(i=0;i<drawitems.Size();i++)
|
||||
{
|
||||
n->itemindex=(int)i;
|
||||
n->left=n->equal=n->right=NULL;
|
||||
n->parent=p;
|
||||
p=n;
|
||||
if (i!=drawitems.Size()-1)
|
||||
{
|
||||
c=SortNodes.GetNew();
|
||||
n->next=c;
|
||||
n=c;
|
||||
}
|
||||
else
|
||||
{
|
||||
n->next=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
SortNode * HWDrawList::FindSortPlane(SortNode * head)
|
||||
{
|
||||
while (head->next && drawitems[head->itemindex].rendertype!=DrawType_FLAT)
|
||||
head=head->next;
|
||||
if (drawitems[head->itemindex].rendertype==DrawType_FLAT) return head;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
SortNode * HWDrawList::FindSortWall(SortNode * head)
|
||||
{
|
||||
float farthest = -FLT_MAX;
|
||||
float nearest = FLT_MAX;
|
||||
SortNode * best = NULL;
|
||||
SortNode * node = head;
|
||||
float bestdist = FLT_MAX;
|
||||
|
||||
while (node)
|
||||
{
|
||||
HWDrawItem * it = &drawitems[node->itemindex];
|
||||
if (it->rendertype == DrawType_WALL)
|
||||
{
|
||||
float d = walls[it->index]->ViewDistance;
|
||||
if (d > farthest) farthest = d;
|
||||
if (d < nearest) nearest = d;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
if (farthest == INT_MIN) return NULL;
|
||||
node = head;
|
||||
farthest = (farthest + nearest) / 2;
|
||||
while (node)
|
||||
{
|
||||
HWDrawItem * it = &drawitems[node->itemindex];
|
||||
if (it->rendertype == DrawType_WALL)
|
||||
{
|
||||
float di = fabsf(walls[it->index]->ViewDistance - farthest);
|
||||
if (!best || di < bestdist)
|
||||
{
|
||||
best = node;
|
||||
bestdist = di;
|
||||
}
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Note: sloped planes are a huge problem...
|
||||
//
|
||||
//==========================================================================
|
||||
void HWDrawList::SortPlaneIntoPlane(SortNode * head,SortNode * sort)
|
||||
{
|
||||
HWFlat * fh= flats[drawitems[head->itemindex].index];
|
||||
HWFlat * fs= flats[drawitems[sort->itemindex].index];
|
||||
|
||||
if (fh->z==fs->z)
|
||||
head->AddToEqual(sort);
|
||||
else if ( (fh->z<fs->z && fh->plane) || (fh->z>fs->z && !fh->plane))
|
||||
head->AddToLeft(sort);
|
||||
else
|
||||
head->AddToRight(sort);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void HWDrawList::SortWallIntoPlane(SortNode * head, SortNode * sort)
|
||||
{
|
||||
HWFlat * fh = flats[drawitems[head->itemindex].index];
|
||||
HWWall * ws = walls[drawitems[sort->itemindex].index];
|
||||
|
||||
bool ceiling = fh->z > SortZ;
|
||||
|
||||
if ((ws->ztop[0] > fh->z || ws->ztop[1] > fh->z) && (ws->zbottom[0] < fh->z || ws->zbottom[1] < fh->z))
|
||||
{
|
||||
// We have to split this wall!
|
||||
|
||||
HWWall *w = NewWall();
|
||||
*w = *ws;
|
||||
|
||||
// Splitting is done in the shader with clip planes, if available
|
||||
if (screen->hwcaps & RFL_NO_CLIP_PLANES)
|
||||
{
|
||||
ws->vertcount = 0; // invalidate current vertices.
|
||||
float newtexv = ws->tcs[HWWall::UPLFT].v + ((ws->tcs[HWWall::LOLFT].v - ws->tcs[HWWall::UPLFT].v) / (ws->zbottom[0] - ws->ztop[0])) * (fh->z - ws->ztop[0]);
|
||||
|
||||
// I make the very big assumption here that translucent walls in sloped sectors
|
||||
// and 3D-floors never coexist in the same level - If that were the case this
|
||||
// code would become extremely more complicated.
|
||||
if (!ceiling)
|
||||
{
|
||||
ws->ztop[1] = w->zbottom[1] = ws->ztop[0] = w->zbottom[0] = fh->z;
|
||||
ws->tcs[HWWall::UPRGT].v = w->tcs[HWWall::LORGT].v = ws->tcs[HWWall::UPLFT].v = w->tcs[HWWall::LOLFT].v = newtexv;
|
||||
}
|
||||
else
|
||||
{
|
||||
w->ztop[1] = ws->zbottom[1] = w->ztop[0] = ws->zbottom[0] = fh->z;
|
||||
w->tcs[HWWall::UPLFT].v = ws->tcs[HWWall::LOLFT].v = w->tcs[HWWall::UPRGT].v = ws->tcs[HWWall::LORGT].v = newtexv;
|
||||
}
|
||||
}
|
||||
|
||||
SortNode * sort2 = SortNodes.GetNew();
|
||||
memset(sort2, 0, sizeof(SortNode));
|
||||
sort2->itemindex = drawitems.Size() - 1;
|
||||
|
||||
head->AddToLeft(sort);
|
||||
head->AddToRight(sort2);
|
||||
}
|
||||
else if ((ws->zbottom[0] < fh->z && !ceiling) || (ws->ztop[0] > fh->z && ceiling)) // completely on the left side
|
||||
{
|
||||
head->AddToLeft(sort);
|
||||
}
|
||||
else
|
||||
{
|
||||
head->AddToRight(sort);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void HWDrawList::SortSpriteIntoPlane(SortNode * head, SortNode * sort)
|
||||
{
|
||||
HWFlat * fh = flats[drawitems[head->itemindex].index];
|
||||
HWSprite * ss = sprites[drawitems[sort->itemindex].index];
|
||||
|
||||
bool ceiling = fh->z > SortZ;
|
||||
|
||||
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)
|
||||
{
|
||||
// We have to split this sprite
|
||||
HWSprite *s = NewSprite();
|
||||
*s = *ss;
|
||||
|
||||
// Splitting is done in the shader with clip planes, if available.
|
||||
// The fallback here only really works for non-y-billboarded sprites.
|
||||
if (screen->hwcaps & RFL_NO_CLIP_PLANES)
|
||||
{
|
||||
float newtexv = ss->vt + ((ss->vb - ss->vt) / (ss->z2 - ss->z1))*(fh->z - ss->z1);
|
||||
|
||||
if (!ceiling)
|
||||
{
|
||||
ss->z1 = s->z2 = fh->z;
|
||||
ss->vt = s->vb = newtexv;
|
||||
}
|
||||
else
|
||||
{
|
||||
s->z1 = ss->z2 = fh->z;
|
||||
s->vt = ss->vb = newtexv;
|
||||
}
|
||||
}
|
||||
|
||||
SortNode * sort2 = SortNodes.GetNew();
|
||||
memset(sort2, 0, sizeof(SortNode));
|
||||
sort2->itemindex = drawitems.Size() - 1;
|
||||
|
||||
head->AddToLeft(sort);
|
||||
head->AddToRight(sort2);
|
||||
}
|
||||
else if ((ss->z2<fh->z && !ceiling) || (ss->z1>fh->z && ceiling)) // completely on the left side
|
||||
{
|
||||
head->AddToLeft(sort);
|
||||
}
|
||||
else
|
||||
{
|
||||
head->AddToRight(sort);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
#define MIN_EQ (0.0005f)
|
||||
|
||||
// Lines start-end and fdiv must intersect.
|
||||
inline double CalcIntersectionVertex(HWWall *w1, HWWall * w2)
|
||||
{
|
||||
float ax = w1->glseg.x1, ay = w1->glseg.y1;
|
||||
float bx = w1->glseg.x2, by = w1->glseg.y2;
|
||||
float cx = w2->glseg.x1, cy = w2->glseg.y1;
|
||||
float dx = w2->glseg.x2, dy = w2->glseg.y2;
|
||||
return ((ay - cy)*(dx - cx) - (ax - cx)*(dy - cy)) / ((bx - ax)*(dy - cy) - (by - ay)*(dx - cx));
|
||||
}
|
||||
|
||||
void HWDrawList::SortWallIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sort)
|
||||
{
|
||||
HWWall * wh= walls[drawitems[head->itemindex].index];
|
||||
HWWall * ws= walls[drawitems[sort->itemindex].index];
|
||||
float v1=wh->PointOnSide(ws->glseg.x1,ws->glseg.y1);
|
||||
float v2=wh->PointOnSide(ws->glseg.x2,ws->glseg.y2);
|
||||
|
||||
if (fabs(v1)<MIN_EQ && fabs(v2)<MIN_EQ)
|
||||
{
|
||||
if (ws->type==RENDERWALL_FOGBOUNDARY && wh->type!=RENDERWALL_FOGBOUNDARY)
|
||||
{
|
||||
head->AddToRight(sort);
|
||||
}
|
||||
else if (ws->type!=RENDERWALL_FOGBOUNDARY && wh->type==RENDERWALL_FOGBOUNDARY)
|
||||
{
|
||||
head->AddToLeft(sort);
|
||||
}
|
||||
else
|
||||
{
|
||||
head->AddToEqual(sort);
|
||||
}
|
||||
}
|
||||
else if (v1<MIN_EQ && v2<MIN_EQ)
|
||||
{
|
||||
head->AddToLeft(sort);
|
||||
}
|
||||
else if (v1>-MIN_EQ && v2>-MIN_EQ)
|
||||
{
|
||||
head->AddToRight(sort);
|
||||
}
|
||||
else
|
||||
{
|
||||
double r = CalcIntersectionVertex(ws, wh);
|
||||
|
||||
float ix=(float)(ws->glseg.x1+r*(ws->glseg.x2-ws->glseg.x1));
|
||||
float iy=(float)(ws->glseg.y1+r*(ws->glseg.y2-ws->glseg.y1));
|
||||
float iu=(float)(ws->tcs[HWWall::UPLFT].u + r * (ws->tcs[HWWall::UPRGT].u - ws->tcs[HWWall::UPLFT].u));
|
||||
float izt=(float)(ws->ztop[0]+r*(ws->ztop[1]-ws->ztop[0]));
|
||||
float izb=(float)(ws->zbottom[0]+r*(ws->zbottom[1]-ws->zbottom[0]));
|
||||
|
||||
ws->vertcount = 0; // invalidate current vertices.
|
||||
HWWall *w= NewWall();
|
||||
*w = *ws;
|
||||
|
||||
w->glseg.x1=ws->glseg.x2=ix;
|
||||
w->glseg.y1=ws->glseg.y2=iy;
|
||||
w->ztop[0]=ws->ztop[1]=izt;
|
||||
w->zbottom[0]=ws->zbottom[1]=izb;
|
||||
w->tcs[HWWall::LOLFT].u = w->tcs[HWWall::UPLFT].u = ws->tcs[HWWall::LORGT].u = ws->tcs[HWWall::UPRGT].u = iu;
|
||||
ws->MakeVertices(di, false);
|
||||
w->MakeVertices(di, false);
|
||||
|
||||
SortNode * sort2=SortNodes.GetNew();
|
||||
memset(sort2,0,sizeof(SortNode));
|
||||
sort2->itemindex=drawitems.Size()-1;
|
||||
|
||||
if (v1>0)
|
||||
{
|
||||
head->AddToLeft(sort2);
|
||||
head->AddToRight(sort);
|
||||
}
|
||||
else
|
||||
{
|
||||
head->AddToLeft(sort);
|
||||
head->AddToRight(sort2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
EXTERN_CVAR(Int, gl_billboard_mode)
|
||||
EXTERN_CVAR(Bool, gl_billboard_faces_camera)
|
||||
EXTERN_CVAR(Bool, gl_billboard_particles)
|
||||
|
||||
inline double CalcIntersectionVertex(HWSprite *s, HWWall * w2)
|
||||
{
|
||||
float ax = s->x1, ay = s->y1;
|
||||
float bx = s->x2, by = s->y2;
|
||||
float cx = w2->glseg.x1, cy = w2->glseg.y1;
|
||||
float dx = w2->glseg.x2, dy = w2->glseg.y2;
|
||||
return ((ay - cy)*(dx - cx) - (ax - cx)*(dy - cy)) / ((bx - ax)*(dy - cy) - (by - ay)*(dx - cx));
|
||||
}
|
||||
|
||||
void HWDrawList::SortSpriteIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sort)
|
||||
{
|
||||
HWWall *wh= walls[drawitems[head->itemindex].index];
|
||||
HWSprite * ss= sprites[drawitems[sort->itemindex].index];
|
||||
|
||||
float v1 = wh->PointOnSide(ss->x1, ss->y1);
|
||||
float v2 = wh->PointOnSide(ss->x2, ss->y2);
|
||||
|
||||
if (fabs(v1)<MIN_EQ && fabs(v2)<MIN_EQ)
|
||||
{
|
||||
if (wh->type==RENDERWALL_FOGBOUNDARY)
|
||||
{
|
||||
head->AddToLeft(sort);
|
||||
}
|
||||
else
|
||||
{
|
||||
head->AddToEqual(sort);
|
||||
}
|
||||
}
|
||||
else if (v1<MIN_EQ && v2<MIN_EQ)
|
||||
{
|
||||
head->AddToLeft(sort);
|
||||
}
|
||||
else if (v1>-MIN_EQ && v2>-MIN_EQ)
|
||||
{
|
||||
head->AddToRight(sort);
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool drawWithXYBillboard = false;//
|
||||
|
||||
// [Nash] has +ROLLSPRITE
|
||||
const bool rotated = false;//
|
||||
|
||||
// cannot sort them at the moment. This requires more complex splitting.
|
||||
/*
|
||||
const bool drawBillboardFacingCamera = gl_billboard_faces_camera;
|
||||
if (drawWithXYBillboard || drawBillboardFacingCamera || rotated)
|
||||
{
|
||||
float v1 = wh->PointOnSide(ss->x, ss->y);
|
||||
if (v1 < 0)
|
||||
{
|
||||
head->AddToLeft(sort);
|
||||
}
|
||||
else
|
||||
{
|
||||
head->AddToRight(sort);
|
||||
}
|
||||
return;
|
||||
}
|
||||
*/
|
||||
double r=CalcIntersectionVertex(ss, wh);
|
||||
|
||||
float ix=(float)(ss->x1 + r * (ss->x2-ss->x1));
|
||||
float iy=(float)(ss->y1 + r * (ss->y2-ss->y1));
|
||||
float iu=(float)(ss->ul + r * (ss->ur-ss->ul));
|
||||
|
||||
HWSprite *s = NewSprite();
|
||||
*s = *ss;
|
||||
|
||||
s->x1=ss->x2=ix;
|
||||
s->y1=ss->y2=iy;
|
||||
s->ul=ss->ur=iu;
|
||||
|
||||
SortNode * sort2=SortNodes.GetNew();
|
||||
memset(sort2,0,sizeof(SortNode));
|
||||
sort2->itemindex=drawitems.Size()-1;
|
||||
|
||||
if (v1>0)
|
||||
{
|
||||
head->AddToLeft(sort2);
|
||||
head->AddToRight(sort);
|
||||
}
|
||||
else
|
||||
{
|
||||
head->AddToLeft(sort);
|
||||
head->AddToRight(sort2);
|
||||
}
|
||||
if (screen->BuffersArePersistent())
|
||||
{
|
||||
s->vertexindex = ss->vertexindex = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
s->CreateVertices(di);
|
||||
ss->CreateVertices(di);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
inline int HWDrawList::CompareSprites(SortNode * a,SortNode * b)
|
||||
{
|
||||
HWSprite * s1= sprites[drawitems[a->itemindex].index];
|
||||
HWSprite * s2= sprites[drawitems[b->itemindex].index];
|
||||
|
||||
if (s1->depth < s2->depth) return 1;
|
||||
if (s1->depth > s2->depth) return -1;
|
||||
return reverseSort? s2->index-s1->index : s1->index-s2->index;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
SortNode * HWDrawList::SortSpriteList(SortNode * head)
|
||||
{
|
||||
SortNode * n;
|
||||
int count;
|
||||
unsigned i;
|
||||
|
||||
static TArray<SortNode*> sortspritelist;
|
||||
|
||||
SortNode * parent=head->parent;
|
||||
|
||||
sortspritelist.Clear();
|
||||
for(count=0,n=head;n;n=n->next) sortspritelist.Push(n);
|
||||
std::stable_sort(sortspritelist.begin(), sortspritelist.end(), [=](SortNode *a, SortNode *b)
|
||||
{
|
||||
return CompareSprites(a, b) < 0;
|
||||
});
|
||||
|
||||
for(i=0;i<sortspritelist.Size();i++)
|
||||
{
|
||||
sortspritelist[i]->next=NULL;
|
||||
if (parent) parent->equal=sortspritelist[i];
|
||||
parent=sortspritelist[i];
|
||||
}
|
||||
return sortspritelist[0];
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
SortNode * HWDrawList::DoSort(HWDrawInfo *di, SortNode * head)
|
||||
{
|
||||
SortNode * node, * sn, * next;
|
||||
|
||||
sn=FindSortPlane(head);
|
||||
if (sn)
|
||||
{
|
||||
if (sn==head) head=head->next;
|
||||
sn->UnlinkFromChain();
|
||||
node=head;
|
||||
head=sn;
|
||||
while (node)
|
||||
{
|
||||
next=node->next;
|
||||
switch(drawitems[node->itemindex].rendertype)
|
||||
{
|
||||
case DrawType_FLAT:
|
||||
SortPlaneIntoPlane(head,node);
|
||||
break;
|
||||
|
||||
case DrawType_WALL:
|
||||
SortWallIntoPlane(head,node);
|
||||
break;
|
||||
|
||||
case DrawType_SPRITE:
|
||||
SortSpriteIntoPlane(head,node);
|
||||
break;
|
||||
}
|
||||
node=next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sn=FindSortWall(head);
|
||||
if (sn)
|
||||
{
|
||||
if (sn==head) head=head->next;
|
||||
sn->UnlinkFromChain();
|
||||
node=head;
|
||||
head=sn;
|
||||
while (node)
|
||||
{
|
||||
next=node->next;
|
||||
switch(drawitems[node->itemindex].rendertype)
|
||||
{
|
||||
case DrawType_WALL:
|
||||
SortWallIntoWall(di, head,node);
|
||||
break;
|
||||
|
||||
case DrawType_SPRITE:
|
||||
SortSpriteIntoWall(di, head, node);
|
||||
break;
|
||||
|
||||
case DrawType_FLAT: break;
|
||||
}
|
||||
node=next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return SortSpriteList(head);
|
||||
}
|
||||
}
|
||||
if (head->left) head->left=DoSort(di, head->left);
|
||||
if (head->right) head->right=DoSort(di, head->right);
|
||||
return sn;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void HWDrawList::Sort(HWDrawInfo *di)
|
||||
{
|
||||
reverseSort = false;
|
||||
SortZ = di->Viewpoint.Pos.Z;
|
||||
MakeSortList();
|
||||
sorted = DoSort(di, SortNodes[SortNodeStart]);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sorting the drawitems first by texture and then by light level
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void HWDrawList::SortWalls()
|
||||
{
|
||||
if (drawitems.Size() > 1)
|
||||
{
|
||||
std::sort(drawitems.begin(), drawitems.end(), [=](const HWDrawItem &a, const HWDrawItem &b) -> bool
|
||||
{
|
||||
HWWall * w1 = walls[a.index];
|
||||
HWWall * w2 = walls[b.index];
|
||||
|
||||
if (w1->texture != w2->texture) return w1->texture < w2->texture;
|
||||
return (w1->flags & 3) < (w2->flags & 3);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void HWDrawList::SortFlats()
|
||||
{
|
||||
if (drawitems.Size() > 1)
|
||||
{
|
||||
std::sort(drawitems.begin(), drawitems.end(), [=](const HWDrawItem &a, const HWDrawItem &b)
|
||||
{
|
||||
HWFlat * w1 = flats[a.index];
|
||||
HWFlat* w2 = flats[b.index];
|
||||
return w1->texture < w2->texture;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
HWWall *HWDrawList::NewWall()
|
||||
{
|
||||
auto wall = (HWWall*)RenderDataAllocator.Alloc(sizeof(HWWall));
|
||||
drawitems.Push(HWDrawItem(DrawType_WALL, walls.Push(wall)));
|
||||
return wall;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
HWFlat *HWDrawList::NewFlat()
|
||||
{
|
||||
auto flat = (HWFlat*)RenderDataAllocator.Alloc(sizeof(HWFlat));
|
||||
drawitems.Push(HWDrawItem(DrawType_FLAT,flats.Push(flat)));
|
||||
return flat;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
HWSprite *HWDrawList::NewSprite()
|
||||
{
|
||||
auto sprite = (HWSprite*)RenderDataAllocator.Alloc(sizeof(HWSprite));
|
||||
drawitems.Push(HWDrawItem(DrawType_SPRITE, sprites.Push(sprite)));
|
||||
return sprite;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void HWDrawList::DoDraw(HWDrawInfo *di, FRenderState &state, bool translucent, int i)
|
||||
{
|
||||
switch(drawitems[i].rendertype)
|
||||
{
|
||||
case DrawType_FLAT:
|
||||
{
|
||||
HWFlat * f= flats[drawitems[i].index];
|
||||
RenderFlat.Clock();
|
||||
f->DrawFlat(di, state, translucent);
|
||||
RenderFlat.Unclock();
|
||||
}
|
||||
break;
|
||||
|
||||
case DrawType_WALL:
|
||||
{
|
||||
HWWall * w= walls[drawitems[i].index];
|
||||
RenderWall.Clock();
|
||||
w->DrawWall(di, state, translucent);
|
||||
RenderWall.Unclock();
|
||||
}
|
||||
break;
|
||||
|
||||
case DrawType_SPRITE:
|
||||
{
|
||||
HWSprite * s= sprites[drawitems[i].index];
|
||||
RenderSprite.Clock();
|
||||
s->DrawSprite(di, state, translucent);
|
||||
RenderSprite.Unclock();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void HWDrawList::Draw(HWDrawInfo *di, FRenderState &state, bool translucent)
|
||||
{
|
||||
for (unsigned i = 0; i < drawitems.Size(); i++)
|
||||
{
|
||||
DoDraw(di, state, translucent, i);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void HWDrawList::DrawWalls(HWDrawInfo *di, FRenderState &state, bool translucent)
|
||||
{
|
||||
RenderWall.Clock();
|
||||
for (auto &item : drawitems)
|
||||
{
|
||||
walls[item.index]->DrawWall(di, state, translucent);
|
||||
}
|
||||
RenderWall.Unclock();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void HWDrawList::DrawFlats(HWDrawInfo *di, FRenderState &state, bool translucent)
|
||||
{
|
||||
RenderFlat.Clock();
|
||||
for (unsigned i = 0; i<drawitems.Size(); i++)
|
||||
{
|
||||
flats[drawitems[i].index]->DrawFlat(di, state, translucent);
|
||||
}
|
||||
RenderFlat.Unclock();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void HWDrawList::DrawSorted(HWDrawInfo *di, FRenderState &state, SortNode * head)
|
||||
{
|
||||
float clipsplit[2];
|
||||
int relation = 0;
|
||||
float z = 0.f;
|
||||
|
||||
state.GetClipSplit(clipsplit);
|
||||
|
||||
if (drawitems[head->itemindex].rendertype == DrawType_FLAT)
|
||||
{
|
||||
z = flats[drawitems[head->itemindex].index]->z;
|
||||
relation = z > di->Viewpoint.Pos.Z ? 1 : -1;
|
||||
}
|
||||
|
||||
|
||||
// left is further away, i.e. for stuff above viewz its z coordinate higher, for stuff below viewz its z coordinate is lower
|
||||
if (head->left)
|
||||
{
|
||||
if (relation == -1)
|
||||
{
|
||||
state.SetClipSplit(clipsplit[0], z); // render below: set flat as top clip plane
|
||||
}
|
||||
else if (relation == 1)
|
||||
{
|
||||
state.SetClipSplit(z, clipsplit[1]); // render above: set flat as bottom clip plane
|
||||
}
|
||||
DrawSorted(di, state, head->left);
|
||||
state.SetClipSplit(clipsplit);
|
||||
}
|
||||
DoDraw(di, state, true, head->itemindex);
|
||||
if (head->equal)
|
||||
{
|
||||
SortNode * ehead = head->equal;
|
||||
while (ehead)
|
||||
{
|
||||
DoDraw(di, state, true, ehead->itemindex);
|
||||
ehead = ehead->equal;
|
||||
}
|
||||
}
|
||||
// right is closer, i.e. for stuff above viewz its z coordinate is lower, for stuff below viewz its z coordinate is higher
|
||||
if (head->right)
|
||||
{
|
||||
if (relation == 1)
|
||||
{
|
||||
state.SetClipSplit(clipsplit[0], z); // render below: set flat as top clip plane
|
||||
}
|
||||
else if (relation == -1)
|
||||
{
|
||||
state.SetClipSplit(z, clipsplit[1]); // render above: set flat as bottom clip plane
|
||||
}
|
||||
DrawSorted(di, state, head->right);
|
||||
state.SetClipSplit(clipsplit);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void HWDrawList::DrawSorted(HWDrawInfo *di, FRenderState &state)
|
||||
{
|
||||
if (drawitems.Size() == 0) return;
|
||||
|
||||
if (!sorted)
|
||||
{
|
||||
screen->mVertexData->Map();
|
||||
Sort(di);
|
||||
screen->mVertexData->Unmap();
|
||||
}
|
||||
state.ClearClipSplit();
|
||||
state.EnableClipDistance(1, true);
|
||||
state.EnableClipDistance(2, true);
|
||||
DrawSorted(di, state, sorted);
|
||||
state.EnableClipDistance(1, false);
|
||||
state.EnableClipDistance(2, false);
|
||||
state.ClearClipSplit();
|
||||
}
|
||||
|
122
source/core/rendering/scene/hw_drawlist.h
Normal file
122
source/core/rendering/scene/hw_drawlist.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
#pragma once
|
||||
|
||||
#include "memarena.h"
|
||||
|
||||
extern FMemArena RenderDataAllocator;
|
||||
void ResetRenderDataAllocator();
|
||||
struct HWDrawInfo;
|
||||
class HWWall;
|
||||
class HWFlat;
|
||||
class HWSprite;
|
||||
class FRenderState;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Intermediate struct to link one draw item into a draw list
|
||||
//
|
||||
// unfortunately this struct must not contain pointers because
|
||||
// the arrays may be reallocated!
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
enum HWDrawItemType
|
||||
{
|
||||
DrawType_WALL,
|
||||
DrawType_FLAT,
|
||||
DrawType_SPRITE,
|
||||
};
|
||||
|
||||
struct HWDrawItem
|
||||
{
|
||||
HWDrawItemType rendertype;
|
||||
int index;
|
||||
|
||||
HWDrawItem(HWDrawItemType _rendertype,int _index) : rendertype(_rendertype),index(_index) {}
|
||||
};
|
||||
|
||||
struct SortNode
|
||||
{
|
||||
int itemindex;
|
||||
SortNode * parent;
|
||||
SortNode * next; // unsorted successor
|
||||
SortNode * left; // left side of this node
|
||||
SortNode * equal; // equal to this node
|
||||
SortNode * right; // right side of this node
|
||||
|
||||
|
||||
void UnlinkFromChain();
|
||||
void Link(SortNode * hook);
|
||||
void AddToEqual(SortNode * newnode);
|
||||
void AddToLeft (SortNode * newnode);
|
||||
void AddToRight(SortNode * newnode);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// One draw list. This contains all info for one type of rendering data
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct HWDrawList
|
||||
{
|
||||
//private:
|
||||
TArray<HWWall*> walls;
|
||||
TArray<HWFlat*> flats;
|
||||
TArray<HWSprite*> sprites;
|
||||
TArray<HWDrawItem> drawitems;
|
||||
int SortNodeStart;
|
||||
float SortZ;
|
||||
SortNode * sorted;
|
||||
bool reverseSort;
|
||||
|
||||
public:
|
||||
HWDrawList()
|
||||
{
|
||||
next=NULL;
|
||||
SortNodeStart=-1;
|
||||
sorted=NULL;
|
||||
}
|
||||
|
||||
~HWDrawList()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
unsigned int Size()
|
||||
{
|
||||
return drawitems.Size();
|
||||
}
|
||||
|
||||
HWWall *NewWall();
|
||||
HWFlat *NewFlat();
|
||||
HWSprite *NewSprite();
|
||||
void Reset();
|
||||
void SortWalls();
|
||||
void SortFlats();
|
||||
|
||||
|
||||
void MakeSortList();
|
||||
SortNode * FindSortPlane(SortNode * head);
|
||||
SortNode * FindSortWall(SortNode * head);
|
||||
void SortPlaneIntoPlane(SortNode * head,SortNode * sort);
|
||||
void SortWallIntoPlane(SortNode * head,SortNode * sort);
|
||||
void SortSpriteIntoPlane(SortNode * head,SortNode * sort);
|
||||
void SortWallIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sort);
|
||||
void SortSpriteIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sort);
|
||||
int CompareSprites(SortNode * a,SortNode * b);
|
||||
SortNode * SortSpriteList(SortNode * head);
|
||||
SortNode * DoSort(HWDrawInfo *di, SortNode * head);
|
||||
void Sort(HWDrawInfo *di);
|
||||
|
||||
void DoDraw(HWDrawInfo *di, FRenderState &state, bool translucent, int i);
|
||||
void Draw(HWDrawInfo *di, FRenderState &state, bool translucent);
|
||||
void DrawWalls(HWDrawInfo *di, FRenderState &state, bool translucent);
|
||||
void DrawFlats(HWDrawInfo *di, FRenderState &state, bool translucent);
|
||||
|
||||
void DrawSorted(HWDrawInfo *di, FRenderState &state, SortNode * head);
|
||||
void DrawSorted(HWDrawInfo *di, FRenderState &state);
|
||||
|
||||
HWDrawList * next;
|
||||
} ;
|
||||
|
||||
|
166
source/core/rendering/scene/hw_drawlistadd.cpp
Normal file
166
source/core/rendering/scene/hw_drawlistadd.cpp
Normal file
|
@ -0,0 +1,166 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// 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
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (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 "hw_dynlightdata.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "hw_drawstructs.h"
|
||||
#include "hw_drawinfo.h"
|
||||
#include "hw_material.h"
|
||||
#include "build.h"
|
||||
#include "polymost.h"
|
||||
#include "gamefuncs.h"
|
||||
|
||||
EXTERN_CVAR(Bool, gl_seamless)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void HWDrawInfo::AddWall(HWWall *wall)
|
||||
{
|
||||
if (wall->flags & HWWall::HWF_TRANSLUCENT)
|
||||
{
|
||||
auto newwall = drawlists[GLDL_TRANSLUCENT].NewWall();
|
||||
*newwall = *wall;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool masked = wall->type != RENDERWALL_M2S ? false : (wall->texture && wall->texture->isMasked());
|
||||
int list;
|
||||
|
||||
if (wall->flags & HWWall::HWF_SKYHACK && wall->type == RENDERWALL_M2S)
|
||||
{
|
||||
list = GLDL_MASKEDWALLSOFS;
|
||||
}
|
||||
else
|
||||
{
|
||||
list = masked ? GLDL_MASKEDWALLS : GLDL_PLAINWALLS;
|
||||
}
|
||||
auto newwall = drawlists[list].NewWall();
|
||||
*newwall = *wall;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void HWDrawInfo::AddMirrorSurface(HWWall *w)
|
||||
{
|
||||
#if 0
|
||||
w->type = RENDERWALL_MIRRORSURFACE;
|
||||
auto newwall = drawlists[GLDL_TRANSLUCENTBORDER].NewWall();
|
||||
*newwall = *w;
|
||||
|
||||
// Invalidate vertices to allow setting of texture coordinates
|
||||
newwall->vertcount = 0;
|
||||
|
||||
FVector3 v = newwall->glseg.Normal();
|
||||
auto tcs = newwall->tcs;
|
||||
tcs[HWWall::LOLFT].u = tcs[HWWall::LORGT].u = tcs[HWWall::UPLFT].u = tcs[HWWall::UPRGT].u = v.X;
|
||||
tcs[HWWall::LOLFT].v = tcs[HWWall::LORGT].v = tcs[HWWall::UPLFT].v = tcs[HWWall::UPRGT].v = v.Z;
|
||||
newwall->MakeVertices(this, false);
|
||||
|
||||
#if 0
|
||||
bool hasDecals = newwall->seg->sidedef && newwall->seg->sidedef->AttachedDecals;
|
||||
if (hasDecals && Level->HasDynamicLights && !isFullbrightScene())
|
||||
{
|
||||
newwall->SetupLights(this, lightdata);
|
||||
}
|
||||
newwall->ProcessDecals(this);
|
||||
#endif
|
||||
newwall->dynlightindex = -1; // the environment map should not be affected by lights - only the decals.
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FDrawInfo::AddFlat
|
||||
//
|
||||
// Checks texture, lighting and translucency settings and puts this
|
||||
// plane in the appropriate render list.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void HWDrawInfo::AddFlat(HWFlat *flat)
|
||||
{
|
||||
int list = GLDL_PLAINFLATS;
|
||||
|
||||
#if 0
|
||||
if (flat->renderstyle != STYLE_Translucent || flat->alpha < 1.f - FLT_EPSILON)
|
||||
{
|
||||
// translucent portals go into the translucent border list.
|
||||
list = GLDL_TRANSLUCENTBORDER;
|
||||
}
|
||||
else if (flat->texture->GetTranslucency())
|
||||
{
|
||||
/*
|
||||
if (flat->stack)
|
||||
{
|
||||
list = GLDL_TRANSLUCENTBORDER;
|
||||
}
|
||||
else
|
||||
*/
|
||||
{
|
||||
list = 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;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void HWDrawInfo::AddSprite(HWSprite *sprite, bool translucent)
|
||||
{
|
||||
#if 0
|
||||
int list;
|
||||
// [BB] Allow models to be drawn in the GLDL_TRANSLUCENT pass.
|
||||
if (translucent || ( (!spriteIsModelOrVoxel(sprite->actor) && !(sprite->actor->cstat & CSTAT_SPRITE_ALIGNMENT_MASK))))
|
||||
{
|
||||
list = GLDL_TRANSLUCENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
list = GLDL_MODELS;
|
||||
}
|
||||
|
||||
auto newsprt = drawlists[list].NewSprite();
|
||||
*newsprt = *sprite;
|
||||
#endif
|
||||
}
|
||||
|
396
source/core/rendering/scene/hw_drawstructs.h
Normal file
396
source/core/rendering/scene/hw_drawstructs.h
Normal file
|
@ -0,0 +1,396 @@
|
|||
#pragma once
|
||||
//==========================================================================
|
||||
//
|
||||
// One wall segment in the draw list
|
||||
//
|
||||
//==========================================================================
|
||||
#include "renderstyle.h"
|
||||
#include "textures.h"
|
||||
#include "fcolormap.h"
|
||||
#include "build.h"
|
||||
#include "gamefuncs.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4244)
|
||||
#endif
|
||||
|
||||
struct HWHorizonInfo;
|
||||
struct HWSkyInfo;
|
||||
class FMaterial;
|
||||
struct FTexCoordInfo;
|
||||
struct FSectorPortalGroup;
|
||||
struct FFlatVertex;
|
||||
struct FDynLightData;
|
||||
class VSMatrix;
|
||||
struct FSpriteModelFrame;
|
||||
class FRenderState;
|
||||
struct HWDecal;
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// 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,
|
||||
HWF_NOSLICE = 256
|
||||
};
|
||||
|
||||
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_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;
|
||||
|
||||
ERenderStyle RenderStyle;
|
||||
|
||||
float ViewDistance;
|
||||
float visibility;
|
||||
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
|
||||
FSectorPortalGroup * portal; // stacked sector portals
|
||||
secplane_t * planemirror; // for plane mirrors
|
||||
walltype *lineportal; // line-to-line portals
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// these are not the same as ytop and ybottom!!!
|
||||
float zceil[2];
|
||||
float zfloor[2];
|
||||
|
||||
unsigned int vertindex;
|
||||
unsigned int vertcount;
|
||||
|
||||
public:
|
||||
walltype * seg;
|
||||
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) {}
|
||||
void SkyTop(HWDrawInfo *di, walltype * seg,sectortype * fs,sectortype * bs, FVector2& v1, FVector2& v2) {}
|
||||
void SkyBottom(HWDrawInfo *di, walltype * seg,sectortype * fs,sectortype * bs, FVector2& v1, FVector2& v2) {}
|
||||
|
||||
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);
|
||||
|
||||
//void ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &normal);
|
||||
//void ProcessDecals(HWDrawInfo *di);
|
||||
|
||||
int CreateVertices(FFlatVertex *&ptr, bool nosplit);
|
||||
|
||||
//int CountVertices();
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// One flat plane in the draw list
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class HWFlat
|
||||
{
|
||||
public:
|
||||
sectortype * sec;
|
||||
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;
|
||||
int iboindex;
|
||||
//int vboheight;
|
||||
|
||||
int plane;
|
||||
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();
|
||||
|
||||
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 which = 7 /*SSRF_RENDERALL*/); // cannot use constant due to circular dependencies.
|
||||
|
||||
void DrawSubsectors(HWDrawInfo *di, FRenderState &state);
|
||||
void DrawFlat(HWDrawInfo* di, FRenderState& state, bool translucent);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// One sprite in the draw list
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
||||
class HWSprite
|
||||
{
|
||||
public:
|
||||
int lightlevel;
|
||||
uint8_t foglevel;
|
||||
uint8_t hw_styleflags;
|
||||
bool fullbright;
|
||||
bool polyoffset;
|
||||
FColormap Colormap;
|
||||
FSpriteModelFrame * modelframe;
|
||||
FRenderStyle RenderStyle;
|
||||
int OverrideShader;
|
||||
|
||||
int translation;
|
||||
int index;
|
||||
float depth;
|
||||
int vertexindex;
|
||||
|
||||
float topclip;
|
||||
float bottomclip;
|
||||
|
||||
float x,y,z; // needed for sorting!
|
||||
|
||||
float ul,ur;
|
||||
float vt,vb;
|
||||
float x1,y1,z1;
|
||||
float x2,y2,z2;
|
||||
float trans;
|
||||
int dynlightindex;
|
||||
|
||||
FGameTexture *texture;
|
||||
spritetype * actor;
|
||||
//TArray<lightlist_t> *lightlist;
|
||||
DRotator Angles;
|
||||
|
||||
|
||||
void SplitSprite(HWDrawInfo *di, sectortype * frontsector, bool translucent);
|
||||
void PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, float spriteheight);
|
||||
bool CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp);
|
||||
|
||||
public:
|
||||
|
||||
void CreateVertices(HWDrawInfo* di) {}
|
||||
void PutSprite(HWDrawInfo *di, bool translucent);
|
||||
void Process(HWDrawInfo *di, AActor* thing,sectortype * sector, int thruportal = false);
|
||||
|
||||
void DrawSprite(HWDrawInfo* di, FRenderState& state, bool translucent) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct DecalVertex
|
||||
{
|
||||
float x, y, z;
|
||||
float u, v;
|
||||
};
|
||||
|
||||
/*
|
||||
struct HWDecal
|
||||
{
|
||||
FGameTexture *texture;
|
||||
TArray<lightlist_t> *lightlist;
|
||||
DBaseDecal *decal;
|
||||
DecalVertex dv[4];
|
||||
float zcenter;
|
||||
unsigned int vertindex;
|
||||
|
||||
FRenderStyle renderstyle;
|
||||
int lightlevel;
|
||||
int rellight;
|
||||
float alpha;
|
||||
FColormap Colormap;
|
||||
int dynlightindex;
|
||||
sectortype *frontsector;
|
||||
FVector3 Normal;
|
||||
|
||||
void DrawDecal(HWDrawInfo *di, FRenderState &state);
|
||||
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
inline float Dist2(float x1,float y1,float x2,float y2)
|
||||
{
|
||||
return sqrtf((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
|
||||
}
|
||||
|
||||
bool hw_SetPlaneTextureRotation(const HWSectorPlane * secplane, FGameTexture * gltexture, VSMatrix &mat);
|
||||
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;
|
||||
}
|
||||
|
399
source/core/rendering/scene/hw_flats.cpp
Normal file
399
source/core/rendering/scene/hw_flats.cpp
Normal file
|
@ -0,0 +1,399 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// 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
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (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/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_flat.cpp
|
||||
** Flat processing
|
||||
**
|
||||
*/
|
||||
|
||||
#include "matrix.h"
|
||||
#include "hw_dynlightdata.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "hw_clock.h"
|
||||
#include "hw_material.h"
|
||||
#include "hw_drawinfo.h"
|
||||
#include "flatvertices.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "hw_drawstructs.h"
|
||||
#include "hw_renderstate.h"
|
||||
#include "texturemanager.h"
|
||||
#include "earcut.hpp"
|
||||
|
||||
#ifdef _DEBUG
|
||||
CVAR(Int, gl_breaksec, -1, 0)
|
||||
#endif
|
||||
|
||||
extern PalEntry GlobalMapFog;
|
||||
extern float GlobalFogDensity;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
#if 0
|
||||
void HWFlat::SetupLights(HWDrawInfo *di, FLightNode * node, FDynLightData &lightdata, int portalgroup)
|
||||
{
|
||||
Plane p;
|
||||
|
||||
lightdata.Clear();
|
||||
if (renderstyle == STYLE_Add && !di->Level->lightadditivesurfaces)
|
||||
{
|
||||
dynlightindex = -1;
|
||||
return; // no lights on additively blended surfaces.
|
||||
}
|
||||
while (node)
|
||||
{
|
||||
FDynamicLight * light = node->lightsource;
|
||||
|
||||
if (!light->IsActive())
|
||||
{
|
||||
node = node->nextLight;
|
||||
continue;
|
||||
}
|
||||
iter_dlightf++;
|
||||
|
||||
// we must do the side check here because gl_GetLight needs the correct plane orientation
|
||||
// which we don't have for Legacy-style 3D-floors
|
||||
double planeh = plane.plane.ZatPoint(light->Pos);
|
||||
if ((planeh<light->Z() && ceiling) || (planeh>light->Z() && !ceiling))
|
||||
{
|
||||
node = node->nextLight;
|
||||
continue;
|
||||
}
|
||||
|
||||
p.Set(plane.plane.Normal(), plane.plane.fD());
|
||||
draw_dlightf += GetLight(lightdata, portalgroup, p, light, false);
|
||||
node = node->nextLight;
|
||||
}
|
||||
|
||||
dynlightindex = screen->mLights->UploadLights(lightdata);
|
||||
}
|
||||
#endif
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CalcPlane fixme - this should be stored in the sector, not be recalculated each frame.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static FVector3 CalcNormal(sectortype* sector, int plane)
|
||||
{
|
||||
FVector3 pt[3];
|
||||
|
||||
auto wal = &wall[sector->wallptr];
|
||||
auto wal2 = &wall[wal->point2];
|
||||
|
||||
pt[0] = { (float)WallStartX(wal), (float)WallStartY(wal), 0 };
|
||||
pt[1] = { (float)WallEndX(wal), (float)WallEndY(wal), 0 };
|
||||
PlanesAtPoint(sector, wal->x, wal->y, plane ? &pt[0].Z : nullptr, plane? nullptr : &pt[0].Z);
|
||||
PlanesAtPoint(sector, wal2->x, wal2->y, plane ? &pt[1].Z : nullptr, plane ? nullptr : &pt[1].Z);
|
||||
|
||||
if (pt[0].X == pt[1].X)
|
||||
{
|
||||
if (pt[0].Y == pt[1].Y) return { 0.f, 0.f, plane ? -1.f : 1.f };
|
||||
pt[2].X = pt[0].X + 4;
|
||||
pt[2].Y = pt[0].Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
pt[2].X = pt[0].X;
|
||||
pt[2].Y = pt[0].Y + 4;
|
||||
}
|
||||
PlanesAtPoint(sector, pt[2].X * 16, pt[2].Y * 16, plane ? &pt[2].Z : nullptr, plane ? nullptr : &pt[2].Z);
|
||||
|
||||
auto normal = (pt[2] - pt[0]) ^ (pt[1] - pt[0]);
|
||||
|
||||
if ((pt[2].Z < 0 && !plane) || (pt[2].Z > 0 && plane)) return -pt[2];
|
||||
return pt[2];
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// this should be buffered later.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void HWFlat::MakeVertices()
|
||||
{
|
||||
int numvertices = sec->wallnum;
|
||||
|
||||
TArray<FVector3> points(numvertices, true);
|
||||
using Point = std::pair<float, float>;
|
||||
std::vector<std::vector<Point>> polygon;
|
||||
std::vector<Point>* curPoly;
|
||||
|
||||
polygon.resize(1);
|
||||
curPoly = &polygon.back();
|
||||
|
||||
for (int i = 0; i < numvertices; i++)
|
||||
{
|
||||
auto wal = &wall[sec->wallptr + i];
|
||||
|
||||
float X = WallStartX(wal);
|
||||
float Y = WallStartY(wal);
|
||||
curPoly->push_back(std::make_pair(X, Y));
|
||||
if (wal->point2 != sec->wallptr+i+1 && i < numvertices - 1)
|
||||
{
|
||||
polygon.resize(polygon.size() + 1);
|
||||
curPoly = &polygon.back();
|
||||
}
|
||||
}
|
||||
// Now make sure that the outer boundary is the first polygon by picking a point that's as much to the outside as possible.
|
||||
int outer = 0;
|
||||
float minx = FLT_MAX;
|
||||
float miny = FLT_MAX;
|
||||
for (size_t a = 0; a < polygon.size(); a++)
|
||||
{
|
||||
for (auto& pt : polygon[a])
|
||||
{
|
||||
if (pt.first < minx || (pt.first == minx && pt.second < miny))
|
||||
{
|
||||
minx = pt.first;
|
||||
miny = pt.second;
|
||||
outer = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (outer != 0) std::swap(polygon[0], polygon[outer]);
|
||||
auto indices = mapbox::earcut(polygon);
|
||||
|
||||
int p = 0;
|
||||
for (size_t a = 0; a < polygon.size(); a++)
|
||||
{
|
||||
for (auto& pt : polygon[a])
|
||||
{
|
||||
float planez;
|
||||
PlanesAtPoint(sec, (pt.first * 16), (pt.second * -16), plane ? &planez : nullptr, !plane ? &planez : nullptr);
|
||||
FVector3 point = { pt.first, pt.second, planez };
|
||||
points[p++] = point;
|
||||
}
|
||||
}
|
||||
|
||||
auto ret = screen->mVertexData->AllocVertices(indices.size());
|
||||
auto vp = ret.first;
|
||||
for (auto i : indices)
|
||||
{
|
||||
auto& pt = points[i];
|
||||
vp->SetVertex(pt.X, pt.Z, pt.Y);
|
||||
vp->SetTexCoord(pt.X / 64.f, pt.Y / 64.f); // todo: align
|
||||
vp++;
|
||||
}
|
||||
vertindex = ret.second;
|
||||
vertcount = indices.size();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
|
||||
{
|
||||
if (screen->BuffersArePersistent())
|
||||
{
|
||||
MakeVertices();
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (sec - sector == gl_breaksec)
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
state.SetNormal(CalcNormal(sector, plane));
|
||||
|
||||
// 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;
|
||||
// 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);
|
||||
state.SetSoftLightLevel(255);
|
||||
state.SetLightParms(128.f, 1 / 1000.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.EnableFog(0);
|
||||
state.SetFog(0, 0);
|
||||
state.SetSoftLightLevel(ShadeDiv >= 1 / 1000.f ? 255 - Scale(shade, 255, numshades) : 255);
|
||||
state.SetLightParms(visibility, ShadeDiv / (numshades - 2));
|
||||
}
|
||||
|
||||
// The shade rgb from the tint is ignored here.
|
||||
state.SetColor(PalEntry(255, globalr, globalg, globalb));
|
||||
|
||||
if (translucent)
|
||||
{
|
||||
state.SetRenderStyle(renderstyle);
|
||||
if (!texture->GetTranslucency()) state.AlphaFunc(Alpha_GEqual, gl_mask_threshold);
|
||||
else state.AlphaFunc(Alpha_GEqual, 0.f);
|
||||
}
|
||||
state.SetMaterial(texture, UF_Texture, 0, 0/*flags & 3*/, TRANSLATION(Translation_Remap + curbasepal, palette), -1);
|
||||
|
||||
state.SetLightIndex(dynlightindex);
|
||||
state.Draw(DT_Triangles, vertindex, vertcount);
|
||||
vertexcount += vertcount;
|
||||
|
||||
if (translucent) state.SetRenderStyle(DefaultRenderStyle());
|
||||
//state.SetObjectColor(0xffffffff);
|
||||
//state.SetAddColor(0);
|
||||
//state.ApplyTextureManipulation(nullptr);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// HWFlat::PutFlat
|
||||
//
|
||||
// submit to the renderer
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void HWFlat::PutFlat(HWDrawInfo *di, int whichplane)
|
||||
{
|
||||
if (!screen->BuffersArePersistent()) // should be made static buffer content later (when the logic is working)
|
||||
{
|
||||
#if 0
|
||||
if (di->Level->HasDynamicLights && texture != nullptr && !di->isFullbrightScene() && !(hacktype & (SSRF_PLANEHACK | SSRF_FLOODHACK)))
|
||||
{
|
||||
SetupLights(di, section->lighthead, lightdata, sector->PortalGroup);
|
||||
}
|
||||
#endif
|
||||
MakeVertices();
|
||||
}
|
||||
plane = whichplane;
|
||||
di->AddFlat(this);
|
||||
rendered_flats++;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Process a sector's flats for rendering
|
||||
// This function is only called once per sector.
|
||||
// Subsequent subsectors are just quickly added to the ss_renderflags array
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void HWFlat::ProcessSector(HWDrawInfo *di, sectortype * frontsector, int which)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (frontsector - sector == gl_breaksec)
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
dynlightindex = -1;
|
||||
|
||||
const auto &vp = di->Viewpoint;
|
||||
|
||||
float florz, ceilz;
|
||||
PlanesAtPoint(frontsector, vp.Pos.X * 16.f, vp.Pos.Y * -16.f, &ceilz, &florz);
|
||||
|
||||
fade = lookups.getFade(frontsector->floorpal); // fog is per sector.
|
||||
visibility = sectorVisibility(frontsector);
|
||||
sec = frontsector;
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
// do floors
|
||||
//
|
||||
//
|
||||
//
|
||||
if ((which & SSRF_RENDERFLOOR) && !(frontsector->floorstat & CSTAT_SECTOR_SKY) && florz <= vp.Pos.Z)
|
||||
{
|
||||
// process the original floor first.
|
||||
|
||||
shade = frontsector->floorshade;
|
||||
palette = frontsector->floorpal;
|
||||
|
||||
//port = frontsector->ValidatePortal(sector_t::floor);
|
||||
#if 0
|
||||
if ((stack = (port != NULL)))
|
||||
{
|
||||
alpha = frontsector->GetAlpha(sector_t::floor);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
alpha = 1.0f;
|
||||
|
||||
if (alpha != 0.f)
|
||||
{
|
||||
int tilenum = frontsector->floorpicnum;
|
||||
tileUpdatePicnum(&tilenum, tilenum, 0);
|
||||
texture = tileGetTexture(tilenum);
|
||||
if (texture && texture->isValid())
|
||||
{
|
||||
//iboindex = frontsector->iboindex[sector_t::floor];
|
||||
renderstyle = STYLE_Translucent;
|
||||
PutFlat(di, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
// do ceilings
|
||||
//
|
||||
//
|
||||
//
|
||||
if ((which & SSRF_RENDERCEILING) && !(frontsector->ceilingstat & CSTAT_SECTOR_SKY) && ceilz >= vp.Pos.Z)
|
||||
{
|
||||
// process the original ceiling first.
|
||||
|
||||
shade = frontsector->ceilingshade;
|
||||
palette = frontsector->ceilingpal;
|
||||
|
||||
|
||||
/*
|
||||
port = frontsector->ValidatePortal(sector_t::ceiling);
|
||||
if ((stack = (port != NULL)))
|
||||
{
|
||||
alpha = frontsector->GetAlpha(sector_t::ceiling);
|
||||
}
|
||||
else*/
|
||||
alpha = 1.0f;
|
||||
|
||||
if (alpha != 0.f)
|
||||
{
|
||||
//iboindex = frontsector->iboindex[sector_t::ceiling];
|
||||
|
||||
int tilenum = frontsector->ceilingpicnum;
|
||||
tileUpdatePicnum(&tilenum, tilenum, 0);
|
||||
texture = tileGetTexture(tilenum);
|
||||
if (texture && texture->isValid())
|
||||
{
|
||||
//iboindex = frontsector->iboindex[sector_t::floor];
|
||||
renderstyle = STYLE_Translucent;
|
||||
PutFlat(di, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
406
source/core/rendering/scene/hw_portal.h
Normal file
406
source/core/rendering/scene/hw_portal.h
Normal file
|
@ -0,0 +1,406 @@
|
|||
#pragma once
|
||||
|
||||
#include "tarray.h"
|
||||
#include "hw_drawinfo.h"
|
||||
#include "hw_drawstructs.h"
|
||||
#include "hw_renderstate.h"
|
||||
#include "hw_material.h"
|
||||
|
||||
class FSkyBox;
|
||||
|
||||
struct HWSkyInfo
|
||||
{
|
||||
float x_offset[2];
|
||||
float y_offset; // doubleskies don't have a y-offset
|
||||
FGameTexture * texture[2];
|
||||
FTextureID skytexno1;
|
||||
bool mirrored;
|
||||
bool doublesky;
|
||||
bool sky2;
|
||||
PalEntry fadecolor;
|
||||
|
||||
bool operator==(const HWSkyInfo & inf)
|
||||
{
|
||||
return !memcmp(this, &inf, sizeof(*this));
|
||||
}
|
||||
bool operator!=(const HWSkyInfo & inf)
|
||||
{
|
||||
return !!memcmp(this, &inf, sizeof(*this));
|
||||
}
|
||||
void init(HWDrawInfo *di, int sky1, PalEntry fadecolor);
|
||||
};
|
||||
|
||||
struct HWHorizonInfo
|
||||
{
|
||||
HWSectorPlane plane;
|
||||
int lightlevel;
|
||||
FColormap colormap;
|
||||
PalEntry specialcolor;
|
||||
};
|
||||
|
||||
struct BoundingRect
|
||||
{
|
||||
double left, top, right, bottom;
|
||||
|
||||
BoundingRect() = default;
|
||||
BoundingRect(bool)
|
||||
{
|
||||
setEmpty();
|
||||
}
|
||||
|
||||
void setEmpty()
|
||||
{
|
||||
left = top = FLT_MAX;
|
||||
bottom = right = -FLT_MAX;
|
||||
}
|
||||
|
||||
bool contains(const BoundingRect& other) const
|
||||
{
|
||||
return left <= other.left && top <= other.top && right >= other.right && bottom >= other.bottom;
|
||||
}
|
||||
|
||||
bool contains(double x, double y) const
|
||||
{
|
||||
return left <= x && top <= y && right >= x && bottom >= y;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool contains(const T& vec) const
|
||||
{
|
||||
return left <= vec.X && top <= vec.Y && right >= vec.X && bottom >= vec.Y;
|
||||
}
|
||||
|
||||
bool intersects(const BoundingRect& other) const
|
||||
{
|
||||
return !(other.left > right ||
|
||||
other.right < left ||
|
||||
other.top > bottom ||
|
||||
other.bottom < top);
|
||||
}
|
||||
|
||||
void Union(const BoundingRect& other)
|
||||
{
|
||||
if (other.left < left) left = other.left;
|
||||
if (other.right > right) right = other.right;
|
||||
if (other.top < top) top = other.top;
|
||||
if (other.bottom > bottom) bottom = other.bottom;
|
||||
}
|
||||
|
||||
double distanceTo(const BoundingRect& other) const
|
||||
{
|
||||
if (intersects(other)) return 0;
|
||||
return std::max(std::min(fabs(left - other.right), fabs(right - other.left)),
|
||||
std::min(fabs(top - other.bottom), fabs(bottom - other.top)));
|
||||
}
|
||||
|
||||
void addVertex(double x, double y)
|
||||
{
|
||||
if (x < left) left = x;
|
||||
if (x > right) right = x;
|
||||
if (y < top) top = y;
|
||||
if (y > bottom) bottom = y;
|
||||
}
|
||||
|
||||
bool operator == (const BoundingRect& other) const
|
||||
{
|
||||
return left == other.left && top == other.top && right == other.right && bottom == other.bottom;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct secplane_t
|
||||
{
|
||||
double a, b, c, d, ic;
|
||||
};
|
||||
|
||||
struct FPortalSceneState;
|
||||
|
||||
class HWPortal
|
||||
{
|
||||
friend struct FPortalSceneState;
|
||||
|
||||
enum
|
||||
{
|
||||
STP_Stencil,
|
||||
STP_DepthClear,
|
||||
STP_DepthRestore,
|
||||
STP_AllInOne
|
||||
};
|
||||
|
||||
TArray<unsigned int> mPrimIndices;
|
||||
unsigned int mTopCap = ~0u, mBottomCap = ~0u;
|
||||
|
||||
void DrawPortalStencil(FRenderState &state, int pass);
|
||||
|
||||
public:
|
||||
FPortalSceneState * mState;
|
||||
TArray<HWWall> lines;
|
||||
BoundingRect boundingBox;
|
||||
int planesused = 0;
|
||||
|
||||
HWPortal(FPortalSceneState *s, bool local = false) : mState(s), boundingBox(false)
|
||||
{
|
||||
}
|
||||
virtual ~HWPortal() {}
|
||||
virtual int ClipSeg(walltype *seg, const DVector3 &viewpos) { return PClip_Inside; }
|
||||
virtual int ClipSubsector(sectortype *sub) { return PClip_Inside; }
|
||||
virtual int ClipPoint(const DVector2 &pos) { return PClip_Inside; }
|
||||
virtual walltype *ClipLine() { return nullptr; }
|
||||
virtual void * GetSource() const = 0; // GetSource MUST be implemented!
|
||||
virtual const char *GetName() = 0;
|
||||
virtual bool AllowSSAO() { return true; }
|
||||
virtual bool IsSky() { return false; }
|
||||
virtual bool NeedCap() { return true; }
|
||||
virtual bool NeedDepthBuffer() { return true; }
|
||||
virtual void DrawContents(HWDrawInfo *di, FRenderState &state) = 0;
|
||||
virtual void RenderAttached(HWDrawInfo *di) {}
|
||||
void SetupStencil(HWDrawInfo *di, FRenderState &state, bool usestencil);
|
||||
void RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestencil);
|
||||
|
||||
void AddLine(HWWall * l)
|
||||
{
|
||||
lines.Push(*l);
|
||||
boundingBox.addVertex(l->glseg.x1, l->glseg.y1);
|
||||
boundingBox.addVertex(l->glseg.x2, l->glseg.y2);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct FPortalSceneState
|
||||
{
|
||||
int MirrorFlag = 0;
|
||||
int PlaneMirrorFlag = 0;
|
||||
int renderdepth = 0;
|
||||
|
||||
int PlaneMirrorMode = 0;
|
||||
bool inskybox = 0;
|
||||
|
||||
UniqueList<HWSkyInfo> UniqueSkies;
|
||||
UniqueList<HWHorizonInfo> UniqueHorizons;
|
||||
UniqueList<secplane_t> UniquePlaneMirrors;
|
||||
|
||||
int skyboxrecursion = 0;
|
||||
|
||||
void BeginScene()
|
||||
{
|
||||
UniqueSkies.Clear();
|
||||
UniqueHorizons.Clear();
|
||||
UniquePlaneMirrors.Clear();
|
||||
}
|
||||
|
||||
bool isMirrored() const
|
||||
{
|
||||
return !!((MirrorFlag ^ PlaneMirrorFlag) & 1);
|
||||
}
|
||||
|
||||
void StartFrame();
|
||||
bool RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di, FRenderState &state);
|
||||
void EndFrame(HWDrawInfo *outer_di, FRenderState &state);
|
||||
void RenderPortal(HWPortal *p, FRenderState &state, bool usestencil, HWDrawInfo *outer_di);
|
||||
};
|
||||
|
||||
extern FPortalSceneState portalState;
|
||||
|
||||
|
||||
class HWScenePortalBase : public HWPortal
|
||||
{
|
||||
protected:
|
||||
HWScenePortalBase(FPortalSceneState *state) : HWPortal(state, false)
|
||||
{
|
||||
|
||||
}
|
||||
public:
|
||||
void ClearClipper(HWDrawInfo *di, Clipper *clipper);
|
||||
virtual bool NeedDepthBuffer() { return true; }
|
||||
virtual void DrawContents(HWDrawInfo *di, FRenderState &state)
|
||||
{
|
||||
if (Setup(di, state, di->mClipper))
|
||||
{
|
||||
di->DrawScene(DM_PORTAL);
|
||||
Shutdown(di, state);
|
||||
}
|
||||
else state.ClearScreen();
|
||||
}
|
||||
virtual bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) = 0;
|
||||
virtual void Shutdown(HWDrawInfo *di, FRenderState &rstate) {}
|
||||
};
|
||||
|
||||
struct HWLinePortal : public HWScenePortalBase
|
||||
{
|
||||
// this must be the same as at the start of line_t, so that we can pass in this structure directly to P_ClipLineToPortal.
|
||||
walltype* line;
|
||||
vec2_t *v1, *v2; // vertices, from v1 to v2
|
||||
DVector2 delta; // precalculated v2 - v1 for side checking
|
||||
|
||||
angle_t angv1, angv2; // for quick comparisons with a line or subsector
|
||||
|
||||
HWLinePortal(FPortalSceneState *state, walltype *line) : HWScenePortalBase(state)
|
||||
{
|
||||
this->line = line;
|
||||
v1 = &line->pos;
|
||||
v2 = &wall[line->point2].pos;
|
||||
CalcDelta();
|
||||
}
|
||||
|
||||
void CalcDelta()
|
||||
{
|
||||
//delta = v2->fPos() - v1->fPos();
|
||||
}
|
||||
|
||||
int ClipSeg(walltype *seg, const DVector3 &viewpos) override;
|
||||
int ClipSubsector(sectortype *sub) override;
|
||||
int ClipPoint(const DVector2 &pos);
|
||||
bool NeedCap() override { return false; }
|
||||
};
|
||||
|
||||
struct HWMirrorPortal : public HWLinePortal
|
||||
{
|
||||
|
||||
protected:
|
||||
bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) override;
|
||||
void Shutdown(HWDrawInfo *di, FRenderState &rstate) override;
|
||||
void * GetSource() const override { return line; }
|
||||
const char *GetName() override;
|
||||
|
||||
public:
|
||||
|
||||
HWMirrorPortal(FPortalSceneState *state, walltype * line)
|
||||
: HWLinePortal(state, line)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct HWLineToLinePortal : public HWLinePortal
|
||||
{
|
||||
protected:
|
||||
bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) override;
|
||||
virtual void * GetSource() const override { return line; }
|
||||
virtual const char *GetName() override;
|
||||
virtual walltype *ClipLine() override { return line; }
|
||||
virtual void RenderAttached(HWDrawInfo *di) override;
|
||||
|
||||
public:
|
||||
|
||||
HWLineToLinePortal(FPortalSceneState *state, walltype *ll)
|
||||
: HWLinePortal(state, ll)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct HWSkyboxPortal : public HWScenePortalBase
|
||||
{
|
||||
bool oldclamp;
|
||||
int old_pm;
|
||||
spritetype * portal;
|
||||
|
||||
protected:
|
||||
bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) override;
|
||||
void Shutdown(HWDrawInfo *di, FRenderState &rstate) override;
|
||||
virtual void * GetSource() const { return portal; }
|
||||
virtual bool IsSky() { return true; }
|
||||
virtual const char *GetName();
|
||||
virtual bool AllowSSAO() override;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
HWSkyboxPortal(FPortalSceneState *state, spritetype * pt) : HWScenePortalBase(state)
|
||||
{
|
||||
portal = pt;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct HWSectorStackPortal : public HWScenePortalBase
|
||||
{
|
||||
TArray<sectortype *> sectors;
|
||||
protected:
|
||||
bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) override;
|
||||
void Shutdown(HWDrawInfo *di, FRenderState &rstate) override;
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual bool IsSky() { return true; } // although this isn't a real sky it can be handled as one.
|
||||
virtual const char *GetName();
|
||||
FSectorPortalGroup *origin;
|
||||
|
||||
public:
|
||||
|
||||
HWSectorStackPortal(FPortalSceneState *state, FSectorPortalGroup *pt) : HWScenePortalBase(state)
|
||||
{
|
||||
origin = pt;
|
||||
}
|
||||
void SetupCoverage(HWDrawInfo *di);
|
||||
void AddSector(sectortype *sub)
|
||||
{
|
||||
sectors.Push(sub);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct HWPlaneMirrorPortal : public HWScenePortalBase
|
||||
{
|
||||
int old_pm;
|
||||
protected:
|
||||
bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) override;
|
||||
void Shutdown(HWDrawInfo *di, FRenderState &rstate) override;
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual const char *GetName();
|
||||
secplane_t * origin;
|
||||
|
||||
public:
|
||||
|
||||
HWPlaneMirrorPortal(FPortalSceneState *state, secplane_t * pt) : HWScenePortalBase(state)
|
||||
{
|
||||
origin = pt;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct HWHorizonPortal : public HWPortal
|
||||
{
|
||||
HWHorizonInfo * origin;
|
||||
unsigned int voffset;
|
||||
unsigned int vcount;
|
||||
friend struct HWEEHorizonPortal;
|
||||
|
||||
protected:
|
||||
virtual void DrawContents(HWDrawInfo *di, FRenderState &state);
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual bool NeedDepthBuffer() { return false; }
|
||||
virtual bool NeedCap() { return false; }
|
||||
virtual const char *GetName();
|
||||
|
||||
public:
|
||||
|
||||
HWHorizonPortal(FPortalSceneState *state, HWHorizonInfo * pt, FRenderViewpoint &vp, bool local = false);
|
||||
};
|
||||
|
||||
struct HWSkyPortal : public HWPortal
|
||||
{
|
||||
HWSkyInfo * origin;
|
||||
FSkyVertexBuffer *vertexBuffer;
|
||||
friend struct HWEEHorizonPortal;
|
||||
|
||||
protected:
|
||||
virtual void DrawContents(HWDrawInfo *di, FRenderState &state);
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual bool IsSky() { return true; }
|
||||
virtual bool NeedDepthBuffer() { return false; }
|
||||
virtual const char *GetName();
|
||||
|
||||
public:
|
||||
|
||||
|
||||
HWSkyPortal(FSkyVertexBuffer *vertexbuffer, FPortalSceneState *state, HWSkyInfo * pt, bool local = false)
|
||||
: HWPortal(state, local)
|
||||
{
|
||||
origin = pt;
|
||||
vertexBuffer = vertexbuffer;
|
||||
}
|
||||
|
||||
};
|
1105
source/core/rendering/scene/hw_walls.cpp
Normal file
1105
source/core/rendering/scene/hw_walls.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -512,7 +512,7 @@ void dbLoadMap(const char *pPath, int *pX, int *pY, int *pZ, short *pAngle, shor
|
|||
#endif
|
||||
|
||||
#ifdef USE_OPENGL
|
||||
Polymost_prepare_loadboard();
|
||||
Polymost::Polymost_prepare_loadboard();
|
||||
#endif
|
||||
|
||||
FString mapname = pPath;
|
||||
|
|
|
@ -724,7 +724,7 @@ void GameInterface::SerializeGameState(FSerializer& arc)
|
|||
viewSetErrorMessage("");
|
||||
Net_ClearFifo();
|
||||
paused = 0;
|
||||
Polymost_prepare_loadboard();
|
||||
Polymost::Polymost_prepare_loadboard();
|
||||
Mus_ResumeSaved();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,10 @@ Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au)
|
|||
#include "dukeactor.h"
|
||||
#include "interpolate.h"
|
||||
|
||||
// temporary hack to pass along RRRA's global fog. Needs to be done better later.
|
||||
extern PalEntry GlobalMapFog;
|
||||
extern float GlobalFogDensity;
|
||||
|
||||
|
||||
BEGIN_DUKE_NS
|
||||
|
||||
|
@ -491,6 +495,8 @@ void displayrooms(int snum, double smoothratio)
|
|||
sect = p->cursectnum;
|
||||
if (sect < 0 || sect >= MAXSECTORS) return;
|
||||
|
||||
GlobalMapFog = fogactive ? 0x999999 : 0;
|
||||
GlobalFogDensity = fogactive ? 350.f : 0.f;
|
||||
GLInterface.SetMapFog(fogactive != 0);
|
||||
DoInterpolations(smoothratio / 65536.);
|
||||
|
||||
|
|
|
@ -51,7 +51,14 @@
|
|||
#include "gamestruct.h"
|
||||
#include "gl_models.h"
|
||||
|
||||
CVAR(Bool, gl_texture, true, 0)
|
||||
CVARD(Bool, hw_hightile, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable hightile texture rendering")
|
||||
bool hw_int_useindexedcolortextures;
|
||||
CUSTOM_CVARD(Bool, hw_useindexedcolortextures, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable indexed color texture rendering")
|
||||
{
|
||||
if (screen) screen->SetTextureFilterMode();
|
||||
}
|
||||
|
||||
EXTERN_CVAR(Bool, gl_texture)
|
||||
|
||||
F2DDrawer twodpsp;
|
||||
static int BufferLock = 0;
|
||||
|
@ -182,6 +189,7 @@ bool PolymostRenderState::Apply(FRenderState& state, GLState& oldState)
|
|||
else
|
||||
{
|
||||
state.EnableFog(0);
|
||||
state.SetFog(0, 0);
|
||||
state.SetSoftLightLevel(ShadeDiv >= 1 / 1000.f ? 255 - Scale(Shade, 255, numshades) : 255);
|
||||
state.SetLightParms(VisFactor, ShadeDiv / (numshades - 2));
|
||||
}
|
||||
|
@ -382,6 +390,11 @@ void renderSetVisibility(float vis)
|
|||
vp.mGlobVis = vis;
|
||||
}
|
||||
|
||||
void renderSetViewpoint(float x, float y, float z)
|
||||
{
|
||||
vp.mCameraPos = {x, z, y, 0};
|
||||
}
|
||||
|
||||
void renderBeginScene()
|
||||
{
|
||||
assert(BufferLock == 0);
|
||||
|
@ -519,8 +532,6 @@ void markTileForPrecache(int tilenum, int palnum)
|
|||
}
|
||||
}
|
||||
|
||||
void polymost_precache(int32_t dapicnum, int32_t dapalnum, int32_t datype);
|
||||
|
||||
void precacheMarkedTiles()
|
||||
{
|
||||
decltype(cachemap)::Iterator it(cachemap);
|
||||
|
@ -529,7 +540,7 @@ void precacheMarkedTiles()
|
|||
{
|
||||
int dapicnum = pair->Key & 0x7fffffff;
|
||||
int dapalnum = pair->Key >> 32;
|
||||
polymost_precache(dapicnum, dapalnum, 0);
|
||||
Polymost::polymost_precache(dapicnum, dapalnum, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,12 +21,6 @@ class F2DDrawer;
|
|||
struct palette_t;
|
||||
extern int xdim, ydim;
|
||||
|
||||
enum
|
||||
{
|
||||
DM_MAINVIEW,
|
||||
DM_OFFSCREEN
|
||||
};
|
||||
|
||||
class PaletteManager
|
||||
{
|
||||
IHardwareTexture* palettetextures[256] = {};
|
||||
|
@ -293,12 +287,6 @@ public:
|
|||
renderState.NPOTEmulation.X = xOffset;
|
||||
}
|
||||
|
||||
void SetFadeDisable(bool yes)
|
||||
{
|
||||
if (yes) renderState.Flags |= RF_FogDisabled;
|
||||
else renderState.Flags &= ~RF_FogDisabled;
|
||||
}
|
||||
|
||||
// Hack...
|
||||
bool useMapFog = false;
|
||||
|
||||
|
@ -345,6 +333,7 @@ extern F2DDrawer twodpsp;
|
|||
void renderSetProjectionMatrix(const float* p);
|
||||
void renderSetViewMatrix(const float* p);
|
||||
void renderSetVisibility(float v);
|
||||
void renderSetViewpoint(float x, float y, float z);
|
||||
void renderBeginScene();
|
||||
void renderFinishScene();
|
||||
void DrawRateStuff();
|
||||
|
|
Loading…
Reference in a new issue