Merge commit 'a5ed7ba8a3eb26d3e3aa46bc87044608eacba57f' into whaven

This commit is contained in:
Christoph Oelckers 2021-04-10 17:00:43 +02:00
commit aedb17e539
104 changed files with 1844 additions and 1739 deletions

View file

@ -1075,7 +1075,6 @@ set (FASTMATH_SOURCES ${FASTMATH_SOURCES})
set (PCH_SOURCES
glbackend/glbackend.cpp
glbackend/gl_palmanager.cpp
glbackend/gl_texture.cpp
thirdparty/src/md4.cpp
@ -1086,7 +1085,6 @@ set (PCH_SOURCES
build/src/engine.cpp
build/src/mdsprite.cpp
build/src/polymost.cpp
build/src/voxmodel.cpp
core/movie/playmve.cpp
core/automap.cpp
@ -1134,6 +1132,8 @@ set (PCH_SOURCES
core/rendering/hw_entrypoint.cpp
core/rendering/hw_models.cpp
core/rendering/hw_voxels.cpp
core/rendering/hw_palmanager.cpp
core/rendering/scene/hw_clipper.cpp
core/rendering/scene/hw_walls.cpp
core/rendering/scene/hw_flats.cpp

View file

@ -200,7 +200,7 @@ enum {
PALETTE_TRANSLUC = 1<<2,
};
EXTERN int32_t g_visibility, parallaxvisibility;
EXTERN int32_t g_visibility;
// blendtable[1] to blendtable[numalphatabs] are considered to be
// alpha-blending tables:
@ -269,12 +269,6 @@ extern FixedBitArray<MAXSECTORS> gotsector;
extern uint32_t drawlinepat;
extern int32_t novoxmips;
extern int16_t tiletovox[MAXTILES];
extern int32_t voxscale[MAXVOXELS];
extern char g_haveVoxels;
extern uint8_t globalr, globalg, globalb;
enum {
@ -362,10 +356,6 @@ void engineLoadBoard(const char *filename, int flags, vec3_t *dapos, int16_t *da
void loadMapBackup(const char* filename);
void G_LoadMapHack(const char* filename, const unsigned char*);
int32_t qloadkvx(int32_t voxindex, const char *filename);
void vox_undefine(int32_t const);
void vox_deinit();
void videoSetCorrectedAspect();
void videoSetViewableArea(int32_t x1, int32_t y1, int32_t x2, int32_t y2);
void renderSetAspect(int32_t daxrange, int32_t daaspect);
@ -448,7 +438,6 @@ inline int32_t ksqrt(uint32_t num)
}
int32_t getangle(int32_t xvect, int32_t yvect);
fixed_t gethiq16angle(int32_t xvect, int32_t yvect);
inline constexpr uint32_t uhypsq(int32_t const dx, int32_t const dy)
{
@ -598,7 +587,6 @@ int32_t md_setmisc(int32_t modelid, float scale, int32_t shadeoff, float zadd, f
EXTERN int32_t nextvoxid;
EXTERN int8_t voxreserve[(MAXVOXELS+7)>>3];
EXTERN int8_t voxrotate[(MAXVOXELS+7)>>3];
#ifdef USE_OPENGL
// TODO: dynamically allocate this
@ -628,13 +616,7 @@ inline int32_t md_tilehasmodel(int32_t const tilenume, int32_t const pal)
}
#endif // defined USE_OPENGL
inline int tilehasmodelorvoxel(int const tilenume, int pal)
{
UNREFERENCED_PARAMETER(pal);
return
(mdinited && hw_models && tile2model[Ptile2tile(tilenume, pal)].modelid != -1) ||
(r_voxels && tiletovox[tilenume] != -1);
}
int tilehasmodelorvoxel(int const tilenume, int pal);
int32_t md_defineframe(int32_t modelid, const char *framename, int32_t tilenume,
int32_t skinnum, float smoothduration, int32_t pal);
@ -647,7 +629,7 @@ int32_t md_definehud (int32_t modelid, int32_t tilex, vec3f_t add,
int32_t md_undefinetile(int32_t tile);
int32_t md_undefinemodel(int32_t modelid);
int32_t loaddefinitionsfile(const char *fn, bool loadadds = false);
int32_t loaddefinitionsfile(const char *fn, bool loadadds = false, bool cumulative = false);
#ifdef USE_OPENGL
# include "polymost.h"
@ -735,9 +717,6 @@ extern int32_t(*insertsprite_replace)(int16_t sectnum, int16_t statnum);
extern int32_t(*deletesprite_replace)(int16_t spritenum);
extern int32_t(*changespritesect_replace)(int16_t spritenum, int16_t newsectnum);
extern int32_t(*changespritestat_replace)(int16_t spritenum, int16_t newstatnum);
#ifdef USE_OPENGL
extern void(*PolymostProcessVoxels_Callback)(void);
#endif
// Masking these into the object index to keep it in 16 bit was probably the single most dumbest and pointless thing Build ever did.
// Gonna be fun to globally replace these to finally lift the limit this imposes on map size.

View file

@ -1,43 +0,0 @@
#pragma once
// nobody uses these. What's so cool about naked numbers? :(
#if 0
// system defines for status bits
#define CEILING_STAT_PLAX BIT(0)
#define CEILING_STAT_SLOPE BIT(1)
#define CEILING_STAT_SWAPXY BIT(2)
#define CEILING_STAT_SMOOSH BIT(3)
#define CEILING_STAT_XFLIP BIT(4)
#define CEILING_STAT_YFLIP BIT(5)
#define CEILING_STAT_RELATIVE BIT(6)
#define CEILING_STAT_TYPE_MASK (BIT(7)|BIT(8))
#define CEILING_STAT_MASKED BIT(7)
#define CEILING_STAT_TRANS BIT(8)
#define CEILING_STAT_TRANS_FLIP (BIT(7)|BIT(8))
#define CEILING_STAT_FAF_BLOCK_HITSCAN BIT(15)
#define FLOOR_STAT_PLAX BIT(0)
#define FLOOR_STAT_SLOPE BIT(1)
#define FLOOR_STAT_SWAPXY BIT(2)
#define FLOOR_STAT_SMOOSH BIT(3)
#define FLOOR_STAT_XFLIP BIT(4)
#define FLOOR_STAT_YFLIP BIT(5)
#define FLOOR_STAT_RELATIVE BIT(6)
#define FLOOR_STAT_TYPE_MASK (BIT(7)|BIT(8))
#define FLOOR_STAT_MASKED BIT(7)
#define FLOOR_STAT_TRANS BIT(8)
#define FLOOR_STAT_TRANS_FLIP (BIT(7)|BIT(8))
#define FLOOR_STAT_FAF_BLOCK_HITSCAN BIT(15)
#define CSTAT_WALL_BLOCK BIT(0)
#define CSTAT_WALL_BOTTOM_SWAP BIT(1)
#define CSTAT_WALL_ALIGN_BOTTOM BIT(2)
#define CSTAT_WALL_XFLIP BIT(3)
#define CSTAT_WALL_MASKED BIT(4)
#define CSTAT_WALL_1WAY BIT(5)
#define CSTAT_WALL_BLOCK_HITSCAN BIT(6)
#define CSTAT_WALL_TRANSLUCENT BIT(7)
#define CSTAT_WALL_YFLIP BIT(8)
#define CSTAT_WALL_TRANS_FLIP BIT(9)
#define CSTAT_WALL_BLOCK_ACTOR (BIT(14)) // my def
#define CSTAT_WALL_WARP_HITSCAN (BIT(15)) // my def
#endif

View file

@ -177,25 +177,6 @@ struct md3model_t : public idmodel_t
*/
};
#define VOXBORDWIDTH 1 //use 0 to save memory, but has texture artifacts; 1 looks better...
#define VOXUSECHAR 0
#if (VOXUSECHAR != 0)
typedef struct { uint8_t x, y, z, u, v; } vert_t;
#else
typedef struct { uint16_t x, y, z, u, v; } vert_t;
#endif
typedef struct { vert_t v[4]; } voxrect_t;
struct voxmodel_t : public mdmodel_t
{
FVoxelModel* model = nullptr;
vec3_t siz;
vec3f_t piv;
int32_t is8bit;
};
EXTERN mdmodel_t **models;
FGameTexture* mdloadskin(idmodel_t* m, int32_t number, int32_t pal, int32_t surf, bool* exact);
@ -206,11 +187,6 @@ EXTERN void md3_vox_calcmat_common(tspriteptr_t tspr, const vec3f_t *a0, float f
EXTERN int32_t mdpause;
EXTERN int32_t nextmodelid;
EXTERN voxmodel_t *voxmodels[MAXVOXELS];
void voxfree(voxmodel_t *m);
voxmodel_t *voxload(int lumpnum);
int32_t polymost_voxdraw(voxmodel_t *m, tspriteptr_t const tspr, bool rotate);
#endif // defined USE_OPENGL

View file

@ -32,7 +32,6 @@ void polymost_deletesprite(int num);
int32_t polymost_maskWallHasTranslucency(walltype const * const wall);
int32_t polymost_spriteHasTranslucency(spritetype const * const tspr);
int32_t polymost_spriteIsModelOrVoxel(spritetype const * const tspr);
void polymost_glreset(void);
void polymost_scansector(int32_t sectnum);

View file

@ -113,12 +113,6 @@ inline void scriptfile_close(scriptfile *sf)
delete sf;
}
inline int32_t scriptfile_addsymbolvalue(scriptfile *sf, char const *name, int32_t val)
{
sf->AddSymbol(name, val);
return 1;
}
typedef struct
{
const char *text;

View file

@ -17,11 +17,8 @@
#include "gamecontrol.h"
#include "palettecontainer.h"
#include "mapinfo.h"
int tileSetHightileReplacement(int picnum, int palnum, const char* filename, float alphacut, float xscale, float yscale, float specpower, float specfactor, uint8_t flags);
int tileSetSkybox(int picnum, int palnum, const char** facenames, int flags);
void tileRemoveReplacement(int num);
#include "hw_voxels.h"
#include "parsefuncs.h"
int32_t getatoken(scriptfile *sf, const tokenlist *tl, int32_t ntokens)
{
@ -39,68 +36,6 @@ int32_t getatoken(scriptfile *sf, const tokenlist *tl, int32_t ntokens)
}
void AddUserMapHack(usermaphack_t&);
#if 0
// For later
{
if (sc.Compare("music"))
{
FString id, mus;
sc.MustGetToken('{');
while (!sc.CheckToken('}'))
{
sc.MustGetToken(TK_Identifier);
if (sc.Compare("id"))
{
sc.MustGetString();
id = sc.String;
}
else if (sc.Compare("file"))
{
sc.MustGetString();
mus = sc.String;
}
}
if (!SetMusicForMap(id, mus, true))
{
sc.ScriptError("Map %s not found in music definition", id.GetChars());
}
char* tokenPtr = pScript->ltextptr;
char* musicID = NULL;
char* fileName = NULL;
char* musicEnd;
if (scriptfile_getbraces(pScript, &musicEnd))
break;
while (pScript->textptr < musicEnd)
{
switch (getatoken(pScript, soundTokens, countof(soundTokens)))
{
case T_ID: scriptfile_getstring(pScript, &musicID); break;
case T_FILE: scriptfile_getstring(pScript, &fileName); break;
}
}
if (!firstPass)
{
if (musicID == NULL)
{
pos.Message(MSG_ERROR, "missing ID for music definition\n");
break;
}
if (fileName == NULL || fileSystem.FileExists(fileName))
break;
if (S_DefineMusic(musicID, fileName) == -1)
pos.Message(MSG_ERROR, "invalid music ID");
}
}
}
#endif
enum scripttoken_t
{
@ -388,186 +323,44 @@ static int32_t defsparser(scriptfile *script)
break;
}
case T_INCLUDEDEFAULT:
{
defsparser_include(G_DefaultDefFile(), script, &pos);
break;
}
case T_DEFINE:
{
FString name;
int32_t number;
if (scriptfile_getstring(script,&name)) break;
if (scriptfile_getsymbol(script,&number)) break;
if (scriptfile_addsymbolvalue(script, name,number) < 0)
pos.Message(MSG_WARNING, "Warning: Symbol %s was NOT redefined to %d", name.GetChars(),number);
break;
}
// OLD (DEPRECATED) DEFINITION SYNTAX
case T_DEFINETEXTURE:
{
int32_t tile,pal,fnoo;
FString fn;
if (scriptfile_getsymbol(script,&tile)) break;
if (scriptfile_getsymbol(script,&pal)) break;
if (scriptfile_getnumber(script,&fnoo)) break; //x-center
if (scriptfile_getnumber(script,&fnoo)) break; //y-center
if (scriptfile_getnumber(script,&fnoo)) break; //x-size
if (scriptfile_getnumber(script,&fnoo)) break; //y-size
if (scriptfile_getstring(script,&fn)) break;
if (!fileSystem.FileExists(fn))
break;
tileSetHightileReplacement(tile,pal,fn,-1.0,1.0,1.0,1.0,1.0,0);
}
break;
case T_DEFINESKYBOX:
{
int32_t tile,pal,i;
FString fn[6];
int happy = 1;
if (scriptfile_getsymbol(script,&tile)) break;
if (scriptfile_getsymbol(script,&pal)) break;
if (scriptfile_getsymbol(script,&i)) break; //future expansion
for (i=0; i<6; i++)
{
if (scriptfile_getstring(script,&fn[i])) break; //grab the 6 faces
if (!fileSystem.FileExists(fn[i]))
happy = 0;
}
if (i < 6 || !happy) break;
tileSetSkybox(tile, pal, (const char **)fn, 0);
}
break;
case T_DEFINETINT:
{
int32_t pal, r,g,b,f;
if (scriptfile_getsymbol(script,&pal)) break;
if (scriptfile_getnumber(script,&r)) break;
if (scriptfile_getnumber(script,&g)) break;
if (scriptfile_getnumber(script,&b)) break;
if (scriptfile_getnumber(script,&f)) break; //effects
lookups.setPaletteTint(pal,r,g,b,0,0,0,f);
}
break;
case T_ALPHAHACK:
{
int32_t tile;
double alpha;
if (scriptfile_getsymbol(script,&tile)) break;
if (scriptfile_getdouble(script,&alpha)) break;
if ((uint32_t)tile < MAXTILES)
TileFiles.tiledata[tile].texture->alphaThreshold = (float)alpha;
}
break;
case T_ALPHAHACKRANGE:
{
int32_t tilenume1,tilenume2;
double alpha;
if (scriptfile_getsymbol(script,&tilenume1)) break;
if (scriptfile_getsymbol(script,&tilenume2)) break;
if (scriptfile_getdouble(script,&alpha)) break;
if (check_tile_range("alphahackrange", &tilenume1, &tilenume2, script, pos))
break;
for (int i=tilenume1; i<=tilenume2; i++)
TileFiles.tiledata[i].texture->alphaThreshold = (float)alpha;
}
case T_LOADGRP:
case T_CACHESIZE:
case T_SHADEFACTOR:
case T_GLOBALGAMEFLAGS:
parseSkip<1>(*script, pos);
break;
case T_SPRITECOL:
{
int32_t tile,col,col2;
if (scriptfile_getsymbol(script,&tile)) break;
if (scriptfile_getnumber(script,&col)) break;
if (scriptfile_getnumber(script,&col2)) break;
}
case T_2DCOLIDXRANGE: // NOTE: takes precedence over 2dcol, see InitCustomColors()
parseSkip<3>(*script, pos);
break;
case T_2DCOL:
{
int32_t col,b,g,r;
if (scriptfile_getnumber(script,&col)) break;
if (scriptfile_getnumber(script,&r)) break;
if (scriptfile_getnumber(script,&g)) break;
if (scriptfile_getnumber(script,&b)) break;
if ((unsigned)col < 256)
{
}
}
parseSkip<4>(*script, pos);
break;
case T_2DCOLIDXRANGE: // NOTE: takes precedence over 2dcol, see InitCustomColors()
{
int32_t col, idx, idxend;
if (scriptfile_getnumber(script,&col)) break;
if (scriptfile_getnumber(script,&idx)) break;
if (scriptfile_getnumber(script,&idxend)) break;
}
case T_DEFINE:
parseDefine(*script, pos);
break;
case T_DEFINETEXTURE:
parseDefineTexture(*script, pos);
break;
case T_DEFINESKYBOX:
parseDefineSkybox(*script, pos);
break;
case T_DEFINETINT:
parseDefineTint(*script, pos);
break;
case T_ALPHAHACK:
parseAlphahack(*script, pos);
break;
case T_ALPHAHACKRANGE:
parseAlphahackRange(*script, pos);
break;
case T_FOGPAL:
{
int32_t p,r,g,b;
if (scriptfile_getsymbol(script,&p)) break;
if (scriptfile_getnumber(script,&r)) break;
if (scriptfile_getnumber(script,&g)) break;
if (scriptfile_getnumber(script,&b)) break;
r = clamp(r, 0, 63);
g = clamp(g, 0, 63);
b = clamp(b, 0, 63);
lookups.makeTable(p, NULL, r<<2, g<<2, b<<2, 1);
}
parseFogpal(*script, pos);
break;
case T_NOFLOORPALRANGE:
{
int32_t b,e,i;
if (scriptfile_getsymbol(script,&b)) break;
if (scriptfile_getsymbol(script,&e)) break;
b = max(b, 1);
e = min(e, MAXPALOOKUPS-1);
for (i = b; i <= e; i++)
lookups.tables[i].noFloorPal = true;
}
break;
case T_LOADGRP:
{
scriptfile_getstring(script,nullptr);
#if 0
if (!scriptfile_getstring(pScript, &fileName) && firstPass)
{
fileSystem.AddAdditionalFile(fileName);
}
#endif
}
break;
case T_CACHESIZE:
{
int32_t j;
if (scriptfile_getnumber(script,&j)) break;
}
break;
case T_SHADEFACTOR:
//scriptfile_getnumber(script, &realmaxshade);
//frealmaxshade = (float)realmaxshade;
parseNoFloorpalRange(*script, pos);
break;
case T_ARTFILE:
{
@ -609,59 +402,17 @@ static int32_t defsparser(scriptfile *script)
}
break;
case T_SETUPTILE:
{
int tile, tmp;
parseSetupTile(*script, pos);
break;
if (scriptfile_getsymbol(script,&tile)) break;
if (check_tile("setuptile", tile, script, pos))
break;
auto& tiled = TileFiles.tiledata[tile];
if (scriptfile_getsymbol(script,&tmp)) break; // XXX
tiled.h_xsize = tmp;
if (scriptfile_getsymbol(script,&tmp)) break;
tiled.h_ysize = tmp;
if (scriptfile_getsymbol(script,&tmp)) break;
tiled.h_xoffs = tmp;
if (scriptfile_getsymbol(script,&tmp)) break;
tiled.h_yoffs = tmp;
break;
}
case T_SETUPTILERANGE:
{
int tile1,tile2,xsiz,ysiz,xoffs,yoffs,i;
if (scriptfile_getsymbol(script,&tile1)) break;
if (scriptfile_getsymbol(script,&tile2)) break;
if (scriptfile_getnumber(script,&xsiz)) break;
if (scriptfile_getnumber(script,&ysiz)) break;
if (scriptfile_getsymbol(script,&xoffs)) break;
if (scriptfile_getsymbol(script,&yoffs)) break;
if (check_tile_range("setuptilerange", &tile1, &tile2, script, pos))
parseSetupTileRange(*script, pos);
break;
for (i=tile1; i<=tile2; i++)
{
auto& tiled = TileFiles.tiledata[i];
tiled.h_xsize = xsiz;
tiled.h_ysize = ysiz;
tiled.h_xoffs = xoffs;
tiled.h_yoffs = yoffs;
}
break;
}
case T_ANIMTILERANGE:
{
SetAnim set;
if (scriptfile_getsymbol(script,&set.tile1)) break;
if (scriptfile_getsymbol(script,&set.tile2)) break;
if (scriptfile_getsymbol(script,&set.speed)) break;
if (scriptfile_getsymbol(script,&set.type)) break;
processSetAnim("animtilerange", pos, set);
parseAnimTileRange(*script, pos);
break;
}
case T_TILEFROMTEXTURE:
{
auto texturepos = scriptfile_getposition(script);
@ -1117,7 +868,7 @@ static int32_t defsparser(scriptfile *script)
break;
}
if (qloadkvx(nextvoxid, fn))
if (voxDefine(nextvoxid, fn))
{
Printf("Failure loading voxel file \"%s\"\n",fn.GetChars());
break;
@ -1588,7 +1339,7 @@ static int32_t defsparser(scriptfile *script)
break;
}
if (qloadkvx(nextvoxid, fn))
if (voxDefine(nextvoxid, fn))
{
voxelpos.Message(MSG_ERROR, "Failure loading voxel file \"%s\"",fn.GetChars());
break;
@ -1629,14 +1380,14 @@ static int32_t defsparser(scriptfile *script)
{
double scale=1.0;
scriptfile_getdouble(script,&scale);
voxscale[lastvoxid] = (int32_t)(65536*scale);
voxscale[lastvoxid] = (float)scale;
if (voxmodels[lastvoxid])
voxmodels[lastvoxid]->scale = scale;
break;
}
case T_ROTATE:
voxrotate[lastvoxid>>3] |= (1 << (lastvoxid&7));
voxrotate.Set(lastvoxid);
break;
}
}
@ -1644,68 +1395,7 @@ static int32_t defsparser(scriptfile *script)
}
break;
case T_SKYBOX:
{
auto skyboxpos = scriptfile_getposition(script);
FString fn[6];
FScanner::SavedPos modelend;
int32_t i, tile = -1, pal = 0, happy = 1;
int flags = 0;
static const tokenlist skyboxtokens[] =
{
{ "tile" ,T_TILE },
{ "pal" ,T_PAL },
{ "ft" ,T_FRONT },{ "front" ,T_FRONT },{ "forward",T_FRONT },
{ "rt" ,T_RIGHT },{ "right" ,T_RIGHT },
{ "bk" ,T_BACK },{ "back" ,T_BACK },
{ "lf" ,T_LEFT },{ "left" ,T_LEFT },{ "lt" ,T_LEFT },
{ "up" ,T_TOP },{ "top" ,T_TOP },{ "ceiling",T_TOP },{ "ceil" ,T_TOP },
{ "dn" ,T_BOTTOM },{ "bottom" ,T_BOTTOM },{ "floor" ,T_BOTTOM },{ "down" ,T_BOTTOM },
{ "nocompress", T_NOCOMPRESS },
{ "nodownsize", T_NODOWNSIZE },
{ "forcefilter", T_FORCEFILTER },
{ "artquality", T_ARTQUALITY },
};
if (scriptfile_getbraces(script,&modelend)) break;
while (!scriptfile_endofblock(script, modelend))
{
switch (getatoken(script,skyboxtokens,countof(skyboxtokens)))
{
//case T_ERROR: Printf("Error on line %s:%d in skybox tokens\n",script->filename,linenum); break;
case T_TILE:
scriptfile_getsymbol(script,&tile); break;
case T_PAL:
scriptfile_getsymbol(script,&pal); break;
case T_FRONT:
scriptfile_getstring(script,&fn[0]); break;
case T_RIGHT:
scriptfile_getstring(script,&fn[1]); break;
case T_BACK:
scriptfile_getstring(script,&fn[2]); break;
case T_LEFT:
scriptfile_getstring(script,&fn[3]); break;
case T_TOP:
scriptfile_getstring(script,&fn[4]); break;
case T_BOTTOM:
scriptfile_getstring(script,&fn[5]); break;
}
}
if (tile < 0) skyboxpos.Message(MSG_ERROR, "skybox: missing 'tile number'"), happy=0;
for (i=0; i<6; i++)
{
if (fn[i].IsEmpty()) skyboxpos.Message(MSG_ERROR, "skybox: missing '%s filename'", skyfaces[i]), happy = 0;
// FIXME?
if (!fileSystem.FileExists(fn[i]))
happy = 0;
}
if (!happy) break;
const char* fns[] = { fn[0].GetChars(), fn[1].GetChars(), fn[2].GetChars(), fn[3].GetChars(), fn[4].GetChars(), fn[5].GetChars() };
tileSetSkybox(tile, pal, fns, flags);
}
parseSkybox(*script, pos);
break;
case T_HIGHPALOOKUP:
{
@ -1914,190 +1604,7 @@ static int32_t defsparser(scriptfile *script)
}
break;
case T_TEXTURE:
{
FScanner::SavedPos textureend;
int32_t tile=-1, token;
static const tokenlist texturetokens[] =
{
{ "pal", T_PAL },
{ "detail", T_DETAIL },
{ "glow", T_GLOW },
{ "specular",T_SPECULAR },
{ "normal", T_NORMAL },
};
if (scriptfile_getsymbol(script,&tile)) break;
if (scriptfile_getbraces(script,&textureend)) break;
while (!scriptfile_endofblock(script, textureend))
{
token = getatoken(script,texturetokens,countof(texturetokens));
switch (token)
{
case T_PAL:
{
auto palpos = scriptfile_getposition(script);
FScanner::SavedPos palend;
int32_t pal=-1, xsiz = 0, ysiz = 0;
FString fn;
double alphacut = -1.0, xscale = 1.0, yscale = 1.0, specpower = 1.0, specfactor = 1.0;
uint8_t flags = 0;
static const tokenlist texturetokens_pal[] =
{
{ "file", T_FILE },{ "name", T_FILE },
{ "alphacut", T_ALPHACUT },
{ "detailscale", T_XSCALE }, { "scale", T_XSCALE }, { "xscale", T_XSCALE }, { "intensity", T_XSCALE },
{ "yscale", T_YSCALE },
{ "specpower", T_SPECPOWER }, { "specularpower", T_SPECPOWER }, { "parallaxscale", T_SPECPOWER },
{ "specfactor", T_SPECFACTOR }, { "specularfactor", T_SPECFACTOR }, { "parallaxbias", T_SPECFACTOR },
{ "nocompress", T_NOCOMPRESS },
{ "nodownsize", T_NODOWNSIZE },
{ "forcefilter", T_FORCEFILTER },
{ "artquality", T_ARTQUALITY },
{ "orig_sizex", T_ORIGSIZEX }, { "orig_sizey", T_ORIGSIZEY }
};
if (scriptfile_getsymbol(script,&pal)) break;
if (scriptfile_getbraces(script,&palend)) break;
while (!scriptfile_endofblock(script, palend))
{
switch (getatoken(script,texturetokens_pal,countof(texturetokens_pal)))
{
case T_FILE:
scriptfile_getstring(script,&fn); break;
case T_ALPHACUT:
scriptfile_getdouble(script,&alphacut); break;
case T_XSCALE:
scriptfile_getdouble(script,&xscale); break;
case T_YSCALE:
scriptfile_getdouble(script,&yscale); break;
case T_SPECPOWER:
scriptfile_getdouble(script,&specpower); break;
case T_SPECFACTOR:
scriptfile_getdouble(script,&specfactor); break;
case T_ORIGSIZEX:
scriptfile_getnumber(script, &xsiz);
break;
case T_ORIGSIZEY:
scriptfile_getnumber(script, &ysiz);
break;
default:
break;
}
}
if ((unsigned)tile >= MAXUSERTILES) break; // message is printed later
if ((unsigned)pal >= MAXPALOOKUPS - RESERVEDPALS)
{
palpos.Message(MSG_ERROR, "missing or invalid 'palette number' for texture definition");
break;
}
if (fn.IsEmpty())
{
palpos.Message(MSG_ERROR, "missing 'file name' for texture definition");
break;
}
if (!fileSystem.FileExists(fn))
{
palpos.Message(MSG_ERROR, "%s not found in replacement for tile %d", fn.GetChars(), tile);
break;
}
if (xsiz > 0 && ysiz > 0)
{
tileSetDummy(tile, xsiz, ysiz);
}
xscale = 1.0f / xscale;
yscale = 1.0f / yscale;
tileSetHightileReplacement(tile,pal,fn,alphacut,xscale,yscale, specpower, specfactor,flags);
}
break;
case T_DETAIL: case T_GLOW: case T_SPECULAR: case T_NORMAL:
{
auto detailpos = scriptfile_getposition(script);
FScanner::SavedPos detailend;
int32_t pal = 0;
char flags = 0;
FString fn;
double xscale = 1.0, yscale = 1.0, specpower = 1.0, specfactor = 1.0;
static const tokenlist texturetokens_pal[] =
{
{ "file", T_FILE },{ "name", T_FILE },
{ "alphacut", T_ALPHACUT },
{ "detailscale", T_XSCALE }, { "scale", T_XSCALE }, { "xscale", T_XSCALE }, { "intensity", T_XSCALE },
{ "yscale", T_YSCALE },
{ "specpower", T_SPECPOWER }, { "specularpower", T_SPECPOWER }, { "parallaxscale", T_SPECPOWER },
{ "specfactor", T_SPECFACTOR }, { "specularfactor", T_SPECFACTOR }, { "parallaxbias", T_SPECFACTOR },
{ "nocompress", T_NOCOMPRESS },
{ "nodownsize", T_NODOWNSIZE },
{ "forcefilter", T_FORCEFILTER },
{ "artquality", T_ARTQUALITY },
};
if (scriptfile_getbraces(script,&detailend)) break;
while (!scriptfile_endofblock(script, detailend))
{
switch (getatoken(script,texturetokens_pal,countof(texturetokens_pal)))
{
case T_FILE:
scriptfile_getstring(script,&fn); break;
case T_XSCALE:
scriptfile_getdouble(script,&xscale); break;
case T_YSCALE:
scriptfile_getdouble(script,&yscale); break;
case T_SPECPOWER:
scriptfile_getdouble(script,&specpower); break;
case T_SPECFACTOR:
scriptfile_getdouble(script,&specfactor); break;
default:
break;
}
}
if ((unsigned)tile >= MAXUSERTILES) break; // message is printed later
if (fn.IsEmpty())
{
detailpos.Message(MSG_ERROR, "missing 'file name' for texture definition");
break;
}
if (!fileSystem.FileExists(fn))
break;
switch (token)
{
case T_DETAIL:
pal = DETAILPAL;
xscale = 1.0f / xscale;
yscale = 1.0f / yscale;
break;
case T_GLOW:
pal = GLOWPAL;
break;
case T_SPECULAR:
pal = SPECULARPAL;
break;
case T_NORMAL:
pal = NORMALPAL;
break;
}
tileSetHightileReplacement(tile,pal,fn,-1.0f,xscale,yscale, specpower, specfactor,flags);
}
break;
default:
break;
}
}
if ((unsigned)tile >= MAXUSERTILES)
{
pos.Message(MSG_ERROR, "missing or invalid 'tile number' for texture definition");
break;
}
}
parseTexture(*script, pos);
break;
case T_UNDEFMODEL:
@ -2290,13 +1797,6 @@ static int32_t defsparser(scriptfile *script)
}
break;
case T_GLOBALGAMEFLAGS:
{
int32_t dummy;
if (scriptfile_getnumber(script,&dummy)) break;
}
break;
case T_MULTIPSKY:
{
FScanner::SavedPos blockend;
@ -3159,7 +2659,7 @@ static int32_t defsparser(scriptfile *script)
break;
FStringf name("%s.%s", resName.GetChars(), resType.GetChars());
fileSystem.CreatePathlessCopy(resName, resID, 0);
fileSystem.CreatePathlessCopy(name, resID, 0);
}
break;
@ -3172,34 +2672,44 @@ static int32_t defsparser(scriptfile *script)
return 0;
}
int32_t loaddefinitionsfile(const char *fn, bool loadadds)
int32_t loaddefinitionsfile(const char *fn, bool loadadds, bool cumulative)
{
scriptfile *script;
script = scriptfile_fromfile(fn);
if (script)
bool done = false;
auto parseit = [&](int lump)
{
Printf(PRINT_NONOTIFY, "Loading \"%s\"\n",fn);
FScanner sc;
sc.OpenLumpNum(lump);
sc.SetNoOctals(true);
sc.SetNoFatalErrors(true);
defsparser(&sc);
done = true;
Printf(PRINT_NONOTIFY, "\n");
};
defsparser(script);
if (!cumulative)
{
int lump = fileSystem.FindFile(fn);
if (lump >= 0)
{
Printf(PRINT_NONOTIFY, "Loading \"%s\"\n", fn);
parseit(lump);
}
}
else
{
int lump, lastlump = 0;
while ((lump = fileSystem.FindLumpFullName(fn, &lastlump)) >= 0)
{
Printf(PRINT_NONOTIFY, "Loading \"%s\"\n", fileSystem.GetFileFullPath(lump).GetChars());
parseit(lump);
}
}
if (userConfig.AddDefs && loadadds) for (auto& m : *userConfig.AddDefs)
{
Printf("Loading module \"%s\"\n",m.GetChars());
defsparser_include(m, NULL, NULL); // Q: should we let the external script see our symbol table?
}
if (script)
scriptfile_close(script);
if (!script) return -1;
defsparser_include(m, nullptr, nullptr); // Q: should we let the external script see our symbol table?
Printf(PRINT_NONOTIFY, "\n");
}
return 0;
}
// vim:ts=4:

View file

@ -32,6 +32,7 @@
#include "gamecontrol.h"
#include "rendering/render.h"
#include "gamefuncs.h"
#include "hw_voxels.h"
#ifdef USE_OPENGL
# include "mdsprite.h"
@ -53,18 +54,6 @@ uint8_t globalr = 255, globalg = 255, globalb = 255;
int16_t pskybits_override = -1;
// This was on the cache but is permanently allocated, so put it into something static. This needs some rethinking anyway
static TArray<TArray<uint8_t>> voxelmemory;
int16_t tiletovox[MAXTILES];
int voxlumps[MAXVOXELS];
char g_haveVoxels;
//#define kloadvoxel loadvoxel
int32_t novoxmips = 1;
int32_t voxscale[MAXVOXELS];
static int32_t beforedrawrooms = 1;
int32_t globalflags;
@ -73,7 +62,6 @@ static int8_t tempbuf[MAXWALLS];
static int32_t no_radarang2 = 0;
static int16_t radarang[1280];
static int32_t qradarang[10240];
const char *engineerrstr = "No error";
@ -151,7 +139,6 @@ fixed_t qglobalang;
int32_t globalpal, globalfloorpal, cosglobalang, singlobalang;
int32_t cosviewingrangeglobalang, sinviewingrangeglobalang;
int32_t xyaspect;
int32_t viewingrangerecip;
static int32_t globalxpanning, globalypanning;
@ -227,11 +214,6 @@ static int32_t engineLoadTables(void)
for (i=0; i<640; i++)
radarang[1279-i] = -radarang[i];
for (i=0; i<5120; i++)
qradarang[i] = FloatToFixed(atan((5119.5 - i) / 1280.) * (-64. / BAngRadian));
for (i=0; i<5120; i++)
qradarang[10239-i] = -qradarang[i];
tablesloaded = 1;
}
@ -671,26 +653,8 @@ int32_t enginePreInit(void)
//
int32_t engineInit(void)
{
if (engineLoadTables())
return 1;
xyaspect = -1;
voxelmemory.Reset();
for (int i=0; i<MAXTILES; i++)
tiletovox[i] = -1;
for (auto& v : voxscale) v = 65536;
memset(voxrotate, 0, sizeof(voxrotate));
paletteloaded = 0;
engineLoadTables();
g_visibility = 512;
parallaxvisibility = 512;
GPalette.Init(MAXPALOOKUPS + 1); // one slot for each translation, plus a separate one for the base palettes.
gi->loadPalette();
if (!mdinited) mdinit();
return 0;
}
@ -750,80 +714,6 @@ void initspritelists(void)
Numsprites = 0;
}
//
// qloadkvx
//
int32_t qloadkvx(int32_t voxindex, const char *filename)
{
if ((unsigned)voxindex >= MAXVOXELS)
return -1;
auto fil = fileSystem.OpenFileReader(filename);
if (!fil.isOpen())
return -1;
int32_t lengcnt = 0;
const int32_t lengtot = fil.GetLength();
for (bssize_t i=0; i<MAXVOXMIPS; i++)
{
int32_t dasiz = fil.ReadInt32();
voxelmemory.Reserve(1);
voxelmemory.Last() = fil.Read(dasiz);
lengcnt += dasiz+4;
if (lengcnt >= lengtot-768)
break;
}
if (voxmodels[voxindex])
{
voxfree(voxmodels[voxindex]);
voxmodels[voxindex] = NULL;
}
voxlumps[voxindex] = fileSystem.FindFile(filename);
g_haveVoxels = 1;
return 0;
}
void vox_undefine(int32_t const tile)
{
int voxindex = tiletovox[tile];
if (voxindex < 0)
return;
if (voxmodels[voxindex])
{
voxfree(voxmodels[voxindex]);
voxmodels[voxindex] = NULL;
}
voxscale[voxindex] = 65536;
voxrotate[voxindex>>3] &= ~(1 << (voxindex&7));
tiletovox[tile] = -1;
// TODO: nextvoxid
}
void vox_deinit()
{
for (auto &vox : voxmodels)
{
voxfree(vox);
vox = nullptr;
}
}
//
// inside
//
@ -977,26 +867,6 @@ int32_t getangle(int32_t xvect, int32_t yvect)
return rv;
}
fixed_t gethiq16angle(int32_t xvect, int32_t yvect)
{
fixed_t rv;
if ((xvect | yvect) == 0)
rv = 0;
else if (xvect == 0)
rv = IntToFixed(512 + ((yvect < 0) << 10));
else if (yvect == 0)
rv = IntToFixed(((xvect < 0) << 10));
else if (xvect == yvect)
rv = IntToFixed(256 + ((xvect < 0) << 10));
else if (xvect == -yvect)
rv = IntToFixed(768 + ((xvect > 0) << 10));
else if (abs(xvect) > abs(yvect))
rv = ((qradarang[5120 + Scale(1280, yvect, xvect)] >> 6) + IntToFixed(((xvect < 0) << 10))) & 0x7FFFFFF;
else rv = ((qradarang[5120 - Scale(1280, xvect, yvect)] >> 6) + IntToFixed(512 + ((yvect < 0) << 10))) & 0x7FFFFFF;
return rv;
}
// Gets the BUILD unit height and z offset of a sprite.
// Returns the z offset, 'height' may be NULL.
@ -1865,3 +1735,10 @@ void alignflorslope(int16_t dasect, int32_t x, int32_t y, int32_t z)
}
int tilehasmodelorvoxel(int const tilenume, int pal)
{
UNREFERENCED_PARAMETER(pal);
return
(mdinited && hw_models && tile2model[Ptile2tile(tilenume, pal)].modelid != -1) ||
(r_voxels && tiletovox[tilenume] != -1);
}

View file

@ -16,6 +16,7 @@
#include "texturemanager.h"
#include "hw_renderstate.h"
#include "printf.h"
#include "hw_voxels.h"
#include "../../glbackend/glbackend.h"
static int32_t curextra=MAXTILES;
@ -23,6 +24,7 @@ static int32_t curextra=MAXTILES;
#define MIN_CACHETIME_PRINT 10
using namespace Polymost;
int32_t polymost_voxdraw(voxmodel_t* m, tspriteptr_t const tspr, bool rotate);
static int32_t addtileP(int32_t model,int32_t tile,int32_t pallet)
{
@ -1538,6 +1540,11 @@ int32_t polymost_mddraw(tspriteptr_t tspr)
return 0;
}
void voxfree(voxmodel_t* m)
{
if (m) delete m;
}
static void mdfree(mdmodel_t *vm)
{
if (vm->mdnum == 1) { voxfree((voxmodel_t *)vm); return; }

View file

@ -26,6 +26,7 @@ Ken Silverman's official web site: http://www.advsys.net/ken
#include "hw_drawinfo.h"
#include "gamestruct.h"
#include "gamestruct.h"
#include "hw_voxels.h"
typedef struct {
@ -35,11 +36,13 @@ typedef struct {
} vec3d_t;
static_assert(sizeof(vec3d_t) == sizeof(double) * 3);
int32_t xyaspect = -1;
int skiptile = -1;
FGameTexture* GetSkyTexture(int basetile, int lognumtiles, const int16_t* tilemap, int remap = 0);
int32_t polymost_voxdraw(voxmodel_t* m, tspriteptr_t const tspr, bool rotate);
int checkTranslucentReplacement(FTextureID picnum, int pal);
@ -2719,9 +2722,9 @@ void polymost_drawsprite(int32_t snum)
if ((globalorientation & 48) != 48) // only non-voxel sprites should do this
{
int const flag = hw_hightile && TileFiles.tiledata[globalpicnum].h_xsize;
off = { (int32_t)tspr->xoffset + (flag ? TileFiles.tiledata[globalpicnum].h_xoffs : tileLeftOffset(globalpicnum)),
(int32_t)tspr->yoffset + (flag ? TileFiles.tiledata[globalpicnum].h_yoffs : tileTopOffset(globalpicnum)) };
int const flag = hw_hightile && TileFiles.tiledata[globalpicnum].hiofs.xsize;
off = { (int32_t)tspr->xoffset + (flag ? TileFiles.tiledata[globalpicnum].hiofs.xoffs : tileLeftOffset(globalpicnum)),
(int32_t)tspr->yoffset + (flag ? TileFiles.tiledata[globalpicnum].hiofs.yoffs : tileTopOffset(globalpicnum)) };
}
int32_t method = DAMETH_MASK | DAMETH_CLAMPED;
@ -2750,14 +2753,14 @@ void polymost_drawsprite(int32_t snum)
if ((tspr->cstat & 48) != 48 && tiletovox[tspr->picnum] >= 0 && voxmodels[tiletovox[tspr->picnum]])
{
int num = tiletovox[tspr->picnum];
if (polymost_voxdraw(voxmodels[num], tspr, voxrotate[num>>3] & (1<<(num&7)))) return;
if (polymost_voxdraw(voxmodels[num], tspr, voxrotate[num])) return;
break; // else, render as flat sprite
}
if ((tspr->cstat & 48) == 48 && tspr->picnum < MAXVOXELS && voxmodels[tspr->picnum])
{
int num = tspr->picnum;
polymost_voxdraw(voxmodels[tspr->picnum], tspr, voxrotate[num >> 3] & (1 << (num & 7)));
polymost_voxdraw(voxmodels[tspr->picnum], tspr, voxrotate[num]);
return;
}
}
@ -2781,8 +2784,8 @@ void polymost_drawsprite(int32_t snum)
vec2_t tsiz;
if (hw_hightile && TileFiles.tiledata[globalpicnum].h_xsize)
tsiz = { TileFiles.tiledata[globalpicnum].h_xsize, TileFiles.tiledata[globalpicnum].h_ysize };
if (hw_hightile && TileFiles.tiledata[globalpicnum].hiofs.xsize)
tsiz = { TileFiles.tiledata[globalpicnum].hiofs.xsize, TileFiles.tiledata[globalpicnum].hiofs.ysize };
else
tsiz = { tileWidth(globalpicnum), tileHeight(globalpicnum) };
@ -3312,7 +3315,7 @@ void renderPrepareMirror(int32_t dax, int32_t day, int32_t daz, fixed_t daang, f
*tposx = (x << 1) + Scale(dx, i, j) - dax;
*tposy = (y << 1) + Scale(dy, i, j) - day;
*tang = ((gethiq16angle(dx, dy) << 1) - daang) & 0x7FFFFFF;
*tang = ((bvectangbam(dx, dy).asq16() << 1) - daang) & 0x7FFFFFF;
inpreparemirror = 1;
@ -3494,6 +3497,23 @@ static void sortsprites(int const start, int const end)
}
}
static 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]);
}
//
// drawmasks
//
@ -3817,4 +3837,151 @@ void renderSetAspect(int32_t daxrange, int32_t daaspect)
xdimscale = Scale(320, xyaspect, xdimen);
}
//Draw voxel model as perfect cubes
int32_t polymost_voxdraw(voxmodel_t* m, tspriteptr_t const tspr, bool rotate)
{
float f, g, k0, zoff;
if ((intptr_t)m == (intptr_t)(-1)) // hackhackhack
return 0;
if ((tspr->cstat & 48) == 32)
return 0;
if ((tspr->cstat & CSTAT_SPRITE_MDLROTATE) || rotate)
{
int myclock = (PlayClock << 3) + MulScale(4 << 3, pm_smoothratio, 16);
tspr->ang = (tspr->ang + myclock) & 2047; // will be applied in md3_vox_calcmat_common.
}
vec3f_t m0 = { m->scale, m->scale, m->scale };
vec3f_t a0 = { 0, 0, m->zadd * m->scale };
k0 = m->bscale / 64.f;
f = (float)tspr->xrepeat * (256.f / 320.f) * k0;
if ((sprite[tspr->owner].cstat & 48) == 16)
{
f *= 1.25f;
a0.y -= tspr->xoffset * bcosf(spriteext[tspr->owner].angoff, -20);
a0.x += tspr->xoffset * bsinf(spriteext[tspr->owner].angoff, -20);
}
if (globalorientation & 8) { m0.z = -m0.z; a0.z = -a0.z; } //y-flipping
if (globalorientation & 4) { m0.x = -m0.x; a0.x = -a0.x; a0.y = -a0.y; } //x-flipping
m0.x *= f; a0.x *= f; f = -f;
m0.y *= f; a0.y *= f;
f = (float)tspr->yrepeat * k0;
m0.z *= f; a0.z *= f;
k0 = (float)(tspr->z + spriteext[tspr->owner].position_offset.z);
f = ((globalorientation & 8) && (sprite[tspr->owner].cstat & 48) != 0) ? -4.f : 4.f;
k0 -= (tspr->yoffset * tspr->yrepeat) * f * m->bscale;
zoff = m->siz.z * .5f;
if (!(tspr->cstat & 128))
zoff += m->piv.z;
else if ((tspr->cstat & 48) != 48)
{
zoff += m->piv.z;
zoff -= m->siz.z * .5f;
}
if (globalorientation & 8) zoff = m->siz.z - zoff;
f = (65536.f * 512.f) / ((float)xdimen * viewingrange);
g = 32.f / ((float)xdimen * Polymost::gxyaspect);
int const shadowHack = !!(tspr->clipdist & TSPR_FLAGS_MDHACK);
m0.y *= f; a0.y = (((float)(tspr->x + spriteext[tspr->owner].position_offset.x - globalposx)) * (1.f / 1024.f) + a0.y) * f;
m0.x *= -f; a0.x = (((float)(tspr->y + spriteext[tspr->owner].position_offset.y - globalposy)) * -(1.f / 1024.f) + a0.x) * -f;
m0.z *= g; a0.z = (((float)(k0 - globalposz - shadowHack)) * -(1.f / 16384.f) + a0.z) * g;
float mat[16];
md3_vox_calcmat_common(tspr, &a0, f, mat);
//Mirrors
if (Polymost::grhalfxdown10x < 0)
{
mat[0] = -mat[0];
mat[4] = -mat[4];
mat[8] = -mat[8];
mat[12] = -mat[12];
}
if (shadowHack)
{
GLInterface.SetDepthFunc(DF_LEqual);
}
int winding = ((Polymost::grhalfxdown10x >= 0) ^ ((globalorientation & 8) != 0) ^ ((globalorientation & 4) != 0)) ? Winding_CW : Winding_CCW;
GLInterface.SetCull(Cull_Back, winding);
float pc[4];
pc[0] = pc[1] = pc[2] = 1.f;
if (!shadowHack)
{
pc[3] = (tspr->cstat & 2) ? glblend[tspr->blend].def[!!(tspr->cstat & 512)].alpha : 1.0f;
pc[3] *= 1.0f - spriteext[tspr->owner].alpha;
SetRenderStyleFromBlend(!!(tspr->cstat & 2), tspr->blend, !!(tspr->cstat & 512));
if (!(tspr->cstat & 2) || spriteext[tspr->owner].alpha > 0.f || pc[3] < 1.0f)
GLInterface.EnableBlend(true); // else GLInterface.EnableBlend(false);
}
else pc[3] = 1.f;
GLInterface.SetShade(std::max(0, globalshade), numshades);
//------------
//transform to Build coords
float omat[16];
memcpy(omat, mat, sizeof(omat));
f = 1.f / 64.f;
g = m0.x * f; mat[0] *= g; mat[1] *= g; mat[2] *= g;
g = m0.y * f; mat[4] = omat[8] * g; mat[5] = omat[9] * g; mat[6] = omat[10] * g;
g = -m0.z * f; mat[8] = omat[4] * g; mat[9] = omat[5] * g; mat[10] = omat[6] * g;
//
mat[12] -= (m->piv.x * mat[0] + m->piv.y * mat[4] + zoff * mat[8]);
mat[13] -= (m->piv.x * mat[1] + m->piv.y * mat[5] + zoff * mat[9]);
mat[14] -= (m->piv.x * mat[2] + m->piv.y * mat[6] + zoff * mat[10]);
//
//Let OpenGL (and perhaps hardware :) handle the matrix rotation
mat[3] = mat[7] = mat[11] = 0.f; mat[15] = 1.f;
for (int i = 0; i < 15; i++) mat[i] *= 1024.f;
// Adjust to backend coordinate system being used by the vertex buffer.
for (int i = 4; i < 8; i++)
{
float f = mat[i];
mat[i] = -mat[i + 4];
mat[i + 4] = -f;
}
GLInterface.SetMatrix(Matrix_Model, mat);
int palId = TRANSLATION(Translation_Remap + curbasepal, globalpal);
GLInterface.SetPalswap(globalpal);
GLInterface.SetFade(sector[tspr->sectnum].floorpal);
auto tex = TexMan.GetGameTexture(m->model->GetPaletteTexture());
GLInterface.SetTexture(tex, TRANSLATION(Translation_Remap + curbasepal, globalpal), CLAMP_NOFILTER_XY, true);
GLInterface.SetModel(m->model, 0, 0, 0);
GLInterface.Draw(DT_Triangles, 0, 0);
GLInterface.SetModel(nullptr, 0, 0, 0);
GLInterface.SetCull(Cull_None);
if (shadowHack)
{
GLInterface.SetDepthFunc(DF_Less);
}
GLInterface.SetIdentityMatrix(Matrix_Model);
return 1;
}

View file

@ -1,230 +0,0 @@
//--------------------------------------- VOX LIBRARY BEGINS ---------------------------------------
#ifdef USE_OPENGL
#include "compat.h"
#include "build.h"
#include "engine_priv.h"
#include "polymost.h"
#include "mdsprite.h"
#include "v_video.h"
#include "flatvertices.h"
#include "hw_renderstate.h"
#include "texturemanager.h"
#include "voxels.h"
#include "gamecontrol.h"
#include "hw_models.h"
#include "printf.h"
#include "palette.h"
#include "../../glbackend/glbackend.h"
using namespace Polymost;
void voxfree(voxmodel_t *m)
{
if (m) delete m;
}
voxmodel_t *voxload(int lumpnum)
{
FVoxel* voxel = R_LoadKVX(lumpnum);
if (voxel != nullptr)
{
voxmodel_t* vm = new voxmodel_t;
*vm = {};
auto pivot = voxel->Mips[0].Pivot;
vm->mdnum = 1; //VOXel model id
vm->scale = vm->bscale = 1.f;
vm->piv.x = float(pivot.X);
vm->piv.y = float(pivot.Y);
vm->piv.z = float(pivot.Z);
vm->siz.x = voxel->Mips[0].SizeX;
vm->siz.y = voxel->Mips[0].SizeY;
vm->siz.z = voxel->Mips[0].SizeZ;
vm->is8bit = true;
voxel->Mips[0].Pivot.Zero(); // Needs to be taken out of the voxel data because it gets baked into the vertex buffer which we cannot use here.
vm->model = new FVoxelModel(voxel, true);
return vm;
}
return nullptr;
}
//Draw voxel model as perfect cubes
int32_t polymost_voxdraw(voxmodel_t* m, tspriteptr_t const tspr, bool rotate)
{
float f, g, k0, zoff;
if ((intptr_t)m == (intptr_t)(-1)) // hackhackhack
return 0;
if ((tspr->cstat & 48) == 32)
return 0;
if ((tspr->cstat & CSTAT_SPRITE_MDLROTATE) || rotate)
{
int myclock = (PlayClock << 3) + MulScale(4 << 3, pm_smoothratio, 16);
tspr->ang = (tspr->ang + myclock) & 2047; // will be applied in md3_vox_calcmat_common.
}
vec3f_t m0 = { m->scale, m->scale, m->scale };
vec3f_t a0 = { 0, 0, m->zadd*m->scale };
k0 = m->bscale / 64.f;
f = (float) tspr->xrepeat * (256.f/320.f) * k0;
if ((sprite[tspr->owner].cstat&48)==16)
{
f *= 1.25f;
a0.y -= tspr->xoffset * bcosf(spriteext[tspr->owner].angoff, -20);
a0.x += tspr->xoffset * bsinf(spriteext[tspr->owner].angoff, -20);
}
if (globalorientation&8) { m0.z = -m0.z; a0.z = -a0.z; } //y-flipping
if (globalorientation&4) { m0.x = -m0.x; a0.x = -a0.x; a0.y = -a0.y; } //x-flipping
m0.x *= f; a0.x *= f; f = -f;
m0.y *= f; a0.y *= f;
f = (float) tspr->yrepeat * k0;
m0.z *= f; a0.z *= f;
k0 = (float) (tspr->z+spriteext[tspr->owner].position_offset.z);
f = ((globalorientation&8) && (sprite[tspr->owner].cstat&48)!=0) ? -4.f : 4.f;
k0 -= (tspr->yoffset*tspr->yrepeat)*f*m->bscale;
zoff = m->siz.z*.5f;
if (!(tspr->cstat&128))
zoff += m->piv.z;
else if ((tspr->cstat&48) != 48)
{
zoff += m->piv.z;
zoff -= m->siz.z*.5f;
}
if (globalorientation&8) zoff = m->siz.z-zoff;
f = (65536.f*512.f) / ((float)xdimen*viewingrange);
g = 32.f / ((float)xdimen*gxyaspect);
int const shadowHack = !!(tspr->clipdist & TSPR_FLAGS_MDHACK);
m0.y *= f; a0.y = (((float)(tspr->x+spriteext[tspr->owner].position_offset.x-globalposx)) * (1.f/1024.f) + a0.y) * f;
m0.x *=-f; a0.x = (((float)(tspr->y+spriteext[tspr->owner].position_offset.y-globalposy)) * -(1.f/1024.f) + a0.x) * -f;
m0.z *= g; a0.z = (((float)(k0 -globalposz - shadowHack)) * -(1.f/16384.f) + a0.z) * g;
float mat[16];
md3_vox_calcmat_common(tspr, &a0, f, mat);
//Mirrors
if (grhalfxdown10x < 0)
{
mat[0] = -mat[0];
mat[4] = -mat[4];
mat[8] = -mat[8];
mat[12] = -mat[12];
}
if (shadowHack)
{
GLInterface.SetDepthFunc(DF_LEqual);
}
int winding = ((grhalfxdown10x >= 0) ^ ((globalorientation & 8) != 0) ^ ((globalorientation & 4) != 0)) ? Winding_CW : Winding_CCW;
GLInterface.SetCull(Cull_Back, winding);
float pc[4];
pc[0] = pc[1] = pc[2] = 1.f;
if (!shadowHack)
{
pc[3] = (tspr->cstat & 2) ? glblend[tspr->blend].def[!!(tspr->cstat & 512)].alpha : 1.0f;
pc[3] *= 1.0f - spriteext[tspr->owner].alpha;
SetRenderStyleFromBlend(!!(tspr->cstat & 2), tspr->blend, !!(tspr->cstat & 512));
if (!(tspr->cstat & 2) || spriteext[tspr->owner].alpha > 0.f || pc[3] < 1.0f)
GLInterface.EnableBlend(true); // else GLInterface.EnableBlend(false);
}
else pc[3] = 1.f;
GLInterface.SetShade(std::max(0, globalshade), numshades);
//------------
//transform to Build coords
float omat[16];
memcpy(omat, mat, sizeof(omat));
f = 1.f/64.f;
g = m0.x*f; mat[0] *= g; mat[1] *= g; mat[2] *= g;
g = m0.y*f; mat[4] = omat[8]*g; mat[5] = omat[9]*g; mat[6] = omat[10]*g;
g =-m0.z*f; mat[8] = omat[4]*g; mat[9] = omat[5]*g; mat[10] = omat[6]*g;
//
mat[12] -= (m->piv.x*mat[0] + m->piv.y*mat[4] + zoff*mat[8]);
mat[13] -= (m->piv.x*mat[1] + m->piv.y*mat[5] + zoff*mat[9]);
mat[14] -= (m->piv.x*mat[2] + m->piv.y*mat[6] + zoff*mat[10]);
//
//Let OpenGL (and perhaps hardware :) handle the matrix rotation
mat[3] = mat[7] = mat[11] = 0.f; mat[15] = 1.f;
for (int i = 0; i < 15; i++) mat[i] *= 1024.f;
// Adjust to backend coordinate system being used by the vertex buffer.
for (int i = 4; i < 8; i++)
{
float f = mat[i];
mat[i] = -mat[i + 4];
mat[i + 4] = -f;
}
GLInterface.SetMatrix(Matrix_Model, mat);
int palId = TRANSLATION(Translation_Remap + curbasepal, globalpal);
GLInterface.SetPalswap(globalpal);
GLInterface.SetFade(sector[tspr->sectnum].floorpal);
auto tex = TexMan.GetGameTexture(m->model->GetPaletteTexture());
GLInterface.SetTexture(tex, TRANSLATION(Translation_Remap + curbasepal, globalpal), CLAMP_NOFILTER_XY, true);
GLInterface.SetModel(m->model, 0, 0, 0);
GLInterface.Draw(DT_Triangles, 0, 0);
GLInterface.SetModel(nullptr, 0, 0, 0);
GLInterface.SetCull(Cull_None);
if (shadowHack)
{
GLInterface.SetDepthFunc(DF_Less);
}
GLInterface.SetIdentityMatrix(Matrix_Model);
return 1;
}
extern int voxlumps[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 (int i = 0; i < MAXVOXELS; i++)
{
int lumpnum = voxlumps[i];
if (lumpnum > 0)
{
voxmodels[i] = voxload(lumpnum);
if (voxmodels[i])
voxmodels[i]->scale = voxscale[i] * (1.f / 65536.f);
else
Printf("Unable to load voxel from %s\n", fileSystem.GetFileFullPath(lumpnum));
}
}
}
#endif
//---------------------------------------- VOX LIBRARY ENDS ----------------------------------------

View file

@ -85,17 +85,17 @@ CUSTOM_CVAR(Bool, adl_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUA
FORWARD_BOOL_CVAR(adl_fullpan);
}
CUSTOM_CVAR(Int, adl_bank, 14, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
CUSTOM_CVAR(Int, adl_bank, 14, CVAR_ARCHIVE | CVAR_VIRTUAL)
{
FORWARD_CVAR(adl_bank);
}
CUSTOM_CVAR(Bool, adl_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
CUSTOM_CVAR(Bool, adl_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_VIRTUAL)
{
FORWARD_BOOL_CVAR(adl_use_custom_bank);
}
CUSTOM_CVAR(String, adl_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
CUSTOM_CVAR(String, adl_custom_bank, "", CVAR_ARCHIVE | CVAR_VIRTUAL)
{
FORWARD_STRING_CVAR(adl_custom_bank);
}
@ -261,12 +261,12 @@ CUSTOM_CVAR(Bool, opn_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUA
FORWARD_BOOL_CVAR(opn_fullpan);
}
CUSTOM_CVAR(Bool, opn_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
CUSTOM_CVAR(Bool, opn_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_VIRTUAL)
{
FORWARD_BOOL_CVAR(opn_use_custom_bank);
}
CUSTOM_CVAR(String, opn_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
CUSTOM_CVAR(String, opn_custom_bank, "", CVAR_ARCHIVE | CVAR_VIRTUAL)
{
FORWARD_STRING_CVAR(opn_custom_bank);
}

View file

@ -707,6 +707,12 @@ void ReadBindings(int lump, bool override)
dest = &AutomapBindings;
sc.MustGetString();
}
else if (sc.Compare("unbind"))
{
sc.MustGetString();
dest->UnbindKey(sc.String);
continue;
}
key = GetConfigKeyFromName(sc.String);
sc.MustGetString();
dest->SetBind(key, sc.String, override);

View file

@ -1287,6 +1287,42 @@ void FScanner::AddSymbol(const char* name, double value)
symbols.Insert(name, sym);
}
//==========================================================================
//
//
//
//==========================================================================
int FScanner::StartBraces(FScanner::SavedPos* braceend)
{
if (CheckString("{"))
{
auto here = SavePos();
SkipToEndOfBlock();
*braceend = SavePos();
RestorePos(here);
return 0;
}
else
{
ScriptError("'{' expected");
return -1;
}
}
//==========================================================================
//
//
//
//==========================================================================
bool FScanner::FoundEndBrace(FScanner::SavedPos& braceend)
{
auto here = SavePos();
return here.SavedScriptPtr >= braceend.SavedScriptPtr;
}
//==========================================================================
//
// a class that remembers a parser position

View file

@ -94,6 +94,8 @@ public:
inline void AddSymbol(const char* name, uint32_t value) { return AddSymbol(name, uint64_t(value)); }
void AddSymbol(const char* name, double value);
void SkipToEndOfBlock();
int StartBraces(FScanner::SavedPos* braceend);
bool FoundEndBrace(FScanner::SavedPos& braceend);
static FString TokenName(int token, const char *string=NULL);
@ -113,7 +115,30 @@ public:
void MustGetNumber(bool evaluate = false);
bool CheckNumber(bool evaluate = false);
bool GetNumber(int& var, bool evaluate = false)
{
if (!GetNumber(evaluate)) return false;
var = Number;
return true;
}
bool GetString(FString& var)
{
if (!GetString()) return false;
var = String;
return true;
}
bool GetFloat(bool evaluate = false);
bool GetFloat(double& var, bool evaluate = false)
{
if (!GetFloat(evaluate)) return false;
var = Float;
return true;
}
void MustGetFloat(bool evaluate = false);
bool CheckFloat(bool evaluate = false);

View file

@ -233,12 +233,14 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
}
name.ToLower();
if (name.IndexOf("__macosx") == 0)
continue; // skip Apple garbage. At this stage only the root folder matters,
if (i == 0)
{
// check for special names, if one of these gets found this must be treated as a normal zip.
bool isspecial = name.IndexOf("/") < 0 || (filter && filter->reservedFolders.Find(name) < filter->reservedFolders.Size());
if (isspecial) break;
name0 = name;
name0 = name.Left(name.LastIndexOf("/")+1);
}
else
{
@ -252,7 +254,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
// at least one of the more common definition lumps must be present.
for (auto &p : filter->requiredPrefixes)
{
if (name.IndexOf(name0 + p) == 0)
if (name.IndexOf(name0 + p) == 0 || name.LastIndexOf(p) == name.Len() - strlen(p))
{
foundspeciallump = true;
break;
@ -272,7 +274,6 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
int len = LittleShort(zip_fh->NameLength);
FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len);
if (name0.IsNotEmpty()) name = name.Mid(name0.Len());
dirptr += sizeof(FZipCentralDirectoryInfo) +
LittleShort(zip_fh->NameLength) +
LittleShort(zip_fh->ExtraLength) +
@ -285,6 +286,13 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
return false;
}
if (name.IndexOf("__macosx") == 0 || name.IndexOf("__MACOSX") == 0)
{
skipped++;
continue; // Weed out Apple's resource fork garbage right here because it interferes with safe operation.
}
if (name0.IsNotEmpty()) name = name.Mid(name0.Len());
// skip Directories
if (name.IsEmpty() || (name.Back() == '/' && LittleLong(zip_fh->UncompressedSize) == 0))
{

View file

@ -76,14 +76,14 @@ struct FileSystem::LumpRecord
shortName.String[8] = 0;
longName = "";
Namespace = lump->GetNamespace();
resourceId = 0;
resourceId = -1;
}
else if ((lump->Flags & LUMPF_EMBEDDED) || !lump->getName() || !*lump->getName())
{
shortName.qword = 0;
longName = "";
Namespace = ns_hidden;
resourceId = 0;
resourceId = -1;
}
else
{

View file

@ -175,10 +175,11 @@ void I_PrintStr(const char *cp)
{
const char * srcp = cp;
FString printData = "";
bool terminal = isatty(STDOUT_FILENO);
while (*srcp != 0)
{
if (*srcp == 0x1c && con_printansi)
if (*srcp == 0x1c && con_printansi && terminal)
{
srcp += 1;
EColorRange range = V_ParseFontColor((const uint8_t*&)srcp, CR_UNTRANSLATED, CR_YELLOW);
@ -224,7 +225,7 @@ void I_PrintStr(const char *cp)
if (StartScreen) CleanProgressBar();
fputs(printData.GetChars(),stdout);
fputs("\033[0m",stdout);
if (terminal) fputs("\033[0m",stdout);
if (StartScreen) RedrawProgressBar(ProgressBarCurPos,ProgressBarMaxPos);
}

View file

@ -80,6 +80,8 @@ FFlatVertexBuffer::FFlatVertexBuffer(int width, int height)
mVertexBuffer = screen->CreateVertexBuffer();
mIndexBuffer = screen->CreateIndexBuffer();
int data[4] = {};
mIndexBuffer->SetData(4, data); // On Vulkan this may not be empty, so set some dummy defaults to avoid crashes.
unsigned int bytesize = BUFFER_SIZE * sizeof(FFlatVertex);
mVertexBuffer->SetData(bytesize, nullptr, false);

View file

@ -200,9 +200,8 @@ struct StreamData
FVector4 uSplitBottomPlane;
FVector4 uDetailParms;
#ifdef NPOT_EMULATION
FVector2 uNpotEmulation;
#endif
FVector4 uNpotEmulation;
FVector4 padding1, padding2, padding3;
};
class FRenderState
@ -274,7 +273,7 @@ public:
mSpecialEffect = EFF_NONE;
mLightIndex = -1;
mStreamData.uInterpolationFactor = 0;
mRenderStyle = LegacyRenderStyles[STYLE_Translucent];
mRenderStyle = DefaultRenderStyle();
mMaterial.Reset();
mBias.Reset();
mPassType = NORMAL_PASS;
@ -295,7 +294,7 @@ public:
mStreamData.uDynLightColor = { 0.0f, 0.0f, 0.0f, 1.0f };
mStreamData.uDetailParms = { 0.0f, 0.0f, 0.0f, 0.0f };
#ifdef NPOT_EMULATION
mStreamData.uNpotEmulation = { 0,0 };
mStreamData.uNpotEmulation = { 0,0,0,0 };
#endif
mModelMatrix.loadIdentity();
mTextureMatrix.loadIdentity();
@ -490,7 +489,7 @@ public:
void SetNpotEmulation(float factor, float offset)
{
#ifdef NPOT_EMULATION
mStreamData.uNpotEmulation = { offset, factor };
mStreamData.uNpotEmulation = { offset, factor, 0, 0 };
#endif
}

View file

@ -202,7 +202,7 @@ void FSkyVertexBuffer::SkyVertexBuild(int r, int c, bool zflip)
// And the texture coordinates.
if (zflip) r = mRows * 2 - r;
vert.u = 0.5 + (-c / (float)mColumns);
vert.u = 0.5f + (-c / (float)mColumns);
vert.v = (r / (float)(2*mRows));
// And finally the vertex.
@ -413,11 +413,13 @@ void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_
{
modelMatrix.translate(0.f, -1250.f, 0.f);
modelMatrix.scale(1.f, texh / 230.f, 1.f);
yscale = 1.f;
}
else if (texh <= 240)
{
modelMatrix.translate(0.f, (200 - texh + texskyoffset) * skyoffsetfactor, 0.f);
modelMatrix.scale(1.f, 1.f + ((texh - 200.f) / 200.f) * 1.17f, 1.f);
yscale = 1.f;
}
else
{

View file

@ -152,6 +152,10 @@ void PolyFrameBuffer::FlushDrawCommands()
}
}
EXTERN_CVAR(Float, vid_brightness)
EXTERN_CVAR(Float, vid_contrast)
EXTERN_CVAR(Float, vid_saturation)
void PolyFrameBuffer::Update()
{
twoD.Reset();
@ -177,8 +181,9 @@ void PolyFrameBuffer::Update()
if (dst)
{
#if 1
// [GEC] with the help of dpJudas a new system of copying and applying gamma in the video buffer
auto copyqueue = std::make_shared<DrawerCommandQueue>(&mFrameMemory);
copyqueue->Push<MemcpyCommand>(dst, pitch / pixelsize, src, w, h, w, pixelsize);
copyqueue->Push<CopyAndApplyGammaCommand>(dst, pitch / pixelsize, src, w, h, w, vid_gamma, vid_contrast, vid_brightness, vid_saturation);
DrawerThreads::Execute(copyqueue);
#else
for (int y = 0; y < h; y++)
@ -366,6 +371,40 @@ FTexture *PolyFrameBuffer::WipeEndScreen()
TArray<uint8_t> PolyFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma)
{
// [GEC] Really necessary to apply gamma, brightness, contrast and saturation for screenshot
std::vector<uint8_t> gammatablebuf(256);
uint8_t* gammatable = gammatablebuf.data();
float InvGamma = 1.0f / clamp<float>(vid_gamma, 0.1f, 4.f);
float Brightness = clamp<float>(vid_brightness, -0.8f, 0.8f);
float Contrast = clamp<float>(vid_contrast, 0.1f, 3.f);
float Saturation = clamp<float>(vid_saturation, -15.0f, 15.f);
for (int x = 0; x < 256; x++)
{
float ramp = (float)(x / 255.f);
// Apply Contrast
// vec4 finalColor = vec4((((originalColor.rgb - vec3(0.5)) * Contrast) + vec3(0.5)), 1.0);
if(vid_contrast != 1.0f)
ramp = (((ramp - 0.5f) * Contrast) + 0.5f);
// Apply Brightness
// vec4 finalColor = vec4(originalColor.rgb + Brightness, 1.0);
if (vid_brightness != 0.0f)
ramp += (Brightness / 2.0f);
// Apply Gamma
// FragColor.rgb = pow(fragColor.rgb, vec3(1.0/gamma));
if (vid_gamma != 1.0f)
ramp = pow(ramp, InvGamma);
// Clamp ramp
ramp = clamp<float>(ramp, 0.0f, 1.f);
gammatable[x] = (uint8_t)(ramp * 255);
}
int w = SCREENWIDTH;
int h = SCREENHEIGHT;
@ -380,9 +419,44 @@ TArray<uint8_t> PolyFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &color_
for (int x = 0; x < w; x++)
{
ScreenshotBuffer[dindex ] = pixels[sindex + 2];
ScreenshotBuffer[dindex + 1] = pixels[sindex + 1];
ScreenshotBuffer[dindex + 2] = pixels[sindex ];
uint32_t red = pixels[sindex + 2];
uint32_t green = pixels[sindex + 1];
uint32_t blue = pixels[sindex];
if (vid_saturation != 1.0f)
{
float NewR = (float)(red / 255.f);
float NewG = (float)(green / 255.f);
float NewB = (float)(blue / 255.f);
// Apply Saturation
// float luma = dot(In, float3(0.2126729, 0.7151522, 0.0721750));
// Out = luma.xxx + Saturation.xxx * (In - luma.xxx);
//float luma = (NewR * 0.2126729f) + (NewG * 0.7151522f) + (NewB * 0.0721750f); // Rec. 709
float luma = (NewR * 0.299f) + (NewG * 0.587f) + (NewB * 0.114f); //Rec. 601
NewR = luma + (Saturation * (NewR - luma));
NewG = luma + (Saturation * (NewG - luma));
NewB = luma + (Saturation * (NewB - luma));
// Clamp All
NewR = clamp<float>(NewR, 0.0f, 1.f);
NewG = clamp<float>(NewG, 0.0f, 1.f);
NewB = clamp<float>(NewB, 0.0f, 1.f);
red = (uint32_t)(NewR * 255.f);
green = (uint32_t)(NewG * 255.f);
blue = (uint32_t)(NewB * 255.f);
}
// Apply Contrast / Brightness / Gamma
red = gammatable[red];
green = gammatable[green];
blue = gammatable[blue];
ScreenshotBuffer[dindex ] = red;
ScreenshotBuffer[dindex + 1] = green;
ScreenshotBuffer[dindex + 2] = blue;
dindex += 3;
sindex += 4;
}

View file

@ -96,3 +96,119 @@ private:
};
inline PolyFrameBuffer *GetPolyFrameBuffer() { return static_cast<PolyFrameBuffer*>(screen); }
// [GEC] Original code of dpJudas, I add the formulas of gamma, brightness, contrast and saturation.
class CopyAndApplyGammaCommand : public DrawerCommand
{
public:
CopyAndApplyGammaCommand(void* dest, int destpitch, const void* src, int width, int height, int srcpitch,
float gamma, float contrast, float brightness, float saturation) : dest(dest), src(src), destpitch(destpitch), width(width), height(height), srcpitch(srcpitch),
gamma(gamma), contrast(contrast), brightness(brightness), saturation(saturation)
{
}
void Execute(DrawerThread* thread)
{
float Saturation = clamp<float>(saturation, -15.0f, 15.f);
std::vector<uint8_t> gammatablebuf(256);
uint8_t* gammatable = gammatablebuf.data();
InitGammaTable(gammatable);
int w = width;
int start = thread->skipped_by_thread(0);
int count = thread->count_for_thread(0, height);
int sstep = thread->num_cores * srcpitch;
int dstep = thread->num_cores * destpitch;
uint32_t* d = (uint32_t*)dest + start * destpitch;
const uint32_t* s = (const uint32_t*)src + start * srcpitch;
for (int y = 0; y < count; y++)
{
for (int x = 0; x < w; x++)
{
uint32_t red = RPART(s[x]);
uint32_t green = GPART(s[x]);
uint32_t blue = BPART(s[x]);
uint32_t alpha = APART(s[x]);
if (saturation != 1.0f)
{
float NewR = (float)(red / 255.f);
float NewG = (float)(green / 255.f);
float NewB = (float)(blue / 255.f);
// Apply Saturation
// float luma = dot(In, float3(0.2126729, 0.7151522, 0.0721750));
// Out = luma.xxx + Saturation.xxx * (In - luma.xxx);
//float luma = (NewR * 0.2126729f) + (NewG * 0.7151522f) + (NewB * 0.0721750f); // Rec. 709
float luma = (NewR * 0.299f) + (NewG * 0.587f) + (NewB * 0.114f); //Rec. 601
NewR = luma + (Saturation * (NewR - luma));
NewG = luma + (Saturation * (NewG - luma));
NewB = luma + (Saturation * (NewB - luma));
// Clamp All
NewR = clamp<float>(NewR, 0.0f, 1.f);
NewG = clamp<float>(NewG, 0.0f, 1.f);
NewB = clamp<float>(NewB, 0.0f, 1.f);
red = (uint32_t)(NewR * 255.f);
green = (uint32_t)(NewG * 255.f);
blue = (uint32_t)(NewB * 255.f);
}
// Apply Contrast / Brightness / Gamma
red = gammatable[red];
green = gammatable[green];
blue = gammatable[blue];
d[x] = MAKEARGB(alpha, (uint8_t)red, (uint8_t)green, (uint8_t)blue);
}
d += dstep;
s += sstep;
}
}
private:
void InitGammaTable(uint8_t *gammatable)
{
float InvGamma = 1.0f / clamp<float>(gamma, 0.1f, 4.f);
float Brightness = clamp<float>(brightness, -0.8f, 0.8f);
float Contrast = clamp<float>(contrast, 0.1f, 3.f);
for (int x = 0; x < 256; x++)
{
float ramp = (float)(x / 255.f);
// Apply Contrast
// vec4 finalColor = vec4((((originalColor.rgb - vec3(0.5)) * Contrast) + vec3(0.5)), 1.0);
if (contrast != 1.0f)
ramp = (((ramp - 0.5f) * Contrast) + 0.5f);
// Apply Brightness
// vec4 finalColor = vec4(originalColor.rgb + Brightness, 1.0);
if (brightness != 0.0f)
ramp += (Brightness / 2.0f);
// Apply Gamma
// FragColor.rgb = pow(fragColor.rgb, vec3(1.0/gamma));
if (gamma != 1.0f)
ramp = pow(ramp, InvGamma);
// Clamp ramp
ramp = clamp<float>(ramp, 0.0f, 1.f);
gammatable[x] = (uint8_t)(ramp * 255);
}
}
void* dest;
const void* src;
int destpitch;
int width;
int height;
int srcpitch;
float gamma;
float contrast;
float brightness;
float saturation;
};

View file

@ -538,12 +538,13 @@ static void MainFP(int x0, int x1, PolyTriangleThreadData* thread)
// frag = frag * vColor;
// frag.rgb = frag.rgb + uFogColor.rgb;
uint32_t startR = (int)((thread->mainVertexShader.Data.uObjectColor.r) * 255.0f);
uint32_t startG = (int)((thread->mainVertexShader.Data.uObjectColor.g) * 255.0f);
uint32_t startB = (int)((thread->mainVertexShader.Data.uObjectColor.b) * 255.0f);
uint32_t rangeR = (int)((thread->mainVertexShader.Data.uAddColor.r) * 255.0f) - startR;
uint32_t rangeG = (int)((thread->mainVertexShader.Data.uAddColor.g) * 255.0f) - startG;
uint32_t rangeB = (int)((thread->mainVertexShader.Data.uAddColor.b) * 255.0f) - startB;
// [GEC] I leave the default floating values.
float startR = thread->mainVertexShader.Data.uObjectColor.r;
float startG = thread->mainVertexShader.Data.uObjectColor.g;
float startB = thread->mainVertexShader.Data.uObjectColor.b;
float rangeR = thread->mainVertexShader.Data.uAddColor.r - startR;
float rangeG = thread->mainVertexShader.Data.uAddColor.g - startG;
float rangeB = thread->mainVertexShader.Data.uAddColor.b - startB;
for (int x = x0; x < x1; x++)
{
@ -555,15 +556,22 @@ static void MainFP(int x0, int x1, PolyTriangleThreadData* thread)
uint32_t gray = (r * 77 + g * 143 + b * 37) >> 8;
gray += (gray >> 7); // gray*=256/255
r = (startR + ((gray * rangeR) >> 8)) << 1;
g = (startG + ((gray * rangeG) >> 8)) << 1;
b = (startB + ((gray * rangeB) >> 8)) << 1;
// [GEC] I use the same method as in shaders using floating values.
// This avoids errors in the invulneravility colormap in Doom and Heretic.
float fgray = (float)(gray / 255.f);
float fr = (startR + (fgray * rangeR)) * 2;
float fg = (startG + (fgray * rangeG)) * 2;
float fb = (startB + (fgray * rangeB)) * 2;
r = MIN(r, (uint32_t)255);
g = MIN(g, (uint32_t)255);
b = MIN(b, (uint32_t)255);
fr = clamp<float>(fr, 0.0f, 1.0f);
fg = clamp<float>(fg, 0.0f, 1.0f);
fb = clamp<float>(fb, 0.0f, 1.0f);
fragcolor[x] = MAKEARGB(a, r, g, b);
r = (uint32_t)(fr * 255.f);
g = (uint32_t)(fg * 255.f);
b = (uint32_t)(fb * 255.f);
fragcolor[x] = MAKEARGB(a, (uint8_t)r, (uint8_t)g, (uint8_t)b);
}
}
else

View file

@ -212,13 +212,18 @@ void VkRenderBuffers::CreateSceneNormal(int width, int height, VkSampleCountFlag
ImageBuilder builder;
builder.setSize(width, height);
builder.setSamples(samples);
builder.setFormat(VK_FORMAT_A2R10G10B10_UNORM_PACK32);
builder.setFormat(SceneNormalFormat);
builder.setUsage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
if (!builder.isFormatSupported(fb->device, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
{
SceneNormalFormat = VK_FORMAT_R8G8B8A8_UNORM;
builder.setFormat(SceneNormalFormat);
}
SceneNormal.Image = builder.create(fb->device);
SceneNormal.Image->SetDebugName("VkRenderBuffers.SceneNormal");
ImageViewBuilder viewbuilder;
viewbuilder.setImage(SceneNormal.Image.get(), VK_FORMAT_A2R10G10B10_UNORM_PACK32);
viewbuilder.setImage(SceneNormal.Image.get(), SceneNormalFormat);
SceneNormal.View = viewbuilder.create(fb->device);
SceneNormal.View->SetDebugName("VkRenderBuffers.SceneNormalView");
}

View file

@ -24,6 +24,7 @@ public:
VkTextureImage SceneFog;
VkFormat SceneDepthStencilFormat = VK_FORMAT_D24_UNORM_S8_UINT;
VkFormat SceneNormalFormat = VK_FORMAT_A2R10G10B10_UNORM_PACK32;
static const int NumPipelineImages = 2;
VkTextureImage PipelineImage[NumPipelineImages];

View file

@ -281,7 +281,7 @@ std::unique_ptr<VulkanRenderPass> VkRenderPassSetup::CreateRenderPass(int clearT
{
auto buffers = GetVulkanFrameBuffer()->GetBuffers();
VkFormat drawBufferFormats[] = { VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_A2R10G10B10_UNORM_PACK32 };
VkFormat drawBufferFormats[] = { VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R8G8B8A8_UNORM, buffers->SceneNormalFormat };
RenderPassBuilder builder;
@ -420,6 +420,7 @@ std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipeli
builder.setTopology(vktopology[key.DrawType]);
builder.setDepthStencilEnable(key.DepthTest, key.DepthWrite, key.StencilTest);
builder.setDepthFunc(depthfunc2vk[key.DepthFunc]);
if (fb->device->UsedDeviceFeatures.depthClamp)
builder.setDepthClampEnable(key.DepthClamp);
builder.setDepthBias(key.DepthBias, 0.0f, 0.0f, 0.0f);

View file

@ -163,9 +163,8 @@ static const char *shaderBindings = R"(
vec4 uSplitBottomPlane;
vec4 uDetailParms;
#ifdef NPOT_EMULATION
vec2 uNpotEmulation;
#endif
vec4 uNpotEmulation;
vec4 padding1, padding2, padding3;
};
layout(set = 0, binding = 3, std140) uniform StreamUBO {
@ -297,6 +296,9 @@ std::unique_ptr<VulkanShader> VkShaderManager::LoadFragShader(FString shadername
code << defines;
code << "\n$placeholder$"; // here the code can later add more needed #defines.
code << "\n#define MAX_STREAM_DATA " << std::to_string(MAX_STREAM_DATA).c_str() << "\n";
#ifdef NPOT_EMULATION
code << "#define NPOT_EMULATION\n";
#endif
code << shaderBindings;
FString placeholder = "\n";

View file

@ -45,7 +45,7 @@ public:
void setMemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits = 0);
void setLinearTiling();
bool isFormatSupported(VulkanDevice *device);
bool isFormatSupported(VulkanDevice *device, VkFormatFeatureFlags bufferFeatures = 0);
std::unique_ptr<VulkanImage> create(VulkanDevice *device, VkDeviceSize* allocatedBytes = nullptr);
std::unique_ptr<VulkanImage> tryCreate(VulkanDevice *device);
@ -410,7 +410,7 @@ inline void ImageBuilder::setMemoryType(VkMemoryPropertyFlags requiredFlags, VkM
allocInfo.memoryTypeBits = memoryTypeBits;
}
inline bool ImageBuilder::isFormatSupported(VulkanDevice *device)
inline bool ImageBuilder::isFormatSupported(VulkanDevice *device, VkFormatFeatureFlags bufferFeatures)
{
VkImageFormatProperties properties = { };
VkResult result = vkGetPhysicalDeviceImageFormatProperties(device->PhysicalDevice.Device, imageInfo.format, imageInfo.imageType, imageInfo.tiling, imageInfo.usage, imageInfo.flags, &properties);
@ -421,6 +421,13 @@ inline bool ImageBuilder::isFormatSupported(VulkanDevice *device)
if (imageInfo.mipLevels > properties.maxMipLevels) return false;
if (imageInfo.arrayLayers > properties.maxArrayLayers) return false;
if ((imageInfo.samples & properties.sampleCounts) != imageInfo.samples) return false;
if (bufferFeatures != 0)
{
VkFormatProperties formatProperties = { };
vkGetPhysicalDeviceFormatProperties(device->PhysicalDevice.Device, imageInfo.format, &formatProperties);
if ((formatProperties.bufferFeatures & bufferFeatures) != bufferFeatures)
return false;
}
return true;
}

View file

@ -108,8 +108,7 @@ bool VulkanDevice::CheckRequiredFeatures(const VkPhysicalDeviceFeatures &f)
{
return
f.samplerAnisotropy == VK_TRUE &&
f.fragmentStoresAndAtomics == VK_TRUE &&
f.depthClamp == VK_TRUE;
f.fragmentStoresAndAtomics == VK_TRUE;
}
void VulkanDevice::SelectPhysicalDevice()

View file

@ -390,7 +390,7 @@ void VulkanFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation)
IHardwareTexture *VulkanFrameBuffer::CreateHardwareTexture(int numchannels)
{
return new VkHardwareTexture();
return new VkHardwareTexture(numchannels);
}
FMaterial* VulkanFrameBuffer::CreateMaterial(FGameTexture* tex, int scaleflags)

View file

@ -37,8 +37,9 @@
VkHardwareTexture *VkHardwareTexture::First = nullptr;
VkHardwareTexture::VkHardwareTexture()
VkHardwareTexture::VkHardwareTexture(int numchannels)
{
mTexelsize = numchannels;
Next = First;
First = this;
if (Next) Next->Prev = this;
@ -126,7 +127,8 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags)
if (!tex->isHardwareCanvas())
{
FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData);
CreateTexture(texbuffer.mWidth, texbuffer.mHeight, 4, VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer);
bool indexed = flags & CTF_Indexed;
CreateTexture(texbuffer.mWidth, texbuffer.mHeight,indexed? 1 : 4, indexed? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer, !indexed);
}
else
{
@ -156,7 +158,7 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags)
}
}
void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels)
void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap)
{
if (w <= 0 || h <= 0)
throw CVulkanError("Trying to create zero size texture");
@ -177,7 +179,7 @@ void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat form
ImageBuilder imgbuilder;
imgbuilder.setFormat(format);
imgbuilder.setSize(w, h, GetMipLevels(w, h));
imgbuilder.setSize(w, h, !mipmap ? 1 : GetMipLevels(w, h));
imgbuilder.setUsage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
mImage.Image = imgbuilder.create(fb->device);
mImage.Image->SetDebugName("VkHardwareTexture.mImage");
@ -203,7 +205,7 @@ void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat form
fb->FrameDeleteList.Buffers.push_back(std::move(stagingBuffer));
mImage.GenerateMipmaps(cmdbuffer);
if (mipmap) mImage.GenerateMipmaps(cmdbuffer);
}
int VkHardwareTexture::GetMipLevels(int w, int h)
@ -268,6 +270,7 @@ uint8_t *VkHardwareTexture::MapBuffer()
unsigned int VkHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name)
{
CreateTexture(w, h, mTexelsize, mTexelsize == 4 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8_UNORM, buffer, mipmap);
return 0;
}
@ -371,10 +374,6 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state)
int clampmode = state.mClampMode;
int translation = state.mTranslation;
auto remap = translation <= 0 ? nullptr : GPalette.TranslationToTable(translation);
if (remap)
translation = remap->Index;
clampmode = base->GetClampMode(clampmode);
for (auto& set : mDescriptorSets)
@ -395,11 +394,24 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state)
MaterialLayerInfo *layer;
auto systex = static_cast<VkHardwareTexture*>(GetLayer(0, state.mTranslation, &layer));
update.addCombinedImageSampler(descriptor.get(), 0, systex->GetImage(layer->layerTexture, state.mTranslation, layer->scaleFlags)->View.get(), sampler, systex->mImage.Layout);
if (!(layer->scaleFlags & CTF_Indexed))
{
for (int i = 1; i < numLayers; i++)
{
auto systex = static_cast<VkHardwareTexture*>(GetLayer(i, 0, &layer));
update.addCombinedImageSampler(descriptor.get(), i, systex->GetImage(layer->layerTexture, 0, layer->scaleFlags)->View.get(), sampler, systex->mImage.Layout);
}
}
else
{
for (int i = 1; i < 3; i++)
{
auto systex = static_cast<VkHardwareTexture*>(GetLayer(i, translation, &layer));
update.addCombinedImageSampler(descriptor.get(), i, systex->GetImage(layer->layerTexture, 0, layer->scaleFlags)->View.get(), sampler, systex->mImage.Layout);
}
numLayers = 3;
}
auto dummyImage = fb->GetRenderPassManager()->GetNullTextureView();
for (int i = numLayers; i < SHADER_MIN_REQUIRED_TEXTURE_LAYERS; i++)

View file

@ -24,7 +24,7 @@ class VkHardwareTexture : public IHardwareTexture
{
friend class VkMaterial;
public:
VkHardwareTexture();
VkHardwareTexture(int numchannels);
~VkHardwareTexture();
static void ResetAll();
@ -45,7 +45,7 @@ public:
private:
void CreateImage(FTexture *tex, int translation, int flags);
void CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels);
void CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap);
static int GetMipLevels(int w, int h);
static VkHardwareTexture *First;

View file

@ -605,13 +605,13 @@ void DStatusBarCore::DrawGraphic(FGameTexture* tex, double x, double y, int flag
//
//============================================================================
void DStatusBarCore::DrawRotated(FTextureID texture, double x, double y, double angle, int flags, double Alpha, double scaleX, double scaleY, PalEntry color, int translation, ERenderStyle style)
void DStatusBarCore::DrawRotated(FTextureID texture, double x, double y, int flags, double angle, double Alpha, double scaleX, double scaleY, PalEntry color, int translation, ERenderStyle style)
{
if (!texture.isValid())
return;
FGameTexture* tex = TexMan.GetGameTexture(texture, !(flags & DI_DONTANIMATE));
DrawRotated(tex, x, y, angle, flags, Alpha, scaleX, scaleY, color, translation, style);
DrawRotated(tex, x, y, flags, angle, Alpha, scaleX, scaleY, color, translation, style);
}
void DStatusBarCore::DrawRotated(FGameTexture* tex, double x, double y, int flags, double angle, double Alpha, double scaleX, double scaleY, PalEntry color, int translation, ERenderStyle style)

View file

@ -186,7 +186,7 @@ public:
void StatusbarToRealCoords(double& x, double& y, double& w, double& h) const;
void DrawGraphic(FGameTexture* texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, PalEntry color = 0xffffffff, int translation = 0, ERenderStyle style = STYLE_Translucent, double clipwidth = -1.0);
void DrawGraphic(FTextureID texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, PalEntry color = 0xffffffff, int translation = 0, ERenderStyle style = STYLE_Translucent, double clipwidth = -1.0);
void DrawRotated(FTextureID texture, double x, double y, double angle, int flags, double Alpha, double scaleX, double scaleY, PalEntry color = 0xffffffff, int translation = 0, ERenderStyle style = STYLE_Translucent);
void DrawRotated(FTextureID texture, double x, double y, int flags, double angle, double Alpha, double scaleX, double scaleY, PalEntry color = 0xffffffff, int translation = 0, ERenderStyle style = STYLE_Translucent);
void DrawRotated(FGameTexture* tex, double x, double y, int flags, double angle, double Alpha, double scaleX, double scaleY, PalEntry color = 0xffffffff, int translation = 0, ERenderStyle style = STYLE_Translucent);
void DrawString(FFont* font, const FString& cstring, double x, double y, int flags, double Alpha, int translation, int spacing, EMonospacing monospacing, int shadowX, int shadowY, double scaleX, double scaleY, int pt);
void TransformRect(double& x, double& y, double& w, double& h, int flags = 0);

View file

@ -48,7 +48,6 @@ void AnimTexture::SetFrameSize(int format, int width, int height)
FTexture::SetSize(width, height);
Image.Resize(width * height * (format == Paletted ? 1 : 3));
memset(Image.Data(), 0, Image.Size());
CleanHardwareTextures();
}
void AnimTexture::SetFrame(const uint8_t* palette, const void* data_)
@ -81,7 +80,6 @@ void AnimTexture::SetFrame(const uint8_t* palette, const void* data_)
}
else memcpy(Image.Data(), data_, Width * Height * (pixelformat == Paletted ? 1 : 3));
}
CleanHardwareTextures();
}
//===========================================================================
@ -156,10 +154,13 @@ void AnimTextures::SetSize(int format, int width, int height)
static_cast<AnimTexture*>(tex[1]->GetTexture())->SetFrameSize(format, width, height);
tex[0]->SetSize(width, height);
tex[1]->SetSize(width, height);
tex[0]->CleanHardwareData();
tex[1]->CleanHardwareData();
}
void AnimTextures::SetFrame(const uint8_t* palette, const void* data)
{
active ^= 1;
static_cast<AnimTexture*>(tex[active]->GetTexture())->SetFrame(palette, data);
tex[active]->CleanHardwareData();
}

View file

@ -30,6 +30,7 @@
#include "v_video.h"
static IHardwareTexture* (*layercallback)(int layer, int translation);
TArray<UserShaderDesc> usershaders;
void FMaterial::SetLayerCallback(IHardwareTexture* (*cb)(int layer, int translation))
{

View file

@ -27,7 +27,6 @@ Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au)
//-------------------------------------------------------------------------
#include "automap.h"
#include "cstat.h"
#include "c_dispatch.h"
#include "c_cvars.h"
#include "gstrings.h"

View file

@ -366,24 +366,14 @@ inline FSerializer &Serialize(FSerializer &arc, const char *key, binangle &obj,
//---------------------------------------------------------------------------
//
// Constants and functions for use with fixedhoriz and friendly functions.
// Functions for use with fixedhoriz and friendly functions.
//
//---------------------------------------------------------------------------
// 280039127 is the maximum horizon in Q16.16 the engine will handle before wrapping around.
constexpr double horizDiff = 280039127 * 3. / 100.;
// Degrees needed to convert horizAngle into pitch degrees.
constexpr double horizDegrees = 183.503609961216825;
// Ratio to convert inverse tangent to -90/90 degrees of pitch.
constexpr double horizRatio = horizDegrees / pi::pi();
// Horizon conversion functions.
inline double HorizToPitch(double horiz) { return atan2(horiz, horizDiff / 65536.) * horizRatio; }
inline double HorizToPitch(fixed_t q16horiz) { return atan2(q16horiz, horizDiff) * horizRatio; }
inline fixed_t PitchToHoriz(double horizAngle) { return xs_CRoundToInt(horizDiff * tan(horizAngle * (pi::pi() / horizDegrees))); }
inline int32_t PitchToBAM(double horizAngle) { return xs_CRoundToInt(clamp(horizAngle * (1073741823.5 / 45.), -INT32_MAX, INT32_MAX)); }
inline double HorizToPitch(double horiz) { return atan2(horiz, 128) * (180. / pi::pi()); }
inline double HorizToPitch(fixed_t q16horiz) { return atan2(q16horiz, IntToFixed(128)) * (180. / pi::pi()); }
inline fixed_t PitchToHoriz(double pitch) { return xs_CRoundToInt(IntToFixed(128) * tan(pitch * (pi::pi() / 180.))); }
inline int32_t PitchToBAM(double pitch) { return xs_CRoundToInt(clamp(pitch * (1073741823.5 / 45.), -INT32_MAX, INT32_MAX)); }
inline constexpr double BAMToPitch(int32_t bam) { return bam * (45. / 1073741823.5); }
@ -512,54 +502,11 @@ inline FSerializer &Serialize(FSerializer &arc, const char *key, fixedhoriz &obj
//---------------------------------------------------------------------------
//
// Double-precision implementation of `getangle()` with associated wrappers and helper functions.
// High precision vector angle function, mainly for the renderer.
//
//---------------------------------------------------------------------------
inline double bradarangf(double vect)
{
return atan(vect) * BRadAngScale;
}
inline double bvectangf(int32_t x, int32_t y)
{
if ((x | y) == 0)
{
return 0;
}
else if (x == 0)
{
return 512 + ((y < 0) << 10);
}
else if (y == 0)
{
return ((x < 0) << 10);
}
else if (x == y)
{
return 256 + ((x < 0) << 10);
}
else if (x == -y)
{
return 768 + ((x > 0) << 10);
}
else if (abs(x) > abs(y))
{
return fmod(bradarangf(double(y) / x) + ((x < 0) << 10), 2048.);
}
else
{
return fmod(bradarangf(double(x) / -y) + 512 + ((y < 0) << 10), 2048.);
}
}
inline int32_t bvectang(int32_t x, int32_t y)
{
return xs_CRoundToInt(bvectangf(x, y));
}
inline fixed_t bvectangq16(int32_t x, int32_t y)
{
return FloatToFixed(bvectangf(x, y));
}
inline binangle bvectangbam(int32_t x, int32_t y)
{
return bamang(xs_CRoundToUInt(bvectangf(x, y) * BAMUNIT));
return radang(atan2(y, x));
}

View file

@ -74,6 +74,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "v_draw.h"
#include "gi.h"
#include "gamefuncs.h"
#include "hw_voxels.h"
#include "hw_palmanager.h"
CVAR(Bool, autoloadlights, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Bool, autoloadbrightmaps, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
@ -135,6 +137,7 @@ void SetConsoleNotifyBuffer();
bool PreBindTexture(FRenderState* state, FGameTexture*& tex, EUpscaleFlags& flags, int& scaleflags, int& clampmode, int& translation, int& overrideshader);
void PostLoadSetup();
void FontCharCreated(FGameTexture* base, FGameTexture* untranslated, FGameTexture* translated);
void LoadVoxelModels();
DBaseStatusBar* StatusBar;
@ -358,7 +361,7 @@ void UserConfig::ProcessOptions()
static const char* defs[] = { "-def", "-h", nullptr };
Args->CollectFiles("-def", defs, ".def");
DefaultDef = Args->CheckValue("-def");
UserDef = Args->CheckValue("-def");
if (DefaultCon.IsEmpty())
{
@ -582,10 +585,10 @@ int GameMain()
G_SaveConfig();
C_DeinitConsole();
V_ClearFonts();
vox_deinit();
voxClear();
ClearPalManager();
TexMan.DeleteAll();
TileFiles.CloseAll(); // delete the texture data before shutting down graphics.
GLInterface.Deinit();
I_ShutdownGraphics();
freeallmodels();
if (gi)
@ -932,6 +935,12 @@ int RunGame()
enginePreInit();
SetupGameButtons();
gameinfo.mBackButton = "engine/graphics/m_back.png";
GPalette.Init(MAXPALOOKUPS + 1); // one slot for each translation, plus a separate one for the base palettes.
gi->loadPalette();
voxInit();
TileFiles.LoadArtSet("tiles%03d.art"); // it's the same for all games.
engineInit();
gi->app_init();
CreateStatusBar();
SetDefaultMenuColors();
@ -943,7 +952,22 @@ int RunGame()
V_LoadTranslations(); // loading the translations must be delayed until the palettes have been fully set up.
lookups.postLoadTables();
PostLoadSetup();
videoInit();
lookups.postLoadLookups();
FMaterial::SetLayerCallback(setpalettelayer);
V_Init2();
twod->Begin(screen->GetWidth(), screen->GetHeight());
twod->End();
UpdateJoystickMenu(NULL);
UpdateVRModes();
setVideoMode();
LoadVoxelModels();
GLInterface.Init(screen->GetWidth());
screen->BeginFrame();
screen->SetTextureFilterMode();
setViewport(hud_size);
D_CheckNetGame();
UpdateGenericUI(ui_generic);
@ -1011,7 +1035,7 @@ void updatePauseStatus()
//
//==========================================================================
void PolymostProcessVoxels(void);
void LoadVoxelModels(void);
void setVideoMode()
{
@ -1022,24 +1046,6 @@ void setVideoMode()
videoClearScreen(0);
}
void videoInit()
{
lookups.postLoadLookups();
V_Init2();
setVideoMode();
PolymostProcessVoxels();
GLInterface.Init(screen->GetWidth());
screen->BeginFrame();
screen->SetTextureFilterMode();
setViewport(hud_size);
}
void G_FatalEngineError(void)
{
I_FatalError("There was a problem initializing the engine: %s\n\nThe application will now close.", engineerrstr);
}
//==========================================================================
//
//
@ -1326,27 +1332,50 @@ void DrawCrosshair(int deftile, int health, double xdelta, double ydelta, double
void LoadDefinitions()
{
loaddefinitionsfile("engine/engine.def"); // Internal stuff that is required.
const char* defsfile = G_DefFile();
cycle_t deftimer;
deftimer.Reset();
deftimer.Clock();
if (!loaddefinitionsfile(defsfile, true))
const char* loaded = nullptr;
const char* defsfile = G_DefFile();
FString razedefsfile = defsfile;
razedefsfile.Substitute(".def", "-raze.def");
loaddefinitionsfile("engine/engine.def", false); // Internal stuff that is required.
// check what we have.
// user .defs override the default ones and are not cumulative.
// if we fine even one Raze-specific file, all of those will be loaded cumulatively.
// otherwise the default rules inherited from older ports apply.
if (userConfig.UserDef.IsNotEmpty())
{
if (!loaddefinitionsfile(userConfig.UserDef, true, false)) loaded = userConfig.UserDef;
}
else
{
if (fileSystem.FileExists(razedefsfile))
{
if (!loaddefinitionsfile(razedefsfile, true, true)) loaded = razedefsfile;
}
else
{
if (!loaddefinitionsfile(defsfile, true, false)) loaded = defsfile;
}
}
if (loaded)
{
deftimer.Unclock();
Printf(PRINT_NONOTIFY, "Definitions file \"%s\" loaded in %.3f ms.\n", defsfile, deftimer.TimeMS());
DPrintf(DMSG_SPAMMY, "Definitions file \"%s\" loaded, %f ms.\n", loaded, deftimer.TimeMS());
}
userConfig.AddDefs.reset();
// load the widescreen replacements last so that they do not clobber the CRC for the original items so that mod-side replacement are picked up.
// load the widescreen replacements last. This ensures that mods still get the correct CRCs for their own tile replacements.
if (fileSystem.FindFile("engine/widescreen.def") >= 0 && !Args->CheckParm("-nowidescreen"))
{
loaddefinitionsfile("engine/widescreen.def");
}
fileSystem.InitHashChains(); // make sure that any resources that got added can be found again.
}
bool M_Active()
@ -1417,3 +1446,10 @@ DEFINE_GLOBAL(gameaction)
DEFINE_GLOBAL(gamestate)
DEFINE_GLOBAL(demoplayback)
DEFINE_GLOBAL(consoleplayer)
void InitBuildTiles()
{
// need to find a better way to handle this thing.
}

View file

@ -65,6 +65,7 @@ struct UserConfig
{
FString gamegrp;
FString CommandMap;
FString UserDef;
FString DefaultDef;
FString DefaultCon;
FString CommandDemo;
@ -221,7 +222,6 @@ void S_PauseSound(bool notmusic, bool notsfx);
void S_ResumeSound(bool notsfx);
void S_SetSoundPaused(int state);
void G_FatalEngineError(void);
enum
{
MaxSmoothRatio = FRACUNIT

View file

@ -148,28 +148,6 @@ 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!
@ -213,10 +191,10 @@ void GetWallSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool
auto tex = tileGetTexture(spr->picnum);
int width, leftofs;
if (render && hw_hightile && TileFiles.tiledata[spr->picnum].h_xsize)
if (render && hw_hightile && TileFiles.tiledata[spr->picnum].hiofs.xsize)
{
width = TileFiles.tiledata[spr->picnum].h_xsize;
leftofs = (TileFiles.tiledata[spr->picnum].h_xoffs + spr->xoffset);
width = TileFiles.tiledata[spr->picnum].hiofs.xsize;
leftofs = (TileFiles.tiledata[spr->picnum].hiofs.xoffs + spr->xoffset);
}
else
{
@ -249,12 +227,12 @@ void GetFlatSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool
auto tex = tileGetTexture(spr->picnum);
int width, height, leftofs, topofs;
if (render && hw_hightile && TileFiles.tiledata[spr->picnum].h_xsize)
if (render && hw_hightile && TileFiles.tiledata[spr->picnum].hiofs.xsize)
{
width = TileFiles.tiledata[spr->picnum].h_xsize * spr->xrepeat;
height = TileFiles.tiledata[spr->picnum].h_ysize * spr->yrepeat;
leftofs = (TileFiles.tiledata[spr->picnum].h_xoffs + spr->xoffset) * spr->xrepeat;
topofs = (TileFiles.tiledata[spr->picnum].h_yoffs + spr->yoffset) * spr->yrepeat;
width = TileFiles.tiledata[spr->picnum].hiofs.xsize * spr->xrepeat;
height = TileFiles.tiledata[spr->picnum].hiofs.ysize * spr->yrepeat;
leftofs = (TileFiles.tiledata[spr->picnum].hiofs.xoffs + spr->xoffset) * spr->xrepeat;
topofs = (TileFiles.tiledata[spr->picnum].hiofs.yoffs + spr->yoffset) * spr->yrepeat;
}
else
{

View file

@ -7,7 +7,6 @@
extern int cameradist, cameraclock;
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(const sectortype* sec, float dax, float day, float* ceilz, float* florz);
void setWallSectors();
void GetWallSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool render = false);

View file

@ -274,6 +274,18 @@ static void DeleteStuff(FileSystem &fileSystem, const TArray<FString>& deletelum
//
//
//==========================================================================
const char* iwad_folders[13] = { "textures/", "hires/", "sounds/", "music/", "maps/" };
const char* iwad_reserved_duke[12] = { ".map", ".con", "menudef", "gldefs", "zscript", "maps/", nullptr };
const char* iwad_reserved_blood[12] = { ".map", ".ini", "menudef", "gldefs", "zscript", "maps/", nullptr };
const char* iwad_reserved_sw[12] = { ".map", "swcustom.txt", "menudef", "gldefs", "zscript", "maps/", nullptr };
const char* iwad_reserved_ex[12] = { ".map", "menudef", "gldefs", "zscript", "maps/", nullptr };
const char** iwad_reserved()
{
return (g_gameType & GAMEFLAG_PSEXHUMED) ? iwad_reserved_ex :
(g_gameType & GAMEFLAG_SW) ? iwad_reserved_sw :
(g_gameType & GAMEFLAG_BLOOD) ? iwad_reserved_blood : iwad_reserved_duke;
}
void InitFileSystem(TArray<GrpEntry>& groups)
{
@ -374,6 +386,8 @@ void InitFileSystem(TArray<GrpEntry>& groups)
}
todelete.Append(userConfig.toBeDeleted);
LumpFilterInfo lfi;
for (auto p : iwad_folders) lfi.reservedFolders.Push(p);
for (auto p = iwad_reserved(); *p; p++) lfi.requiredPrefixes.Push(*p);
lfi.dotFilter = LumpFilter;

View file

@ -189,6 +189,7 @@ static void GameTicker()
case ga_newgame:
FX_StopAllSounds();
case ga_newgamenostopsound:
DeleteScreenJob();
newGameStarted = true;
FX_SetReverb(0);
gi->FreeLevelData();

View file

@ -38,6 +38,7 @@
#include "raze_music.h"
#include "filesystem.h"
#include "printf.h"
#include "raze_sound.h"
FString gSkillNames[MAXSKILLS];
FString gVolumeNames[MAXVOLUMES];
@ -109,7 +110,8 @@ bool SetMusicForMap(const char* mapname, const char* music, bool namehack)
{
if (!stricmp(mapname, specials[i]))
{
// todo: store this properly.
if (specialmusic.Size() <= i) specialmusic.Resize(i + 1);
specialmusic[i] = music;
return true;
}
}
@ -127,7 +129,7 @@ bool SetMusicForMap(const char* mapname, const char* music, bool namehack)
if (numMatches != 4 || toupper(b1) != 'E' || toupper(b2) != 'L')
return false;
index = FindMapByLevelNum(ep*100 + lev);
index = FindMapByLevelNum(levelnum(ep - 1, lev - 1));
}
if (index != nullptr)

View file

@ -742,3 +742,29 @@ DEFINE_ACTION_FUNCTION(_PlayerMenu, DrawPlayerSprite)
return 0;
}
#ifdef _WIN32
EXTERN_CVAR(Bool, vr_enable_quadbuffered)
#endif
void UpdateVRModes(bool considerQuadBuffered)
{
FOptionValues** pVRModes = OptionValues.CheckKey("VRMode");
if (pVRModes == nullptr) return;
TArray<FOptionValues::Pair>& vals = (*pVRModes)->mValues;
TArray<FOptionValues::Pair> filteredValues;
int cnt = vals.Size();
for (int i = 0; i < cnt; ++i) {
auto const& mode = vals[i];
if (mode.Value == 7) { // Quad-buffered stereo
#ifdef _WIN32
if (!vr_enable_quadbuffered) continue;
#else
continue; // Remove quad-buffered option on Mac and Linux
#endif
if (!considerQuadBuffered) continue; // Probably no compatible screen mode was found
}
filteredValues.Push(mode);
}
vals = filteredValues;
}

406
source/core/parsefuncs.h Normal file
View file

@ -0,0 +1,406 @@
/*
** parsefuncs.h
** handlers for .def parser
** only to be included by the actual parser
**
**---------------------------------------------------------------------------
** Copyright 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.
**---------------------------------------------------------------------------
**
**
*/
int tileSetHightileReplacement(int picnum, int palnum, const char* filename, float alphacut, float xscale, float yscale, float specpower, float specfactor);
int tileSetSkybox(int picnum, int palnum, FString* facenames);
void tileRemoveReplacement(int num);
//===========================================================================
//
//
//
//===========================================================================
template<int cnt>
void parseSkip(FScanner& sc, FScriptPosition& pos)
{
for (int i = 0; i < cnt; i++) if (!sc.GetString()) return;
}
void parseDefine(FScanner& sc, FScriptPosition& pos)
{
FString name;
if (!sc.GetString(name)) return;
if (!sc.GetNumber()) return;
sc.AddSymbol(name, sc.Number);
}
//===========================================================================
//
//
//
//===========================================================================
void parseDefineTexture(FScanner& sc, FScriptPosition& pos)
{
int tile, palette;
if (!sc.GetNumber(tile, true)) return;
if (!sc.GetNumber(palette, true)) return;
if (!sc.GetNumber(true)) return; //formerly x-center, unused
if (!sc.GetNumber(true)) return; //formerly y-center, unused
if (!sc.GetNumber(true)) return; //formerly x-size, unused
if (!sc.GetNumber(true)) return; //formerly y-size, unused
if (!sc.GetString()) return;
tileSetHightileReplacement(tile, palette, sc.String, -1.0, 1.0, 1.0, 1.0, 1.0);
}
//===========================================================================
//
//
//
//===========================================================================
static void parseTexturePaletteBlock(FScanner& sc, FScriptPosition& pos, int tile)
{
FScanner::SavedPos blockend;
int pal = -1, xsiz = 0, ysiz = 0;
FString fn;
double alphacut = -1.0, xscale = 1.0, yscale = 1.0, specpower = 1.0, specfactor = 1.0;
if (!sc.GetNumber(pal, true)) return;
if (sc.StartBraces(&blockend)) return;
while (!sc.FoundEndBrace(blockend))
{
sc.GetString();
if (sc.Compare("file")) sc.GetString(fn);
else if (sc.Compare("alphacut")) sc.GetFloat(alphacut, true);
else if (sc.Compare({ "xscale", "scale", "intensity", "detailscale" })) sc.GetFloat(xscale, true); // what's the point of all of these names?
else if (sc.Compare("yscale")) sc.GetFloat(yscale, true);
else if (sc.Compare({ "specpower", "specularpower", "parallaxscale" })) sc.GetFloat(specpower, true);
else if (sc.Compare({ "specfactor", "specularfactor", "parallaxbias" })) sc.GetFloat(specfactor, true);
else if (sc.Compare("orig_sizex")) sc.GetNumber(xsiz, true);
else if (sc.Compare("orig_sizey")) sc.GetNumber(ysiz, true);
};
if ((unsigned)tile < MAXUSERTILES)
{
if ((unsigned)pal >= MAXPALOOKUPS - RESERVEDPALS)
{
pos.Message(MSG_ERROR, "missing or invalid 'palette number' for texture definition");
}
else if (fn.IsEmpty())
{
pos.Message(MSG_ERROR, "missing 'file name' for texture definition");
}
else if (!fileSystem.FileExists(fn))
{
pos.Message(MSG_ERROR, "%s not found in replacement for tile %d", fn.GetChars(), tile);
}
else
{
if (xsiz > 0 && ysiz > 0)
{
tileSetDummy(tile, xsiz, ysiz);
}
xscale = 1.0f / xscale;
yscale = 1.0f / yscale;
tileSetHightileReplacement(tile, pal, fn, alphacut, xscale, yscale, specpower, specfactor);
}
}
}
static void parseTextureSpecialBlock(FScanner& sc, FScriptPosition& pos, int tile, int specialpal)
{
FScanner::SavedPos blockend;
int pal = -1;
FString fn;
double xscale = 1.0, yscale = 1.0, specpower = 1.0, specfactor = 1.0;
if (!sc.GetNumber(pal, true)) return;
if (sc.StartBraces(&blockend)) return;
while (!sc.FoundEndBrace(blockend))
{
sc.GetString();
if (sc.Compare("file")) sc.GetString(fn);
else if (sc.Compare({ "xscale", "scale", "intensity", "detailscale" })) sc.GetFloat(xscale, true); // what's the point of all of these names?
else if (sc.Compare("yscale")) sc.GetFloat(yscale, true);
else if (sc.Compare({ "specpower", "specularpower", "parallaxscale" })) sc.GetFloat(specpower, true);
else if (sc.Compare({ "specfactor", "specularfactor", "parallaxbias" })) sc.GetFloat(specfactor, true);
};
if ((unsigned)tile < MAXUSERTILES)
{
if (fn.IsEmpty())
{
pos.Message(MSG_ERROR, "missing 'file name' for texture definition");
}
else if (!fileSystem.FileExists(fn))
{
pos.Message(MSG_ERROR, "%s not found in replacement for tile %d", fn.GetChars(), tile);
}
else
{
if (pal == DETAILPAL)
{
xscale = 1.0f / xscale;
yscale = 1.0f / yscale;
}
tileSetHightileReplacement(tile, pal, fn, -1.f, xscale, yscale, specpower, specfactor);
}
}
}
void parseTexture(FScanner& sc, FScriptPosition& pos)
{
FScanner::SavedPos blockend;
int tile = -1;
if (!sc.GetNumber(tile, true)) return;
ValidateTilenum("texture", tile, pos); // do not abort, we still need to parse over the data.
if (sc.StartBraces(&blockend)) return;
while (!sc.FoundEndBrace(blockend))
{
sc.MustGetString();
if (sc.Compare("pal")) parseTexturePaletteBlock(sc, pos, tile);
else if (sc.Compare("detail")) parseTextureSpecialBlock(sc, pos, tile, DETAILPAL);
else if (sc.Compare("glow")) parseTextureSpecialBlock(sc, pos, tile, GLOWPAL);
else if (sc.Compare("specular")) parseTextureSpecialBlock(sc, pos, tile, SPECULARPAL);
else if (sc.Compare("normal")) parseTextureSpecialBlock(sc, pos, tile, NORMALPAL);
}
}
//===========================================================================
//
//
//
//===========================================================================
void parseDefineSkybox(FScanner& sc, FScriptPosition& pos)
{
int tile, palette;
FString fn[6];
if (!sc.GetNumber(tile, true)) return;
if (!sc.GetNumber(palette, true)) return;
if (!sc.GetNumber(true)) return; //'future extension' (for what?)
for (int i = 0; i < 6; i++)
{
if (!sc.GetString()) return;
fn[i] = sc.String;
}
tileSetSkybox(tile, palette, fn);
}
//===========================================================================
//
//
//
//===========================================================================
void parseSkybox(FScanner& sc, FScriptPosition& pos)
{
FString faces[6];
FScanner::SavedPos blockend;
int tile = -1, pal = 0;
if (sc.StartBraces(&blockend)) return;
while (!sc.FoundEndBrace(blockend))
{
sc.MustGetString();
if (sc.Compare("tile")) sc.GetNumber(tile, true);
else if (sc.Compare("pal")) sc.GetNumber(pal, true);
else if (sc.Compare({ "ft", "front", "forward" })) sc.GetString(faces[0]);
else if (sc.Compare({ "rt", "right" })) sc.GetString(faces[1]);
else if (sc.Compare({ "bk", "back" })) sc.GetString(faces[2]);
else if (sc.Compare({ "lt", "lf", "left" })) sc.GetString(faces[3]);
else if (sc.Compare({ "up", "ceiling", "top", "ceil" })) sc.GetString(faces[4]);
else if (sc.Compare({ "dn", "floor", "bottom", "down" })) sc.GetString(faces[5]);
// skip over everything else.
}
if (tile < 0)
{
pos.Message(MSG_ERROR, "skybox: missing tile number");
return;
}
tileSetSkybox(tile, pal, faces);
}
//===========================================================================
//
//
//
//===========================================================================
void parseSetupTile(FScanner& sc, FScriptPosition& pos)
{
int tile;
if (!sc.GetNumber(tile, true)) return;
if (!ValidateTilenum("setuptile", tile, pos)) return;
auto& tiled = TileFiles.tiledata[tile];
if (!sc.GetNumber(tiled.hiofs.xsize, true)) return;
if (!sc.GetNumber(tiled.hiofs.ysize, true)) return;
if (!sc.GetNumber(tiled.hiofs.xoffs, true)) return;
if (!sc.GetNumber(tiled.hiofs.yoffs, true)) return;
}
//===========================================================================
//
//
//
//===========================================================================
void parseSetupTileRange(FScanner& sc, FScriptPosition& pos)
{
int tilestart, tileend;
if (!sc.GetNumber(tilestart, true)) return;
if (!sc.GetNumber(tileend, true)) return;
if (!ValidateTileRange("setuptilerange", tilestart, tileend, pos)) return;
TileOffs hiofs;
if (!sc.GetNumber(hiofs.xsize, true)) return;
if (!sc.GetNumber(hiofs.ysize, true)) return;
if (!sc.GetNumber(hiofs.xoffs, true)) return;
if (!sc.GetNumber(hiofs.yoffs, true)) return;
for (int i = tilestart; i <= tileend; i++) TileFiles.tiledata[i].hiofs = hiofs;
}
//===========================================================================
//
//
//
//===========================================================================
void parseAnimTileRange(FScanner& sc, FScriptPosition& pos)
{
SetAnim set;
if (!sc.GetNumber(set.tile1, true)) return;
if (!sc.GetNumber(set.tile2, true)) return;
if (!sc.GetNumber(set.speed, true)) return;
if (!sc.GetNumber(set.type, true)) return;
processSetAnim("animtilerange", pos, set);
}
//===========================================================================
//
//
//
//===========================================================================
void parseAlphahack(FScanner& sc, FScriptPosition& pos)
{
int tile;
if (!sc.GetNumber(tile, true)) return;
if (!sc.GetFloat(true)) return;
if ((unsigned)tile < MAXTILES) TileFiles.tiledata[tile].texture->alphaThreshold = (float)sc.Float;
}
//===========================================================================
//
//
//
//===========================================================================
void parseAlphahackRange(FScanner& sc, FScriptPosition& pos)
{
int tilestart, tileend;
if (!sc.GetNumber(tilestart, true)) return;
if (!sc.GetNumber(tileend, true)) return;
if (!sc.GetFloat(true)) return;
if (!ValidateTileRange("alphahackrange", tilestart, tileend, pos)) return;
for (int i = tilestart; i <= tileend; i++)
TileFiles.tiledata[i].texture->alphaThreshold = (float)sc.Number;
}
//===========================================================================
//
//
//
//===========================================================================
void parseDefineTint(FScanner& sc, FScriptPosition& pos)
{
int pal, r, g, b, f;
if (!sc.GetNumber(pal, true)) return;
if (!sc.GetNumber(r)) return;
if (!sc.GetNumber(g)) return;
if (!sc.GetNumber(b)) return;
if (!sc.GetNumber(f)) return;
lookups.setPaletteTint(pal, r, g, b, 0, 0, 0, f);
}
//===========================================================================
//
//
//
//===========================================================================
void parseFogpal(FScanner& sc, FScriptPosition& pos)
{
int pal, r, g, b;
if (!sc.GetNumber(pal, true)) return;
if (!sc.GetNumber(r)) return;
if (!sc.GetNumber(g)) return;
if (!sc.GetNumber(b)) return;
r = clamp(r, 0, 63);
g = clamp(g, 0, 63);
b = clamp(b, 0, 63);
lookups.makeTable(pal, nullptr, r << 2, g << 2, b << 2, 1);
}
//===========================================================================
//
//
//
//===========================================================================
void parseNoFloorpalRange(FScanner& sc, FScriptPosition& pos)
{
int start, end;
if (!sc.GetNumber(start, true)) return;
if (!sc.GetNumber(end, true)) return;
if (start > 1) start = 1;
if (end > MAXPALOOKUPS - 1) end = MAXPALOOKUPS - 1;
for (int i = start; i <= end; i++)
lookups.tables[i].noFloorPal = true;
}

View file

@ -46,6 +46,7 @@
static bool mus_blocked;
static FString lastStartedMusic;
TArray<FString> specialmusic;
MusicAliasMap MusicAliases;
MusicAliasMap LevelMusicAliases;
@ -132,23 +133,27 @@ FileReader OpenMusic(const char* musicname)
if (!reader.isOpen())
{
int lumpnum = LookupMusic(musicname);
if (mus_extendedlookup && lumpnum >= 0)
if (mus_extendedlookup || lumpnum < 0)
{
if (lumpnum >= 0)
{
// EDuke also looks in a subfolder named after the main game resource. Do this as well if extended lookup is active.
auto rfn = fileSystem.GetResourceFileName(fileSystem.GetFileContainer(lumpnum));
auto rfbase = ExtractFileBase(rfn);
FStringf aliasMusicname("music/%s/%s", rfbase.GetChars(), musicname);
lumpnum = LookupMusic(aliasMusicname);
int newlumpnum = LookupMusic(aliasMusicname);
if (newlumpnum >= 0) lumpnum = newlumpnum;
}
if (lumpnum == -1)
{
// Always look in the 'music' subfolder as well. This gets used by multiple setups to store ripped CD tracks.
FStringf aliasMusicname("music/%s", musicname);
lumpnum = LookupMusic(aliasMusicname);
int newlumpnum = LookupMusic(aliasMusicname, lumpnum >= 0);
if (newlumpnum >= 0) lumpnum = newlumpnum;
}
if (lumpnum == -1 && (g_gameType & GAMEFLAG_SW))
{
// Some Shadow Warrioe distributions have the music in a subfolder named 'classic'. Check that, too.
// Some Shadow Warrior distributions have the music in a subfolder named 'classic'. Check that, too.
FStringf aliasMusicname("classic/music/%s", musicname);
lumpnum = fileSystem.FindFile(aliasMusicname);
}

View file

@ -6,6 +6,7 @@
typedef TMap<FName, FName> MusicAliasMap;
extern MusicAliasMap MusicAliases;
extern TArray<FString> specialmusic;
// Totally minimalistic interface - should be all the game modules need.
void Mus_InitMusic();

View file

@ -142,7 +142,11 @@ int S_LookupSound(const char* fn)
static const char * const sndformats[] = { "OGG", "FLAC", "WAV" };
if (snd_extendedlookup)
{
int lump = fileSystem.FindFileWithExtensions(StripExtension(fn), sndformats, countof(sndformats));
auto newfn = StripExtension(fn);
int lump = fileSystem.FindFileWithExtensions(newfn, sndformats, countof(sndformats));
if (lump >= 0) return lump;
newfn = "sound/" + newfn;
lump = fileSystem.FindFileWithExtensions(newfn, sndformats, countof(sndformats));
if (lump >= 0) return lump;
}
return fileSystem.FindFile(fn);

View file

@ -35,7 +35,7 @@
#include <memory>
#include "m_crc32.h"
#include "glbackend.h"
#include "hw_palmanager.h"
#include "resourcefile.h"
#include "imagehelpers.h"
@ -44,6 +44,8 @@
#include "build.h"
#include "v_video.h"
static PaletteManager* palmanager;
//===========================================================================
//
// This class manages the hardware data for the indexed render mode.
@ -138,4 +140,24 @@ IHardwareTexture* PaletteManager::GetLookup(int index)
return nullptr;
}
//===========================================================================
//
//
//
//===========================================================================
IHardwareTexture *setpalettelayer(int layer, int translation)
{
if (!palmanager) palmanager = new PaletteManager;
if (layer == 1)
return palmanager->GetPalette(GetTranslationType(translation) - Translation_Remap);
else if (layer == 2)
return palmanager->GetLookup(GetTranslationIndex(translation));
else return nullptr;
}
void ClearPalManager()
{
if (palmanager) delete palmanager;
palmanager = nullptr;
}

View file

@ -0,0 +1,24 @@
#pragma once
#include "gl_hwtexture.h"
struct palette_t;
class PaletteManager
{
IHardwareTexture* palettetextures[256] = {};
IHardwareTexture* lookuptextures[256] = {};
unsigned FindPalswap(const uint8_t* paldata, palette_t& fadecolor);
public:
~PaletteManager();
void DeleteAll();
IHardwareTexture *GetPalette(int index);
IHardwareTexture* GetLookup(int index);
};
IHardwareTexture* setpalettelayer(int layer, int translation);
void ClearPalManager();

View file

@ -0,0 +1,114 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2021 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 2 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_voxels.cpp
**
** voxel handling.
**
**/
#include "build.h"
#include "voxels.h"
#include "hw_voxels.h"
#include "gamecontrol.h"
int16_t tiletovox[MAXTILES];
static int voxlumps[MAXVOXELS];
float voxscale[MAXVOXELS];
voxmodel_t* voxmodels[MAXVOXELS];
FixedBitArray<MAXVOXELS> voxrotate;
void voxInit()
{
for (auto& v : tiletovox) v = -1;
for (auto& v : voxscale) v = 1.f;
voxrotate.Zero();
}
void voxClear()
{
for (auto& vox : voxmodels)
{
if (vox) delete vox;
vox = nullptr;
}
}
int voxDefine(int voxindex, const char* filename)
{
if ((unsigned)voxindex >= MAXVOXELS)
return -1;
int i = fileSystem.FindFile(filename);
voxlumps[voxindex] = i;
return i < 0 ? -1 : 0;
}
static voxmodel_t* voxload(int lumpnum)
{
FVoxel* voxel = R_LoadKVX(lumpnum);
if (voxel != nullptr)
{
voxmodel_t* vm = new voxmodel_t;
*vm = {};
auto pivot = voxel->Mips[0].Pivot;
vm->mdnum = 1; //VOXel model id
vm->scale = vm->bscale = 1.f;
vm->piv.x = float(pivot.X);
vm->piv.y = float(pivot.Y);
vm->piv.z = float(pivot.Z);
vm->siz.x = voxel->Mips[0].SizeX;
vm->siz.y = voxel->Mips[0].SizeY;
vm->siz.z = voxel->Mips[0].SizeZ;
vm->is8bit = true;
voxel->Mips[0].Pivot.Zero(); // Needs to be taken out of the voxel data because it gets baked into the vertex buffer which we cannot use here.
vm->model = new FVoxelModel(voxel, true);
return vm;
}
return nullptr;
}
void LoadVoxelModels()
{
for (int i = 0; i < MAXVOXELS; i++)
{
int lumpnum = voxlumps[i];
if (lumpnum > 0)
{
voxmodels[i] = voxload(lumpnum);
if (voxmodels[i])
voxmodels[i]->scale = voxscale[i];
else
Printf("Unable to load voxel from %s\n", fileSystem.GetFileFullPath(lumpnum));
}
else
{
auto index = fileSystem.FindResource(i, "KVX");
if (index >= 0)
{
voxmodels[i] = voxload(index);
}
}
}
}

View file

@ -0,0 +1,24 @@
#pragma once
#include <stdint.h>
#include "mdsprite.h"
// We still need the relation to mdmodel_t as long as the model code hasn't been redone.
struct voxmodel_t : public mdmodel_t
{
FVoxelModel* model = nullptr;
vec3_t siz;
vec3f_t piv;
int32_t is8bit;
};
extern int16_t tiletovox[];
extern float voxscale[];
extern voxmodel_t* voxmodels[MAXVOXELS];
extern FixedBitArray<MAXVOXELS> voxrotate;
void voxInit();
void voxClear();
int voxDefine(int voxindex, const char* filename);

View file

@ -40,6 +40,7 @@
#include "gamefuncs.h"
#include "hw_portal.h"
#include "gamestruct.h"
#include "hw_voxels.h"
//==========================================================================
@ -48,8 +49,10 @@
//
//==========================================================================
void BunchDrawer::Init(HWDrawInfo *_di, Clipper* c, vec2_t& view)
void BunchDrawer::Init(HWDrawInfo *_di, Clipper* c, vec2_t& view, binangle a1, binangle a2)
{
ang1 = a1;
ang2 = a2;
di = _di;
clipper = c;
viewx = view.x * (1/ 16.f);
@ -82,6 +85,8 @@ void BunchDrawer::StartScene()
Bunches.Clear();
CompareData.Clear();
gotsector.Zero();
gotsector2.Zero();
gotwall.Zero();
}
//==========================================================================
@ -90,14 +95,16 @@ void BunchDrawer::StartScene()
//
//==========================================================================
void BunchDrawer::StartBunch(int sectnum, int linenum, binangle startan, binangle endan)
bool BunchDrawer::StartBunch(int sectnum, int linenum, binangle startan, binangle endan, bool portal)
{
FBunch* bunch = &Bunches[LastBunch = Bunches.Reserve(1)];
bunch->sectnum = sectnum;
bunch->startline = bunch->endline = linenum;
bunch->startangle = startan;
bunch->endangle = endan;
bunch->startangle = (startan.asbam() - ang1.asbam()) > ANGLE_180? ang1 :startan;
bunch->endangle = (endan.asbam() - ang2.asbam()) < ANGLE_180 ? ang2 : endan;
bunch->portal = portal;
return bunch->endangle != ang2;
}
//==========================================================================
@ -106,10 +113,11 @@ void BunchDrawer::StartBunch(int sectnum, int linenum, binangle startan, binangl
//
//==========================================================================
void BunchDrawer::AddLineToBunch(int line, binangle newan)
bool BunchDrawer::AddLineToBunch(int line, binangle newan)
{
Bunches[LastBunch].endline++;
Bunches[LastBunch].endangle = newan;
Bunches[LastBunch].endangle = (newan.asbam() - ang2.asbam()) < ANGLE_180 ? ang2 : newan;
return Bunches[LastBunch].endangle != ang2;
}
//==========================================================================
@ -181,7 +189,7 @@ bool BunchDrawer::CheckClip(walltype* wal)
//
//==========================================================================
int BunchDrawer::ClipLine(int line)
int BunchDrawer::ClipLine(int line, bool portal)
{
auto wal = &wall[line];
@ -194,7 +202,7 @@ int BunchDrawer::ClipLine(int line)
return CL_Skip;
}
if (!clipper->SafeCheckRange(startAngle, endAngle))
if (!portal && !clipper->SafeCheckRange(startAngle, endAngle))
{
return CL_Skip;
}
@ -202,7 +210,7 @@ int BunchDrawer::ClipLine(int line)
if (wal->nextwall == -1 || (wal->cstat & CSTAT_WALL_1WAY) || CheckClip(wal))
{
// one-sided
clipper->SafeAddClipRange(startAngle, endAngle);
if (!portal) clipper->SafeAddClipRange(startAngle, endAngle);
return CL_Draw;
}
else
@ -224,14 +232,15 @@ void BunchDrawer::ProcessBunch(int bnch)
ClipWall.Clock();
for (int i = bunch->startline; i <= bunch->endline; i++)
{
int clipped = ClipLine(i);
int clipped = ClipLine(i, bunch->portal);
if (clipped & CL_Draw)
{
show2dwall.Set(i);
//if (gl_render_walls)
if (!gotwall[i])
{
gotwall.Set(i);
ClipWall.Unclock();
Bsp.Unclock();
SetupWall.Clock();
@ -249,7 +258,7 @@ void BunchDrawer::ProcessBunch(int bnch)
if (clipped & CL_Pass)
{
ClipWall.Unclock();
ProcessSector(wall[i].nextsector);
ProcessSector(wall[i].nextsector, false);
ClipWall.Clock();
}
}
@ -288,7 +297,7 @@ int BunchDrawer::WallInFront(int wall1, int wall2)
if ((t1 * t2) >= 0)
{
t2 = PointOnLineSide(viewx, viewy, x1s, y1s, dx, dy);
return((t2 * t1) < 0);
return((t2 * t1) <= 0);
}
dx = x2e - x2s;
@ -304,7 +313,7 @@ int BunchDrawer::WallInFront(int wall1, int wall2)
if ((t1 * t2) >= 0)
{
t2 = PointOnLineSide(viewx, viewy, x2s, y2s, dx, dy);
return((t2 * t1) >= 0);
return((t2 * t1) > 0);
}
return(-2);
}
@ -415,6 +424,7 @@ int BunchDrawer::FindClosestBunch()
}
}
//Printf("picked bunch starting at %d\n", Bunches[closest].startline);
return closest;
}
@ -424,10 +434,10 @@ int BunchDrawer::FindClosestBunch()
//
//==========================================================================
void BunchDrawer::ProcessSector(int sectnum)
void BunchDrawer::ProcessSector(int sectnum, bool portal)
{
if (gotsector[sectnum]) return;
gotsector.Set(sectnum);
if (gotsector2[sectnum]) return;
gotsector2.Set(sectnum);
auto sect = &sector[sectnum];
bool inbunch;
@ -436,6 +446,9 @@ void BunchDrawer::ProcessSector(int sectnum)
SetupSprite.Clock();
int z;
if (!gotsector[sectnum])
{
gotsector.Set(sectnum);
SectIterator it(sectnum);
while ((z = it.NextIndex()) >= 0)
{
@ -458,6 +471,7 @@ void BunchDrawer::ProcessSector(int sectnum)
}
}
SetupSprite.Unclock();
}
if (automapping)
show2dsector.Set(sectnum);
@ -478,36 +492,26 @@ void BunchDrawer::ProcessSector(int sectnum)
DVector2 start = { WallStartX(thiswall), WallStartY(thiswall) };
DVector2 end = { WallStartX(thiswall->point2), WallStartY(thiswall->point2) };
#endif
binangle ang1 = thiswall->clipangle;
binangle ang2 = wall[thiswall->point2].clipangle;
binangle walang1 = thiswall->clipangle;
binangle walang2 = wall[thiswall->point2].clipangle;
if (ang1.asbam() - ang2.asbam() < ANGLE_180)
// outside the visible area or seen from the backside.
if ((walang1.asbam() - ang1.asbam() > ANGLE_180 && walang2.asbam() - ang1.asbam() > ANGLE_180) ||
(walang1.asbam() - ang2.asbam() < ANGLE_180 && walang2.asbam() - ang2.asbam() < ANGLE_180) ||
(walang1.asbam() - walang2.asbam() < ANGLE_180))
{
// Backside
inbunch = false;
}
/* disabled because it only fragments the bunches without any performance gain.
else if (!clipper->SafeCheckRange(ang1, ang2))
else if (!inbunch)
{
// is it visible?
inbunch = false;
}
*/
else if (!inbunch || ang2.asbam() - startangle.asbam() >= 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;
startangle = walang1;
//Printf("Starting bunch:\n\tWall %d\n", sect->wallptr + i);
inbunch = StartBunch(sectnum, sect->wallptr + i, walang1, walang2, portal);
}
else
{
AddLineToBunch(sect->wallptr + i, ang2);
//Printf("\tWall %d\n", sect->wallptr + i);
inbunch = AddLineToBunch(sect->wallptr + i, walang2);
}
if (thiswall->point2 != sect->wallptr + i + 1) inbunch = false;
}
@ -519,16 +523,39 @@ void BunchDrawer::ProcessSector(int sectnum)
//
//==========================================================================
void BunchDrawer::RenderScene(const int* viewsectors, unsigned sectcount)
void BunchDrawer::RenderScene(const int* viewsectors, unsigned sectcount, bool portal)
{
Bsp.Clock();
for(unsigned i=0;i<sectcount;i++)
ProcessSector(viewsectors[i]);
//Printf("----------------------------------------- \nstart at sector %d\n", viewsectors[0]);
auto process = [&]()
{
for (unsigned i = 0; i < sectcount; i++)
ProcessSector(viewsectors[i], portal);
while (Bunches.Size() > 0)
{
int closest = FindClosestBunch();
ProcessBunch(closest);
DeleteBunch(closest);
}
};
Bsp.Clock();
if (ang1.asbam() != 0 || ang2.asbam() != 0)
{
process();
}
else
{
// with a 360° field of view we need to split the scene into two halves.
// The BunchInFront check can fail with angles that may wrap around.
auto rotang = di->Viewpoint.RotAngle;
ang1 = bamang(rotang - ANGLE_90);
ang2 = bamang(rotang + ANGLE_90);
process();
clipper->Clear();
gotsector2.Zero();
ang1 = bamang(rotang + ANGLE_90);
ang2 = bamang(rotang - ANGLE_90);
process();
}
Bsp.Unclock();
}

View file

@ -11,7 +11,8 @@ struct FBunch
int sectnum;
int startline;
int endline;
binangle startangle; // in pseudo angles for the clipper
bool portal;
binangle startangle;
binangle endangle;
};
@ -27,6 +28,9 @@ class BunchDrawer
vec2_t iview;
float gcosang, gsinang;
FixedBitArray<MAXSECTORS> gotsector;
FixedBitArray<MAXSECTORS> gotsector2;
FixedBitArray<MAXWALLS> gotwall;
binangle ang1, ang2;
private:
@ -38,19 +42,19 @@ private:
};
void StartScene();
void StartBunch(int sectnum, int linenum, binangle startan, binangle endan);
void AddLineToBunch(int line, binangle newan);
bool StartBunch(int sectnum, int linenum, binangle startan, binangle endan, bool portal);
bool AddLineToBunch(int line, binangle newan);
void DeleteBunch(int index);
bool CheckClip(walltype* wal);
int ClipLine(int line);
int ClipLine(int line, bool portal);
void ProcessBunch(int bnch);
int WallInFront(int wall1, int wall2);
int BunchInFront(FBunch* b1, FBunch* b2);
int FindClosestBunch();
void ProcessSector(int sectnum);
void ProcessSector(int sectnum, bool portal);
public:
void Init(HWDrawInfo* _di, Clipper* c, vec2_t& view);
void RenderScene(const int* viewsectors, unsigned sectcount);
void Init(HWDrawInfo* _di, Clipper* c, vec2_t& view, binangle a1, binangle a2);
void RenderScene(const int* viewsectors, unsigned sectcount, bool portal);
const FixedBitArray<MAXSECTORS>& GotSector() const { return gotsector; }
};

View file

@ -358,29 +358,6 @@ void Clipper::DoRemoveClipRange(angle_t start, angle_t end)
//
//-----------------------------------------------------------------------------
binangle Clipper::PointToAngle(const vec2_t& pos)
{
vec2_t vec = pos - viewpoint;
#if 0
if (vec.x == 0 && vec.y == 0)
{
return 0;
}
else
{
double result = vec.y / double(abs(vec.x) + fabs(vec.y));
if (vec.x < 0)
{
result = 2. - result;
}
return bamang(xs_Fix<30>::ToFix(result));
}
#else
return q16ang(gethiq16angle(vec.x, vec.y));
#endif
}
void Clipper::DumpClipper()
{
for (auto node = cliphead; node; node = node->next)

View file

@ -144,7 +144,29 @@ public:
void DumpClipper();
binangle PointToAngle(const vec2_t& point);
binangle PointToAngle(const vec2_t& pos)
{
vec2_t vec = pos - viewpoint;
#if 0
if (vec.x == 0 && vec.y == 0)
{
return bamang(0);
}
else
{
double result = vec.y / double(abs(vec.x) + fabs(vec.y));
if (vec.x < 0)
{
result = 2. - result;
}
return bamang(xs_Fix<30>::ToFix(result));
}
#else
return bvectangbam(vec.x, vec.y);
#endif
}
};

View file

@ -41,6 +41,7 @@
#include "gamecvars.h"
#include "gamestruct.h"
#include "automap.h"
#include "hw_voxels.h"
EXTERN_CVAR(Float, r_visibility)
CVAR(Bool, gl_no_skyclear, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
@ -210,7 +211,7 @@ angle_t HWDrawInfo::FrustumAngle()
// 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;
if (a1 >= ANGLE_90) return 0xffffffff; // it's either below 90 or bust.
return a1;
}
@ -300,14 +301,14 @@ void HWDrawInfo::DispatchSprites()
{
HWSprite hwsprite;
int num = tiletovox[tspr->picnum];
if (hwsprite.ProcessVoxel(this, voxmodels[tiletovox[tspr->picnum]], tspr, &sector[tspr->sectnum], voxrotate[num >> 3] & (1 << (num & 7))))
if (hwsprite.ProcessVoxel(this, voxmodels[tiletovox[tspr->picnum]], tspr, &sector[tspr->sectnum], voxrotate[num]))
continue;
}
else if ((tspr->cstat & CSTAT_SPRITE_ALIGNMENT) == CSTAT_SPRITE_ALIGNMENT_SLAB && tspr->picnum < MAXVOXELS && voxmodels[tspr->picnum])
{
HWSprite hwsprite;
int num = tspr->picnum;
hwsprite.ProcessVoxel(this, voxmodels[tspr->picnum], tspr, &sector[tspr->sectnum], voxrotate[num >> 3] & (1 << (num & 7)));
hwsprite.ProcessVoxel(this, voxmodels[tspr->picnum], tspr, &sector[tspr->sectnum], voxrotate[num]);
continue;
}
}
@ -363,12 +364,12 @@ void HWDrawInfo::DispatchSprites()
//
//-----------------------------------------------------------------------------
void HWDrawInfo::CreateScene()
void HWDrawInfo::CreateScene(bool portal)
{
const auto& vp = Viewpoint;
angle_t a1 = FrustumAngle();
mClipper->SafeAddClipRange(bamang(vp.RotAngle + a1), bamang(vp.RotAngle - a1));
if (a1 != 0xffffffff) mClipper->SafeAddClipRange(bamang(vp.RotAngle + a1), bamang(vp.RotAngle - a1));
// reset the portal manager
portalState.StartFrame();
@ -384,11 +385,12 @@ void HWDrawInfo::CreateScene()
geoofs = { 0,0 };
vec2_t view = { int(vp.Pos.X * 16), int(vp.Pos.Y * -16) };
mDrawer.Init(this, mClipper, view);
if (a1 != 0xffffffff) mDrawer.Init(this, mClipper, view, bamang(vp.RotAngle - a1), bamang(vp.RotAngle + a1));
else mDrawer.Init(this, mClipper, view, bamang(0), bamang(0));
if (vp.SectNums)
mDrawer.RenderScene(vp.SectNums, vp.SectCount);
mDrawer.RenderScene(vp.SectNums, vp.SectCount, portal);
else
mDrawer.RenderScene(&vp.SectCount, 1);
mDrawer.RenderScene(&vp.SectCount, 1, portal);
SetupSprite.Clock();
gi->processSprites(tsprite, spritesortcnt, view.x, view.y, vp.Pos.Z * -256, bamang(vp.RotAngle), vp.TicFrac * 65536);
@ -420,8 +422,9 @@ void HWDrawInfo::CreateScene()
mClipper->Clear();
mClipper->SafeAddClipRange(bamang(vp.RotAngle + a1), bamang(vp.RotAngle - a1));
mDrawer.Init(this, mClipper, view);
mDrawer.RenderScene(&drawsect, 1);
if (a1 != 0xffffffff) mDrawer.Init(this, mClipper, view, bamang(vp.RotAngle - a1), bamang(vp.RotAngle + a1));
else mDrawer.Init(this, mClipper, view, bamang(0), bamang(0));
mDrawer.RenderScene(&drawsect, 1, false);
for (int i = 0; i < eff.geocnt; i++)
{
@ -451,8 +454,9 @@ void HWDrawInfo::CreateScene()
mClipper->Clear();
mClipper->SafeAddClipRange(bamang(vp.RotAngle + a1), bamang(vp.RotAngle - a1));
mDrawer.Init(this, mClipper, view);
mDrawer.RenderScene(&drawsect, 1);
if (a1 != 0xffffffff) mDrawer.Init(this, mClipper, view, bamang(vp.RotAngle - a1), bamang(vp.RotAngle + a1));
else mDrawer.Init(this, mClipper, view, bamang(0), bamang(0));
mDrawer.RenderScene(&drawsect, 1, false);
for (int i = 0; i < eff.geocnt; i++)
{
@ -669,7 +673,7 @@ void HWDrawInfo::Set3DViewport(FRenderState &state)
//
//-----------------------------------------------------------------------------
void HWDrawInfo::DrawScene(int drawmode)
void HWDrawInfo::DrawScene(int drawmode, bool portal)
{
static int recursion = 0;
static int ssao_portals_available = 0;
@ -691,7 +695,7 @@ void HWDrawInfo::DrawScene(int drawmode)
ssao_portals_available--;
}
CreateScene();
CreateScene(portal);
auto& RenderState = *screen->RenderState();
RenderState.SetDepthMask(true);
@ -724,7 +728,7 @@ void HWDrawInfo::DrawScene(int drawmode)
void HWDrawInfo::ProcessScene(bool toscreen)
{
portalState.BeginScene();
DrawScene(toscreen ? DM_MAINVIEW : DM_OFFSCREEN);
DrawScene(toscreen ? DM_MAINVIEW : DM_OFFSCREEN, false);
if (toscreen && isBlood())
{
gotsector = mDrawer.GotSector(); // Blood needs this to implement some lighting effect hacks. Needs to be refactored to use better info.

View file

@ -158,8 +158,8 @@ public:
void ClearBuffers();
HWDrawInfo *EndDrawInfo();
void DrawScene(int drawmode);
void CreateScene();
void DrawScene(int drawmode, bool portal);
void CreateScene(bool portal);
void DispatchSprites();
void RenderScene(FRenderState &state);
void RenderTranslucent(FRenderState &state);

View file

@ -95,7 +95,7 @@ void HWDrawInfo::AddFlat(HWFlat *flat)
{
int list;;
if (flat->RenderStyle != LegacyRenderStyles[STYLE_Translucent] || flat->alpha < 1.f - FLT_EPSILON) // flat->texture->GetTranslucency() - fixme
if (flat->RenderStyle != LegacyRenderStyles[STYLE_Translucent] || flat->alpha < 1.f - FLT_EPSILON || checkTranslucentReplacement(flat->texture->GetID(), flat->palette))
{
// translucent portals go into the translucent border list.
list = flat->sprite? GLDL_TRANSLUCENT : GLDL_TRANSLUCENTBORDER;

View file

@ -11,6 +11,9 @@
#include "gamefuncs.h"
#include "render.h"
#include "matrix.h"
#include "gamecontrol.h"
#include "hw_renderstate.h"
#include "hw_cvars.h"
#ifdef _MSC_VER
#pragma warning(disable:4244)
@ -26,6 +29,7 @@ struct FDynLightData;
class VSMatrix;
struct FSpriteModelFrame;
class FRenderState;
struct voxmodel_t;
struct HWSectorPlane
{
@ -192,7 +196,6 @@ public:
void SetupLights(HWDrawInfo *di, FDynLightData &lightdata);
void MakeVertices(HWDrawInfo *di, bool nosplit);
void SetLightAndFog(FRenderState& state);
void SkyPlane(HWDrawInfo *di, sectortype *sector, int plane, bool allowmirror);
void SkyLine(HWDrawInfo *di, sectortype *sec, walltype *line);
@ -356,3 +359,71 @@ inline float sectorVisibility(sectortype* sec)
}
inline const float hw_density = 0.35f;
int checkTranslucentReplacement(FTextureID picnum, int pal);
inline bool maskWallHasTranslucency(const walltype* wall)
{
return (wall->cstat & CSTAT_WALL_TRANSLUCENT) || checkTranslucentReplacement(tileGetTexture(wall->picnum)->GetID(), wall->pal);
}
inline bool spriteHasTranslucency(const spritetype* tspr)
{
if ((tspr->cstat & CSTAT_SPRITE_TRANSLUCENT) || //(tspr->clipdist & TSPR_FLAGS_DRAW_LAST) ||
((unsigned)tspr->owner < MAXSPRITES && spriteext[tspr->owner].alpha))
return true;
return checkTranslucentReplacement(tileGetTexture(tspr->picnum)->GetID(), tspr->pal);
}
inline void SetSpriteTranslucency(const spritetype* sprite, float& alpha, FRenderStyle& RenderStyle)
{
bool trans = (sprite->cstat & CSTAT_SPRITE_TRANSLUCENT);
if (trans)
{
RenderStyle = GetRenderStyle(0, !!(sprite->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT));
alpha = GetAlphaFromBlend((sprite->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT) ? DAMETH_TRANS2 : DAMETH_TRANS1, 0);
}
else
{
RenderStyle = LegacyRenderStyles[STYLE_Translucent];
alpha = 1.f;
}
alpha *= 1.f - spriteext[sprite->owner].alpha;
}
//==========================================================================
//
//
//
//==========================================================================
extern PalEntry GlobalMapFog;
extern float GlobalFogDensity;
__forceinline void SetLightAndFog(FRenderState& state, PalEntry fade, int palette, int shade, int visibility, float alpha, bool setcolor = true)
{
// 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;
shade = clamp(shade, 0, numshades - 1);
// Disable brightmaps if non-black fog is used.
if (ShadeDiv >= 1 / 1000.f && foggy)
{
state.EnableFog(1);
float density = GlobalMapFog ? GlobalFogDensity : 350.f - Scale(numshades - shade, 150, numshades);
state.SetFog((GlobalMapFog) ? GlobalMapFog : fade, density * hw_density);
state.SetSoftLightLevel(255);
state.SetLightParms(128.f, 1 / 1000.f);
}
else
{
state.EnableFog(0);
state.SetFog(0, 0);
state.SetSoftLightLevel(gl_fogmode != 0 && ShadeDiv >= 1 / 1000.f ? 255 - Scale(shade, 255, numshades) : 255);
state.SetLightParms(visibility, ShadeDiv / (numshades - 2));
}
// The shade rgb from the tint is ignored here.
state.SetColor(globalr * (1 / 255.f), globalg * (1 / 255.f), globalb * (1 / 255.f), alpha);
}

View file

@ -41,9 +41,6 @@
CVAR(Int, gl_breaksec, -1, 0)
#endif
extern PalEntry GlobalMapFog;
extern float GlobalFogDensity;
//==========================================================================
//
//
@ -124,8 +121,8 @@ void HWFlat::MakeVertices()
auto ret = screen->mVertexData->AllocVertices(6);
auto vp = ret.first;
float x = !(sprite->cstat & CSTAT_SECTOR_XFLIP) ? 0.f : 1.f;
float y = !(sprite->cstat & CSTAT_SECTOR_YFLIP) ? 0.f : 1.f;
float x = !(sprite->cstat & CSTAT_SPRITE_XFLIP) ? 0.f : 1.f;
float y = !(sprite->cstat & CSTAT_SPRITE_YFLIP) ? 0.f : 1.f;
for (unsigned i = 0; i < 6; i++)
{
const static unsigned indices[] = { 0, 1, 2, 0, 2, 3 };
@ -170,28 +167,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
else state.SetNormal({ 0, -1, 0 });
}
// Fog must be done before the texture so that the texture selector can override it.
bool foggy = (GlobalMapFog || (fade & 0xffffff));
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 * hw_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.SetColorAlpha(PalEntry(255, globalr, globalg, globalb), alpha);
SetLightAndFog(state, fade, palette, shade, visibility, alpha);
if (translucent)
{
@ -202,7 +178,8 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
state.SetRenderStyle(RenderStyle);
state.SetTextureMode(RenderStyle);
if (!texture->GetTranslucency()) state.AlphaFunc(Alpha_GEqual, gl_mask_threshold);
if (!texture || !checkTranslucentReplacement(texture->GetID(), palette)) state.AlphaFunc(Alpha_GEqual, texture->alphaThreshold);
else state.AlphaFunc(Alpha_GEqual, 0.f);
}
state.SetMaterial(texture, UF_Texture, 0, sprite == nullptr? CLAMP_NONE : CLAMP_XY, TRANSLATION(Translation_Remap + curbasepal, palette), -1);
@ -366,7 +343,7 @@ void HWFlat::ProcessFlatSprite(HWDrawInfo* di, spritetype* sprite, sectortype* s
z = sprite->z * (1 / -256.f);
if (z == di->Viewpoint.Pos.Z) return; // looking right at the edge.
visibility = sectorVisibility(&sector[sprite->sectnum]);// *(4.f / 5.f); // The factor comes directly from Polymost. No idea why this uses a different visibility setting. Bad projection math?
visibility = sectorVisibility(&sector[sprite->sectnum]) *(4.f / 5.f); // The factor comes directly from Polymost. What is it with Build and these magic factors?
// Weird Build logic that really makes no sense.
if ((sprite->cstat & CSTAT_SPRITE_ONE_SIDED) != 0 && (di->Viewpoint.Pos.Z < z) == ((sprite->cstat & CSTAT_SPRITE_YFLIP) == 0))
@ -380,17 +357,8 @@ void HWFlat::ProcessFlatSprite(HWDrawInfo* di, spritetype* sprite, sectortype* s
palette = sprite->pal;
fade = lookups.getFade(sector[sprite->sectnum].floorpal); // fog is per sector.
bool trans = (sprite->cstat & CSTAT_SPRITE_TRANSLUCENT);
if (trans)
{
RenderStyle = GetRenderStyle(0, !!(sprite->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT));
alpha = GetAlphaFromBlend((sprite->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT) ? DAMETH_TRANS2 : DAMETH_TRANS1, 0);
}
else
{
RenderStyle = LegacyRenderStyles[STYLE_Translucent];
alpha = 1.f;
}
SetSpriteTranslucency(sprite, alpha, RenderStyle);
PutFlat(di, 0);
}
}

View file

@ -400,9 +400,10 @@ void HWScenePortalBase::DrawContents(HWDrawInfo* di, FRenderState& state)
{
if (Setup(di, state, di->mClipper))
{
gi->EnterPortal(di->Viewpoint.CameraSprite, GetType());
di->DrawScene(DM_PORTAL);
gi->LeavePortal(di->Viewpoint.CameraSprite, GetType());
auto type = GetType();
gi->EnterPortal(di->Viewpoint.CameraSprite, type);
di->DrawScene(DM_PORTAL, type == PORTAL_SECTOR_CEILING);
gi->LeavePortal(di->Viewpoint.CameraSprite, type);
Shutdown(di, state);
}
else state.ClearScreen();
@ -430,8 +431,8 @@ void HWScenePortalBase::ClearClipper(HWDrawInfo *di, Clipper *clipper)
clipper->SafeAddClipRange(bamang(0), bamang(0xffffffff));
for (unsigned int i = 0; i < lines.Size(); i++)
{
binangle startang = q16ang(gethiq16angle(lines[i].seg->x - view.x, lines[i].seg->y - view.y));
binangle endang = q16ang(gethiq16angle(wall[lines[i].seg->point2].x - view.x, wall[lines[i].seg->point2].y - view.y));
binangle startang = bvectangbam(lines[i].seg->x - view.x, lines[i].seg->y - view.y);
binangle endang = bvectangbam(wall[lines[i].seg->point2].x - view.x, wall[lines[i].seg->point2].y - view.y);
if (endang.asbam() - startang.asbam() >= ANGLE_180)
{
@ -573,14 +574,17 @@ bool HWMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clippe
int newx = int((x << 1) + Scale(dx, i, j) - view.x);
int newy = int((y << 1) + Scale(dy, i, j) - view.y);
int newan = ((gethiq16angle(dx, dy) << 1) - bamang(vp.RotAngle).asq16()) & 0x7FFFFFF;
vp.RotAngle = q16ang(newan).asbam();
auto myan = bvectangbam(dx, dy);
auto newan = myan + myan - bamang(vp.RotAngle);
vp.RotAngle = newan.asbam();
vp.SectNums = nullptr;
vp.SectCount = line->sector;
vp.Pos.X = newx / 16.f;
vp.Pos.Y = newy / -16.f;
vp.HWAngles.Yaw = -90.f + q16ang(newan).asdeg();
vp.HWAngles.Yaw = -90.f + newan.asdeg();
double FocalTangent = tan(vp.FieldOfView.Radians() / 2);
DAngle an = 270. - vp.HWAngles.Yaw.Degrees;
@ -597,9 +601,9 @@ bool HWMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clippe
angle_t af = di->FrustumAngle();
if (af < ANGLE_180) clipper->SafeAddClipRange(bamang(vp.RotAngle + af), bamang(vp.RotAngle - af));
auto startan = gethiq16angle(line->x - newx, line->y - newy);
auto endan = gethiq16angle(wall[line->point2].x - newx, wall[line->point2].y - newy);
clipper->SafeAddClipRange(q16ang(startan), q16ang(endan)); // we check the line from the backside so angles are reversed.
auto startan = bvectangbam(line->x - newx, line->y - newy);
auto endan = bvectangbam(wall[line->point2].x - newx, wall[line->point2].y - newy);
clipper->SafeAddClipRange(startan, endan); // we check the line from the backside so angles are reversed.
return true;
}
@ -646,10 +650,10 @@ bool HWLineToLinePortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *cl
int dx2 = wall[line->point2].x - line->x;
int dy2 = wall[line->point2].y - line->y;
int srcang = gethiq16angle(dx, dy);
int destang = gethiq16angle(-dx, -dy);
auto srcang = bvectangbam(dx, dy);
auto destang = bvectangbam(-dx, -dy);
vp.RotAngle += q16ang(destang - srcang).asbam();
vp.RotAngle += (destang - srcang).asbam();
#endif
// Nothing in the entire setup mandates that both lines have the same length.
@ -669,9 +673,9 @@ bool HWLineToLinePortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *cl
angle_t af = di->FrustumAngle();
if (af < ANGLE_180) clipper->SafeAddClipRange(bamang(vp.RotAngle + af), bamang(vp.RotAngle - af));
auto startan = gethiq16angle(origin->x - origx, origin->y - origy);
auto endan = gethiq16angle(wall[origin->point2].x - origx, wall[origin->point2].y - origy);
clipper->SafeAddClipRange(q16ang(endan), q16ang(startan));
auto startan = bvectangbam(origin->x - origx, origin->y - origy);
auto endan = bvectangbam(wall[origin->point2].x - origx, wall[origin->point2].y - origy);
clipper->SafeAddClipRange(endan, startan);
return true;
}
@ -723,9 +727,9 @@ bool HWLineToSpritePortal::Setup(HWDrawInfo* di, FRenderState& rstate, Clipper*
angle_t af = di->FrustumAngle();
if (af < ANGLE_180) clipper->SafeAddClipRange(bamang(vp.RotAngle + af), bamang(vp.RotAngle - af));
auto startan = gethiq16angle(origin->x - origx, origin->y - origy);
auto endan = gethiq16angle(wall[origin->point2].x - origx, wall[origin->point2].y - origy);
clipper->SafeAddClipRange(q16ang(endan), q16ang(startan));
auto startan = bvectangbam(origin->x - origx, origin->y - origy);
auto endan = bvectangbam(wall[origin->point2].x - origx, wall[origin->point2].y - origy);
clipper->SafeAddClipRange(endan, startan);
return true;
}

View file

@ -32,6 +32,7 @@
CVAR(Bool,gl_noskyboxes, false, 0)
FGameTexture* GetSkyTexture(int basetile, int lognumtiles, const int16_t* tilemap, int remap);
FGameTexture* SkyboxReplacement(FTextureID picnum, int palnum);
//==========================================================================
//
@ -42,14 +43,14 @@ FGameTexture* GetSkyTexture(int basetile, int lognumtiles, const int16_t* tilema
void initSkyInfo(HWDrawInfo *di, HWSkyInfo* sky, sectortype* sector, int plane, PalEntry FadeColor)
{
int picnum = plane == plane_ceiling ? sector->ceilingpicnum : sector->floorpicnum;
int palette = plane == plane_ceiling ? sector->ceilingpal : sector->floorpal;
int32_t dapyscale = 0, dapskybits = 0, dapyoffs = 0, daptileyscale = 0;
FGameTexture* skytex = nullptr;
FGameTexture* skytex = SkyboxReplacement(tileGetTexture(picnum)->GetID(), palette);
int realskybits = 0;
// todo: check for skybox replacement.
if (!skytex)
{
int palette = plane == plane_ceiling ? sector->ceilingpal : sector->floorpal;
int remap = TRANSLATION(Translation_Remap + curbasepal, palette);
int16_t const* dapskyoff = getpsky(picnum, &dapyscale, &dapskybits, &dapyoffs, &daptileyscale);
@ -179,12 +180,7 @@ void HWWall::SkyTop(HWDrawInfo *di, walltype * seg,sectortype * fs,sectortype *
{
if (bs->ceilingstat & CSTAT_SECTOR_SKY)
{
float c1, c2, f1, f2;
PlanesAtPoint(bs, v1.X * 16.f, v1.Y * -16.f, &c1, &f1);
PlanesAtPoint(bs, v2.X * 16.f, v2.Y * -16.f, &c2, &f2);
// if the back sector is closed the sky must be drawn!
if (c1 > f1 || c2 > f2) return;
return;
}
flags |= HWF_SKYHACK; // mid textures on such lines need special treatment!
@ -231,14 +227,10 @@ void HWWall::SkyBottom(HWDrawInfo *di, walltype * seg,sectortype * fs,sectortype
}
else if (fs->floorstat & CSTAT_SECTOR_SKY)
{
float c1, c2, f1, f2;
PlanesAtPoint(bs, v1.X * 16.f, v1.Y * -16.f, &c1, &f1);
PlanesAtPoint(bs, v2.X * 16.f, v2.Y * -16.f, &c2, &f2);
if (bs->floorstat & CSTAT_SECTOR_SKY)
{
// if the back sector is closed the sky must be drawn!
if (c1 > f1 || c2 > f2) return;
return;
}
flags |= HWF_SKYHACK; // mid textures on such lines need special treatment!
}

View file

@ -26,7 +26,8 @@
#include "hw_renderstate.h"
#include "skyboxtexture.h"
CVAR(Float, skyoffsettest, 0, 0)
CVAR(Float, skyoffsettest, 0, 0)
//-----------------------------------------------------------------------------
//
//
@ -34,6 +35,8 @@
//-----------------------------------------------------------------------------
void HWSkyPortal::DrawContents(HWDrawInfo *di, FRenderState &state)
{
int indexed = hw_int_useindexedcolortextures;
hw_int_useindexedcolortextures = false; // this code does not work with indexed textures.
bool drawBoth = false;
auto &vp = di->Viewpoint;
@ -101,6 +104,7 @@ void HWSkyPortal::DrawContents(HWDrawInfo *di, FRenderState &state)
//di->lightmode = oldlightmode;
state.SetDepthClamp(oldClamp);
}
hw_int_useindexedcolortextures = indexed;
}
const char *HWSkyPortal::GetName() { return "Sky"; }

View file

@ -44,10 +44,7 @@
#include "hw_renderstate.h"
#include "hw_models.h"
#include "hw_viewpointbuffer.h"
extern PalEntry GlobalMapFog;
extern float GlobalFogDensity;
#include "hw_voxels.h"
//==========================================================================
//
@ -74,7 +71,7 @@ void HWSprite::DrawSprite(HWDrawInfo* di, FRenderState& state, bool translucent)
state.SetRenderStyle(RenderStyle);
state.SetTextureMode(RenderStyle);
if (!texture || !texture->GetTranslucency()) state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold);
if (!texture || !checkTranslucentReplacement(texture->GetID(), palette)) state.AlphaFunc(Alpha_GEqual, texture->alphaThreshold);
else state.AlphaFunc(Alpha_Greater, 0.f);
if (RenderStyle.BlendOp == STYLEOP_Add && RenderStyle.DestAlpha == STYLEALPHA_One)
@ -113,36 +110,15 @@ void HWSprite::DrawSprite(HWDrawInfo* di, FRenderState& state, bool translucent)
}
// 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.
int shade = this->shade;
PalEntry color(255, globalr, globalg, globalb);
if (this->shade > numshades) // handling of SW's shadow hack using a shade of 127.
{
shade = sector[sprite->sectnum].floorshade;
color = 0xff000000;
}
shade = clamp(shade, 0, numshades - 1);
if (ShadeDiv >= 1 / 1000.f && foggy && !foglayer)
{
state.EnableFog(1);
float density = GlobalMapFog ? GlobalFogDensity : 350.f - Scale(numshades - shade, 150, numshades);
state.SetFog((GlobalMapFog) ? GlobalMapFog : fade, density * hw_density);
state.SetSoftLightLevel(255);
state.SetLightParms(128.f, 1 / 1000.f);
}
else
{
state.EnableFog(0);
state.SetFog(0, 0);
state.SetSoftLightLevel(ShadeDiv >= 1 / 1000.f ? 255 - Scale(shade, 255, numshades) : 255);
state.SetLightParms(visibility, ShadeDiv / (numshades - 2));
state.SetColor(0, 0, 0, alpha);
}
// The shade rgb from the tint is ignored here.
state.SetColorAlpha(color, alpha);
SetLightAndFog(state, fade, palette, shade, visibility, alpha, this->shade <= numshades);
if (modelframe == 0)
{
@ -157,7 +133,11 @@ void HWSprite::DrawSprite(HWDrawInfo* di, FRenderState& state, bool translucent)
state.SetLightIndex(-1);
state.Draw(DT_TriangleStrip, vertexindex, 4);
if (ShadeDiv >= 1 / 1000.f && foggy && foglayer)
if (foglayer)
{
bool foggy = (GlobalMapFog || (fade & 0xffffff));
auto ShadeDiv = lookups.tables[palette].ShadeFactor;
if (ShadeDiv >= 1 / 1000.f && foggy)
{
// If we get here we know that we have colored fog and no fixed colormap.
float density = GlobalMapFog ? GlobalFogDensity : 350.f - Scale(numshades - shade, 150, numshades);
@ -168,6 +148,7 @@ void HWSprite::DrawSprite(HWDrawInfo* di, FRenderState& state, bool translucent)
state.SetTextureMode(TM_NORMAL);
}
}
}
else
{
state.EnableModelMatrix(true);
@ -352,17 +333,7 @@ void HWSprite::Process(HWDrawInfo* di, spritetype* spr, sectortype* sector, int
fade = lookups.getFade(sector->floorpal); // fog is per sector.
visibility = sectorVisibility(sector);
bool trans = (spr->cstat & CSTAT_SPRITE_TRANSLUCENT);
if (trans)
{
RenderStyle = GetRenderStyle(0, !!(spr->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT));
alpha = GetAlphaFromBlend((spr->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT) ? DAMETH_TRANS2 : DAMETH_TRANS1, 0);
}
else
{
RenderStyle = LegacyRenderStyles[STYLE_Translucent];
alpha = 1.f;
}
SetSpriteTranslucency(spr, alpha, RenderStyle);
x = spr->x * (1 / 16.f);
z = spr->z * (1 / -256.f);
@ -375,12 +346,12 @@ void HWSprite::Process(HWDrawInfo* di, spritetype* spr, sectortype* sector, int
int tilenum = spr->picnum;
int xsize, ysize, tilexoff, tileyoff;
if (hw_hightile && TileFiles.tiledata[tilenum].h_xsize)
if (hw_hightile && TileFiles.tiledata[tilenum].hiofs.xsize)
{
xsize = TileFiles.tiledata[tilenum].h_xsize;
ysize = TileFiles.tiledata[tilenum].h_ysize;
tilexoff = TileFiles.tiledata[tilenum].h_xoffs;
tileyoff = TileFiles.tiledata[tilenum].h_yoffs;
xsize = TileFiles.tiledata[tilenum].hiofs.xsize;
ysize = TileFiles.tiledata[tilenum].hiofs.ysize;
tilexoff = TileFiles.tiledata[tilenum].hiofs.xoffs;
tileyoff = TileFiles.tiledata[tilenum].hiofs.yoffs;
}
else
{
@ -436,6 +407,12 @@ void HWSprite::Process(HWDrawInfo* di, spritetype* spr, sectortype* sector, int
z1 = z + yoff;
z2 = z + height + yoff;
if (z1 < z2)
{
// Make sure that z1 is the higher one. Some utilities expect it to be oriented this way.
std::swap(z1, z2);
std::swap(vt, vb);
}
}
else
{
@ -459,7 +436,7 @@ void HWSprite::Process(HWDrawInfo* di, spritetype* spr, sectortype* sector, int
}
#endif
PutSprite(di, alpha < 1.f-FLT_EPSILON || modelframe == 0);
PutSprite(di, true);
rendered_sprites++;
}
@ -487,23 +464,13 @@ bool HWSprite::ProcessVoxel(HWDrawInfo* di, voxmodel_t* vox, spritetype* spr, se
if ((spr->cstat & CSTAT_SPRITE_MDLROTATE) || rotate)
{
int myclock = (PlayClock << 3) + MulScale(4 << 3, (int)di->Viewpoint.TicFrac, 16);
ang = (ang + myclock) & 2047; // will be applied in md3_vox_calcmat_common.
ang = (ang + myclock) & 2047;
}
if (!vox || (spr->cstat & CSTAT_SPRITE_ALIGNMENT) == CSTAT_SPRITE_ALIGNMENT_FLOOR) return false;
bool trans = (spr->cstat & CSTAT_SPRITE_TRANSLUCENT);
if (trans)
{
RenderStyle = GetRenderStyle(0, !!(spr->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT));
alpha = GetAlphaFromBlend((spr->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT) ? DAMETH_TRANS2 : DAMETH_TRANS1, 0);
}
else
{
RenderStyle = LegacyRenderStyles[STYLE_Translucent];
alpha = 1.f;
}
SetSpriteTranslucency(spr, alpha, RenderStyle);
auto sprext = &spriteext[spr->owner];
@ -568,7 +535,7 @@ bool HWSprite::ProcessVoxel(HWDrawInfo* di, voxmodel_t* vox, spritetype* spr, se
auto vp = di->Viewpoint;
depth = (float)((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin);
PutSprite(di, alpha < 1.f - FLT_EPSILON);
PutSprite(di, spriteHasTranslucency(sprite));
rendered_sprites++;
return true;
}

View file

@ -39,9 +39,6 @@
#include "flatvertices.h"
#include "glbackend/glbackend.h"
extern PalEntry GlobalMapFog;
extern float GlobalFogDensity;
//==========================================================================
//
// Create vertices for one wall
@ -104,7 +101,7 @@ void HWWall::RenderFogBoundary(HWDrawInfo *di, FRenderState &state)
if (gl_fogmode)// && !di->isFullbrightScene())
{
state.EnableDrawBufferAttachments(false);
SetLightAndFog(state);
SetLightAndFog(state, fade, palette, shade, visibility, alpha);
state.SetEffect(EFF_FOGBOUNDARY);
state.AlphaFunc(Alpha_GEqual, 0.f);
state.SetDepthBias(-1, -128);
@ -115,38 +112,6 @@ void HWWall::RenderFogBoundary(HWDrawInfo *di, FRenderState &state)
}
}
//==========================================================================
//
//
//
//==========================================================================
void HWWall::SetLightAndFog(FRenderState& state)
{
// 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 * hw_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.SetColorAlpha(PalEntry(255, globalr, globalg, globalb), alpha);
}
//==========================================================================
//
//
@ -163,7 +128,7 @@ void HWWall::RenderMirrorSurface(HWDrawInfo *di, FRenderState &state)
// Use sphere mapping for this
state.SetEffect(EFF_SPHEREMAP);
SetLightAndFog(state);
SetLightAndFog(state, fade, palette, shade, visibility, alpha, false);
state.SetColor(PalEntry(25, globalr >> 1, globalg >> 1, globalb >> 1));
state.SetRenderStyle(STYLE_Add);
@ -176,7 +141,7 @@ void HWWall::RenderMirrorSurface(HWDrawInfo *di, FRenderState &state)
state.EnableTextureMatrix(false);
state.SetEffect(EFF_NONE);
state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold);
state.AlphaFunc(Alpha_GEqual, 0.5f);
state.SetDepthFunc(DF_Less);
state.SetRenderStyle(STYLE_Translucent);
@ -190,11 +155,8 @@ void HWWall::RenderMirrorSurface(HWDrawInfo *di, FRenderState &state)
void HWWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags)
{
//int tmode = state.GetTextureMode();
state.SetMaterial(texture, UF_Texture, 0, sprite == nullptr? (flags & (HWF_CLAMPX | HWF_CLAMPY)) : CLAMP_XY, TRANSLATION(Translation_Remap + curbasepal, palette), -1);
SetLightAndFog(state);
SetLightAndFog(state, fade, palette, shade, visibility, alpha);
state.SetMaterial(texture, UF_Texture, 0, sprite == nullptr ? (flags & (HWF_CLAMPX | HWF_CLAMPY)) : CLAMP_XY, TRANSLATION(Translation_Remap + curbasepal, palette), -1);
int h = (int)texture->GetDisplayHeight();
int h2 = 1 << sizeToBits(h);
@ -238,7 +200,7 @@ void HWWall::RenderTranslucentWall(HWDrawInfo *di, FRenderState &state)
state.SetRenderStyle(RenderStyle);
state.SetTextureMode(RenderStyle);
if (!texture->GetTranslucency()) state.AlphaFunc(Alpha_GEqual, gl_mask_threshold);
if (!texture || !checkTranslucentReplacement(texture->GetID(), palette)) state.AlphaFunc(Alpha_GEqual, texture->alphaThreshold);
else state.AlphaFunc(Alpha_GEqual, 0.f);
RenderTexturedWall(di, state, HWWall::RWF_TEXTURED);
state.SetRenderStyle(STYLE_Translucent);
@ -752,7 +714,7 @@ void HWWall::DoTexture(HWDrawInfo* di, walltype* wal, walltype* refwall, float r
tcs[UPRGT].v = setv(topleft, topright, glseg.fracright);
tcs[LORGT].v = setv(bottomleft, bottomright, glseg.fracright);
if (th == pow2size) CheckTexturePosition(); // for NPOT textures this adjustment can break things.
bool trans = type == RENDERWALL_M2S && (wal->cstat & CSTAT_WALL_TRANSLUCENT);
bool trans = type == RENDERWALL_M2S && maskWallHasTranslucency(wal);
if (trans)
{
RenderStyle = GetRenderStyle(0, !!(wal->cstat & CSTAT_WALL_TRANS_FLIP));
@ -896,7 +858,7 @@ void HWWall::Process(HWDrawInfo* di, walltype* wal, sectortype* frontsector, sec
#ifdef _DEBUG
if (wal - wall == 843)
if (wal - wall == 788)
{
int a = 0;
}
@ -993,12 +955,15 @@ void HWWall::Process(HWDrawInfo* di, walltype* wal, sectortype* frontsector, sec
{
float bch1a = bch1;
float bch2a = bch2;
if (ffh1 > bch1 && ffh2 > bch2)
if (ffh1 > bch1 || ffh2 > bch2)
{
// the back sector's floor obstructs part of this wall. Todo: Handle the portal case better.
if ((ffh1 > bch1 && ffh2 > bch2) || frontsector->portalflags == PORTAL_SECTOR_FLOOR)
{
// the back sector's floor obstructs part of this wall
bch2a = ffh2;
bch1a = ffh1;
}
}
if (bch1a < fch1 || bch2a < fch2)
{
@ -1028,12 +993,15 @@ void HWWall::Process(HWDrawInfo* di, walltype* wal, sectortype* frontsector, sec
// lower texture
if (!(frontsector->floorstat & backsector->floorstat & CSTAT_SECTOR_SKY))
{
if (fch1 < bfh1 && fch2 < bfh2)
if (fch1 < bfh1 || fch2 < bfh2)
{
// the back sector's ceiling obstructs part of this wall. Todo: Handle the portal case better.
if ((fch1 < bfh1 && fch2 < bfh2) || frontsector->portalflags == PORTAL_SECTOR_CEILING)
{
// the back sector's ceiling obstructs part of this wall.
bfh1 = fch1;
bfh2 = fch2;
}
}
if (bfh1 > ffh1 || bfh2 > ffh2)
{
@ -1049,7 +1017,6 @@ void HWWall::Process(HWDrawInfo* di, walltype* wal, sectortype* frontsector, sec
}
}
}
globalr = globalg = globalb = 255;
}
void HWWall::ProcessWallSprite(HWDrawInfo* di, spritetype* spr, sectortype* sector)
@ -1090,24 +1057,13 @@ void HWWall::ProcessWallSprite(HWDrawInfo* di, spritetype* spr, sectortype* sect
fade = lookups.getFade(sector->floorpal); // fog is per sector.
visibility = sectorVisibility(sector);
bool trans = (sprite->cstat & CSTAT_SPRITE_TRANSLUCENT);
if (trans)
{
RenderStyle = GetRenderStyle(0, !!(sprite->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT));
alpha = GetAlphaFromBlend((sprite->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT) ? DAMETH_TRANS2 : DAMETH_TRANS1, 0);
}
else
{
RenderStyle = LegacyRenderStyles[STYLE_Translucent];
alpha = 1.f;
}
SetSpriteTranslucency(sprite, alpha, RenderStyle);
int height, topofs;
if (hw_hightile && TileFiles.tiledata[spr->picnum].h_xsize)
if (hw_hightile && TileFiles.tiledata[spr->picnum].hiofs.xsize)
{
height = TileFiles.tiledata[spr->picnum].h_ysize;
topofs = (TileFiles.tiledata[spr->picnum].h_yoffs + spr->yoffset);
height = TileFiles.tiledata[spr->picnum].hiofs.ysize;
topofs = (TileFiles.tiledata[spr->picnum].hiofs.yoffs + spr->yoffset);
}
else
{
@ -1160,5 +1116,5 @@ void HWWall::ProcessWallSprite(HWDrawInfo* di, spritetype* spr, sectortype* sect
zbottom[0] = zbottom[1] = floorz;
}
}
PutWall(di, trans);
PutWall(di, spriteHasTranslucency(sprite));
}

View file

@ -646,7 +646,6 @@ void SerializeMap(FSerializer& arc)
("numshades", numshades) // is this really needed?
("visibility", g_visibility)
("parallaxtype", parallaxtype)
("parallaxvisibility", parallaxvisibility)
("parallaxyo", parallaxyoffs_override)
("parallaxys", parallaxyscale_override)
("pskybits", pskybits_override)

View file

@ -840,7 +840,7 @@ public:
clock += now - lastTime;
if (clock == 0) clock = 1;
}
bool skiprequest = clock > 100'000'000 && inputState.CheckAllInput() && !processed;
bool skiprequest = clock > 100'000'000 && inputState.CheckAllInput() && !processed && job.job->fadestate != DScreenJob::fadeout;
lastTime = now;
if (screenfade < 1.f && !M_Active())
@ -848,6 +848,7 @@ public:
float ms = (clock / 1'000'000) / job.job->fadetime;
screenfade = clamp(ms, 0.f, 1.f);
twod->SetScreenFade(screenfade);
if (job.job->fadestate != DScreenJob::fadeout)
job.job->fadestate = DScreenJob::fadein;
}
else
@ -915,6 +916,7 @@ public:
startTime = -1;
clock = 0;
jobs[index].job->fadestate = DScreenJob::fadeout;
gamestate = GS_INTRO; // block menu and console during fadeout - this can cause timing problems.
actionState = State_Fadeout;
}
else
@ -959,6 +961,7 @@ void DeleteScreenJob()
delete runner;
runner = nullptr;
}
twod->SetScreenFade(1);
}
void RunScreenJobFrame()

View file

@ -47,6 +47,7 @@
#include "c_dispatch.h"
#include "sc_man.h"
#include "gamestruct.h"
#include "hw_voxels.h"
#include "hw_renderstate.h"
@ -59,7 +60,7 @@ enum
BuildTiles TileFiles;
int tileSetHightileReplacement(int picnum, int palnum, const char* filename, float alphacut, float xscale, float yscale, float specpower, float specfactor, uint8_t flags);
int tileSetHightileReplacement(int picnum, int palnum, const char* filename, float alphacut, float xscale, float yscale, float specpower, float specfactor);
//==========================================================================
//
@ -144,7 +145,7 @@ void BuildTiles::Init()
tile.RotTile = { -1,-1 };
tile.replacement = ReplacementType::Art;
tile.alphaThreshold = 0.5;
tile.h_xsize = 0;
tile.hiofs = {};
}
}
@ -256,7 +257,7 @@ void BuildTiles::InvalidateTile(int num)
if ((unsigned) num < MAXTILES)
{
auto tex = tiledata[num].texture;
tex->GetTexture()->SystemTextures.Clean();
tex->CleanHardwareData();
tiledata[num].rawCache.data.Clear();
}
}
@ -513,7 +514,7 @@ int tileImportFromTexture(const char* fn, int tilenum, int alphacut, int istextu
TexMan.AddGameTexture(tex);
TileFiles.tiledata[tilenum].backup = TileFiles.tiledata[tilenum].texture = tex;
if (istexture)
tileSetHightileReplacement(tilenum, 0, fn, (float)(255 - alphacut) * (1.f / 255.f), 1.0f, 1.0f, 1.0, 1.0, 0);
tileSetHightileReplacement(tilenum, 0, fn, (float)(255 - alphacut) * (1.f / 255.f), 1.0f, 1.0f, 1.0, 1.0);
return 0;
}
@ -648,7 +649,7 @@ void artSetupMapArt(const char* filename)
void tileDelete(int tile)
{
TileFiles.tiledata[tile].texture = TileFiles.tiledata[tile].backup = TexMan.GameByIndex(0);
vox_undefine(tile);
tiletovox[tile] = -1; // clear the link but don't clear the voxel. It may be in use for another tile.
md_undefinetile(tile);
}

View file

@ -257,6 +257,11 @@ struct RawCacheNode
uint64_t lastUseTime;
};
struct TileOffs
{
int xsize, ysize, xoffs, yoffs;
};
struct TileDesc
{
FGameTexture* texture; // the currently active tile
@ -269,8 +274,7 @@ struct TileDesc
float alphaThreshold;
// Sprite offset hackery for hires replacements. This only gets used for sprites in the 3D view, nothing else.
uint16_t h_xsize, h_ysize;
int8_t h_xoffs, h_yoffs;
TileOffs hiofs;
};

View file

@ -48,15 +48,17 @@
#include "sc_man.h"
#include "gamestruct.h"
#include "hw_renderstate.h"
#include "skyboxtexture.h"
CVARD(Bool, hw_shadeinterpolate, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable shade interpolation")
struct HightileReplacement
{
FGameTexture* faces[6]; // only one gets used by a texture, the other 5 are for skyboxes only
FGameTexture* image;
FVector2 scale;
float alphacut, specpower, specfactor;
uint16_t palnum, flags;
uint16_t palnum;
bool issky;
};
static TMap<int, TArray<HightileReplacement>> tileReplacements;
@ -91,7 +93,7 @@ static void AddReplacement(int picnum, const HightileReplacement& replace)
auto& Hightiles = tileReplacements[picnum];
for (auto& ht : Hightiles)
{
if (replace.palnum == ht.palnum && (replace.faces[1] == nullptr) == (ht.faces[1] == nullptr))
if (replace.palnum == ht.palnum && replace.issky == ht.issky)
{
ht = replace;
return;
@ -125,7 +127,7 @@ static HightileReplacement* FindReplacement(FTextureID picnum, int palnum, bool
{
for (auto& rep : *Hightiles)
{
if (rep.palnum == palnum && (rep.faces[1] != nullptr) == skybox) return &rep;
if (rep.palnum == palnum && rep.issky == skybox) return &rep;
}
if (!palnum || palnum >= MAXPALOOKUPS - RESERVEDPALS) break;
palnum = 0;
@ -137,11 +139,19 @@ int checkTranslucentReplacement(FTextureID picnum, int pal)
{
FGameTexture* tex = nullptr;
auto si = FindReplacement(picnum, pal, 0);
if (si && hw_hightile) tex = si->faces[0];
if (si && hw_hightile) tex = si->image;
if (!tex || tex->GetTexelWidth() == 0 || tex->GetTexelHeight() == 0) return false;
return tex && tex->GetTranslucency();
}
FGameTexture* SkyboxReplacement(FTextureID picnum, int palnum)
{
auto hr = FindReplacement(picnum, palnum, true);
if (!hr) return nullptr;
return hr->image;
}
//==========================================================================
//
// Processes data from .def files into the textures
@ -163,19 +173,19 @@ void PostLoadSetup()
{
if (rep.palnum == GLOWPAL)
{
glowTex = rep.faces[0];
glowTex = rep.image;
}
if (rep.palnum == NORMALPAL)
{
normalTex = rep.faces[0];
normalTex = rep.image;
}
if (rep.palnum == SPECULARPAL)
{
specTex = rep.faces[0];
specTex = rep.image;
}
if (rep.palnum == DETAILPAL)
{
detailTex = rep.faces[0];
detailTex = rep.image;
scalex = rep.scale.X;
scaley = rep.scale.Y;
}
@ -185,10 +195,10 @@ void PostLoadSetup()
{
for (auto& rep : *Hightile)
{
if (rep.faces[1]) continue; // do not muck around with skyboxes (yet)
if (rep.issky) continue; // do not muck around with skyboxes (yet)
if (rep.palnum < NORMALPAL)
{
auto tex = rep.faces[0];
auto tex = rep.image;
// Make a copy so that multiple appearances of the same texture with different layers can be handled. They will all refer to the same internal texture anyway.
tex = MakeGameTexture(tex->GetTexture(), "", ETextureType::Any);
if (glowTex) tex->SetGlowmap(glowTex->GetTexture());
@ -196,7 +206,7 @@ void PostLoadSetup()
if (normalTex) tex->SetNormalmap(normalTex->GetTexture());
if (specTex) tex->SetSpecularmap(specTex->GetTexture());
tex->SetDetailScale(scalex, scaley);
rep.faces[0] = tex;
rep.image = tex;
}
}
}
@ -237,7 +247,7 @@ void PostLoadSetup()
//
//==========================================================================
int tileSetHightileReplacement(int picnum, int palnum, const char* filename, float alphacut, float xscale, float yscale, float specpower, float specfactor, uint8_t flags)
int tileSetHightileReplacement(int picnum, int palnum, const char* filename, float alphacut, float xscale, float yscale, float specpower, float specfactor)
{
if ((uint32_t)picnum >= (uint32_t)MAXTILES) return -1;
if ((uint32_t)palnum >= (uint32_t)MAXPALOOKUPS) return -1;
@ -257,13 +267,12 @@ int tileSetHightileReplacement(int picnum, int palnum, const char* filename, flo
return -1;
}
replace.faces[0] = TexMan.GetGameTexture(texid);
if (replace.faces[0] == nullptr)
replace.image = TexMan.GetGameTexture(texid);
replace.alphacut = min(alphacut,1.f);
replace.scale = { xscale, yscale };
replace.specpower = specpower; // currently unused
replace.specfactor = specfactor; // currently unused
replace.flags = flags;
replace.issky = 0;
replace.palnum = (uint16_t)palnum;
AddReplacement(picnum, replace);
return 0;
@ -276,7 +285,7 @@ int tileSetHightileReplacement(int picnum, int palnum, const char* filename, flo
//
//==========================================================================
int tileSetSkybox(int picnum, int palnum, const char **facenames, int flags )
int tileSetSkybox(int picnum, int palnum, FString* facenames)
{
if ((uint32_t)picnum >= (uint32_t)MAXTILES) return -1;
if ((uint32_t)palnum >= (uint32_t)MAXPALOOKUPS) return -1;
@ -289,17 +298,24 @@ int tileSetSkybox(int picnum, int palnum, const char **facenames, int flags )
}
HightileReplacement replace = {};
for (auto &face : replace.faces)
FGameTexture *faces[6];
for (int i = 0; i < 6; i++)
{
FTextureID texid = TexMan.CheckForTexture(*facenames, ETextureType::Any);
FTextureID texid = TexMan.CheckForTexture(facenames[i], ETextureType::Any);
if (!texid.isValid())
{
Printf("%s: Skybox image for tile %d does not exist or is invalid\n", *facenames, picnum);
Printf("%s: Skybox image for tile %d does not exist or is invalid\n", facenames[i].GetChars(), picnum);
return -1;
}
face = TexMan.GetGameTexture(texid);
faces[i] = TexMan.GetGameTexture(texid);
}
replace.flags = flags;
FSkyBox* sbtex = new FSkyBox("");
memcpy(sbtex->faces, faces, sizeof(faces));
sbtex->previous = faces[0]; // won't ever be used, just to be safe.
sbtex->fliptop = true;
replace.image = MakeGameTexture(sbtex, "", ETextureType::Override);
TexMan.AddGameTexture(replace.image, false);
replace.issky = 1;
replace.palnum = (uint16_t)palnum;
AddReplacement(picnum, replace);
return 0;
@ -341,7 +357,7 @@ bool PickTexture(FRenderState *state, FGameTexture* tex, int paletteid, TextureP
if (rep)
{
tex = rep->faces[0];
tex = rep->image;
}
if (!rep || rep->palnum != hipalswap || (h.tintFlags & TINTF_APPLYOVERALTPAL))
applytint = true;

View file

@ -38,6 +38,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "v_2ddrawer.h"
#include "v_video.h"
#include "v_font.h"
#include "hw_voxels.h"
#include "glbackend/glbackend.h"
BEGIN_BLD_NS

View file

@ -656,7 +656,7 @@ void ParseScript(int lumpnum)
if (dword_44CE0[gParseLevel] == 0)
{
// In the RFS files I have seen the outermost directory is not part of what goes into the file system.
auto inp1 = strchr(inp, '\\');
auto inp1 = strpbrk(inp, "/\\");
if (!inp1 || !fileSystem.CreatePathlessCopy(inp1 + 1, ID, nFlags))
{
// I'll activate this when I find evidence that it is needed. Otherwise the risk of picking up unwanted data is too high.

View file

@ -465,9 +465,6 @@ void GameInterface::app_init()
HookReplaceFunctions();
Printf(PRINT_NONOTIFY, "Initializing Build 3D engine\n");
engineInit();
Printf(PRINT_NONOTIFY, "Loading tiles\n");
if (!tileInit(0, NULL))
I_FatalError("TILES###.ART files not found");

View file

@ -115,6 +115,28 @@ void levelLoadMapInfo(IniFile *pIni, MapRecord *pLevelInfo, const char *pzSectio
static const char* DefFile(void)
{
int found = -1;
if (userConfig.DefaultCon.IsEmpty() || userConfig.DefaultCon.CompareNoCase("blood.ini") == 0)
{
int numlumps = fileSystem.GetNumEntries();
for (int i = numlumps - 1; i >= 0; i--)
{
if (fileSystem.GetFileContainer(i) <= fileSystem.GetMaxIwadNum()) break;
FString fn = fileSystem.GetFileFullName(i, false);
FString ext = fn.Right(4);
if (ext.CompareNoCase(".ini") == 0)
{
if (fileSystem.CheckNumForFullName(fn) != i) continue;
if (found == -1) found = i;
else
{
found = -1;
break;
}
}
}
}
if (found >= 0) return fileSystem.GetFileFullName(found);
// The command line parser stores this in the CON field.
return userConfig.DefaultCon.IsNotEmpty() ? userConfig.DefaultCon.GetChars() : "blood.ini";
}

View file

@ -122,7 +122,6 @@ extern short voxelIndex[MAXTILES];
extern int nPrecacheCount;
int tileInit(char a1, const char *a2);
void tileProcessGLVoxels(void);
void tilePreloadTile(int nTile);
void tilePrecacheTile(int nTile, int nType, HitList& hits);

View file

@ -44,14 +44,11 @@ char surfType[kMaxTiles];
signed char tileShade[kMaxTiles];
short voxelIndex[kMaxTiles];
const char *pzBaseFileName = "TILES%03i.ART"; //"TILES%03i.ART";
int tileInit(char a1, const char *a2)
{
UNREFERENCED_PARAMETER(a1);
if (artLoaded)
return 1;
TileFiles.artLoadFiles(a2 ? a2 : pzBaseFileName);
for (int i = 0; i < kMaxTiles; i++)
voxelIndex[i] = 0;
@ -81,32 +78,9 @@ int tileInit(char a1, const char *a2)
}
artLoaded = 1;
#ifdef USE_OPENGL
PolymostProcessVoxels_Callback = tileProcessGLVoxels;
#endif
return 1;
}
#ifdef USE_OPENGL
void tileProcessGLVoxels(void)
{
static bool voxInit = false;
if (voxInit)
return;
voxInit = true;
for (int i = 0; i < kMaxVoxels; i++)
{
auto index = fileSystem.FindResource(i, "KVX");
if (index >= 0)
{
voxmodels[i] = voxload(index);
}
}
}
#endif
char tileGetSurfType(int hit)
{
int n = hit & 0x3fff;

View file

@ -266,7 +266,7 @@ void WeaponDraw(PLAYER *pPlayer, int shade, double xpos, double ypos, int palnum
if (pPlayer->weaponTimer == 0) // playing idle QAV?
{
// Double shotgun fix from BloodGDX.
if (/*!IsOriginalDemo() &&*/ (pPlayer->weaponState == -1 || (pPlayer->curWeapon == 3 && pPlayer->weaponState == 7)) && isOriginalQAV())
if (/*!IsOriginalDemo() &&*/ (pPlayer->weaponState == -1 || (pPlayer->curWeapon == 3 && pPlayer->weaponState == 7))/* && isOriginalQAV()*/)
duration = pQAV->duration - 1;
else duration = (PlayClock + MulScale(4, smoothratio, 16)) % pQAV->duration;
}

View file

@ -4505,7 +4505,7 @@ void handle_se27(DDukeActor* actor)
//
//---------------------------------------------------------------------------
void handle_se24(DDukeActor *actor, int16_t *list1, int16_t *list2, int TRIPBOMB, int LASERLINE, int CRANE, int shift)
void handle_se24(DDukeActor *actor, int16_t *list1, int16_t *list2, bool scroll, int TRIPBOMB, int LASERLINE, int CRANE, int shift)
{
int* t = &actor->temp_data[0];
@ -4575,7 +4575,7 @@ void handle_se24(DDukeActor *actor, int16_t *list1, int16_t *list2, int TRIPBOMB
}
}
}
sector[actor->s.sectnum].addfloorxpan(actor->s.yvel / 128.f);
if (scroll) sector[actor->s.sectnum].addfloorxpan(actor->s.yvel / 128.f);
}
//---------------------------------------------------------------------------

View file

@ -3697,7 +3697,7 @@ void moveeffectors_d(void) //STATNUM 3
{
static int16_t list1[] = { BLOODPOOL, PUKE, FOOTPRINTS, FOOTPRINTS2, FOOTPRINTS3, FOOTPRINTS4, BULLETHOLE, BLOODSPLAT1, BLOODSPLAT2, BLOODSPLAT3, BLOODSPLAT4, -1 };
static int16_t list2[] = { BOLT1, BOLT1 + 1,BOLT1 + 2, BOLT1 + 3, SIDEBOLT1, SIDEBOLT1 + 1, SIDEBOLT1 + 2, SIDEBOLT1 + 3, -1 };
handle_se24(act, list1, list2, TRIPBOMB, LASERLINE, CRANE, 2);
handle_se24(act, list1, list2, false, TRIPBOMB, LASERLINE, CRANE, 2);
break;
}
case SE_35:

View file

@ -3576,7 +3576,7 @@ void moveeffectors_r(void) //STATNUM 3
{
static int16_t list1[] = { BLOODPOOL, PUKE, FOOTPRINTS, FOOTPRINTS2, FOOTPRINTS3, -1 };
static int16_t list2[] = { BOLT1, BOLT1 + 1,BOLT1 + 2, BOLT1 + 3, -1 };
handle_se24(act, list1, list2, BULLETHOLE, -1, CRANE, 1);
handle_se24(act, list1, list2, st != 156, BULLETHOLE, -1, CRANE, 1);
break;
}

View file

@ -84,7 +84,7 @@ void handle_se19(DDukeActor* i, int BIGFORCE);
void handle_se20(DDukeActor* i);
void handle_se21(DDukeActor* i);
void handle_se22(DDukeActor* i);
void handle_se24(DDukeActor* actor, int16_t* list1, int16_t* list2, int TRIPBOMB, int LASERLINE, int CRANE, int shift);
void handle_se24(DDukeActor* actor, int16_t* list1, int16_t* list2, bool scroll, int TRIPBOMB, int LASERLINE, int CRANE, int shift);
void handle_se25(DDukeActor* a, int t_index, int snd1, int snd2);
void handle_se26(DDukeActor* i);
void handle_se27(DDukeActor* i);

View file

@ -230,9 +230,6 @@ static void setupbackdrop()
static void initTiles()
{
if (TileFiles.artLoadFiles("tiles%03i.art") < 0)
I_FatalError("Failed loading art.");
tileDelete(TILE_MIRROR);
skiptile = TILE_W_FORCEFIELD + 1;
@ -310,9 +307,6 @@ void GameInterface::app_init()
OnEvent(EVENT_INIT);
if (engineInit())
G_FatalEngineError();
//Net_SendClientInfo();
initTiles();

View file

@ -65,7 +65,6 @@ inline DDukeActor* getSndActor(const void* source)
return source ? &hittype[((spritetype*)source) - sprite] : nullptr;
}
TArray<FString> specialmusic;
static FSoundID currentCommentarySound;
static DDukeActor* currentCommentarySprite; // todo: GC this once actors become objects

View file

@ -74,8 +74,6 @@ void S_ParseDeveloperCommentary();
void StopCommentary();
bool StartCommentary(int tag, DDukeActor* sprnum);
extern TArray<FString> specialmusic;
END_DUKE_NS

View file

@ -785,7 +785,8 @@ void spawneffector(DDukeActor* actor)
break;
}
case 156:
if (!isRRRA()) break;
break;
case 34:
StartInterpolation(sect, Interp_Sect_FloorPanX);
break;

View file

@ -75,12 +75,6 @@ void ResetEngine()
void InstallEngine()
{
TileFiles.LoadArtSet("tiles%03d.art");
if (engineInit())
{
G_FatalEngineError();
}
uploadCinemaPalettes();
LoadPaletteLookups();
}

View file

@ -193,7 +193,7 @@ static void Intermission(MapRecord *from_map, MapRecord *to_map)
gameaction = ga_nextlevel;
}
});
}, true, true);
}
}

View file

@ -1123,7 +1123,7 @@ void CameraView(PLAYERp pp, int *tx, int *ty, int *tz, short *tsectnum, binangle
{
sp = &sprite[i];
ang = q16ang(gethiq16angle(*tx - sp->x, *ty - sp->y));
ang = bvectangbam(*tx - sp->x, *ty - sp->y);
ang_test = getincangle(ang.asbuild(), sp->ang) < sp->lotag;
FAFcansee_test =
@ -1568,7 +1568,7 @@ drawscreen(PLAYERp pp, double smoothratio)
if (TEST_BOOL1(pp->remote_sprite))
tang = buildang(pp->remote_sprite->ang);
else
tang = q16ang(gethiq16angle(pp->sop_remote->xmid - tx, pp->sop_remote->ymid - ty));
tang = bvectangbam(pp->sop_remote->xmid - tx, pp->sop_remote->ymid - ty);
}
if (TEST(pp->Flags, PF_VIEW_FROM_OUTSIDE))

View file

@ -199,7 +199,6 @@ void GameInterface::app_init()
registerosdcommands();
engineInit();
auto pal = fileSystem.LoadFile("3drealms.pal", 0);
if (pal.Size() >= 768)
{
@ -220,8 +219,6 @@ void GameInterface::app_init()
"the full version. Read the Ordering Info screens for details.");
}
TileFiles.LoadArtSet("tiles%03d.art");
//Connect();
SortBreakInfo();
parallaxtype = 1;

View file

@ -110,8 +110,10 @@ static void so_setpointinterpolation(so_interp *interp, int element)
return;
for (i = 0; i < interp->numinterpolations; i++)
{
if (interp->data[i].curelement == element)
return;
}
so_interp::interp_data *data = &interp->data[interp->numinterpolations++];
@ -129,7 +131,7 @@ static void so_setspriteanginterpolation(so_interp *interp, int32_t spritenum)
return;
for (i = 0; i < interp->numinterpolations; i++)
if (interp->data[i].curelement == -1)
if (interp->data[i].curelement == -1 && interp->data[i].spriteofang == spritenum)
return;
so_interp::interp_data *data = &interp->data[interp->numinterpolations++];
@ -148,9 +150,16 @@ static void so_stopdatainterpolation(so_interp *interp, int element)
int32_t i;
for (i = 0; i < interp->numinterpolations; i++)
if (interp->data[i].curelement == element)
{
if (interp->data[i].curelement == -1)
{
if (interp->data[i].spriteofang == element) break;
}
else if (interp->data[i].curelement == element)
break;
}
if (i == interp->numinterpolations)
return;
@ -219,7 +228,7 @@ void so_setspriteinterpolation(SECTOR_OBJECTp sop, spritetype *sp)
so_setpointinterpolation(interp, snum | soi_spry);
if (!interp->hasvator)
so_setpointinterpolation(interp, snum | soi_sprz);
so_setspriteanginterpolation(interp, int(sp - sprite));
so_setspriteanginterpolation(interp, snum);
}
void so_stopspriteinterpolation(SECTOR_OBJECTp sop, spritetype *sp)

View file

@ -5471,7 +5471,7 @@ DoPlayerStopOperate(PLAYERp pp)
if (TEST_BOOL1(pp->remote_sprite))
pp->angle.ang = pp->angle.oang = buildang(pp->remote_sprite->ang);
else
pp->angle.ang = pp->angle.oang = q16ang(gethiq16angle(pp->sop_remote->xmid - pp->posx, pp->sop_remote->ymid - pp->posy));
pp->angle.ang = pp->angle.oang = bvectangbam(pp->sop_remote->xmid - pp->posx, pp->sop_remote->ymid - pp->posy);
}
if (pp->sop_control)
@ -7148,7 +7148,9 @@ domovethings(void)
// auto tracking mode for single player multi-game
if (numplayers <= 1 && PlayerTrackingMode && pnum == screenpeek && screenpeek != myconnectindex)
{
Player[screenpeek].angle.settarget(bvectangf(Player[myconnectindex].posx - Player[screenpeek].posx, Player[myconnectindex].posy - Player[screenpeek].posy));
int deltax = Player[myconnectindex].posx - Player[screenpeek].posx;
int deltay = Player[myconnectindex].posy - Player[screenpeek].posy;
Player[screenpeek].angle.settarget(bvectangbam(deltax, deltay));
}
if (!TEST(pp->Flags, PF_DEAD))

View file

@ -695,7 +695,7 @@ private:
void DisplayMinibarInventory(PLAYERp pp)
{
int InventoryBoxX = MINI_BAR_INVENTORY_BOX_X;
int InventoryBoxY = MINI_BAR_INVENTORY_BOX_Y;
int InventoryBoxY = MINI_BAR_INVENTORY_BOX_Y - 200;
int InventoryXoff = 0;
int InventoryYoff = 1;

View file

@ -40,6 +40,7 @@ Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
#include "razemenu.h"
#include "quotemgr.h"
#include "mapinfo.h"
#include "hw_voxels.h"
BEGIN_SW_NS
@ -231,7 +232,7 @@ void LoadKVXFromScript(const char* filename)
GetToken(false);
// Load the voxel file into memory
if (!qloadkvx(lNumber,token))
if (!voxDefine(lNumber,token))
{
// Store the sprite and voxel numbers for later use
aVoxelArray[lTile].Voxel = lNumber; // Voxel num

View file

@ -86,20 +86,3 @@ bool GLInstance::SetTexture(FGameTexture* tex, int paletteid, int sampler, bool
return true;
}
//===========================================================================
//
// stand-ins for the texture system. Nothing of this is used right now, but needs to be present to satisfy the linker
//
//===========================================================================
void InitBuildTiles()
{
}
TArray<UserShaderDesc> usershaders;
void UpdateVRModes(bool considerQuadBuffered = true)
{
// should update the menu.
}

View file

@ -70,33 +70,16 @@ void Draw2D(F2DDrawer* drawer, FRenderState& state);
GLInstance GLInterface;
GLInstance::GLInstance()
:palmanager(this)
{
VSMatrix mat(0);
matrixArray.Push(mat);
}
IHardwareTexture *setpalettelayer(int layer, int translation)
{
if (layer == 1)
return GLInterface.palmanager.GetPalette(GetTranslationType(translation) - Translation_Remap);
else if (layer == 2)
return GLInterface.palmanager.GetLookup(GetTranslationIndex(translation));
else return nullptr;
}
void GLInstance::Init(int ydim)
{
FMaterial::SetLayerCallback(setpalettelayer);
new(&renderState) PolymostRenderState; // reset to defaults.
}
void GLInstance::Deinit()
{
palmanager.DeleteAll();
lastPalswapIndex = -1;
}
void GLInstance::Draw(EDrawType type, size_t start, size_t count)
{
assert (BufferLock > 0);

View file

@ -21,25 +21,6 @@ class F2DDrawer;
struct palette_t;
extern int xdim, ydim;
class PaletteManager
{
IHardwareTexture* palettetextures[256] = {};
IHardwareTexture* lookuptextures[256] = {};
GLInstance* const inst;
unsigned FindPalswap(const uint8_t* paldata, palette_t& fadecolor);
public:
PaletteManager(GLInstance *inst_) : inst(inst_)
{}
~PaletteManager();
void DeleteAll();
IHardwareTexture *GetPalette(int index);
IHardwareTexture* GetLookup(int index);
};
struct glinfo_t {
float maxanisotropy;
};
@ -76,8 +57,6 @@ class GLInstance
public:
TArray<PolymostRenderState> rendercommands;
PaletteManager palmanager;
int lastPalswapIndex = -1;
FGameTexture* currentTexture = nullptr;
int MatrixChange = 0;
@ -90,8 +69,6 @@ public:
void Init(int y);
void Deinit();
static int GetTexDimension(int value)
{
//if (value > gl.max_texturesize) return gl.max_texturesize;

Some files were not shown because too many files have changed in this diff Show more