Merge commit '9406e6d2adc4a8a70e28fd4167ca6f0bac33a7ce' into whaven

This commit is contained in:
Christoph Oelckers 2021-03-19 00:42:44 +01:00
commit df85d3277d
37 changed files with 6161 additions and 771 deletions

View file

@ -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/.+")

View file

@ -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"

View file

@ -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_); }

View file

@ -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

View file

@ -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))
{

View file

@ -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

View file

@ -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));
}

View file

@ -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

View file

@ -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]);
}
}
}

View file

@ -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 ----------------------------------------

View file

@ -9,7 +9,6 @@
class FRenderState;
struct secplane_t;
struct subsector_t;
struct FFlatVertex
{

View file

@ -4,8 +4,6 @@
#include "tarray.h"
#include "vectors.h"
struct FLevelLocals;
namespace hwrenderer
{

View file

@ -45,7 +45,6 @@
#include "hw_shadowmap.h"
struct sector_t;
struct FPortalSceneState;
class FSkyVertexBuffer;
class IIndexBuffer;

View file

@ -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

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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();

View 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();
}

View 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);

View 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 = &sector[wal->nextsector];
sectortype* frontsector = &sector[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], &sector[bunch->sectnum], wall[i].nextsector<0? nullptr : &sector[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 = &sector[sectnum];
bool inbunch;
angle_t startangle;
SetupFlat.Clock();
HWFlat flat;
flat.ProcessSector(di, &sector[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);
}
}

View 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);
};

View 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);
}
}

View 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

View 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);
}
*/

View 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);

View 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();
}

View 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;
} ;

View 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
}

View 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;
}

View 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);
}
}
}
}

View 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;
}
};

File diff suppressed because it is too large Load diff

View file

@ -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;

View file

@ -724,7 +724,7 @@ void GameInterface::SerializeGameState(FSerializer& arc)
viewSetErrorMessage("");
Net_ClearFifo();
paused = 0;
Polymost_prepare_loadboard();
Polymost::Polymost_prepare_loadboard();
Mus_ResumeSaved();
}
}

View file

@ -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.);

View file

@ -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);
}
}

View file

@ -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();