mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-26 11:40:44 +00:00
Merge branch 'newrenderer'
This commit is contained in:
commit
2f9e32f748
336 changed files with 30036 additions and 14899 deletions
|
@ -638,6 +638,9 @@ file( GLOB HEADER_FILES
|
|||
core/music/*.h
|
||||
core/menu/*.h
|
||||
core/input/*.h
|
||||
core/rendering/*.h
|
||||
core/rendering/scene/*.h
|
||||
core/nodebuilder/*.h
|
||||
|
||||
common/audio/sound/thirdparty/*.h
|
||||
common/audio/sound/*.h
|
||||
|
@ -746,7 +749,6 @@ set( NOT_COMPILED_SOURCE_FILES
|
|||
games/blood/src/callback.cpp
|
||||
games/blood/src/choke.cpp
|
||||
games/blood/src/controls.cpp
|
||||
games/blood/src/credits.cpp
|
||||
games/blood/src/db.cpp
|
||||
games/blood/src/dude.cpp
|
||||
games/blood/src/d_menu.cpp
|
||||
|
@ -832,7 +834,6 @@ set( NOT_COMPILED_SOURCE_FILES
|
|||
games/duke/src/spawn_r.cpp
|
||||
|
||||
# Shadow Warrior
|
||||
games/sw/src/2d.cpp
|
||||
games/sw/src/actor.cpp
|
||||
games/sw/src/ai.cpp
|
||||
games/sw/src/break.cpp
|
||||
|
@ -1019,19 +1020,15 @@ set (FASTMATH_SOURCES ${FASTMATH_SOURCES})
|
|||
set (PCH_SOURCES
|
||||
|
||||
glbackend/glbackend.cpp
|
||||
glbackend/gl_palmanager.cpp
|
||||
glbackend/gl_texture.cpp
|
||||
glbackend/gl_models.cpp
|
||||
|
||||
thirdparty/src/md4.cpp
|
||||
|
||||
# Todo: Split out the license-safe code from this.
|
||||
build/src/clip.cpp
|
||||
build/src/defs.cpp
|
||||
build/src/engine.cpp
|
||||
build/src/mdsprite.cpp
|
||||
build/src/polymost.cpp
|
||||
build/src/voxmodel.cpp
|
||||
|
||||
core/movie/playmve.cpp
|
||||
core/movie/movieplayer.cpp
|
||||
|
@ -1050,6 +1047,7 @@ set (PCH_SOURCES
|
|||
core/gamehud.cpp
|
||||
core/gamefuncs.cpp
|
||||
core/gameinput.cpp
|
||||
core/g_mapinfo.cpp
|
||||
core/interpolate.cpp
|
||||
core/inputstate.cpp
|
||||
core/maphack.cpp
|
||||
|
@ -1064,12 +1062,38 @@ set (PCH_SOURCES
|
|||
core/precache.cpp
|
||||
core/quotes.cpp
|
||||
core/screenshot.cpp
|
||||
core/sectorgeometry.cpp
|
||||
core/raze_music.cpp
|
||||
core/raze_sound.cpp
|
||||
core/palette.cpp
|
||||
core/zcompile.cpp
|
||||
core/statusbar2.cpp
|
||||
core/gi.cpp
|
||||
core/defparser.cpp
|
||||
|
||||
core/nodebuilder/nodebuild.cpp
|
||||
core/nodebuilder/nodebuild_classify_nosse2.cpp
|
||||
core/nodebuilder/nodebuild_events.cpp
|
||||
core/nodebuilder/nodebuild_extract.cpp
|
||||
core/nodebuilder/nodebuild_gl.cpp
|
||||
core/nodebuilder/nodebuild_utility.cpp
|
||||
|
||||
core/rendering/hw_entrypoint.cpp
|
||||
core/rendering/hw_models.cpp
|
||||
core/rendering/hw_voxels.cpp
|
||||
core/rendering/hw_palmanager.cpp
|
||||
core/rendering/hw_sections.cpp
|
||||
core/rendering/scene/hw_clipper.cpp
|
||||
core/rendering/scene/hw_walls.cpp
|
||||
core/rendering/scene/hw_flats.cpp
|
||||
core/rendering/scene/hw_sprites.cpp
|
||||
core/rendering/scene/hw_drawlistadd.cpp
|
||||
core/rendering/scene/hw_drawlist.cpp
|
||||
core/rendering/scene/hw_drawinfo.cpp
|
||||
core/rendering/scene/hw_bunchdrawer.cpp
|
||||
core/rendering/scene/hw_portal.cpp
|
||||
core/rendering/scene/hw_skyportal.cpp
|
||||
core/rendering/scene/hw_sky.cpp
|
||||
|
||||
core/console/c_notifybuffer.cpp
|
||||
core/console/d_event.cpp
|
||||
|
@ -1274,6 +1298,7 @@ set (PCH_SOURCES
|
|||
games/exhumed/all.cpp
|
||||
games/blood/all.cpp
|
||||
games/sw/all.cpp
|
||||
|
||||
)
|
||||
|
||||
if( ${HAVE_VM_JIT} )
|
||||
|
@ -1363,6 +1388,8 @@ include_directories(
|
|||
core/dobject
|
||||
core/menu
|
||||
core/input
|
||||
core/rendering
|
||||
core/rendering/scene
|
||||
platform
|
||||
common/audio/sound
|
||||
common/audio/music
|
||||
|
@ -1513,6 +1540,8 @@ source_group("Core\\2D" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/2d
|
|||
source_group("Core\\Console" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/console/.+")
|
||||
source_group("Core\\DObject" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/dobject/.+")
|
||||
source_group("Core\\Menu" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/menu/.+")
|
||||
source_group("Core\\Rendering" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/rendering/.+")
|
||||
source_group("Core\\Rendering\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/rendering/scene/.+")
|
||||
source_group("Rendering" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/glbackend/.+")
|
||||
source_group("Platform" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/platform/.+")
|
||||
source_group("Platform\\Win32" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/platform/win32/.+")
|
||||
|
|
|
@ -15,12 +15,10 @@
|
|||
|
||||
static_assert('\xff' == 255, "Char must be unsigned!");
|
||||
|
||||
#if !defined __cplusplus || (__cplusplus < 201103L && !defined _MSC_VER)
|
||||
# error C++11 or greater is required.
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "printf.h"
|
||||
#include "palette.h"
|
||||
#include "binaryangle.h"
|
||||
|
||||
//Make all variables in BUILD.H defined in the ENGINE,
|
||||
//and externed in GAME
|
||||
|
@ -35,7 +33,6 @@ EXTERN int16_t sintable[2048];
|
|||
#include "buildtiles.h"
|
||||
#include "c_cvars.h"
|
||||
#include "cmdlib.h"
|
||||
#include "binaryangle.h"
|
||||
#include "mathutil.h"
|
||||
|
||||
typedef int64_t coord_t;
|
||||
|
@ -48,11 +45,6 @@ enum
|
|||
|
||||
MAXVOXMIPS = 5,
|
||||
|
||||
MAXXDIM = 7680,
|
||||
MAXYDIM = 3200,
|
||||
MINXDIM = 640,
|
||||
MINYDIM = 480,
|
||||
|
||||
MAXWALLSB = ((MAXWALLS >> 2) + (MAXWALLS >> 3)),
|
||||
|
||||
MAXVOXELS = 1024,
|
||||
|
@ -100,24 +92,11 @@ enum {
|
|||
};
|
||||
|
||||
|
||||
enum {
|
||||
SPR_XFLIP = 4,
|
||||
SPR_YFLIP = 8,
|
||||
|
||||
SPR_WALL = 16,
|
||||
SPR_FLOOR = 32,
|
||||
SPR_ALIGN_MASK = 32+16,
|
||||
};
|
||||
|
||||
#include "buildtypes.h"
|
||||
|
||||
using usectortype = sectortype;
|
||||
using uwalltype = walltype;
|
||||
using uspritetype = spritetype;
|
||||
|
||||
using uspriteptr_t = uspritetype const *;
|
||||
using uwallptr_t = uwalltype const *;
|
||||
using usectorptr_t = usectortype const *;
|
||||
using uspriteptr_t = spritetype const *;
|
||||
using uwallptr_t = walltype const *;
|
||||
using usectorptr_t = sectortype const *;
|
||||
using tspriteptr_t = tspritetype *;
|
||||
|
||||
|
||||
|
@ -150,21 +129,14 @@ typedef struct {
|
|||
#define SPREXT_TSPRACCESS 16
|
||||
#define SPREXT_TEMPINVISIBLE 32
|
||||
|
||||
#define NEG_ALPHA_TO_BLEND(alpha, blend, orientation) do { \
|
||||
if ((alpha) < 0) { (blend) = -(alpha); (alpha) = 0; (orientation) |= RS_TRANS1; } \
|
||||
} while (0)
|
||||
|
||||
// using the clipdist field
|
||||
enum
|
||||
{
|
||||
TSPR_FLAGS_MDHACK = 1u<<0u,
|
||||
TSPR_FLAGS_DRAW_LAST = 1u<<1u,
|
||||
TSPR_FLAGS_NO_SHADOW = 1u<<2u,
|
||||
TSPR_FLAGS_INVISIBLE_WITH_SHADOW = 1u<<3u,
|
||||
};
|
||||
|
||||
EXTERN int32_t guniqhudid;
|
||||
EXTERN int32_t spritesortcnt;
|
||||
|
||||
struct usermaphack_t
|
||||
{
|
||||
|
@ -176,55 +148,35 @@ struct usermaphack_t
|
|||
EXTERN spriteext_t *spriteext;
|
||||
EXTERN spritesmooth_t *spritesmooth;
|
||||
|
||||
// Wrapper that makes an array of pointers look like an array of references. (Refactoring helper.)
|
||||
|
||||
template<class T, int size>
|
||||
class ReferenceArray
|
||||
{
|
||||
T* data[size];
|
||||
public:
|
||||
T& operator[](size_t index)
|
||||
{
|
||||
assert(index < size);
|
||||
return *data[index];
|
||||
}
|
||||
|
||||
void set(int pos, T* spr)
|
||||
{
|
||||
data[pos] = spr;
|
||||
}
|
||||
};
|
||||
|
||||
EXTERN sectortype *sector;
|
||||
EXTERN walltype *wall;
|
||||
EXTERN spritetype *sprite;
|
||||
EXTERN tspriteptr_t tsprite;
|
||||
EXTERN int leveltimer;
|
||||
|
||||
extern sectortype sectorbackup[MAXSECTORS];
|
||||
extern walltype wallbackup[MAXWALLS];
|
||||
|
||||
|
||||
static inline tspriteptr_t renderMakeTSpriteFromSprite(tspriteptr_t const tspr, uint16_t const spritenum)
|
||||
inline tspriteptr_t renderAddTSpriteFromSprite(spritetype* tsprite, int& spritesortcnt, uint16_t const spritenum)
|
||||
{
|
||||
auto tspr = &tsprite[spritesortcnt++];
|
||||
auto const spr = &sprite[spritenum];
|
||||
|
||||
*tspr = *spr;
|
||||
|
||||
tspr->clipdist = 0;
|
||||
tspr->owner = spritenum;
|
||||
|
||||
return tspr;
|
||||
}
|
||||
|
||||
static inline tspriteptr_t renderAddTSpriteFromSprite(uint16_t const spritenum)
|
||||
// returns: 0=continue sprite collecting;
|
||||
// 1=break out of sprite collecting;
|
||||
inline int32_t renderAddTsprite(spritetype* tsprite, int& spritesortcnt, int16_t z, int16_t sectnum)
|
||||
{
|
||||
return renderMakeTSpriteFromSprite(&tsprite[spritesortcnt++], spritenum);
|
||||
if (spritesortcnt >= MAXSPRITESONSCREEN) return 1;
|
||||
renderAddTSpriteFromSprite(tsprite, spritesortcnt, z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
EXTERN int16_t maskwall[MAXWALLSB], maskwallcnt;
|
||||
EXTERN int16_t thewall[MAXWALLSB];
|
||||
EXTERN tspriteptr_t tspriteptr[MAXSPRITESONSCREEN + 1];
|
||||
|
||||
EXTERN int32_t xdim, ydim;
|
||||
EXTERN int32_t yxaspect, viewingrange;
|
||||
|
@ -235,30 +187,15 @@ EXTERN int32_t display_mirror;
|
|||
|
||||
EXTERN int32_t randomseed;
|
||||
|
||||
EXTERN int16_t numshades;
|
||||
EXTERN uint8_t paletteloaded;
|
||||
|
||||
// Return type is int because this gets passed to variadic functions where structs may produce undefined behavior.
|
||||
inline int shadeToLight(int shade)
|
||||
{
|
||||
shade = clamp(shade, 0, numshades-1);
|
||||
int light = Scale(numshades-1-shade, 255, numshades-1);
|
||||
return PalEntry(255,light,light,light);
|
||||
}
|
||||
|
||||
EXTERN int32_t maxspritesonscreen;
|
||||
|
||||
enum {
|
||||
PALETTE_MAIN = 1<<0,
|
||||
PALETTE_SHADE = 1<<1,
|
||||
PALETTE_TRANSLUC = 1<<2,
|
||||
};
|
||||
|
||||
EXTERN int32_t g_visibility, parallaxvisibility;
|
||||
|
||||
// blendtable[1] to blendtable[numalphatabs] are considered to be
|
||||
// alpha-blending tables:
|
||||
EXTERN uint8_t numalphatabs;
|
||||
EXTERN int32_t g_visibility;
|
||||
|
||||
EXTERN vec2_t windowxy1, windowxy2;
|
||||
|
||||
|
@ -271,13 +208,13 @@ typedef struct {
|
|||
// The proportion at which looking up/down affects the apparent 'horiz' of
|
||||
// a parallaxed sky, scaled by 65536 (so, a value of 65536 makes it align
|
||||
// with the drawn surrounding scene):
|
||||
int32_t horizfrac;
|
||||
int horizfrac;
|
||||
|
||||
// The texel index offset in the y direction of a parallaxed sky:
|
||||
// XXX: currently always 0.
|
||||
int32_t yoffs;
|
||||
int yoffs;
|
||||
|
||||
int8_t lognumtiles; // 1<<lognumtiles: number of tiles in multi-sky
|
||||
int lognumtiles; // 1<<lognumtiles: number of tiles in multi-sky
|
||||
int16_t tileofs[MAXPSKYTILES]; // for 0 <= j < (1<<lognumtiles): tile offset relative to basetile
|
||||
|
||||
int32_t yscale;
|
||||
|
@ -299,6 +236,11 @@ static inline psky_t *getpskyidx(int32_t picnum)
|
|||
EXTERN psky_t * tileSetupSky(int32_t tilenum);
|
||||
psky_t* defineSky(int32_t const tilenum, int horiz, int lognumtiles, const uint16_t* tileofs, int yoff = 0);
|
||||
|
||||
// Get properties of parallaxed sky to draw.
|
||||
// Returns: pointer to tile offset array. Sets-by-pointer the other three.
|
||||
const int16_t* getpsky(int32_t picnum, int32_t* dapyscale, int32_t* dapskybits, int32_t* dapyoffs, int32_t* daptileyscale);
|
||||
|
||||
|
||||
EXTERN char parallaxtype;
|
||||
EXTERN int32_t parallaxyoffs_override, parallaxyscale_override;
|
||||
extern int16_t pskybits_override;
|
||||
|
@ -313,17 +255,11 @@ EXTERN int16_t prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES];
|
|||
EXTERN int16_t nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES];
|
||||
|
||||
EXTERN uint8_t gotpic[(MAXTILES+7)>>3];
|
||||
EXTERN char gotsector[(MAXSECTORS+7)>>3];
|
||||
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 {
|
||||
|
@ -332,8 +268,6 @@ enum {
|
|||
GLOBAL_NO_GL_FOGSHADE = 1<<2,
|
||||
};
|
||||
|
||||
extern int32_t globalflags;
|
||||
|
||||
extern const char *engineerrstr;
|
||||
|
||||
EXTERN int32_t editorzrange[2];
|
||||
|
@ -377,22 +311,8 @@ SPRITE VARIABLES:
|
|||
be in some sector, and must have some kind of status that you define.
|
||||
|
||||
|
||||
TILE VARIABLES:
|
||||
NUMTILES - the number of tiles found TILES.DAT.
|
||||
|
||||
TIMING VARIABLES:
|
||||
NUMFRAMES - The number of times the draw3dscreen function was called
|
||||
since the engine was initialized. This helps to determine frame
|
||||
rate. (Frame rate = numframes * 120 / I_GetBuildTime().)
|
||||
|
||||
OTHER VARIABLES:
|
||||
|
||||
STARTUMOST[320] is an array of the highest y-coordinates on each column
|
||||
that my engine is allowed to write to. You need to set it only
|
||||
once.
|
||||
STARTDMOST[320] is an array of the lowest y-coordinates on each column
|
||||
that my engine is allowed to write to. You need to set it only
|
||||
once.
|
||||
SINTABLE[2048] is a sin table with 2048 angles rather than the
|
||||
normal 360 angles for higher precision. Also since SINTABLE is in
|
||||
all integers, the range is multiplied by 16383, so instead of the
|
||||
|
@ -425,29 +345,14 @@ 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);
|
||||
|
||||
void plotpixel(int32_t x, int32_t y, char col);
|
||||
FCanvasTexture *renderSetTarget(int16_t tilenume);
|
||||
void renderRestoreTarget();
|
||||
void renderPrepareMirror(int32_t dax, int32_t day, int32_t daz, fixed_t daang, fixed_t dahoriz, int16_t dawall,
|
||||
int32_t *tposx, int32_t *tposy, fixed_t *tang);
|
||||
void renderCompleteMirror(void);
|
||||
|
||||
int32_t renderDrawRoomsQ16(int32_t daposx, int32_t daposy, int32_t daposz, fixed_t daang, fixed_t dahoriz, int16_t dacursectnum);
|
||||
|
||||
void renderDrawMasks(void);
|
||||
void setVideoMode();
|
||||
void videoInit();
|
||||
void videoClearViewableArea(int32_t dacol);
|
||||
void videoClearScreen(int32_t dacol);
|
||||
void renderDrawMapView(int32_t dax, int32_t day, int32_t zoome, int16_t ang);
|
||||
|
||||
class F2DDrawer;
|
||||
|
||||
|
@ -498,13 +403,12 @@ void updatesectorneighbor(int32_t const x, int32_t const y, int16_t * const sect
|
|||
void updatesectorneighborz(int32_t const x, int32_t const y, int32_t const z, int16_t * const sectnum, int32_t initialMaxDistance = INITIALUPDATESECTORDIST, int32_t maxDistance = MAXUPDATESECTORDIST) ATTRIBUTE((nonnull(4)));
|
||||
|
||||
int findwallbetweensectors(int sect1, int sect2);
|
||||
static FORCE_INLINE int sectoradjacent(int sect1, int sect2) { return findwallbetweensectors(sect1, sect2) != -1; }
|
||||
inline int sectoradjacent(int sect1, int sect2) { return findwallbetweensectors(sect1, sect2) != -1; }
|
||||
int32_t getsectordist(vec2_t const in, int const sectnum, vec2_t * const out = nullptr);
|
||||
extern const int16_t *chsecptr_onextwall;
|
||||
int32_t checksectorpointer(int16_t i, int16_t sectnum);
|
||||
|
||||
#if !KRANDDEBUG
|
||||
static FORCE_INLINE int32_t krand(void)
|
||||
inline int32_t krand(void)
|
||||
{
|
||||
randomseed = (randomseed * 1664525ul) + 221297ul;
|
||||
return ((uint32_t) randomseed)>>16;
|
||||
|
@ -513,16 +417,19 @@ static FORCE_INLINE int32_t krand(void)
|
|||
int32_t krand(void);
|
||||
#endif
|
||||
|
||||
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 int32_t ksqrt(uint32_t num)
|
||||
{
|
||||
return int(sqrt((float)num));
|
||||
}
|
||||
|
||||
static FORCE_INLINE constexpr uint32_t uhypsq(int32_t const dx, int32_t const dy)
|
||||
int32_t getangle(int32_t xvect, int32_t yvect);
|
||||
|
||||
inline constexpr uint32_t uhypsq(int32_t const dx, int32_t const dy)
|
||||
{
|
||||
return (uint32_t)dx*dx + (uint32_t)dy*dy;
|
||||
}
|
||||
|
||||
static FORCE_INLINE int32_t logapproach(int32_t const val, int32_t const targetval)
|
||||
inline int32_t logapproach(int32_t const val, int32_t const targetval)
|
||||
{
|
||||
int32_t const dif = targetval - val;
|
||||
return (dif>>1) ? val + (dif>>1) : targetval;
|
||||
|
@ -551,36 +458,36 @@ void yax_getzsofslope(int sectNum, int playerX, int playerY, int32_t* pCeilZ, in
|
|||
int32_t yax_getceilzofslope(int const sectnum, vec2_t const vect);
|
||||
int32_t yax_getflorzofslope(int const sectnum, vec2_t const vect);
|
||||
|
||||
static FORCE_INLINE int32_t getceilzofslope(int16_t sectnum, int32_t dax, int32_t day)
|
||||
inline int32_t getceilzofslope(int16_t sectnum, int32_t dax, int32_t day)
|
||||
{
|
||||
return getceilzofslopeptr((usectorptr_t)§or[sectnum], dax, day);
|
||||
}
|
||||
|
||||
static FORCE_INLINE int32_t getflorzofslope(int16_t sectnum, int32_t dax, int32_t day)
|
||||
inline int32_t getflorzofslope(int16_t sectnum, int32_t dax, int32_t day)
|
||||
{
|
||||
return getflorzofslopeptr((usectorptr_t)§or[sectnum], dax, day);
|
||||
}
|
||||
|
||||
static FORCE_INLINE void getzsofslope(int16_t sectnum, int32_t dax, int32_t day, int32_t *ceilz, int32_t *florz)
|
||||
inline void getzsofslope(int16_t sectnum, int32_t dax, int32_t day, int32_t *ceilz, int32_t *florz)
|
||||
{
|
||||
getzsofslopeptr((usectorptr_t)§or[sectnum], dax, day, ceilz, florz);
|
||||
}
|
||||
|
||||
static FORCE_INLINE void getcorrectzsofslope(int16_t sectnum, int32_t dax, int32_t day, int32_t *ceilz, int32_t *florz)
|
||||
inline void getcorrectzsofslope(int16_t sectnum, int32_t dax, int32_t day, int32_t *ceilz, int32_t *florz)
|
||||
{
|
||||
vec2_t closest = { dax, day };
|
||||
getsectordist(closest, sectnum, &closest);
|
||||
getzsofslopeptr((usectorptr_t)§or[sectnum], closest.x, closest.y, ceilz, florz);
|
||||
}
|
||||
|
||||
static FORCE_INLINE int32_t getcorrectceilzofslope(int16_t sectnum, int32_t dax, int32_t day)
|
||||
inline int32_t getcorrectceilzofslope(int16_t sectnum, int32_t dax, int32_t day)
|
||||
{
|
||||
vec2_t closest = { dax, day };
|
||||
getsectordist(closest, sectnum, &closest);
|
||||
return getceilzofslopeptr((usectorptr_t)§or[sectnum], closest.x, closest.y);
|
||||
}
|
||||
|
||||
static FORCE_INLINE int32_t getcorrectflorzofslope(int16_t sectnum, int32_t dax, int32_t day)
|
||||
inline int32_t getcorrectflorzofslope(int16_t sectnum, int32_t dax, int32_t day)
|
||||
{
|
||||
vec2_t closest = { dax, day };
|
||||
getsectordist(closest, sectnum, &closest);
|
||||
|
@ -589,12 +496,12 @@ static FORCE_INLINE int32_t getcorrectflorzofslope(int16_t sectnum, int32_t dax,
|
|||
|
||||
// Is <wal> a red wall in a safe fashion, i.e. only if consistency invariant
|
||||
// ".nextsector >= 0 iff .nextwall >= 0" holds.
|
||||
static FORCE_INLINE int32_t redwallp(uwallptr_t wal)
|
||||
inline int32_t redwallp(uwallptr_t wal)
|
||||
{
|
||||
return (wal->nextwall >= 0 && wal->nextsector >= 0);
|
||||
}
|
||||
|
||||
static FORCE_INLINE int32_t E_SpriteIsValid(const int32_t i)
|
||||
inline int32_t E_SpriteIsValid(const int32_t i)
|
||||
{
|
||||
return ((unsigned)i < MAXSPRITES && sprite[i].statnum != MAXSTATUS);
|
||||
}
|
||||
|
@ -602,7 +509,6 @@ static FORCE_INLINE int32_t E_SpriteIsValid(const int32_t i)
|
|||
|
||||
void alignceilslope(int16_t dasect, int32_t x, int32_t y, int32_t z);
|
||||
void alignflorslope(int16_t dasect, int32_t x, int32_t y, int32_t z);
|
||||
int32_t sectorofwall(int16_t wallNum);
|
||||
void setslope(int32_t sectnum, int32_t cf, int16_t slope);
|
||||
|
||||
int32_t lintersect(int32_t originX, int32_t originY, int32_t originZ,
|
||||
|
@ -612,13 +518,6 @@ int32_t lintersect(int32_t originX, int32_t originY, int32_t originZ,
|
|||
|
||||
int32_t rayintersect(int32_t x1, int32_t y1, int32_t z1, int32_t vx, int32_t vy, int32_t vz, int32_t x3,
|
||||
int32_t y3, int32_t x4, int32_t y4, int32_t *intx, int32_t *inty, int32_t *intz);
|
||||
#if !defined NETCODE_DISABLE
|
||||
void do_insertsprite_at_headofstat(int16_t spritenum, int16_t statnum);
|
||||
int32_t insertspritestat(int16_t statnum);
|
||||
void do_deletespritestat(int16_t deleteme);
|
||||
void do_insertsprite_at_headofsect(int16_t spritenum, int16_t sectnum);
|
||||
void do_deletespritesect(int16_t deleteme);
|
||||
#endif
|
||||
int32_t insertsprite(int16_t sectnum, int16_t statnum);
|
||||
int32_t deletesprite(int16_t spritenum);
|
||||
|
||||
|
@ -638,49 +537,15 @@ inline void setspritepos(int spnum, int x, int y, int z)
|
|||
int32_t setspritez(int16_t spritenum, const vec3_t *) ATTRIBUTE((nonnull(2)));
|
||||
|
||||
int32_t spriteheightofsptr(uspriteptr_t spr, int32_t *height, int32_t alsotileyofs);
|
||||
static FORCE_INLINE int32_t spriteheightofs(int16_t i, int32_t *height, int32_t alsotileyofs)
|
||||
inline int32_t spriteheightofs(int16_t i, int32_t *height, int32_t alsotileyofs)
|
||||
{
|
||||
return spriteheightofsptr((uspriteptr_t)&sprite[i], height, alsotileyofs);
|
||||
}
|
||||
|
||||
int videoCaptureScreen();
|
||||
|
||||
struct OutputFileCounter {
|
||||
uint16_t count = 0;
|
||||
FileWriter *opennextfile(char *, char *);
|
||||
FileWriter *opennextfile_withext(char *, const char *);
|
||||
};
|
||||
|
||||
// PLAG: line utility functions
|
||||
typedef struct s_equation
|
||||
{
|
||||
float a, b, c;
|
||||
} _equation;
|
||||
|
||||
#define STATUS2DSIZ 144
|
||||
#define STATUS2DSIZ2 26
|
||||
|
||||
#ifdef USE_OPENGL
|
||||
void renderSetRollAngle(float rolla);
|
||||
#endif
|
||||
|
||||
void Polymost_Startup();
|
||||
|
||||
typedef uint16_t polytintflags_t;
|
||||
|
||||
enum cutsceneflags {
|
||||
CUTSCENE_FORCEFILTER = 1,
|
||||
CUTSCENE_FORCENOFILTER = 2,
|
||||
CUTSCENE_TEXTUREFILTER = 4,
|
||||
};
|
||||
|
||||
enum {
|
||||
TEXFILTER_OFF = 0, // GL_NEAREST
|
||||
TEXFILTER_ON = 5, // GL_LINEAR_MIPMAP_LINEAR
|
||||
};
|
||||
|
||||
extern int32_t gltexmaxsize;
|
||||
|
||||
EXTERN_CVAR(Bool, hw_animsmoothing)
|
||||
EXTERN_CVAR(Bool, hw_hightile)
|
||||
EXTERN_CVAR(Bool, hw_models)
|
||||
|
@ -692,7 +557,6 @@ EXTERN_CVAR(Bool, hw_useindexedcolortextures)
|
|||
EXTERN_CVAR(Bool, hw_parallaxskypanning)
|
||||
EXTERN_CVAR(Bool, r_voxels)
|
||||
|
||||
extern int32_t r_downsize;
|
||||
extern int32_t mdtims, omdtims;
|
||||
|
||||
extern int32_t r_rortexture;
|
||||
|
@ -705,11 +569,8 @@ int32_t md_loadmodel(const char *fn);
|
|||
int32_t md_setmisc(int32_t modelid, float scale, int32_t shadeoff, float zadd, float yoffset, int32_t flags);
|
||||
// int32_t md_tilehasmodel(int32_t tilenume, int32_t pal);
|
||||
|
||||
extern TArray<FString> g_clipMapFiles;
|
||||
|
||||
EXTERN int32_t nextvoxid;
|
||||
EXTERN int8_t voxreserve[(MAXVOXELS+7)>>3];
|
||||
EXTERN int8_t voxrotate[(MAXVOXELS+7)>>3];
|
||||
EXTERN FixedBitArray<MAXVOXELS>voxreserve;
|
||||
|
||||
#ifdef USE_OPENGL
|
||||
// TODO: dynamically allocate this
|
||||
|
@ -723,7 +584,7 @@ typedef struct
|
|||
int16_t framenum; // calculate the number from the name when declaring
|
||||
int16_t nexttile;
|
||||
uint16_t smoothduration;
|
||||
hudtyp *hudmem[2];
|
||||
hudtyp hudmem[2];
|
||||
int8_t skinnum;
|
||||
char pal;
|
||||
} tile2model_t;
|
||||
|
@ -733,19 +594,13 @@ typedef struct
|
|||
EXTERN int32_t mdinited;
|
||||
EXTERN tile2model_t tile2model[MAXTILES+EXTRATILES];
|
||||
|
||||
static FORCE_INLINE int32_t md_tilehasmodel(int32_t const tilenume, int32_t const pal)
|
||||
inline int32_t md_tilehasmodel(int32_t const tilenume, int32_t const pal)
|
||||
{
|
||||
return mdinited ? tile2model[Ptile2tile(tilenume,pal)].modelid : -1;
|
||||
}
|
||||
#endif // defined USE_OPENGL
|
||||
|
||||
static FORCE_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);
|
||||
|
@ -758,12 +613,6 @@ 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, bool cumulative = false);
|
||||
|
||||
// if loadboard() fails with -2 return, try loadoldboard(). if it fails with
|
||||
// -2, board is dodgy
|
||||
int32_t engineLoadBoardV5V6(const char *filename, char fromwhere, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum);
|
||||
|
||||
#ifdef USE_OPENGL
|
||||
# include "polymost.h"
|
||||
#endif
|
||||
|
@ -772,7 +621,7 @@ extern int skiptile;
|
|||
|
||||
static vec2_t const zerovec = { 0, 0 };
|
||||
|
||||
static FORCE_INLINE int inside_p(int32_t const x, int32_t const y, int const sectnum) { return (sectnum >= 0 && inside(x, y, sectnum) == 1); }
|
||||
inline int inside_p(int32_t const x, int32_t const y, int const sectnum) { return (sectnum >= 0 && inside(x, y, sectnum) == 1); }
|
||||
|
||||
#define SET_AND_RETURN(Lval, Rval) \
|
||||
do \
|
||||
|
@ -842,15 +691,11 @@ extern int32_t rintersect(int32_t x1, int32_t y1, int32_t z1,
|
|||
int32_t *intx, int32_t *inty, int32_t *intz);
|
||||
|
||||
extern int32_t(*animateoffs_replace)(int const tilenum, int fakevar);
|
||||
extern int32_t(*getpalookup_replace)(int32_t davis, int32_t dashade);
|
||||
extern void(*initspritelists_replace)(void);
|
||||
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.
|
||||
|
@ -867,6 +712,23 @@ enum EHitBits
|
|||
|
||||
void updateModelInterpolation();
|
||||
|
||||
inline void tileUpdatePicnum(int* const tileptr, int const obj, int stat)
|
||||
{
|
||||
auto& tile = *tileptr;
|
||||
|
||||
if (picanm[tile].sf & PICANM_ANIMTYPE_MASK)
|
||||
tile += animateoffs(tile, obj);
|
||||
|
||||
if (((obj & 16384) == 16384) && (stat & CSTAT_WALL_ROTATE_90) && RotTile(tile).newtile != -1)
|
||||
tile = RotTile(tile).newtile;
|
||||
}
|
||||
|
||||
inline void setgotpic(int32_t tilenume)
|
||||
{
|
||||
gotpic[tilenume >> 3] |= 1 << (tilenume & 7);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#include "iterators.h"
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
//ceilingstat/floorstat:
|
||||
// bit 0: 1 = parallaxing, 0 = not "P"
|
||||
// bit 1: 1 = groudraw, 0 = not
|
||||
// bit 1: 1 = sloped, 0 = not
|
||||
// bit 2: 1 = swap x&y, 0 = not "F"
|
||||
// bit 3: 1 = double smooshiness "E"
|
||||
// bit 4: 1 = x-flip "F"
|
||||
|
@ -17,9 +17,38 @@
|
|||
// bit 9: 1 = blocking ceiling/floor
|
||||
// bit 10: 1 = YAX'ed ceiling/floor
|
||||
// bit 11: 1 = hitscan-sensitive ceiling/floor
|
||||
// bits 12-15: reserved
|
||||
// bits 12-14: reserved
|
||||
// bit 15: SW: block FAF hitscans
|
||||
|
||||
//////////////////// Version 7 map format ////////////////////
|
||||
enum
|
||||
{
|
||||
CSTAT_SECTOR_SKY = 1,
|
||||
CSTAT_SECTOR_SLOPE = 2,
|
||||
CSTAT_SECTOR_SWAPXY = 4,
|
||||
CSTAT_SECTOR_TEXHALF = 8,
|
||||
CSTAT_SECTOR_XFLIP = 16,
|
||||
CSTAT_SECTOR_YFLIP = 32,
|
||||
CSTAT_SECTOR_ALIGN = 64,
|
||||
CSTAT_SECTOR_TRANS = 128,
|
||||
CSTAT_SECTOR_TRANS_INVERT = 256,
|
||||
CSTAT_SECTOR_METHOD = 384,
|
||||
|
||||
SECTOREX_CLOUDSCROLL = 1,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PORTAL_SECTOR_FLOOR = 1,
|
||||
PORTAL_SECTOR_CEILING = 2,
|
||||
PORTAL_SECTOR_FLOOR_REFLECT = 3,
|
||||
PORTAL_SECTOR_CEILING_REFLECT = 4,
|
||||
PORTAL_WALL_VIEW = 5,
|
||||
PORTAL_WALL_MIRROR = 6,
|
||||
PORTAL_WALL_TO_SPRITE = 7,
|
||||
PORTAL_SECTOR_GEOMETRY = 8,
|
||||
};
|
||||
|
||||
|
||||
//40 bytes
|
||||
struct sectortype
|
||||
|
@ -40,7 +69,11 @@ struct sectortype
|
|||
int16_t hitag;
|
||||
int16_t extra;
|
||||
|
||||
uint8_t dirty;
|
||||
uint8_t exflags;
|
||||
float ceilingxpan_, ceilingypan_, floorxpan_, floorypan_;
|
||||
uint8_t portalflags;
|
||||
int8_t portalnum;
|
||||
|
||||
int ceilingxpan() const { return int(ceilingxpan_); }
|
||||
int ceilingypan() const { return int(ceilingypan_); }
|
||||
|
@ -80,7 +113,7 @@ struct walltype
|
|||
};
|
||||
vec2_t pos;
|
||||
};
|
||||
int16_t point2, nextwall, nextsector;
|
||||
int16_t point2, nextwall, sector, nextsector;
|
||||
uint16_t cstat;
|
||||
int16_t picnum, overpicnum;
|
||||
int8_t shade;
|
||||
|
@ -91,6 +124,9 @@ struct walltype
|
|||
int16_t hitag;
|
||||
int16_t extra;
|
||||
float xpan_, ypan_;
|
||||
binangle clipangle;
|
||||
uint8_t portalflags;
|
||||
uint16_t portalnum;
|
||||
|
||||
int xpan() const { return int(xpan_); }
|
||||
int ypan() const { return int(ypan_); }
|
||||
|
@ -216,19 +252,13 @@ struct spritetype
|
|||
int8_t xoffset, yoffset;
|
||||
int16_t sectnum, statnum;
|
||||
int16_t oang, ang, owner;
|
||||
union {
|
||||
struct
|
||||
{
|
||||
union {
|
||||
int16_t xvel, index;
|
||||
};
|
||||
int16_t yvel;
|
||||
union {
|
||||
int16_t zvel, inittype;
|
||||
};
|
||||
union {
|
||||
int16_t xvel, index;
|
||||
};
|
||||
int16_t yvel;
|
||||
union {
|
||||
int16_t zvel, inittype;
|
||||
};
|
||||
vec3_16_t vel;
|
||||
};
|
||||
union {
|
||||
int16_t lotag, type;
|
||||
};
|
||||
|
@ -237,6 +267,7 @@ struct spritetype
|
|||
};
|
||||
int16_t extra;
|
||||
int16_t detail;
|
||||
int time;
|
||||
|
||||
#if 0
|
||||
// make sure we do not accidentally copy this
|
||||
|
@ -287,39 +318,41 @@ struct spritetype
|
|||
|
||||
int32_t interpolatedx(double const smoothratio, int const scale = 16)
|
||||
{
|
||||
return ox + MulScale(x - ox, smoothratio, scale);
|
||||
return interpolatedvalue(ox, x, smoothratio, scale);
|
||||
}
|
||||
|
||||
int32_t interpolatedy(double const smoothratio, int const scale = 16)
|
||||
{
|
||||
return oy + MulScale(y - oy, smoothratio, scale);
|
||||
return interpolatedvalue(oy, y, smoothratio, scale);
|
||||
}
|
||||
|
||||
int32_t interpolatedz(double const smoothratio, int const scale = 16)
|
||||
{
|
||||
return oz + MulScale(z - oz, smoothratio, scale);
|
||||
return interpolatedvalue(oz, z, smoothratio, scale);
|
||||
}
|
||||
|
||||
vec2_t interpolatedvec2(double const smoothratio, int const scale = 16)
|
||||
{
|
||||
return vec2_t({
|
||||
return
|
||||
{
|
||||
interpolatedx(smoothratio, scale),
|
||||
interpolatedy(smoothratio, scale)
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
vec3_t interpolatedvec3(double const smoothratio, int const scale = 16)
|
||||
{
|
||||
return vec3_t({
|
||||
return
|
||||
{
|
||||
interpolatedx(smoothratio, scale),
|
||||
interpolatedy(smoothratio, scale),
|
||||
interpolatedz(smoothratio, scale)
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
int16_t interpolatedang(double const smoothratio)
|
||||
{
|
||||
return oang + MulScale(((ang + 1024 - oang) & 2047) - 1024, smoothratio, 16);
|
||||
return interpolatedangle(oang, ang, smoothratio, 16);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -11,54 +11,9 @@
|
|||
#include "m_alloc.h"
|
||||
#include "intvec.h"
|
||||
#include "m_swap.h"
|
||||
#include "serializer.h"
|
||||
|
||||
////////// Compiler detection //////////
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define EDUKE32_GCC_PREREQ(major, minor) (major < __GNUC__ || (major == __GNUC__ && minor <= __GNUC_MINOR__))
|
||||
#else
|
||||
# define EDUKE32_GCC_PREREQ(major, minor) 0
|
||||
#endif
|
||||
|
||||
|
||||
////////// Language detection //////////
|
||||
|
||||
////////// Language and compiler feature polyfills //////////
|
||||
|
||||
# define EXTERNC
|
||||
|
||||
#ifndef UNREFERENCED_PARAMETER
|
||||
# define UNREFERENCED_PARAMETER(x) (x) = (x)
|
||||
#endif
|
||||
|
||||
#if defined __GNUC__ || defined __clang__
|
||||
# define ATTRIBUTE(attrlist) __attribute__(attrlist)
|
||||
#else
|
||||
# define ATTRIBUTE(attrlist)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef MAY_ALIAS
|
||||
# ifdef _MSC_VER
|
||||
# define MAY_ALIAS
|
||||
# else
|
||||
# define MAY_ALIAS __attribute__((may_alias))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FORCE_INLINE
|
||||
# ifdef _MSC_VER
|
||||
# define FORCE_INLINE __forceinline
|
||||
# else
|
||||
# ifdef __GNUC__
|
||||
# define FORCE_INLINE inline __attribute__((always_inline))
|
||||
# else
|
||||
# define FORCE_INLINE inline
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
# define fallthrough__ [[fallthrough]]
|
||||
|
||||
////////// Architecture detection //////////
|
||||
|
@ -103,45 +58,18 @@
|
|||
|
||||
#include "engineerrors.h"
|
||||
|
||||
////////// DEPRECATED: Standard library prefixing //////////
|
||||
|
||||
typedef intptr_t ssize_t;
|
||||
|
||||
typedef ssize_t bssize_t;
|
||||
typedef intptr_t bssize_t;
|
||||
|
||||
#define BMAX_PATH 256
|
||||
|
||||
////////// Metaprogramming structs //////////
|
||||
|
||||
using std::enable_if_t;
|
||||
using native_t = intptr_t;
|
||||
|
||||
typedef struct MAY_ALIAS {
|
||||
int32_t x, y;
|
||||
} vec2_t;
|
||||
|
||||
typedef struct {
|
||||
float x, y;
|
||||
} vec2f_t;
|
||||
|
||||
typedef struct {
|
||||
double x, y;
|
||||
} vec2d_t;
|
||||
|
||||
typedef struct MAY_ALIAS {
|
||||
union {
|
||||
struct { int32_t x, y, z; };
|
||||
vec2_t vec2;
|
||||
};
|
||||
} vec3_t;
|
||||
|
||||
typedef struct MAY_ALIAS {
|
||||
union {
|
||||
struct { int16_t x, y, z; };
|
||||
vec2_16_t vec2;
|
||||
};
|
||||
} vec3_16_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
|
@ -155,57 +83,14 @@ typedef struct {
|
|||
|
||||
static_assert(sizeof(vec3f_t) == sizeof(float) * 3);
|
||||
|
||||
typedef struct {
|
||||
union { double x; double d; };
|
||||
union { double y; double u; };
|
||||
union { double z; double v; };
|
||||
} vec3d_t;
|
||||
|
||||
static_assert(sizeof(vec3d_t) == sizeof(double) * 3);
|
||||
|
||||
|
||||
////////// Language tricks that depend on size_t //////////
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
////////// Pointer management //////////
|
||||
|
||||
#define DO_FREE_AND_NULL(var) do { \
|
||||
Xfree(var); (var) = NULL; \
|
||||
} while (0)
|
||||
|
||||
|
||||
////////// Data serialization //////////
|
||||
|
||||
inline int32_t B_LITTLE32(int32_t val) { return LittleLong(val); }
|
||||
inline uint32_t B_LITTLE32(uint32_t val) { return LittleLong(val); }
|
||||
inline int32_t B_LITTLE16(int16_t val) { return LittleShort(val); }
|
||||
inline uint32_t B_LITTLE16(uint16_t val) { return LittleShort(val); }
|
||||
|
||||
static FORCE_INLINE void B_BUF32(void * const buf, uint32_t const x) { *(uint32_t *) buf = x; }
|
||||
static FORCE_INLINE uint32_t B_UNBUF32(void const * const buf) { return *(uint32_t const *) buf; }
|
||||
static FORCE_INLINE uint16_t B_UNBUF16(void const * const buf) { return *(uint16_t const *) buf; }
|
||||
|
||||
|
||||
|
||||
////////// Abstract data operations //////////
|
||||
|
||||
using std::min;
|
||||
using std::max;
|
||||
|
||||
////////// Bitfield manipulation //////////
|
||||
|
||||
// This once was a static array, requiring a memory acces where a shift would suffice.
|
||||
// Revert the above to a real bit shift through some C++ operator magic. That saves me from reverting all the code that uses this construct.
|
||||
// Note: Only occurs 25 times in the code, should be removed for good.
|
||||
static struct
|
||||
{
|
||||
constexpr uint8_t operator[](int index) const { return 1 << index; };
|
||||
} pow2char;
|
||||
|
||||
|
||||
static FORCE_INLINE void bitmap_set(uint8_t *const ptr, int const n) { ptr[n>>3] |= 1 << (n&7); }
|
||||
static FORCE_INLINE char bitmap_test(uint8_t const *const ptr, int const n) { return ptr[n>>3] & (1 << (n&7)); }
|
||||
inline void bitmap_set(uint8_t *const ptr, int const n) { ptr[n>>3] |= 1 << (n&7); }
|
||||
inline char bitmap_test(uint8_t const *const ptr, int const n) { return ptr[n>>3] & (1 << (n&7)); }
|
||||
|
||||
////////// Utility functions //////////
|
||||
|
||||
|
@ -230,42 +115,4 @@ void bfirst_search_try(T *const list, uint8_t *const bitmap, T *const eltnumptr,
|
|||
}
|
||||
}
|
||||
|
||||
////////// PANICKING ALLOCATION WRAPPERS //////////
|
||||
|
||||
|
||||
#define Xstrdup(s) (strdup(s))
|
||||
#define Xmalloc(size) (M_Malloc(size))
|
||||
#define Xcalloc(nmemb, size) (M_Calloc(nmemb, size))
|
||||
#define Xrealloc(ptr, size) (M_Realloc(ptr, size))
|
||||
#define Xfree(ptr) (M_Free(ptr))
|
||||
|
||||
////////// Inlined external libraries //////////
|
||||
|
||||
/* End dependence on compat.o object. */
|
||||
|
||||
inline FSerializer& Serialize(FSerializer& arc, const char* key, vec2_t& c, vec2_t* def)
|
||||
{
|
||||
if (def && !memcmp(&c, def, sizeof(c))) return arc;
|
||||
if (arc.BeginObject(key))
|
||||
{
|
||||
arc("x", c.x, def? &def->x : nullptr)
|
||||
("y", c.y, def ? &def->y : nullptr)
|
||||
.EndObject();
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
|
||||
inline FSerializer& Serialize(FSerializer& arc, const char* key, vec3_t& c, vec3_t* def)
|
||||
{
|
||||
if (def && !memcmp(&c, def, sizeof(c))) return arc;
|
||||
if (arc.BeginObject(key))
|
||||
{
|
||||
arc("x", c.x, def ? &def->x : nullptr)
|
||||
("y", c.y, def ? &def->y : nullptr)
|
||||
("z", c.z, def ? &def->z : nullptr)
|
||||
.EndObject();
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
|
||||
#endif // compat_h_
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
#pragma once
|
||||
// nobody uses these. What's so cool about naked numbers? :(
|
||||
|
||||
// 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
|
|
@ -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,15 +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);
|
||||
|
||||
int md3postload_polymer(md3model_t* m);
|
||||
//int32_t md_thinoutmodel(int32_t modelid, uint8_t *usedframebitmap);
|
||||
EXTERN void md_freevbos(void);
|
||||
|
||||
#endif // defined USE_OPENGL
|
||||
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
|
||||
// Ken Silverman's official web site: "http://www.advsys.net/ken"
|
||||
// See the included license file "BUILDLIC.TXT" for license info.
|
||||
//
|
||||
// This file has been modified from Ken Silverman's original release
|
||||
// by Jonathon Fowler (jf@jonof.id.au)
|
||||
// by the EDuke32 team (development@voidpoint.com)
|
||||
|
||||
#ifndef mmulti_h_
|
||||
#define mmulti_h_
|
||||
|
||||
#define MAXMULTIPLAYERS 16
|
||||
|
||||
extern int myconnectindex, numplayers;
|
||||
extern int connecthead, connectpoint2[MAXMULTIPLAYERS];
|
||||
|
||||
|
||||
#endif // mmulti_h_
|
||||
|
|
@ -4,18 +4,20 @@
|
|||
|
||||
#include "mdsprite.h"
|
||||
|
||||
typedef struct { uint8_t r, g, b, a; } coltype;
|
||||
typedef struct { float r, g, b, a; } coltypef;
|
||||
extern tspritetype pm_tsprite[MAXSPRITESONSCREEN];
|
||||
extern int pm_spritesortcnt;
|
||||
extern int pm_smoothratio;
|
||||
|
||||
|
||||
namespace Polymost
|
||||
{
|
||||
extern float gtang;
|
||||
extern double gxyaspect;
|
||||
extern float grhalfxdown10x;
|
||||
extern float gcosang, gsinang, gcosang2, gsinang2;
|
||||
extern int pm_smoothratio;
|
||||
|
||||
extern void Polymost_prepare_loadboard(void);
|
||||
|
||||
void polymost_outputGLDebugMessage(uint8_t severity, const char* format, ...);
|
||||
|
||||
//void phex(char v, char *s);
|
||||
void polymost_drawsprite(int32_t snum);
|
||||
|
@ -25,57 +27,40 @@ void polymost_initosdfuncs(void);
|
|||
void polymost_drawrooms(void);
|
||||
void polymost_prepareMirror(int32_t dax, int32_t day, int32_t daz, fixed_t daang, fixed_t dahoriz, int16_t mirrorWall);
|
||||
void polymost_completeMirror();
|
||||
void polymost_deletesprite(int num);
|
||||
|
||||
int32_t polymost_maskWallHasTranslucency(uwalltype const * const wall);
|
||||
int32_t polymost_spriteHasTranslucency(tspritetype const * const tspr);
|
||||
int32_t polymost_spriteIsModelOrVoxel(tspritetype const * const tspr);
|
||||
int32_t polymost_maskWallHasTranslucency(walltype const * const wall);
|
||||
int32_t polymost_spriteHasTranslucency(spritetype const * const tspr);
|
||||
|
||||
void polymost_glreset(void);
|
||||
|
||||
enum {
|
||||
INVALIDATE_ALL,
|
||||
INVALIDATE_ART,
|
||||
INVALIDATE_ALL_NON_INDEXED,
|
||||
INVALIDATE_ART_NON_INDEXED
|
||||
};
|
||||
|
||||
void polymost_scansector(int32_t sectnum);
|
||||
|
||||
extern float curpolygonoffset;
|
||||
|
||||
}
|
||||
|
||||
void renderPrepareMirror(int32_t dax, int32_t day, int32_t daz, fixed_t daang, fixed_t dahoriz, int16_t dawall,
|
||||
int32_t* tposx, int32_t* tposy, fixed_t* tang);
|
||||
void renderCompleteMirror(void);
|
||||
|
||||
int32_t renderDrawRoomsQ16(int32_t daposx, int32_t daposy, int32_t daposz, fixed_t daang, fixed_t dahoriz, int16_t dacursectnum);
|
||||
|
||||
void renderDrawMasks(void);
|
||||
|
||||
// PLAG: line utility functions
|
||||
typedef struct s_equation
|
||||
{
|
||||
float a, b, c;
|
||||
} _equation;
|
||||
|
||||
void renderSetRollAngle(float rolla);
|
||||
|
||||
|
||||
// these are defined in engine.cpp.
|
||||
extern int16_t globalpicnum;
|
||||
|
||||
#define POLYMOST_CHOOSE_FOG_PAL(fogpal, pal) \
|
||||
((fogpal) ? (fogpal) : (pal))
|
||||
static FORCE_INLINE int32_t get_floor_fogpal(usectorptr_t const sec)
|
||||
{
|
||||
return POLYMOST_CHOOSE_FOG_PAL(sec->fogpal, sec->floorpal);
|
||||
}
|
||||
static FORCE_INLINE int32_t get_ceiling_fogpal(usectorptr_t const sec)
|
||||
{
|
||||
return POLYMOST_CHOOSE_FOG_PAL(sec->fogpal, sec->ceilingpal);
|
||||
}
|
||||
static FORCE_INLINE int32_t fogshade(int32_t const shade, int32_t const pal)
|
||||
{
|
||||
return (globalflags & GLOBAL_NO_GL_FOGSHADE) ? 0 : shade;
|
||||
}
|
||||
|
||||
static constexpr inline int check_nonpow2(int32_t const x)
|
||||
{
|
||||
return (x > 1 && (x&(x-1)));
|
||||
}
|
||||
|
||||
static inline float polymost_invsqrt_approximation(float x)
|
||||
{
|
||||
#if !B_BIG_ENDIAN
|
||||
float const haf = x * .5f;
|
||||
union { float f; uint32_t i; } n = { x };
|
||||
n.i = 0x5f375a86 - (n.i >> 1);
|
||||
return n.f * (1.5f - haf * (n.f * n.f));
|
||||
#else
|
||||
// this is the comment
|
||||
return 1.f / sqrtf(x);
|
||||
#endif
|
||||
}
|
||||
extern float fcosglobalang, fsinglobalang;
|
||||
extern float fydimen, fviewingrange;
|
||||
extern int32_t viewingrangerecip;
|
||||
|
||||
// Flags of the <dameth> argument of various functions
|
||||
enum {
|
||||
|
@ -96,11 +81,4 @@ enum {
|
|||
DAMETH_BACKFACECULL = -1,
|
||||
};
|
||||
|
||||
#define DAMETH_NARROW_MASKPROPS(dameth) (((dameth)&(~DAMETH_TRANS1))|(((dameth)&DAMETH_TRANS1)>>1))
|
||||
static_assert(DAMETH_NARROW_MASKPROPS(DAMETH_MASKPROPS) == DAMETH_MASK);
|
||||
|
||||
extern float fcosglobalang, fsinglobalang;
|
||||
extern float fydimen, fviewingrange;
|
||||
extern int32_t viewingrangerecip;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,136 +0,0 @@
|
|||
|
||||
#ifndef BUILD_SCRIPTFILE_H_
|
||||
#define BUILD_SCRIPTFILE_H_
|
||||
|
||||
#include "sc_man.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
|
||||
|
||||
using scriptfile = FScanner;
|
||||
|
||||
|
||||
inline int32_t scriptfile_getnumber(scriptfile *sf, int32_t *num)
|
||||
{
|
||||
bool res = sf->GetNumber();
|
||||
if (num)
|
||||
{
|
||||
if (res) *num = sf->Number;
|
||||
else *num = 0;
|
||||
}
|
||||
return !res;
|
||||
}
|
||||
|
||||
inline int32_t scriptfile_getdouble(scriptfile *sf, double *num)
|
||||
{
|
||||
bool res = sf->GetFloat();
|
||||
if (num)
|
||||
{
|
||||
if (res) *num = sf->Float;
|
||||
else *num = 0;
|
||||
}
|
||||
return !res;
|
||||
}
|
||||
|
||||
inline int32_t scriptfile_getstring(scriptfile *sf, FString *st)
|
||||
{
|
||||
bool res = sf->GetString();
|
||||
if (st)
|
||||
{
|
||||
if (res) *st = sf->String;
|
||||
else *st = "";
|
||||
}
|
||||
return !res;
|
||||
}
|
||||
|
||||
inline int32_t scriptfile_getsymbol(scriptfile *sf, int32_t *num)
|
||||
{
|
||||
bool res = sf->GetNumber(true);
|
||||
if (num)
|
||||
{
|
||||
if (res) *num = sf->Number;
|
||||
else *num = 0;
|
||||
}
|
||||
return !res;
|
||||
}
|
||||
|
||||
inline int32_t scriptfile_getsymbol(scriptfile* sf, int64_t* num)
|
||||
{
|
||||
bool res = sf->GetNumber(true);
|
||||
if (num)
|
||||
{
|
||||
if (res) *num = sf->BigNumber;
|
||||
else *num = 0;
|
||||
}
|
||||
return !res;
|
||||
}
|
||||
|
||||
inline FScriptPosition scriptfile_getposition(scriptfile *sf)
|
||||
{
|
||||
return FScriptPosition(*sf);
|
||||
}
|
||||
|
||||
inline int32_t scriptfile_getbraces(scriptfile *sf, FScanner::SavedPos *braceend)
|
||||
{
|
||||
if (sf->CheckString("{"))
|
||||
{
|
||||
auto here = sf->SavePos();
|
||||
sf->SkipToEndOfBlock();
|
||||
*braceend = sf->SavePos();
|
||||
sf->RestorePos(here);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sf->ScriptError("'{' expected");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
inline bool scriptfile_endofblock(scriptfile* sf, FScanner::SavedPos& braceend)
|
||||
{
|
||||
auto here = sf->SavePos();
|
||||
return here.SavedScriptPtr >= braceend.SavedScriptPtr;
|
||||
}
|
||||
|
||||
inline void scriptfile_setposition(scriptfile* sf, const FScanner::SavedPos& pos)
|
||||
{
|
||||
sf->RestorePos(pos);
|
||||
}
|
||||
|
||||
inline scriptfile *scriptfile_fromfile(const char *fn)
|
||||
{
|
||||
int lump = fileSystem.FindFile(fn);
|
||||
if (lump < 0) return nullptr;
|
||||
auto sc = new FScanner;
|
||||
sc->OpenLumpNum(lump);
|
||||
sc->SetNoOctals(true);
|
||||
sc->SetNoFatalErrors(true);
|
||||
return sc;
|
||||
}
|
||||
|
||||
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;
|
||||
int32_t tokenid;
|
||||
}
|
||||
tokenlist;
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
T_EOF = -2,
|
||||
T_ERROR = -1,
|
||||
};
|
||||
|
||||
#endif
|
|
@ -10,7 +10,9 @@
|
|||
#include "clip.h"
|
||||
#include "engine_priv.h"
|
||||
#include "printf.h"
|
||||
#include "gamefuncs.h"
|
||||
|
||||
enum { MAXCLIPDIST = 1024 };
|
||||
|
||||
static int16_t clipnum;
|
||||
static linetype clipit[MAXCLIPNUM];
|
||||
|
@ -21,46 +23,83 @@ static uint8_t clipsectormap[(MAXSECTORS+7)>>3];
|
|||
static uint8_t origclipsectormap[(MAXSECTORS+7)>>3];
|
||||
static int16_t clipobjectval[MAXCLIPNUM];
|
||||
static uint8_t clipignore[(MAXCLIPNUM+7)>>3];
|
||||
static int32_t rxi[8], ryi[8];
|
||||
|
||||
|
||||
|
||||
int32_t quickloadboard=0;
|
||||
|
||||
static int32_t numclipmaps;
|
||||
|
||||
static int32_t numclipsects; // number in sectq[]
|
||||
static int16_t *sectoidx;
|
||||
static int16_t *sectq; // [numsectors]
|
||||
static int16_t pictoidx[MAXTILES]; // maps tile num to clipinfo[] index
|
||||
static int16_t *tempictoidx;
|
||||
|
||||
static usectortype *loadsector;
|
||||
static uwalltype *loadwall, *loadwallinv;
|
||||
static uspritetype *loadsprite;
|
||||
|
||||
vec2_t hitscangoal = { (1<<29)-1, (1<<29)-1 };
|
||||
int32_t hitallsprites = 0;
|
||||
|
||||
void engineInitClipMaps()
|
||||
////////// CLIPMOVE //////////
|
||||
|
||||
|
||||
// x1, y1: in/out
|
||||
// rest x/y: out
|
||||
template <typename T>
|
||||
static inline void get_wallspr_points(T const * const spr, int32_t *x1, int32_t *x2,
|
||||
int32_t *y1, int32_t *y2)
|
||||
{
|
||||
numclipmaps = 0;
|
||||
numclipsects = 0;
|
||||
//These lines get the 2 points of the rotated sprite
|
||||
//Given: (x1, y1) starts out as the center point
|
||||
|
||||
DO_FREE_AND_NULL(sectq);
|
||||
DO_FREE_AND_NULL(sectoidx);
|
||||
DO_FREE_AND_NULL(tempictoidx);
|
||||
DO_FREE_AND_NULL(loadsector);
|
||||
DO_FREE_AND_NULL(loadwall);
|
||||
DO_FREE_AND_NULL(loadwallinv);
|
||||
DO_FREE_AND_NULL(loadsprite);
|
||||
const int32_t tilenum=spr->picnum, ang=spr->ang;
|
||||
const int32_t xrepeat = spr->xrepeat;
|
||||
int32_t xoff = tileLeftOffset(tilenum) + spr->xoffset;
|
||||
int32_t k, l, dax, day;
|
||||
|
||||
// two's complement trick, -1 = 0xff
|
||||
memset(&pictoidx, -1, sizeof(pictoidx));
|
||||
if (spr->cstat&4)
|
||||
xoff = -xoff;
|
||||
|
||||
numsectors = 0;
|
||||
numwalls = 0;
|
||||
dax = bsin(ang) * xrepeat;
|
||||
day = -bcos(ang) * xrepeat;
|
||||
|
||||
l = tileWidth(tilenum);
|
||||
k = (l>>1)+xoff;
|
||||
|
||||
*x1 -= MulScale(dax,k, 16);
|
||||
*x2 = *x1 + MulScale(dax,l, 16);
|
||||
|
||||
*y1 -= MulScale(day,k, 16);
|
||||
*y2 = *y1 + MulScale(day,l, 16);
|
||||
}
|
||||
|
||||
////////// CLIPMOVE //////////
|
||||
// x1, y1: in/out
|
||||
// rest x/y: out
|
||||
template <typename T>
|
||||
static inline void get_floorspr_points(T const * const spr, int32_t px, int32_t py,
|
||||
int32_t *x1, int32_t *x2, int32_t *x3, int32_t *x4,
|
||||
int32_t *y1, int32_t *y2, int32_t *y3, int32_t *y4)
|
||||
{
|
||||
const int32_t tilenum = spr->picnum;
|
||||
const int32_t cosang = bcos(spr->ang);
|
||||
const int32_t sinang = bsin(spr->ang);
|
||||
|
||||
vec2_t const span = { tileWidth(tilenum), tileHeight(tilenum)};
|
||||
vec2_t const repeat = { spr->xrepeat, spr->yrepeat };
|
||||
|
||||
vec2_t adjofs = { tileLeftOffset(tilenum) + spr->xoffset, tileTopOffset(tilenum) + spr->yoffset };
|
||||
|
||||
if (spr->cstat & 4)
|
||||
adjofs.x = -adjofs.x;
|
||||
|
||||
if (spr->cstat & 8)
|
||||
adjofs.y = -adjofs.y;
|
||||
|
||||
vec2_t const center = { ((span.x >> 1) + adjofs.x) * repeat.x, ((span.y >> 1) + adjofs.y) * repeat.y };
|
||||
vec2_t const rspan = { span.x * repeat.x, span.y * repeat.y };
|
||||
vec2_t const ofs = { -MulScale(cosang, rspan.y, 16), -MulScale(sinang, rspan.y, 16) };
|
||||
|
||||
*x1 += DMulScale(sinang, center.x, cosang, center.y, 16) - px;
|
||||
*y1 += DMulScale(sinang, center.y, -cosang, center.x, 16) - py;
|
||||
|
||||
*x2 = *x1 - MulScale(sinang, rspan.x, 16);
|
||||
*y2 = *y1 + MulScale(cosang, rspan.x, 16);
|
||||
|
||||
*x3 = *x2 + ofs.x, *x4 = *x1 + ofs.x;
|
||||
*y3 = *y2 + ofs.y, *y4 = *y1 + ofs.y;
|
||||
}
|
||||
|
||||
int32_t clipmoveboxtracenum = 3;
|
||||
|
||||
|
@ -155,14 +194,14 @@ static void addclipline(int32_t dax1, int32_t day1, int32_t dax2, int32_t day2,
|
|||
clipit[clipnum].x2 = dax2; clipit[clipnum].y2 = day2;
|
||||
clipobjectval[clipnum] = daoval;
|
||||
|
||||
uint32_t const mask = pow2char[clipnum&7];
|
||||
uint32_t const mask = (1 << (clipnum&7));
|
||||
uint8_t &value = clipignore[clipnum>>3];
|
||||
value = (value & ~mask) | (-nofix & mask);
|
||||
|
||||
clipnum++;
|
||||
}
|
||||
|
||||
static FORCE_INLINE void clipmove_tweak_pos(const vec3_t *pos, int32_t gx, int32_t gy, int32_t x1, int32_t y1, int32_t x2,
|
||||
inline void clipmove_tweak_pos(const vec3_t *pos, int32_t gx, int32_t gy, int32_t x1, int32_t y1, int32_t x2,
|
||||
int32_t y2, int32_t *daxptr, int32_t *dayptr)
|
||||
{
|
||||
int32_t daz;
|
||||
|
@ -175,34 +214,6 @@ static FORCE_INLINE void clipmove_tweak_pos(const vec3_t *pos, int32_t gx, int32
|
|||
}
|
||||
}
|
||||
|
||||
int32_t getceilzofslope_old(int32_t sectnum, int32_t dax, int32_t day)
|
||||
{
|
||||
int32_t dx, dy, i, j;
|
||||
|
||||
if (!(sector[sectnum].ceilingstat&2)) return sector[sectnum].ceilingz;
|
||||
j = sector[sectnum].wallptr;
|
||||
dx = wall[wall[j].point2].x-wall[j].x;
|
||||
dy = wall[wall[j].point2].y-wall[j].y;
|
||||
i = (ksqrtasm_old(dx*dx+dy*dy)); if (i == 0) return(sector[sectnum].ceilingz);
|
||||
i = DivScale(sector[sectnum].ceilingheinum,i, 15);
|
||||
dx *= i; dy *= i;
|
||||
return sector[sectnum].ceilingz+DMulScale(dx,day-wall[j].y,-dy,dax-wall[j].x, 23);
|
||||
}
|
||||
|
||||
int32_t getflorzofslope_old(int32_t sectnum, int32_t dax, int32_t day)
|
||||
{
|
||||
int32_t dx, dy, i, j;
|
||||
|
||||
if (!(sector[sectnum].floorstat&2)) return sector[sectnum].floorz;
|
||||
j = sector[sectnum].wallptr;
|
||||
dx = wall[wall[j].point2].x-wall[j].x;
|
||||
dy = wall[wall[j].point2].y-wall[j].y;
|
||||
i = (ksqrtasm_old(dx*dx+dy*dy)); if (i == 0) return sector[sectnum].floorz;
|
||||
i = DivScale(sector[sectnum].floorheinum,i, 15);
|
||||
dx *= i; dy *= i;
|
||||
return sector[sectnum].floorz+DMulScale(dx,day-wall[j].y,-dy,dax-wall[j].x, 23);
|
||||
}
|
||||
|
||||
// Returns: should clip?
|
||||
static int cliptestsector(int const dasect, int const nextsect, int32_t const flordist, int32_t const ceildist, vec2_t const pos, int32_t const posz)
|
||||
{
|
||||
|
@ -214,20 +225,6 @@ static int cliptestsector(int const dasect, int const nextsect, int32_t const fl
|
|||
{
|
||||
case ENGINECOMPATIBILITY_NONE:
|
||||
break;
|
||||
case ENGINECOMPATIBILITY_19950829:
|
||||
{
|
||||
int32_t daz = getflorzofslope_old(dasect, pos.x, pos.y);
|
||||
int32_t daz2 = getflorzofslope_old(nextsect, pos.x, pos.y);
|
||||
|
||||
if (daz2 < daz && (sec2->floorstat&1) == 0)
|
||||
if (posz >= daz2-(flordist-1)) return 1;
|
||||
daz = getceilzofslope_old(dasect, pos.x, pos.y);
|
||||
daz2 = getceilzofslope_old(nextsect, pos.x, pos.y);
|
||||
if (daz2 > daz && (sec2->ceilingstat&1) == 0)
|
||||
if (posz <= daz2+(ceildist-1)) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
{
|
||||
int32_t daz = getflorzofslope(dasect, pos.x, pos.y);
|
||||
|
@ -491,7 +488,7 @@ int32_t clipmove(vec3_t * const pos, int16_t * const sectnum, int32_t xvect, int
|
|||
|
||||
//Extra walldist for sprites on sector lines
|
||||
vec2_t const diff = { goal.x - (pos->x), goal.y - (pos->y) };
|
||||
int32_t const rad = clip_nsqrtasm(compat_maybe_truncate_to_int32(uhypsq(diff.x, diff.y))) + MAXCLIPDIST + walldist + 8;
|
||||
int32_t const rad = ksqrt(compat_maybe_truncate_to_int32(uhypsq(diff.x, diff.y))) + MAXCLIPDIST + walldist + 8;
|
||||
vec2_t const clipMin = { cent.x - rad, cent.y - rad };
|
||||
vec2_t const clipMax = { cent.x + rad, cent.y + rad };
|
||||
|
||||
|
@ -550,7 +547,7 @@ int32_t clipmove(vec3_t * const pos, int16_t * const sectnum, int32_t xvect, int
|
|||
{
|
||||
clipyou = 1;
|
||||
}
|
||||
else if (editstatus == 0)
|
||||
else
|
||||
{
|
||||
clipmove_tweak_pos(pos, diff.x, diff.y, p1.x, p1.y, p2.x, p2.y, &v.x, &v.y);
|
||||
clipyou = cliptestsector(dasect, wal->nextsector, flordist, ceildist, v, pos->z);
|
||||
|
@ -570,7 +567,7 @@ int32_t clipmove(vec3_t * const pos, int16_t * const sectnum, int32_t xvect, int
|
|||
|
||||
if (clipyou)
|
||||
{
|
||||
int16_t const objtype = curspr ? (int16_t)(curspr - (uspritetype *)sprite) + 49152 : (int16_t)j + 32768;
|
||||
int16_t const objtype = curspr ? (int16_t)(curspr - sprite) + 49152 : (int16_t)j + 32768;
|
||||
|
||||
//Add 2 boxes at endpoints
|
||||
int32_t bsz = walldist; if (diff.x < 0) bsz = -bsz;
|
||||
|
@ -616,7 +613,7 @@ int32_t clipmove(vec3_t * const pos, int16_t * const sectnum, int32_t xvect, int
|
|||
if ((cstat&dasprclipmask) == 0)
|
||||
continue;
|
||||
|
||||
vec2_t p1 = *(vec2_t const *)spr;
|
||||
auto p1 = spr->pos.vec2;
|
||||
|
||||
switch (cstat & (CSTAT_SPRITE_ALIGNMENT_WALL | CSTAT_SPRITE_ALIGNMENT_FLOOR))
|
||||
{
|
||||
|
@ -989,11 +986,6 @@ void getzrange(const vec3_t *pos, int16_t sectnum,
|
|||
vec2_t closest = pos->vec2;
|
||||
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
||||
getsectordist(closest, sectnum, &closest);
|
||||
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
||||
{
|
||||
*ceilz = getceilzofslope_old(sectnum,closest.x,closest.y);
|
||||
*florz = getflorzofslope_old(sectnum,closest.x,closest.y);
|
||||
}
|
||||
else
|
||||
getzsofslope(sectnum,closest.x,closest.y,ceilz,florz);
|
||||
*ceilhit = sectnum+16384; *florhit = sectnum+16384;
|
||||
|
@ -1037,11 +1029,8 @@ void getzrange(const vec3_t *pos, int16_t sectnum,
|
|||
if (wall[j].cstat&dawalclipmask) continue; // XXX?
|
||||
auto const sec = (usectorptr_t)§or[k];
|
||||
|
||||
if (editstatus == 0)
|
||||
{
|
||||
if (((sec->ceilingstat&1) == 0) && (pos->z <= sec->ceilingz+(3<<8))) continue;
|
||||
if (((sec->floorstat&1) == 0) && (pos->z >= sec->floorz-(3<<8))) continue;
|
||||
}
|
||||
if (((sec->ceilingstat&1) == 0) && (pos->z <= sec->ceilingz+(3<<8))) continue;
|
||||
if (((sec->floorstat&1) == 0) && (pos->z >= sec->floorz-(3<<8))) continue;
|
||||
|
||||
if (bitmap_test(clipsectormap, k) == 0)
|
||||
addclipsect(k);
|
||||
|
@ -1061,11 +1050,6 @@ void getzrange(const vec3_t *pos, int16_t sectnum,
|
|||
closest = pos->vec2;
|
||||
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
|
||||
getsectordist(closest, k, &closest);
|
||||
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
||||
{
|
||||
daz = getceilzofslope_old(k, closest.x,closest.y);
|
||||
daz2 = getflorzofslope_old(k, closest.x,closest.y);
|
||||
}
|
||||
else
|
||||
getzsofslope(k, closest.x,closest.y, &daz,&daz2);
|
||||
|
||||
|
@ -1241,7 +1225,7 @@ static int32_t hitscan_trysector(const vec3_t *sv, usectorptr_t sec, hitdata_t *
|
|||
auto const wal2 = (uwallptr_t)&wall[wal->point2];
|
||||
int32_t j, dax=wal2->x-wal->x, day=wal2->y-wal->y;
|
||||
|
||||
i = nsqrtasm(compat_maybe_truncate_to_int32(uhypsq(dax,day))); if (i == 0) return 1; //continue;
|
||||
i = ksqrt(compat_maybe_truncate_to_int32(uhypsq(dax,day))); if (i == 0) return 1; //continue;
|
||||
i = DivScale(heinum,i, 15);
|
||||
dax *= i; day *= i;
|
||||
|
||||
|
@ -1273,22 +1257,22 @@ static int32_t hitscan_trysector(const vec3_t *sv, usectorptr_t sec, hitdata_t *
|
|||
{
|
||||
if (tmp==NULL)
|
||||
{
|
||||
if (inside(x1,y1,sec-(usectortype *)sector) == 1)
|
||||
if (inside(x1,y1,sec-sector) == 1)
|
||||
{
|
||||
hit_set(hit, sec-(usectortype *)sector, -1, -1, x1, y1, z1);
|
||||
hit_set(hit, sec-sector, -1, -1, x1, y1, z1);
|
||||
hitscan_hitsectcf = (how+1)>>1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int32_t curidx=(int32_t)tmp[0];
|
||||
auto const curspr=(uspritetype *)tmp[1];
|
||||
auto const curspr=(spritetype *)tmp[1];
|
||||
const int32_t thislastsec = tmp[2];
|
||||
|
||||
if (!thislastsec)
|
||||
{
|
||||
if (inside(x1,y1,sec-(usectortype *)sector) == 1)
|
||||
hit_set(hit, curspr->sectnum, -1, curspr-(uspritetype *)sprite, x1, y1, z1);
|
||||
if (inside(x1,y1,sec-sector) == 1)
|
||||
hit_set(hit, curspr->sectnum, -1, curspr-sprite, x1, y1, z1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1476,7 +1460,7 @@ int32_t hitscan(const vec3_t *sv, int16_t sectnum, int32_t vx, int32_t vy, int32
|
|||
{
|
||||
if (picanm[tilenum].sf&PICANM_TEXHITSCAN_BIT)
|
||||
{
|
||||
tileUpdatePicnum(&tilenum, 0);
|
||||
tileUpdatePicnum(&tilenum, 0, 0);
|
||||
|
||||
if (tileLoad(tilenum))
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -8,84 +8,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "cmdlib.h"
|
||||
|
||||
#ifndef ENGINE_PRIV_H
|
||||
#define ENGINE_PRIV_H
|
||||
|
||||
#define MAXARTFILES_BASE 200
|
||||
#define MAXARTFILES_TOTAL 220
|
||||
#define MAXCLIPDIST 1024
|
||||
|
||||
// Uncomment to clear the screen before each top-level draw (classic only).
|
||||
// FIXME: doesn't work with mirrors.
|
||||
//#define ENGINE_CLEAR_SCREEN
|
||||
|
||||
extern intptr_t asm1, asm2;
|
||||
extern int32_t globalx1, globaly2;
|
||||
|
||||
|
||||
extern uint16_t sqrtable[4096], shlookup[4096+256],sqrtable_old[2048];
|
||||
|
||||
|
||||
static inline int32_t nsqrtasm(uint32_t a)
|
||||
{
|
||||
// JBF 20030901: This was a damn lot simpler to reverse engineer than
|
||||
// msqrtasm was. Really, it was just like simplifying an algebra equation.
|
||||
uint16_t c;
|
||||
|
||||
if (a & 0xff000000) // test eax, 0xff000000 / jnz short over24
|
||||
{
|
||||
c = shlookup[(a >> 24) + 4096]; // mov ebx, eax
|
||||
// over24: shr ebx, 24
|
||||
// mov cx, word ptr shlookup[ebx*2+8192]
|
||||
}
|
||||
else
|
||||
{
|
||||
c = shlookup[a >> 12]; // mov ebx, eax
|
||||
// shr ebx, 12
|
||||
// mov cx, word ptr shlookup[ebx*2]
|
||||
// jmp short under24
|
||||
}
|
||||
a >>= c&0xff; // under24: shr eax, cl
|
||||
a = (a&0xffff0000)|(sqrtable[a]); // mov ax, word ptr sqrtable[eax*2]
|
||||
a >>= ((c&0xff00) >> 8); // mov cl, ch
|
||||
// shr eax, cl
|
||||
return a;
|
||||
}
|
||||
|
||||
static inline int32_t getclipmask(int32_t a, int32_t b, int32_t c, int32_t d)
|
||||
{
|
||||
// Ken did this
|
||||
d = ((a<0)<<3) + ((b<0)<<2) + ((c<0)<<1) + (d<0);
|
||||
return (((d<<4)^0xf0)|d);
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline int32_t ksqrtasm_old(int32_t n)
|
||||
{
|
||||
uint32_t shift = 0;
|
||||
n = abs((int32_t)n);
|
||||
while (n >= 2048)
|
||||
{
|
||||
n >>= 2;
|
||||
++shift;
|
||||
}
|
||||
uint32_t const s = sqrtable_old[n];
|
||||
return (s << shift) >> 10;
|
||||
}
|
||||
|
||||
inline int32_t clip_nsqrtasm(int32_t n)
|
||||
{
|
||||
if (enginecompatibility_mode == ENGINECOMPATIBILITY_19950829)
|
||||
return ksqrtasm_old(n);
|
||||
return nsqrtasm(n);
|
||||
}
|
||||
|
||||
extern int16_t thesector[MAXWALLSB], thewall[MAXWALLSB];
|
||||
extern int16_t bunchfirst[MAXWALLSB], bunchlast[MAXWALLSB];
|
||||
extern int16_t maskwall[MAXWALLSB], maskwallcnt;
|
||||
extern tspriteptr_t tspriteptr[MAXSPRITESONSCREEN + 1];
|
||||
extern int32_t xdimen, xdimenrecip, halfxdimen, xdimenscale, xdimscale, ydimen;
|
||||
extern int32_t globalpal, globalfloorpal;
|
||||
extern int32_t xdimen, xdimenscale, xdimscale, ydimen;
|
||||
extern float fxdimen;
|
||||
extern int32_t globalposx, globalposy, globalposz;
|
||||
extern fixed_t qglobalhoriz, qglobalang;
|
||||
|
@ -99,170 +28,35 @@ extern int16_t globalpicnum;
|
|||
|
||||
extern int32_t globalorientation;
|
||||
|
||||
extern int16_t editstatus;
|
||||
|
||||
extern int16_t searchit;
|
||||
extern int16_t searchsector, searchwall, searchstat;
|
||||
extern int16_t searchbottomwall, searchisbottom;
|
||||
|
||||
extern char inpreparemirror;
|
||||
|
||||
extern int16_t sectorborder[256];
|
||||
extern int32_t hitallsprites;
|
||||
|
||||
extern int32_t xb1[MAXWALLSB];
|
||||
extern int32_t rx1[MAXWALLSB], ry1[MAXWALLSB];
|
||||
extern int16_t bunchp2[MAXWALLSB];
|
||||
extern int16_t numscans, numbunches;
|
||||
extern int32_t rxi[8], ryi[8];
|
||||
extern int32_t reciptable[2048];
|
||||
|
||||
|
||||
// int32_t wallmost(int16_t *mostbuf, int32_t w, int32_t sectnum, char dastat);
|
||||
int32_t wallfront(int32_t l1, int32_t l2);
|
||||
|
||||
void set_globalang(fixed_t const ang);
|
||||
|
||||
int32_t animateoffs(int tilenum, int fakevar);
|
||||
|
||||
static FORCE_INLINE int32_t bad_tspr(tspriteptr_t tspr)
|
||||
inline int32_t bad_tspr(tspriteptr_t tspr)
|
||||
{
|
||||
// NOTE: tspr->owner >= MAXSPRITES (could be model) has to be handled by
|
||||
// caller.
|
||||
return (tspr->owner < 0 || (unsigned)tspr->picnum >= MAXTILES);
|
||||
}
|
||||
|
||||
//
|
||||
// getpalookup (internal)
|
||||
//
|
||||
static FORCE_INLINE int32_t getpalookup(int32_t davis, int32_t dashade)
|
||||
{
|
||||
if (getpalookup_replace)
|
||||
return getpalookup_replace(davis, dashade);
|
||||
return min(max(dashade + (davis >> 8), 0), numshades - 1);
|
||||
}
|
||||
|
||||
static FORCE_INLINE int32_t getpalookupsh(int32_t davis) { return getpalookup(davis, globalshade) << 8; }
|
||||
|
||||
////// yax'y stuff //////
|
||||
#ifdef USE_OPENGL
|
||||
extern void polymost_scansector(int32_t sectnum);
|
||||
#endif
|
||||
int32_t renderAddTsprite(int16_t z, int16_t sectnum);
|
||||
|
||||
|
||||
static FORCE_INLINE void setgotpic(int32_t tilenume)
|
||||
{
|
||||
gotpic[tilenume>>3] |= pow2char[tilenume&7];
|
||||
}
|
||||
|
||||
|
||||
// Get properties of parallaxed sky to draw.
|
||||
// Returns: pointer to tile offset array. Sets-by-pointer the other three.
|
||||
const int16_t* getpsky(int32_t picnum, int32_t* dapyscale, int32_t* dapskybits, int32_t* dapyoffs, int32_t* daptileyscale);
|
||||
|
||||
static FORCE_INLINE void set_globalpos(int32_t const x, int32_t const y, int32_t const z)
|
||||
inline void set_globalpos(int32_t const x, int32_t const y, int32_t const z)
|
||||
{
|
||||
globalposx = x, fglobalposx = (float)x;
|
||||
globalposy = y, fglobalposy = (float)y;
|
||||
globalposz = z, fglobalposz = (float)z;
|
||||
}
|
||||
|
||||
template <typename T> static FORCE_INLINE void tileUpdatePicnum(T * const tileptr, int const obj)
|
||||
{
|
||||
auto &tile = *tileptr;
|
||||
|
||||
if (picanm[tile].sf & PICANM_ANIMTYPE_MASK)
|
||||
tile += animateoffs(tile, obj);
|
||||
|
||||
if (((obj & 16384) == 16384) && (globalorientation & CSTAT_WALL_ROTATE_90) && RotTile(tile).newtile != -1)
|
||||
tile = RotTile(tile).newtile;
|
||||
}
|
||||
|
||||
// x1, y1: in/out
|
||||
// rest x/y: out
|
||||
template <typename T>
|
||||
static inline void get_wallspr_points(T const * const spr, int32_t *x1, int32_t *x2,
|
||||
int32_t *y1, int32_t *y2)
|
||||
{
|
||||
//These lines get the 2 points of the rotated sprite
|
||||
//Given: (x1, y1) starts out as the center point
|
||||
|
||||
const int32_t tilenum=spr->picnum, ang=spr->ang;
|
||||
const int32_t xrepeat = spr->xrepeat;
|
||||
int32_t xoff = tileLeftOffset(tilenum) + spr->xoffset;
|
||||
int32_t k, l, dax, day;
|
||||
|
||||
if (spr->cstat&4)
|
||||
xoff = -xoff;
|
||||
|
||||
dax = bsin(ang) * xrepeat;
|
||||
day = -bcos(ang) * xrepeat;
|
||||
|
||||
l = tileWidth(tilenum);
|
||||
k = (l>>1)+xoff;
|
||||
|
||||
*x1 -= MulScale(dax,k, 16);
|
||||
*x2 = *x1 + MulScale(dax,l, 16);
|
||||
|
||||
*y1 -= MulScale(day,k, 16);
|
||||
*y2 = *y1 + MulScale(day,l, 16);
|
||||
}
|
||||
|
||||
// x1, y1: in/out
|
||||
// rest x/y: out
|
||||
template <typename T>
|
||||
static inline void get_floorspr_points(T const * const spr, int32_t px, int32_t py,
|
||||
int32_t *x1, int32_t *x2, int32_t *x3, int32_t *x4,
|
||||
int32_t *y1, int32_t *y2, int32_t *y3, int32_t *y4)
|
||||
{
|
||||
const int32_t tilenum = spr->picnum;
|
||||
const int32_t cosang = bcos(spr->ang);
|
||||
const int32_t sinang = bsin(spr->ang);
|
||||
|
||||
vec2_t const span = { tileWidth(tilenum), tileHeight(tilenum)};
|
||||
vec2_t const repeat = { spr->xrepeat, spr->yrepeat };
|
||||
|
||||
vec2_t adjofs = { tileLeftOffset(tilenum) + spr->xoffset, tileTopOffset(tilenum) + spr->yoffset };
|
||||
|
||||
if (spr->cstat & 4)
|
||||
adjofs.x = -adjofs.x;
|
||||
|
||||
if (spr->cstat & 8)
|
||||
adjofs.y = -adjofs.y;
|
||||
|
||||
vec2_t const center = { ((span.x >> 1) + adjofs.x) * repeat.x, ((span.y >> 1) + adjofs.y) * repeat.y };
|
||||
vec2_t const rspan = { span.x * repeat.x, span.y * repeat.y };
|
||||
vec2_t const ofs = { -MulScale(cosang, rspan.y, 16), -MulScale(sinang, rspan.y, 16) };
|
||||
|
||||
*x1 += DMulScale(sinang, center.x, cosang, center.y, 16) - px;
|
||||
*y1 += DMulScale(sinang, center.y, -cosang, center.x, 16) - py;
|
||||
|
||||
*x2 = *x1 - MulScale(sinang, rspan.x, 16);
|
||||
*y2 = *y1 + MulScale(cosang, rspan.x, 16);
|
||||
|
||||
*x3 = *x2 + ofs.x, *x4 = *x1 + ofs.x;
|
||||
*y3 = *y2 + ofs.y, *y4 = *y1 + ofs.y;
|
||||
}
|
||||
|
||||
inline int widthBits(int num)
|
||||
{
|
||||
int w = tileWidth(num);
|
||||
int j = 15;
|
||||
|
||||
while ((j > 1) && ((1 << j) > w))
|
||||
j--;
|
||||
return j;
|
||||
return sizeToBits(tileWidth(num));
|
||||
}
|
||||
|
||||
inline int heightBits(int num)
|
||||
{
|
||||
int w = tileHeight(num);
|
||||
int j = 15;
|
||||
|
||||
while ((j > 1) && ((1 << j) > w))
|
||||
j--;
|
||||
return j;
|
||||
return sizeToBits(tileHeight(num));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,18 +16,20 @@
|
|||
#include "texturemanager.h"
|
||||
#include "hw_renderstate.h"
|
||||
#include "printf.h"
|
||||
#include "hw_voxels.h"
|
||||
#include "../../glbackend/glbackend.h"
|
||||
|
||||
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)
|
||||
static int32_t addtileP(int32_t ,int32_t tile,int32_t pallet)
|
||||
{
|
||||
// tile >= 0 && tile < MAXTILES
|
||||
|
||||
UNREFERENCED_PARAMETER(model);
|
||||
if (curextra==MAXTILES+EXTRATILES-1)
|
||||
{
|
||||
Printf("warning: max EXTRATILES reached\n");
|
||||
|
@ -97,27 +99,23 @@ void freeallmodels()
|
|||
if (models)
|
||||
{
|
||||
for (i=0; i<nextmodelid; i++) mdfree(models[i]);
|
||||
DO_FREE_AND_NULL(models);
|
||||
M_Free(models);
|
||||
models = nullptr;
|
||||
nummodelsalloced = 0;
|
||||
nextmodelid = 0;
|
||||
}
|
||||
|
||||
memset(tile2model,-1,sizeof(tile2model));
|
||||
for (i=0; i<MAXTILES; i++)
|
||||
memset(tile2model[i].hudmem, 0, sizeof(tile2model[i].hudmem));
|
||||
|
||||
curextra=MAXTILES;
|
||||
|
||||
if (vertlist)
|
||||
{
|
||||
DO_FREE_AND_NULL(vertlist);
|
||||
M_Free(vertlist);
|
||||
vertlist = nullptr;
|
||||
allocmodelverts = maxmodelverts = 0;
|
||||
allocmodeltris = maxmodeltris = 0;
|
||||
}
|
||||
|
||||
#ifdef POLYMER
|
||||
DO_FREE_AND_NULL(tribuf);
|
||||
#endif
|
||||
}
|
||||
|
||||
void mdinit()
|
||||
|
@ -134,7 +132,7 @@ int32_t md_loadmodel(const char *fn)
|
|||
|
||||
if (nextmodelid >= nummodelsalloced)
|
||||
{
|
||||
ml = (mdmodel_t **)Xrealloc(models,(nummodelsalloced+MODELALLOCGROUP)*sizeof(void *));
|
||||
ml = (mdmodel_t **)M_Realloc(models,(nummodelsalloced+MODELALLOCGROUP)*sizeof(void *));
|
||||
models = ml; nummodelsalloced += MODELALLOCGROUP;
|
||||
}
|
||||
|
||||
|
@ -246,7 +244,7 @@ int32_t md_defineanimation(int32_t modelid, const char *framestart, const char *
|
|||
ma.fpssc = fpssc;
|
||||
ma.flags = flags;
|
||||
|
||||
map = (mdanim_t *)Xmalloc(sizeof(mdanim_t));
|
||||
map = (mdanim_t *)M_Malloc(sizeof(mdanim_t));
|
||||
|
||||
memcpy(map, &ma, sizeof(ma));
|
||||
|
||||
|
@ -256,110 +254,6 @@ int32_t md_defineanimation(int32_t modelid, const char *framestart, const char *
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// FIXME: CURRENTLY DISABLED: interpolation may access frames we consider 'unused'?
|
||||
int32_t md_thinoutmodel(int32_t modelid, uint8_t *usedframebitmap)
|
||||
{
|
||||
md3model_t *m;
|
||||
md3surf_t *s;
|
||||
mdanim_t *anm;
|
||||
int32_t i, surfi, sub, usedframes;
|
||||
static int16_t otonframe[1024];
|
||||
|
||||
if ((uint32_t)modelid >= (uint32_t)nextmodelid) return -1;
|
||||
m = (md3model_t *)models[modelid];
|
||||
if (m->mdnum != 3) return -2;
|
||||
|
||||
for (anm=m->animations; anm; anm=anm->next)
|
||||
{
|
||||
if (anm->endframe <= anm->startframe)
|
||||
{
|
||||
// Printf("backward anim %d-%d\n", anm->startframe, anm->endframe);
|
||||
return -3;
|
||||
}
|
||||
|
||||
for (i=anm->startframe; i<anm->endframe; i++)
|
||||
usedframebitmap[i>>3] |= pow2char[i&7];
|
||||
}
|
||||
|
||||
sub = 0;
|
||||
for (i=0; i<m->numframes; i++)
|
||||
{
|
||||
if (!(usedframebitmap[i>>3]&pow2char[i&7]))
|
||||
{
|
||||
sub++;
|
||||
otonframe[i] = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
otonframe[i] = i-sub;
|
||||
}
|
||||
|
||||
usedframes = m->numframes - sub;
|
||||
if (usedframes==0 || usedframes==m->numframes)
|
||||
return usedframes;
|
||||
|
||||
//// THIN OUT! ////
|
||||
|
||||
for (i=0; i<m->numframes; i++)
|
||||
{
|
||||
if (otonframe[i]>=0 && otonframe[i] != i)
|
||||
{
|
||||
if (m->muladdframes)
|
||||
memcpy(&m->muladdframes[2*otonframe[i]], &m->muladdframes[2*i], 2*sizeof(vec3f_t));
|
||||
memcpy(&m->head.frames[otonframe[i]], &m->head.frames[i], sizeof(md3frame_t));
|
||||
}
|
||||
}
|
||||
|
||||
for (surfi=0; surfi < m->head.numsurfs; surfi++)
|
||||
{
|
||||
s = &m->head.surfs[surfi];
|
||||
|
||||
for (i=0; i<m->numframes; i++)
|
||||
if (otonframe[i]>=0 && otonframe[i] != i)
|
||||
memcpy(&s->xyzn[otonframe[i]*s->numverts], &s->xyzn[i*s->numverts], s->numverts*sizeof(md3xyzn_t));
|
||||
}
|
||||
|
||||
////// tweak frame indices in various places
|
||||
|
||||
for (anm=m->animations; anm; anm=anm->next)
|
||||
{
|
||||
if (otonframe[anm->startframe]==-1 || otonframe[anm->endframe-1]==-1)
|
||||
Printf("md %d WTF: anm %d %d\n", modelid, anm->startframe, anm->endframe);
|
||||
|
||||
anm->startframe = otonframe[anm->startframe];
|
||||
anm->endframe = otonframe[anm->endframe-1];
|
||||
}
|
||||
|
||||
for (i=0; i<MAXTILES+EXTRATILES; i++)
|
||||
if (tile2model[i].modelid == modelid)
|
||||
{
|
||||
if (otonframe[tile2model[i].framenum]==-1)
|
||||
Printf("md %d WTF: tile %d, fr %d\n", modelid, i, tile2model[i].framenum);
|
||||
tile2model[i].framenum = otonframe[tile2model[i].framenum];
|
||||
}
|
||||
|
||||
////// realloc & change "numframes" everywhere
|
||||
|
||||
if (m->muladdframes)
|
||||
m->muladdframes = Xrealloc(m->muladdframes, 2*sizeof(vec3f_t)*usedframes);
|
||||
m->head.frames = Xrealloc(m->head.frames, sizeof(md3frame_t)*usedframes);
|
||||
|
||||
for (surfi=0; surfi < m->head.numsurfs; surfi++)
|
||||
{
|
||||
m->head.surfs[surfi].numframes = usedframes;
|
||||
// CAN'T do that because xyzn is offset from a larger block when loaded from md3:
|
||||
// m->head.surfs[surfi].xyzn = Xrealloc(m->head.surfs[surfi].xyzn, s->numverts*usedframes*sizeof(md3xyzn_t));
|
||||
}
|
||||
|
||||
m->head.numframes = usedframes;
|
||||
m->numframes = usedframes;
|
||||
|
||||
////////////
|
||||
return usedframes;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t md_defineskin(int32_t modelid, const char *skinfn, int32_t palnum, int32_t skinnum, int32_t surfnum, float param, float specpower, float specfactor, int32_t flags)
|
||||
{
|
||||
mdskinmap_t *sk, *skl;
|
||||
|
@ -381,7 +275,7 @@ int32_t md_defineskin(int32_t modelid, const char *skinfn, int32_t palnum, int32
|
|||
break;
|
||||
if (!sk)
|
||||
{
|
||||
sk = (mdskinmap_t *)Xcalloc(1,sizeof(mdskinmap_t));
|
||||
sk = (mdskinmap_t *)M_Calloc(1,sizeof(mdskinmap_t));
|
||||
|
||||
if (!skl) m->skinmap = sk;
|
||||
else skl->next = sk;
|
||||
|
@ -410,9 +304,7 @@ int32_t md_definehud(int32_t modelid, int32_t tilex, vec3f_t add, int32_t angadd
|
|||
if ((uint32_t)modelid >= (uint32_t)nextmodelid) return -1;
|
||||
if ((uint32_t)tilex >= (uint32_t)MAXTILES) return -2;
|
||||
|
||||
tile2model[tilex].hudmem[(flags>>2)&1] = (hudtyp *)Xmalloc(sizeof(hudtyp));
|
||||
|
||||
hudtyp * const hud = tile2model[tilex].hudmem[(flags>>2)&1];
|
||||
hudtyp * const hud = &tile2model[tilex].hudmem[(flags>>2)&1];
|
||||
|
||||
hud->add = add;
|
||||
hud->angadd = ((int16_t)angadd)|2048;
|
||||
|
@ -429,8 +321,6 @@ int32_t md_undefinetile(int32_t tile)
|
|||
|
||||
tile2model[tile].modelid = -1;
|
||||
tile2model[tile].nexttile = -1;
|
||||
DO_FREE_AND_NULL(tile2model[tile].hudmem[0]);
|
||||
DO_FREE_AND_NULL(tile2model[tile].hudmem[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -446,8 +336,6 @@ int32_t md_undefinemodel(int32_t modelid)
|
|||
if (tile2model[i].modelid == modelid)
|
||||
{
|
||||
tile2model[i].modelid = -1;
|
||||
DO_FREE_AND_NULL(tile2model[i].hudmem[0]);
|
||||
DO_FREE_AND_NULL(tile2model[i].hudmem[1]);
|
||||
}
|
||||
|
||||
if (models)
|
||||
|
@ -669,23 +557,23 @@ static md2model_t *md2load(FileReader & fil, const char *filnam)
|
|||
|
||||
int32_t ournumskins, ournumglcmds;
|
||||
|
||||
m = (md2model_t *)Xcalloc(1,sizeof(md2model_t));
|
||||
m = (md2model_t *)M_Calloc(1,sizeof(md2model_t));
|
||||
m->mdnum = 2; m->scale = .01f;
|
||||
|
||||
fil.Read((char *)&head,sizeof(md2head_t));
|
||||
#if B_BIG_ENDIAN != 0
|
||||
head.id = B_LITTLE32(head.id); head.vers = B_LITTLE32(head.vers);
|
||||
head.skinxsiz = B_LITTLE32(head.skinxsiz); head.skinysiz = B_LITTLE32(head.skinysiz);
|
||||
head.framebytes = B_LITTLE32(head.framebytes); head.numskins = B_LITTLE32(head.numskins);
|
||||
head.numverts = B_LITTLE32(head.numverts); head.numuv = B_LITTLE32(head.numuv);
|
||||
head.numtris = B_LITTLE32(head.numtris); head.numglcmds = B_LITTLE32(head.numglcmds);
|
||||
head.numframes = B_LITTLE32(head.numframes); head.ofsskins = B_LITTLE32(head.ofsskins);
|
||||
head.ofsuv = B_LITTLE32(head.ofsuv); head.ofstris = B_LITTLE32(head.ofstris);
|
||||
head.ofsframes = B_LITTLE32(head.ofsframes); head.ofsglcmds = B_LITTLE32(head.ofsglcmds);
|
||||
head.ofseof = B_LITTLE32(head.ofseof);
|
||||
head.id = LittleLong(head.id); head.vers = LittleLong(head.vers);
|
||||
head.skinxsiz = LittleLong(head.skinxsiz); head.skinysiz = LittleLong(head.skinysiz);
|
||||
head.framebytes = LittleLong(head.framebytes); head.numskins = LittleLong(head.numskins);
|
||||
head.numverts = LittleLong(head.numverts); head.numuv = LittleLong(head.numuv);
|
||||
head.numtris = LittleLong(head.numtris); head.numglcmds = LittleLong(head.numglcmds);
|
||||
head.numframes = LittleLong(head.numframes); head.ofsskins = LittleLong(head.ofsskins);
|
||||
head.ofsuv = LittleLong(head.ofsuv); head.ofstris = LittleLong(head.ofstris);
|
||||
head.ofsframes = LittleLong(head.ofsframes); head.ofsglcmds = LittleLong(head.ofsglcmds);
|
||||
head.ofseof = LittleLong(head.ofseof);
|
||||
#endif
|
||||
|
||||
if ((head.id != IDP2_MAGIC) || (head.vers != 8)) { Xfree(m); return 0; } //"IDP2"
|
||||
if ((head.id != IDP2_MAGIC) || (head.vers != 8)) { M_Free(m); return 0; } //"IDP2"
|
||||
|
||||
ournumskins = head.numskins ? head.numskins : 1;
|
||||
ournumglcmds = head.numglcmds ? head.numglcmds : 1;
|
||||
|
@ -696,29 +584,29 @@ static md2model_t *md2load(FileReader & fil, const char *filnam)
|
|||
m->numglcmds = head.numglcmds;
|
||||
m->framebytes = head.framebytes;
|
||||
|
||||
m->frames = (char *)Xmalloc(m->numframes*m->framebytes);
|
||||
m->glcmds = (int32_t *)Xmalloc(ournumglcmds*sizeof(int32_t));
|
||||
m->tris = (md2tri_t *)Xmalloc(head.numtris*sizeof(md2tri_t));
|
||||
m->uv = (md2uv_t *)Xmalloc(head.numuv*sizeof(md2uv_t));
|
||||
m->frames = (char *)M_Malloc(m->numframes*m->framebytes);
|
||||
m->glcmds = (int32_t *)M_Malloc(ournumglcmds*sizeof(int32_t));
|
||||
m->tris = (md2tri_t *)M_Malloc(head.numtris*sizeof(md2tri_t));
|
||||
m->uv = (md2uv_t *)M_Malloc(head.numuv*sizeof(md2uv_t));
|
||||
|
||||
fil.Seek(head.ofsframes,FileReader::SeekSet);
|
||||
if (fil.Read((char *)m->frames,m->numframes*m->framebytes) != m->numframes*m->framebytes)
|
||||
{ Xfree(m->uv); Xfree(m->tris); Xfree(m->glcmds); Xfree(m->frames); Xfree(m); return 0; }
|
||||
{ M_Free(m->uv); M_Free(m->tris); M_Free(m->glcmds); M_Free(m->frames); M_Free(m); return 0; }
|
||||
|
||||
if (m->numglcmds > 0)
|
||||
{
|
||||
fil.Seek(head.ofsglcmds,FileReader::SeekSet);
|
||||
if (fil.Read((char *)m->glcmds,m->numglcmds*sizeof(int32_t)) != (int32_t)(m->numglcmds*sizeof(int32_t)))
|
||||
{ Xfree(m->uv); Xfree(m->tris); Xfree(m->glcmds); Xfree(m->frames); Xfree(m); return 0; }
|
||||
{ M_Free(m->uv); M_Free(m->tris); M_Free(m->glcmds); M_Free(m->frames); M_Free(m); return 0; }
|
||||
}
|
||||
|
||||
fil.Seek(head.ofstris,FileReader::SeekSet);
|
||||
if (fil.Read((char *)m->tris,head.numtris*sizeof(md2tri_t)) != (int32_t)(head.numtris*sizeof(md2tri_t)))
|
||||
{ Xfree(m->uv); Xfree(m->tris); Xfree(m->glcmds); Xfree(m->frames); Xfree(m); return 0; }
|
||||
{ M_Free(m->uv); M_Free(m->tris); M_Free(m->glcmds); M_Free(m->frames); M_Free(m); return 0; }
|
||||
|
||||
fil.Seek(head.ofsuv,FileReader::SeekSet);
|
||||
if (fil.Read((char *)m->uv,head.numuv*sizeof(md2uv_t)) != (int32_t)(head.numuv*sizeof(md2uv_t)))
|
||||
{ Xfree(m->uv); Xfree(m->tris); Xfree(m->glcmds); Xfree(m->frames); Xfree(m); return 0; }
|
||||
{ M_Free(m->uv); M_Free(m->tris); M_Free(m->glcmds); M_Free(m->frames); M_Free(m); return 0; }
|
||||
|
||||
#if B_BIG_ENDIAN != 0
|
||||
{
|
||||
|
@ -730,27 +618,27 @@ static md2model_t *md2load(FileReader & fil, const char *filnam)
|
|||
{
|
||||
fr = (md2frame_t *)f;
|
||||
l = (int32_t *)&fr->mul;
|
||||
for (j=5; j>=0; j--) l[j] = B_LITTLE32(l[j]);
|
||||
for (j=5; j>=0; j--) l[j] = LittleLong(l[j]);
|
||||
f += m->framebytes;
|
||||
}
|
||||
|
||||
for (i = m->numglcmds-1; i>=0; i--)
|
||||
{
|
||||
m->glcmds[i] = B_LITTLE32(m->glcmds[i]);
|
||||
m->glcmds[i] = LittleLong(m->glcmds[i]);
|
||||
}
|
||||
for (i = head.numtris-1; i>=0; i--)
|
||||
{
|
||||
m->tris[i].v[0] = B_LITTLE16(m->tris[i].v[0]);
|
||||
m->tris[i].v[1] = B_LITTLE16(m->tris[i].v[1]);
|
||||
m->tris[i].v[2] = B_LITTLE16(m->tris[i].v[2]);
|
||||
m->tris[i].u[0] = B_LITTLE16(m->tris[i].u[0]);
|
||||
m->tris[i].u[1] = B_LITTLE16(m->tris[i].u[1]);
|
||||
m->tris[i].u[2] = B_LITTLE16(m->tris[i].u[2]);
|
||||
m->tris[i].v[0] = LittleShort(m->tris[i].v[0]);
|
||||
m->tris[i].v[1] = LittleShort(m->tris[i].v[1]);
|
||||
m->tris[i].v[2] = LittleShort(m->tris[i].v[2]);
|
||||
m->tris[i].u[0] = LittleShort(m->tris[i].u[0]);
|
||||
m->tris[i].u[1] = LittleShort(m->tris[i].u[1]);
|
||||
m->tris[i].u[2] = LittleShort(m->tris[i].u[2]);
|
||||
}
|
||||
for (i = head.numuv-1; i>=0; i--)
|
||||
{
|
||||
m->uv[i].u = B_LITTLE16(m->uv[i].u);
|
||||
m->uv[i].v = B_LITTLE16(m->uv[i].v);
|
||||
m->uv[i].u = LittleShort(m->uv[i].u);
|
||||
m->uv[i].v = LittleShort(m->uv[i].v);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -760,15 +648,15 @@ static md2model_t *md2load(FileReader & fil, const char *filnam)
|
|||
if ((st[i] == '/') || (st[i] == '\\')) { i++; break; }
|
||||
if (i<0) i=0;
|
||||
st[i] = 0;
|
||||
m->basepath = (char *)Xmalloc(i+1);
|
||||
m->basepath = (char *)M_Malloc(i+1);
|
||||
strcpy(m->basepath, st);
|
||||
|
||||
m->skinfn = (char *)Xmalloc(ournumskins*64);
|
||||
m->skinfn = (char *)M_Malloc(ournumskins*64);
|
||||
if (m->numskins > 0)
|
||||
{
|
||||
fil.Seek(head.ofsskins,FileReader::SeekSet);
|
||||
if (fil.Read(m->skinfn,64*m->numskins) != 64*m->numskins)
|
||||
{ Xfree(m->glcmds); Xfree(m->frames); Xfree(m); return 0; }
|
||||
{ M_Free(m->glcmds); M_Free(m->frames); M_Free(m); return 0; }
|
||||
}
|
||||
|
||||
maxmodelverts = max(maxmodelverts, m->numverts);
|
||||
|
@ -778,7 +666,7 @@ static md2model_t *md2load(FileReader & fil, const char *filnam)
|
|||
|
||||
// the MD2 is now loaded internally - let's begin the MD3 conversion process
|
||||
//Printf("Beginning md3 conversion.\n");
|
||||
m3 = (md3model_t *)Xcalloc(1, sizeof(md3model_t));
|
||||
m3 = (md3model_t *)M_Calloc(1, sizeof(md3model_t));
|
||||
m3->mdnum = 3; m3->texture = nullptr; m3->scale = m->scale;
|
||||
m3->head.id = IDP3_MAGIC; m3->head.vers = 15;
|
||||
|
||||
|
@ -791,8 +679,8 @@ static md2model_t *md2load(FileReader & fil, const char *filnam)
|
|||
m3->numskins = m3->head.numskins;
|
||||
m3->numframes = m3->head.numframes;
|
||||
|
||||
m3->head.frames = (md3frame_t *)Xcalloc(m3->head.numframes, sizeof(md3frame_t));
|
||||
m3->muladdframes = (vec3f_t *)Xcalloc(m->numframes * 2, sizeof(vec3f_t));
|
||||
m3->head.frames = (md3frame_t *)M_Calloc(m3->head.numframes, sizeof(md3frame_t));
|
||||
m3->muladdframes = (vec3f_t *)M_Calloc(m->numframes * 2, sizeof(vec3f_t));
|
||||
|
||||
f = (md2frame_t *)(m->frames);
|
||||
|
||||
|
@ -810,7 +698,7 @@ static md2model_t *md2load(FileReader & fil, const char *filnam)
|
|||
|
||||
m3->head.tags = NULL;
|
||||
|
||||
m3->head.surfs = (md3surf_t *)Xcalloc(1, sizeof(md3surf_t));
|
||||
m3->head.surfs = (md3surf_t *)M_Calloc(1, sizeof(md3surf_t));
|
||||
s = m3->head.surfs;
|
||||
|
||||
// model converting
|
||||
|
@ -827,9 +715,9 @@ static md2model_t *md2load(FileReader & fil, const char *filnam)
|
|||
|
||||
s->shaders = NULL;
|
||||
|
||||
s->tris = (md3tri_t *)Xcalloc(head.numtris, sizeof(md3tri_t));
|
||||
s->uv = (md3uv_t *)Xcalloc(s->numverts, sizeof(md3uv_t));
|
||||
s->xyzn = (md3xyzn_t *)Xcalloc(s->numverts * m->numframes, sizeof(md3xyzn_t));
|
||||
s->tris = (md3tri_t *)M_Calloc(head.numtris, sizeof(md3tri_t));
|
||||
s->uv = (md3uv_t *)M_Calloc(s->numverts, sizeof(md3uv_t));
|
||||
s->xyzn = (md3xyzn_t *)M_Calloc(s->numverts * m->numframes, sizeof(md3xyzn_t));
|
||||
|
||||
//memoryusage += (s->numverts * m->numframes * sizeof(md3xyzn_t));
|
||||
//Printf("Current model geometry memory usage : %i.\n", memoryusage);
|
||||
|
@ -874,7 +762,7 @@ static md2model_t *md2load(FileReader & fil, const char *filnam)
|
|||
{
|
||||
mdskinmap_t *sk;
|
||||
|
||||
sk = (mdskinmap_t *)Xcalloc(1,sizeof(mdskinmap_t));
|
||||
sk = (mdskinmap_t *)M_Calloc(1,sizeof(mdskinmap_t));
|
||||
sk->palette = 0;
|
||||
sk->skinnum = 0;
|
||||
sk->surfnum = 0;
|
||||
|
@ -891,12 +779,12 @@ static md2model_t *md2load(FileReader & fil, const char *filnam)
|
|||
m3->skinmap = sk;
|
||||
}
|
||||
|
||||
m3->indexes = (uint16_t *)Xmalloc(sizeof(uint16_t) * s->numtris);
|
||||
m3->vindexes = (uint16_t *)Xmalloc(sizeof(uint16_t) * s->numtris * 3);
|
||||
m3->maxdepths = (float *)Xmalloc(sizeof(float) * s->numtris);
|
||||
m3->indexes = (uint16_t *)M_Malloc(sizeof(uint16_t) * s->numtris);
|
||||
m3->vindexes = (uint16_t *)M_Malloc(sizeof(uint16_t) * s->numtris * 3);
|
||||
m3->maxdepths = (float *)M_Malloc(sizeof(float) * s->numtris);
|
||||
|
||||
// die MD2 ! DIE !
|
||||
Xfree(m->skinfn); Xfree(m->basepath); Xfree(m->uv); Xfree(m->tris); Xfree(m->glcmds); Xfree(m->frames); Xfree(m);
|
||||
M_Free(m->skinfn); M_Free(m->basepath); M_Free(m->uv); M_Free(m->tris); M_Free(m->glcmds); M_Free(m->frames); M_Free(m);
|
||||
|
||||
return ((md2model_t *)m3);
|
||||
}
|
||||
|
@ -948,7 +836,7 @@ static md3model_t *md3load(FileReader & fil)
|
|||
md3model_t *m;
|
||||
md3surf_t *s;
|
||||
|
||||
m = (md3model_t *)Xcalloc(1,sizeof(md3model_t));
|
||||
m = (md3model_t *)M_Calloc(1,sizeof(md3model_t));
|
||||
m->mdnum = 3; m->texture = nullptr; m->scale = .01f;
|
||||
|
||||
m->muladdframes = NULL;
|
||||
|
@ -956,15 +844,15 @@ static md3model_t *md3load(FileReader & fil)
|
|||
fil.Read(&m->head,SIZEOF_MD3HEAD_T);
|
||||
|
||||
#if B_BIG_ENDIAN != 0
|
||||
m->head.id = B_LITTLE32(m->head.id); m->head.vers = B_LITTLE32(m->head.vers);
|
||||
m->head.flags = B_LITTLE32(m->head.flags); m->head.numframes = B_LITTLE32(m->head.numframes);
|
||||
m->head.numtags = B_LITTLE32(m->head.numtags); m->head.numsurfs = B_LITTLE32(m->head.numsurfs);
|
||||
m->head.numskins = B_LITTLE32(m->head.numskins); m->head.ofsframes = B_LITTLE32(m->head.ofsframes);
|
||||
m->head.ofstags = B_LITTLE32(m->head.ofstags); m->head.ofssurfs = B_LITTLE32(m->head.ofssurfs);
|
||||
m->head.eof = B_LITTLE32(m->head.eof);
|
||||
m->head.id = LittleLong(m->head.id); m->head.vers = LittleLong(m->head.vers);
|
||||
m->head.flags = LittleLong(m->head.flags); m->head.numframes = LittleLong(m->head.numframes);
|
||||
m->head.numtags = LittleLong(m->head.numtags); m->head.numsurfs = LittleLong(m->head.numsurfs);
|
||||
m->head.numskins = LittleLong(m->head.numskins); m->head.ofsframes = LittleLong(m->head.ofsframes);
|
||||
m->head.ofstags = LittleLong(m->head.ofstags); m->head.ofssurfs = LittleLong(m->head.ofssurfs);
|
||||
m->head.eof = LittleLong(m->head.eof);
|
||||
#endif
|
||||
|
||||
if ((m->head.id != IDP3_MAGIC) && (m->head.vers != 15)) { Xfree(m); return 0; } //"IDP3"
|
||||
if ((m->head.id != IDP3_MAGIC) && (m->head.vers != 15)) { M_Free(m); return 0; } //"IDP3"
|
||||
|
||||
m->numskins = m->head.numskins; //<- dead code?
|
||||
m->numframes = m->head.numframes;
|
||||
|
@ -972,19 +860,19 @@ static md3model_t *md3load(FileReader & fil)
|
|||
ofsurf = m->head.ofssurfs;
|
||||
|
||||
fil.Seek(m->head.ofsframes,FileReader::SeekSet); i = m->head.numframes*sizeof(md3frame_t);
|
||||
m->head.frames = (md3frame_t *)Xmalloc(i);
|
||||
m->head.frames = (md3frame_t *)M_Malloc(i);
|
||||
fil.Read(m->head.frames,i);
|
||||
|
||||
if (m->head.numtags == 0) m->head.tags = NULL;
|
||||
else
|
||||
{
|
||||
fil.Seek(m->head.ofstags,FileReader::SeekSet); i = m->head.numtags*sizeof(md3tag_t);
|
||||
m->head.tags = (md3tag_t *)Xmalloc(i);
|
||||
m->head.tags = (md3tag_t *)M_Malloc(i);
|
||||
fil.Read(m->head.tags,i);
|
||||
}
|
||||
|
||||
fil.Seek(m->head.ofssurfs,FileReader::SeekSet);
|
||||
m->head.surfs = (md3surf_t *)Xcalloc(m->head.numsurfs, sizeof(md3surf_t));
|
||||
m->head.surfs = (md3surf_t *)M_Calloc(m->head.numsurfs, sizeof(md3surf_t));
|
||||
// NOTE: We assume that NULL is represented by all-zeros.
|
||||
// surfs[0].geometry is for POLYMER_MD_PROCESS_CHECK (else: crashes).
|
||||
// surfs[i].geometry is for FREE_SURFS_GEOMETRY.
|
||||
|
@ -997,13 +885,13 @@ static md3model_t *md3load(FileReader & fil)
|
|||
for (i = m->head.numframes-1; i>=0; i--)
|
||||
{
|
||||
l = (int32_t *)&m->head.frames[i].min;
|
||||
for (j=3+3+3+1-1; j>=0; j--) l[j] = B_LITTLE32(l[j]);
|
||||
for (j=3+3+3+1-1; j>=0; j--) l[j] = LittleLong(l[j]);
|
||||
}
|
||||
|
||||
for (i = m->head.numtags-1; i>=0; i--)
|
||||
{
|
||||
l = (int32_t *)&m->head.tags[i].p;
|
||||
for (j=3+3+3+3-1; j>=0; j--) l[j] = B_LITTLE32(l[j]);
|
||||
for (j=3+3+3+3-1; j>=0; j--) l[j] = LittleLong(l[j]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1018,9 +906,9 @@ static md3model_t *md3load(FileReader & fil)
|
|||
#if B_BIG_ENDIAN != 0
|
||||
{
|
||||
int32_t j, *l;
|
||||
s->id = B_LITTLE32(s->id);
|
||||
s->id = LittleLong(s->id);
|
||||
l = (int32_t *)&s->flags;
|
||||
for (j=1+1+1+1+1+1+1+1+1+1-1; j>=0; j--) l[j] = B_LITTLE32(l[j]);
|
||||
for (j=1+1+1+1+1+1+1+1+1+1-1; j>=0; j--) l[j] = LittleLong(l[j]);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1037,7 +925,7 @@ static md3model_t *md3load(FileReader & fil)
|
|||
//memoryusage += (s->numverts * s->numframes * sizeof(md3xyzn_t));
|
||||
//Printf("Current model geometry memory usage : %i.\n", memoryusage);
|
||||
|
||||
s->tris = (md3tri_t *)Xmalloc((leng[0] + leng[1]) + (leng[2] + leng[3]));
|
||||
s->tris = (md3tri_t *)M_Malloc((leng[0] + leng[1]) + (leng[2] + leng[3]));
|
||||
|
||||
s->shaders = (md3shader_t *)(((intptr_t)s->tris)+leng[0]);
|
||||
s->uv = (md3uv_t *)(((intptr_t)s->shaders)+leng[1]);
|
||||
|
@ -1054,23 +942,23 @@ static md3model_t *md3load(FileReader & fil)
|
|||
|
||||
for (i=s->numtris-1; i>=0; i--)
|
||||
{
|
||||
for (j=2; j>=0; j--) s->tris[i].i[j] = B_LITTLE32(s->tris[i].i[j]);
|
||||
for (j=2; j>=0; j--) s->tris[i].i[j] = LittleLong(s->tris[i].i[j]);
|
||||
}
|
||||
for (i=s->numshaders-1; i>=0; i--)
|
||||
{
|
||||
s->shaders[i].i = B_LITTLE32(s->shaders[i].i);
|
||||
s->shaders[i].i = LittleLong(s->shaders[i].i);
|
||||
}
|
||||
for (i=s->numverts-1; i>=0; i--)
|
||||
{
|
||||
l = (int32_t *)&s->uv[i].u;
|
||||
l[0] = B_LITTLE32(l[0]);
|
||||
l[1] = B_LITTLE32(l[1]);
|
||||
l[0] = LittleLong(l[0]);
|
||||
l[1] = LittleLong(l[1]);
|
||||
}
|
||||
for (i=s->numframes*s->numverts-1; i>=0; i--)
|
||||
{
|
||||
s->xyzn[i].x = (int16_t)B_LITTLE16((uint16_t)s->xyzn[i].x);
|
||||
s->xyzn[i].y = (int16_t)B_LITTLE16((uint16_t)s->xyzn[i].y);
|
||||
s->xyzn[i].z = (int16_t)B_LITTLE16((uint16_t)s->xyzn[i].z);
|
||||
s->xyzn[i].x = (int16_t)LittleShort((uint16_t)s->xyzn[i].x);
|
||||
s->xyzn[i].y = (int16_t)LittleShort((uint16_t)s->xyzn[i].y);
|
||||
s->xyzn[i].z = (int16_t)LittleShort((uint16_t)s->xyzn[i].z);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1080,9 +968,9 @@ static md3model_t *md3load(FileReader & fil)
|
|||
ofsurf += s->ofsend;
|
||||
}
|
||||
|
||||
m->indexes = (uint16_t *)Xmalloc(sizeof(uint16_t) * maxtrispersurf);
|
||||
m->vindexes = (uint16_t *)Xmalloc(sizeof(uint16_t) * maxtrispersurf * 3);
|
||||
m->maxdepths = (float *)Xmalloc(sizeof(float) * maxtrispersurf);
|
||||
m->indexes = (uint16_t *)M_Malloc(sizeof(uint16_t) * maxtrispersurf);
|
||||
m->vindexes = (uint16_t *)M_Malloc(sizeof(uint16_t) * maxtrispersurf * 3);
|
||||
m->maxdepths = (float *)M_Malloc(sizeof(float) * maxtrispersurf);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
@ -1219,7 +1107,7 @@ void md3_vox_calcmat_common(tspriteptr_t tspr, const vec3f_t *a0, float f, float
|
|||
}
|
||||
|
||||
static void md3draw_handle_triangles(const md3surf_t *s, uint16_t *indexhandle,
|
||||
int32_t texunits, const md3model_t *M)
|
||||
int32_t , const md3model_t *M)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
|
@ -1241,10 +1129,6 @@ static void md3draw_handle_triangles(const md3surf_t *s, uint16_t *indexhandle,
|
|||
}
|
||||
}
|
||||
GLInterface.Draw(DT_Triangles, data.second, s->numtris *3);
|
||||
|
||||
#ifndef USE_GLEXT
|
||||
UNREFERENCED_PARAMETER(texunits);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int32_t polymost_md3draw(md3model_t *m, tspriteptr_t tspr)
|
||||
|
@ -1261,9 +1145,6 @@ static int32_t polymost_md3draw(md3model_t *m, tspriteptr_t tspr)
|
|||
const uint8_t lpal = ((unsigned)owner < MAXSPRITES) ? sprite[tspr->owner].pal : tspr->pal;
|
||||
const int32_t sizyrep = tileHeight(tspr->picnum) * tspr->yrepeat;
|
||||
|
||||
polymost_outputGLDebugMessage(3, "polymost_md3draw(m:%p, tspr:%p)", m, tspr);
|
||||
// if ((tspr->cstat&48) == 32) return 0;
|
||||
|
||||
updateanimation((md2model_t *)m, tspr, lpal);
|
||||
|
||||
//create current&next frame's vertex list from whole list
|
||||
|
@ -1558,12 +1439,12 @@ static void md3free(md3model_t *m)
|
|||
for (anim=m->animations; anim; anim=nanim)
|
||||
{
|
||||
nanim = anim->next;
|
||||
Xfree(anim);
|
||||
M_Free(anim);
|
||||
}
|
||||
for (sk=m->skinmap; sk; sk=nsk)
|
||||
{
|
||||
nsk = sk->next;
|
||||
Xfree(sk);
|
||||
M_Free(sk);
|
||||
}
|
||||
|
||||
if (m->head.surfs)
|
||||
|
@ -1571,21 +1452,21 @@ static void md3free(md3model_t *m)
|
|||
for (bssize_t surfi=m->head.numsurfs-1; surfi>=0; surfi--)
|
||||
{
|
||||
md3surf_t *s = &m->head.surfs[surfi];
|
||||
Xfree(s->tris);
|
||||
Xfree(s->geometry); // FREE_SURFS_GEOMETRY
|
||||
M_Free(s->tris);
|
||||
M_Free(s->geometry); // FREE_SURFS_GEOMETRY
|
||||
}
|
||||
Xfree(m->head.surfs);
|
||||
M_Free(m->head.surfs);
|
||||
}
|
||||
Xfree(m->head.tags);
|
||||
Xfree(m->head.frames);
|
||||
M_Free(m->head.tags);
|
||||
M_Free(m->head.frames);
|
||||
|
||||
Xfree(m->muladdframes);
|
||||
M_Free(m->muladdframes);
|
||||
|
||||
Xfree(m->indexes);
|
||||
Xfree(m->vindexes);
|
||||
Xfree(m->maxdepths);
|
||||
M_Free(m->indexes);
|
||||
M_Free(m->vindexes);
|
||||
M_Free(m->maxdepths);
|
||||
|
||||
Xfree(m);
|
||||
M_Free(m);
|
||||
}
|
||||
|
||||
//---------------------------------------- MD3 LIBRARY ENDS ----------------------------------------
|
||||
|
@ -1607,7 +1488,7 @@ static mdmodel_t *mdload(const char *filnam)
|
|||
fil.Read(&i,4);
|
||||
fil.Seek(0,FileReader::SeekSet);
|
||||
|
||||
switch (B_LITTLE32(i))
|
||||
switch (LittleLong(i))
|
||||
{
|
||||
case IDP2_MAGIC:
|
||||
// Printf("Warning: model \"%s\" is version IDP2; wanted version IDP3\n",filnam);
|
||||
|
@ -1641,7 +1522,7 @@ int32_t polymost_mddraw(tspriteptr_t tspr)
|
|||
{
|
||||
if (maxmodelverts > allocmodelverts)
|
||||
{
|
||||
vertlist = (vec3f_t *) Xrealloc(vertlist, sizeof(vec3f_t)*maxmodelverts);
|
||||
vertlist = (vec3f_t *) M_Realloc(vertlist, sizeof(vec3f_t)*maxmodelverts);
|
||||
allocmodelverts = maxmodelverts;
|
||||
}
|
||||
|
||||
|
@ -1654,6 +1535,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; }
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,209 +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 "glbackend/gl_models.h"
|
||||
|
||||
#include "palette.h"
|
||||
#include "../../glbackend/glbackend.h"
|
||||
|
||||
void voxfree(voxmodel_t *m)
|
||||
{
|
||||
if (!m)
|
||||
return;
|
||||
|
||||
Xfree(m);
|
||||
}
|
||||
|
||||
voxmodel_t *voxload(int lumpnum)
|
||||
{
|
||||
FVoxel* voxel = R_LoadKVX(lumpnum);
|
||||
if (voxel != nullptr)
|
||||
{
|
||||
voxmodel_t* vm = (voxmodel_t*)Xmalloc(sizeof(voxmodel_t));
|
||||
memset(vm, 0, sizeof(voxmodel_t));
|
||||
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;
|
||||
|
||||
polymost_outputGLDebugMessage(3, "polymost_voxdraw(m:%p, tspr:%p)", m, tspr);
|
||||
|
||||
//updateanimation((md2model *)m,tspr);
|
||||
|
||||
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];
|
||||
|
||||
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);
|
||||
|
||||
pc[0] = (float)globalr * (1.f / 255.f);
|
||||
pc[1] = (float)globalg * (1.f / 255.f);
|
||||
pc[2] = (float)globalb * (1.f / 255.f);
|
||||
GLInterface.SetColor(pc[0], pc[1], pc[2], pc[3]);
|
||||
|
||||
//------------
|
||||
|
||||
//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);
|
||||
GLInterface.SetFadeDisable(false);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------- VOX LIBRARY ENDS ----------------------------------------
|
|
@ -739,12 +739,12 @@ void F2DDrawer::AddPoly(FGameTexture *texture, FVector2 *points, int npoints,
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void F2DDrawer::AddPoly(FGameTexture* img, FVector4* vt, size_t vtcount, unsigned int* ind, size_t idxcount, int translation, PalEntry color, FRenderStyle style, int clipx1, int clipy1, int clipx2, int clipy2)
|
||||
void F2DDrawer::AddPoly(FGameTexture* img, FVector4* vt, size_t vtcount, const unsigned int* ind, size_t idxcount, int translation, PalEntry color, FRenderStyle style, int clipx1, int clipy1, int clipx2, int clipy2)
|
||||
{
|
||||
RenderCommand dg;
|
||||
int method = 0;
|
||||
|
||||
if (!img->isValid()) return;
|
||||
if (!img || !img->isValid()) return;
|
||||
|
||||
dg.mType = DrawTypeTriangles;
|
||||
if (clipx1 > 0 || clipy1 > 0 || clipx2 < GetWidth() - 1 || clipy2 < GetHeight() - 1)
|
||||
|
@ -770,14 +770,28 @@ void F2DDrawer::AddPoly(FGameTexture* img, FVector4* vt, size_t vtcount, unsigne
|
|||
Set(ptr, vt[i].X, vt[i].Y, 0.f, vt[i].Z, vt[i].W, color);
|
||||
ptr++;
|
||||
}
|
||||
|
||||
dg.mIndexIndex = mIndices.Size();
|
||||
mIndices.Reserve(idxcount);
|
||||
for (size_t i = 0; i < idxcount; i++)
|
||||
|
||||
if (idxcount > 0)
|
||||
{
|
||||
mIndices[dg.mIndexIndex + i] = ind[i] + dg.mVertIndex;
|
||||
mIndices.Reserve(idxcount);
|
||||
for (size_t i = 0; i < idxcount; i++)
|
||||
{
|
||||
mIndices[dg.mIndexIndex + i] = ind[i] + dg.mVertIndex;
|
||||
}
|
||||
dg.mIndexCount = (int)idxcount;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we have no index buffer, treat this as an unindexed list of triangles.
|
||||
mIndices.Reserve(vtcount);
|
||||
for (size_t i = 0; i < vtcount; i++)
|
||||
{
|
||||
mIndices[dg.mIndexIndex + i] = int(i + dg.mVertIndex);
|
||||
}
|
||||
dg.mIndexCount = (int)vtcount;
|
||||
|
||||
}
|
||||
dg.mIndexCount = (int)idxcount;
|
||||
AddCommand(&dg);
|
||||
}
|
||||
|
||||
|
|
|
@ -189,7 +189,7 @@ public:
|
|||
void AddPoly(FGameTexture *texture, FVector2 *points, int npoints,
|
||||
double originx, double originy, double scalex, double scaley,
|
||||
DAngle rotation, const FColormap &colormap, PalEntry flatcolor, double lightlevel, uint32_t *indices, size_t indexcount);
|
||||
void AddPoly(FGameTexture* img, FVector4 *vt, size_t vtcount, unsigned int *ind, size_t idxcount, int translation, PalEntry color, FRenderStyle style, int clipx1, int clipy1, int clipx2, int clipy2);
|
||||
void AddPoly(FGameTexture* img, FVector4 *vt, size_t vtcount, const unsigned int *ind, size_t idxcount, int translation, PalEntry color, FRenderStyle style, int clipx1, int clipy1, int clipx2, int clipy2);
|
||||
void FillPolygon(int* rx1, int* ry1, int* xb1, int32_t npoints, int picnum, int palette, int shade, int props, const FVector2& xtex, const FVector2& ytex, const FVector2& otex,
|
||||
int clipx1, int clipy1, int clipx2, int clipy2);
|
||||
void AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, int local_origin = false, double flatscale = 1.0, PalEntry color = 0xffffffff, ERenderStyle rs = STYLE_Normal);
|
||||
|
|
|
@ -50,7 +50,7 @@ CVAR(Bool, ui_screenborder_classic_scaling, true, CVAR_ARCHIVE)
|
|||
// nonsense that graphics should not be able to actually use that extra screen space.
|
||||
|
||||
extern bool setsizeneeded;
|
||||
CUSTOM_CVAR(Bool, vid_allowtrueultrawide, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_NOINITCALL)
|
||||
CUSTOM_CVAR(Int, vid_allowtrueultrawide, 1, CVAR_ARCHIVE|CVAR_NOINITCALL)
|
||||
{
|
||||
setsizeneeded = true;
|
||||
}
|
||||
|
@ -324,6 +324,22 @@ DEFINE_ACTION_FUNCTION(_Screen, ClearClipRect)
|
|||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_Screen, ClearScreen)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
twod->ClearScreen();
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_Screen, SetScreenFade)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_FLOAT(x);
|
||||
twod->SetScreenFade(float(x));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void F2DDrawer::GetClipRect(int *x, int *y, int *w, int *h)
|
||||
{
|
||||
if (x) *x = clipleft;
|
||||
|
@ -1263,11 +1279,20 @@ static void VirtualToRealCoords(F2DDrawer *drawer, double Width, double Height,
|
|||
{
|
||||
float myratio = float(handleaspect ? ActiveRatio (Width, Height) : (4.0 / 3.0));
|
||||
|
||||
// if 21:9 AR, map to 16:9 for all callers.
|
||||
// this allows for black bars and stops the stretching of fullscreen images
|
||||
if ((myratio > 1.7f) && !vid_allowtrueultrawide) {
|
||||
myratio = 16.0f / 9.0f;
|
||||
}
|
||||
// if 21:9 AR, map to 16:9 for all callers.
|
||||
// this allows for black bars and stops the stretching of fullscreen images
|
||||
|
||||
switch (vid_allowtrueultrawide)
|
||||
{
|
||||
case 1:
|
||||
default:
|
||||
myratio = MIN(64.0f / 27.0f, myratio);
|
||||
break;
|
||||
case 0:
|
||||
myratio = MIN(16.0f / 9.0f, myratio);
|
||||
case -1:
|
||||
break;
|
||||
}
|
||||
|
||||
double right = x + w;
|
||||
double bottom = y + h;
|
||||
|
|
|
@ -138,6 +138,10 @@ void S_StopCustomStream(SoundStream *stream)
|
|||
|
||||
void S_PauseAllCustomStreams(bool on)
|
||||
{
|
||||
static bool paused = false;
|
||||
|
||||
if (paused == on) return;
|
||||
paused = on;
|
||||
for (auto s : customStreams)
|
||||
{
|
||||
s->SetPaused(on);
|
||||
|
|
|
@ -293,8 +293,8 @@ CCMD (md5sum)
|
|||
}
|
||||
for (int i = 1; i < argv.argc(); ++i)
|
||||
{
|
||||
FileReader fr;
|
||||
if (!fr.OpenFile(argv[i]))
|
||||
FileReader fr = fileSystem.OpenFileReader(argv[i]);
|
||||
if (!fr.isOpen())
|
||||
{
|
||||
Printf("%s: %s\n", argv[i], strerror(errno));
|
||||
}
|
||||
|
|
|
@ -1107,4 +1107,4 @@ xy(menu_change, "menu/change")
|
|||
xy(menu_advance, "menu/advance")
|
||||
|
||||
xx(zoomsize)
|
||||
|
||||
xx(ScreenJobRunner)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -120,7 +122,30 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GetNumber(int64_t& var, bool evaluate = false)
|
||||
{
|
||||
if (!GetNumber(evaluate)) return false;
|
||||
var = BigNumber;
|
||||
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);
|
||||
|
||||
|
|
|
@ -61,12 +61,9 @@
|
|||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
// Requires SDL 2.0.6 or newer
|
||||
//#define SDL2_STATIC_LIBRARY
|
||||
|
||||
#if defined SDL2_STATIC_LIBRARY && defined HAVE_VULKAN
|
||||
#if defined HAVE_VULKAN
|
||||
#include <SDL_vulkan.h>
|
||||
#endif // SDL2_STATIC_LIBRARY && HAVE_VULKAN
|
||||
#endif // HAVE_VULKAN
|
||||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
||||
|
@ -118,30 +115,7 @@ CCMD(vid_list_sdl_render_drivers)
|
|||
|
||||
namespace Priv
|
||||
{
|
||||
#ifdef SDL2_STATIC_LIBRARY
|
||||
|
||||
#define SDL2_OPTIONAL_FUNCTION(RESULT, NAME, ...) \
|
||||
RESULT(*NAME)(__VA_ARGS__) = SDL_ ## NAME
|
||||
|
||||
#else // !SDL2_STATIC_LIBRARY
|
||||
|
||||
FModule library("SDL2");
|
||||
|
||||
#define SDL2_OPTIONAL_FUNCTION(RESULT, NAME, ...) \
|
||||
static TOptProc<library, RESULT(*)(__VA_ARGS__)> NAME("SDL_" #NAME)
|
||||
|
||||
#endif // SDL2_STATIC_LIBRARY
|
||||
|
||||
SDL2_OPTIONAL_FUNCTION(int, GetWindowBordersSize, SDL_Window *window, int *top, int *left, int *bottom, int *right);
|
||||
#ifdef HAVE_VULKAN
|
||||
SDL2_OPTIONAL_FUNCTION(void, Vulkan_GetDrawableSize, SDL_Window *window, int *width, int *height);
|
||||
SDL2_OPTIONAL_FUNCTION(SDL_bool, Vulkan_GetInstanceExtensions, SDL_Window *window, unsigned int *count, const char **names);
|
||||
SDL2_OPTIONAL_FUNCTION(SDL_bool, Vulkan_CreateSurface, SDL_Window *window, VkInstance instance, VkSurfaceKHR *surface);
|
||||
#endif
|
||||
|
||||
#undef SDL2_OPTIONAL_FUNCTION
|
||||
|
||||
static const uint32_t VulkanWindowFlag = 0x1000'0000;
|
||||
static const uint32_t VulkanWindowFlag = SDL_WINDOW_VULKAN;
|
||||
|
||||
SDL_Window *window;
|
||||
bool vulkanEnabled;
|
||||
|
@ -240,22 +214,21 @@ void I_GetVulkanDrawableSize(int *width, int *height)
|
|||
{
|
||||
assert(Priv::vulkanEnabled);
|
||||
assert(Priv::window != nullptr);
|
||||
assert(Priv::Vulkan_GetDrawableSize);
|
||||
Priv::Vulkan_GetDrawableSize(Priv::window, width, height);
|
||||
SDL_Vulkan_GetDrawableSize(Priv::window, width, height);
|
||||
}
|
||||
|
||||
bool I_GetVulkanPlatformExtensions(unsigned int *count, const char **names)
|
||||
{
|
||||
assert(Priv::vulkanEnabled);
|
||||
assert(Priv::window != nullptr);
|
||||
return Priv::Vulkan_GetInstanceExtensions(Priv::window, count, names) == SDL_TRUE;
|
||||
return SDL_Vulkan_GetInstanceExtensions(Priv::window, count, names) == SDL_TRUE;
|
||||
}
|
||||
|
||||
bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface)
|
||||
{
|
||||
assert(Priv::vulkanEnabled);
|
||||
assert(Priv::window != nullptr);
|
||||
return Priv::Vulkan_CreateSurface(Priv::window, instance, surface) == SDL_TRUE;
|
||||
return SDL_Vulkan_CreateSurface(Priv::window, instance, surface) == SDL_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -419,20 +392,19 @@ SDLVideo::SDLVideo ()
|
|||
return;
|
||||
}
|
||||
|
||||
#ifndef SDL2_STATIC_LIBRARY
|
||||
// Load optional SDL functions
|
||||
if (!Priv::library.IsLoaded())
|
||||
// Fail gracefully if we somehow reach here after linking against a SDL2 library older than 2.0.6.
|
||||
SDL_version sdlver;
|
||||
SDL_GetVersion(&sdlver);
|
||||
if (!(sdlver.patch >= 6))
|
||||
{
|
||||
Priv::library.Load({ "libSDL2-2.0.so.0", "libSDL2-2.0.so", "libSDL2.so" });
|
||||
I_FatalError("Only SDL 2.0.6 or later is supported.");
|
||||
}
|
||||
#endif // !SDL2_STATIC_LIBRARY
|
||||
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
Priv::softpolyEnabled = vid_preferbackend == 2;
|
||||
#endif
|
||||
#ifdef HAVE_VULKAN
|
||||
Priv::vulkanEnabled = vid_preferbackend == 1
|
||||
&& Priv::Vulkan_GetDrawableSize && Priv::Vulkan_GetInstanceExtensions && Priv::Vulkan_CreateSurface;
|
||||
Priv::vulkanEnabled = vid_preferbackend == 1;
|
||||
|
||||
if (Priv::vulkanEnabled)
|
||||
{
|
||||
|
@ -539,7 +511,7 @@ int SystemBaseFrameBuffer::GetClientWidth()
|
|||
|
||||
#ifdef HAVE_VULKAN
|
||||
assert(Priv::vulkanEnabled);
|
||||
Priv::Vulkan_GetDrawableSize(Priv::window, &width, nullptr);
|
||||
SDL_Vulkan_GetDrawableSize(Priv::window, &width, nullptr);
|
||||
#endif
|
||||
|
||||
return width;
|
||||
|
@ -562,7 +534,7 @@ int SystemBaseFrameBuffer::GetClientHeight()
|
|||
|
||||
#ifdef HAVE_VULKAN
|
||||
assert(Priv::vulkanEnabled);
|
||||
Priv::Vulkan_GetDrawableSize(Priv::window, nullptr, &height);
|
||||
SDL_Vulkan_GetDrawableSize(Priv::window, nullptr, &height);
|
||||
#endif
|
||||
|
||||
return height;
|
||||
|
@ -745,10 +717,10 @@ void ProcessSDLWindowEvent(const SDL_WindowEvent &event)
|
|||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_MOVED:
|
||||
if (!vid_fullscreen && Priv::GetWindowBordersSize)
|
||||
if (!vid_fullscreen)
|
||||
{
|
||||
int top = 0, left = 0;
|
||||
Priv::GetWindowBordersSize(Priv::window, &top, &left, nullptr, nullptr);
|
||||
SDL_GetWindowBordersSize(Priv::window, &top, &left, nullptr, nullptr);
|
||||
win_x = event.data1-left;
|
||||
win_y = event.data2-top;
|
||||
}
|
||||
|
|
|
@ -371,7 +371,6 @@ SystemBaseFrameBuffer::~SystemBaseFrameBuffer()
|
|||
SetWindowLong(Window, GWL_STYLE, WS_VISIBLE | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW);
|
||||
SetWindowLong(Window, GWL_EXSTYLE, WS_EX_WINDOWEDGE);
|
||||
SetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
I_GetEvent();
|
||||
|
||||
static_cast<Win32BaseVideo *>(Video)->Shutdown();
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
class FRenderState;
|
||||
struct secplane_t;
|
||||
struct subsector_t;
|
||||
|
||||
struct FFlatVertex
|
||||
{
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
#include "tarray.h"
|
||||
#include "vectors.h"
|
||||
|
||||
struct FLevelLocals;
|
||||
|
||||
namespace hwrenderer
|
||||
{
|
||||
|
||||
|
|
|
@ -62,13 +62,7 @@
|
|||
#include "hw_renderstate.h"
|
||||
#include "v_video.h"
|
||||
#include "hwrenderer/data/buffers.h"
|
||||
|
||||
// 57 world units roughly represent one sky texel for the glTranslate call.
|
||||
enum
|
||||
{
|
||||
skyoffsetfactor = 57
|
||||
};
|
||||
|
||||
#include "version.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
@ -150,7 +144,7 @@ FSkyVertexBuffer::~FSkyVertexBuffer()
|
|||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FSkyVertexBuffer::SkyVertex(int r, int c, bool zflip)
|
||||
void FSkyVertexBuffer::SkyVertexDoom(int r, int c, bool zflip)
|
||||
{
|
||||
static const FAngle maxSideAngle = 60.f;
|
||||
static const float scale = 10000.;
|
||||
|
@ -187,6 +181,37 @@ void FSkyVertexBuffer::SkyVertex(int r, int c, bool zflip)
|
|||
mVertices.Push(vert);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FSkyVertexBuffer::SkyVertexBuild(int r, int c, bool zflip)
|
||||
{
|
||||
static const FAngle maxSideAngle = 60.f;
|
||||
static const float scale = 10000.;
|
||||
|
||||
FAngle topAngle = (c / (float)mColumns * 360.f);
|
||||
FVector2 pos = topAngle.ToVector(scale);
|
||||
float z = (!zflip) ? (mRows - r) * 4000.f : -(mRows - r) * 4000.f;
|
||||
|
||||
FSkyVertex vert;
|
||||
|
||||
vert.color = r == 0 ? 0xffffff : 0xffffffff;
|
||||
|
||||
// And the texture coordinates.
|
||||
if (zflip) r = mRows * 2 - r;
|
||||
vert.u = 0.5f + (-c / (float)mColumns);
|
||||
vert.v = (r / (float)(2*mRows));
|
||||
|
||||
// And finally the vertex.
|
||||
vert.x = pos.X;
|
||||
vert.y = z - 1.f;
|
||||
vert.z = pos.Y;
|
||||
|
||||
mVertices.Push(vert);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
@ -194,27 +219,58 @@ void FSkyVertexBuffer::SkyVertex(int r, int c, bool zflip)
|
|||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FSkyVertexBuffer::CreateSkyHemisphere(int hemi)
|
||||
void FSkyVertexBuffer::CreateSkyHemisphereDoom(int hemi)
|
||||
{
|
||||
int r, c;
|
||||
bool zflip = !!(hemi & SKYHEMI_LOWER);
|
||||
|
||||
mPrimStart.Push(mVertices.Size());
|
||||
mPrimStartDoom.Push(mVertices.Size());
|
||||
|
||||
for (c = 0; c < mColumns; c++)
|
||||
{
|
||||
SkyVertex(1, c, zflip);
|
||||
SkyVertexDoom(1, c, zflip);
|
||||
}
|
||||
|
||||
// The total number of triangles per hemisphere can be calculated
|
||||
// as follows: rows * columns * 2 + 2 (for the top cap).
|
||||
for (r = 0; r < mRows; r++)
|
||||
{
|
||||
mPrimStart.Push(mVertices.Size());
|
||||
mPrimStartDoom.Push(mVertices.Size());
|
||||
for (c = 0; c <= mColumns; c++)
|
||||
{
|
||||
SkyVertex(r + zflip, c, zflip);
|
||||
SkyVertex(r + 1 - zflip, c, zflip);
|
||||
SkyVertexDoom(r + zflip, c, zflip);
|
||||
SkyVertexDoom(r + 1 - zflip, c, zflip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FSkyVertexBuffer::CreateSkyHemisphereBuild(int hemi)
|
||||
{
|
||||
int r, c;
|
||||
bool zflip = !!(hemi & SKYHEMI_LOWER);
|
||||
|
||||
mPrimStartBuild.Push(mVertices.Size());
|
||||
|
||||
for (c = 0; c < mColumns; c++)
|
||||
{
|
||||
SkyVertexBuild(1, c, zflip);
|
||||
}
|
||||
|
||||
// The total number of triangles per hemisphere can be calculated
|
||||
// as follows: rows * columns * 2 + 2 (for the top cap).
|
||||
for (r = 0; r < mRows; r++)
|
||||
{
|
||||
mPrimStartBuild.Push(mVertices.Size());
|
||||
for (c = 0; c <= mColumns; c++)
|
||||
{
|
||||
SkyVertexBuild(r + zflip, c, zflip);
|
||||
SkyVertexBuild(r + 1 - zflip, c, zflip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -248,9 +304,13 @@ void FSkyVertexBuffer::CreateDome()
|
|||
|
||||
mColumns = 128;
|
||||
mRows = 4;
|
||||
CreateSkyHemisphere(SKYHEMI_UPPER);
|
||||
CreateSkyHemisphere(SKYHEMI_LOWER);
|
||||
mPrimStart.Push(mVertices.Size());
|
||||
CreateSkyHemisphereDoom(SKYHEMI_UPPER);
|
||||
CreateSkyHemisphereDoom(SKYHEMI_LOWER);
|
||||
mPrimStartDoom.Push(mVertices.Size());
|
||||
|
||||
CreateSkyHemisphereBuild(SKYHEMI_UPPER);
|
||||
CreateSkyHemisphereBuild(SKYHEMI_LOWER);
|
||||
mPrimStartBuild.Push(mVertices.Size());
|
||||
|
||||
mSideStart = mVertices.Size();
|
||||
mFaceStart[0] = mSideStart + 10;
|
||||
|
@ -324,7 +384,7 @@ void FSkyVertexBuffer::CreateDome()
|
|||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelMatrix, VSMatrix &textureMatrix, bool tiled)
|
||||
void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelMatrix, VSMatrix &textureMatrix, bool tiled, float xscale, float yscale)
|
||||
{
|
||||
float texw = tex->GetDisplayWidth();
|
||||
float texh = tex->GetDisplayHeight();
|
||||
|
@ -332,37 +392,46 @@ void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_
|
|||
modelMatrix.loadIdentity();
|
||||
modelMatrix.rotate(-180.0f + x_offset, 0.f, 1.f, 0.f);
|
||||
|
||||
float xscale = texw < 1024.f ? floorf(1024.f / float(texw)) : 1.f;
|
||||
float yscale = 1.f;
|
||||
if (xscale == 0) xscale = texw < 1024.f ? floorf(1024.f / float(texw)) : 1.f;
|
||||
auto texskyoffset = tex->GetSkyOffset() + skyoffset;
|
||||
if (texh <= 128 && tiled)
|
||||
if (yscale == 0)
|
||||
{
|
||||
modelMatrix.translate(0.f, (-40 + texskyoffset)*skyoffsetfactor, 0.f);
|
||||
modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f);
|
||||
yscale = 240.f / texh;
|
||||
}
|
||||
else if (texh < 128)
|
||||
{
|
||||
// smaller sky textures must be tiled. We restrict it to 128 sky pixels, though
|
||||
modelMatrix.translate(0.f, -1250.f, 0.f);
|
||||
modelMatrix.scale(1.f, 128 / 230.f, 1.f);
|
||||
yscale = float(128 / texh); // intentionally left as integer.
|
||||
}
|
||||
else if (texh < 200)
|
||||
{
|
||||
modelMatrix.translate(0.f, -1250.f, 0.f);
|
||||
modelMatrix.scale(1.f, texh / 230.f, 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);
|
||||
if (texh <= 128 && tiled)
|
||||
{
|
||||
modelMatrix.translate(0.f, (-40 + texskyoffset) * skyoffsetfactor, 0.f);
|
||||
modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f);
|
||||
yscale = 240.f / texh;
|
||||
}
|
||||
else if (texh < 128)
|
||||
{
|
||||
// smaller sky textures must be tiled. We restrict it to 128 sky pixels, though
|
||||
modelMatrix.translate(0.f, -1250.f, 0.f);
|
||||
modelMatrix.scale(1.f, 128 / 230.f, 1.f);
|
||||
yscale = float(128 / texh); // intentionally left as integer.
|
||||
}
|
||||
else if (texh < 200)
|
||||
{
|
||||
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
|
||||
{
|
||||
modelMatrix.translate(0.f, (-40 + texskyoffset) * skyoffsetfactor, 0.f);
|
||||
modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f);
|
||||
yscale = 240.f / texh;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
modelMatrix.translate(0.f, (-40 + texskyoffset)*skyoffsetfactor, 0.f);
|
||||
modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f);
|
||||
yscale = 240.f / texh;
|
||||
modelMatrix.translate(0.f, (-40 + texskyoffset) * skyoffsetfactor, 0.f);
|
||||
modelMatrix.scale(1.f, 0.8f * 1.17f, 1.f);
|
||||
}
|
||||
textureMatrix.loadIdentity();
|
||||
textureMatrix.scale(mirror ? -xscale : xscale, yscale, 1.f);
|
||||
|
@ -375,7 +444,7 @@ void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_
|
|||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FSkyVertexBuffer::RenderRow(FRenderState& state, EDrawType prim, int row, bool apply)
|
||||
void FSkyVertexBuffer::RenderRow(FRenderState& state, EDrawType prim, int row, TArray<unsigned int>& mPrimStart, bool apply)
|
||||
{
|
||||
state.Draw(prim, mPrimStart[row], mPrimStart[row + 1] - mPrimStart[row]);
|
||||
}
|
||||
|
@ -386,36 +455,35 @@ void FSkyVertexBuffer::RenderRow(FRenderState& state, EDrawType prim, int row, b
|
|||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FSkyVertexBuffer::RenderDome(FRenderState& state, FGameTexture* tex, float x_offset, float y_offset, bool mirror, int mode, bool tiled)
|
||||
void FSkyVertexBuffer::RenderDome(FRenderState& state, FGameTexture* tex, int mode, bool which)
|
||||
{
|
||||
if (tex)
|
||||
auto& primStart = which ? mPrimStartBuild : mPrimStartDoom;
|
||||
if (tex && tex->isValid())
|
||||
{
|
||||
state.SetMaterial(tex, UF_Texture, 0, CLAMP_NONE, 0, -1);
|
||||
state.EnableModelMatrix(true);
|
||||
state.EnableTextureMatrix(true);
|
||||
|
||||
SetupMatrices(tex, x_offset, y_offset, mirror, mode, state.mModelMatrix, state.mTextureMatrix, tiled);
|
||||
}
|
||||
|
||||
int rc = mRows + 1;
|
||||
|
||||
// The caps only get drawn for the main layer but not for the overlay.
|
||||
if (mode == FSkyVertexBuffer::SKYMODE_MAINLAYER && tex != NULL)
|
||||
if (mode == FSkyVertexBuffer::SKYMODE_MAINLAYER && tex != nullptr)
|
||||
{
|
||||
auto& col = R_GetSkyCapColor(tex);
|
||||
state.SetObjectColor(col.first);
|
||||
state.EnableTexture(false);
|
||||
RenderRow(state, DT_TriangleFan, 0);
|
||||
RenderRow(state, DT_TriangleFan, 0, primStart);
|
||||
|
||||
state.SetObjectColor(col.second);
|
||||
RenderRow(state, DT_TriangleFan, rc);
|
||||
RenderRow(state, DT_TriangleFan, rc, primStart);
|
||||
state.EnableTexture(true);
|
||||
}
|
||||
state.SetObjectColor(0xffffffff);
|
||||
for (int i = 1; i <= mRows; i++)
|
||||
{
|
||||
RenderRow(state, DT_TriangleStrip, i, i == 1);
|
||||
RenderRow(state, DT_TriangleStrip, rc + i, false);
|
||||
RenderRow(state, DT_TriangleStrip, i, primStart, i == 1);
|
||||
RenderRow(state, DT_TriangleStrip, rc + i, primStart, false);
|
||||
}
|
||||
|
||||
state.EnableTextureMatrix(false);
|
||||
|
@ -423,13 +491,29 @@ void FSkyVertexBuffer::RenderDome(FRenderState& state, FGameTexture* tex, float
|
|||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// This is only for Doom-style skies.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FSkyVertexBuffer::RenderDome(FRenderState& state, FGameTexture* tex, float x_offset, float y_offset, bool mirror, int mode, bool tiled, float xscale, float yscale)
|
||||
{
|
||||
if (tex)
|
||||
{
|
||||
SetupMatrices(tex, x_offset, y_offset, mirror, mode, state.mModelMatrix, state.mTextureMatrix, tiled, xscale, yscale);
|
||||
}
|
||||
RenderDome(state, tex, mode, false);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FSkyVertexBuffer::RenderBox(FRenderState& state, FTextureID texno, FSkyBox* tex, float x_offset, bool sky2, float stretch, const FVector3& skyrotatevector, const FVector3& skyrotatevector2)
|
||||
void FSkyVertexBuffer::RenderBox(FRenderState& state, FSkyBox* tex, float x_offset, bool sky2, float stretch, const FVector3& skyrotatevector, const FVector3& skyrotatevector2)
|
||||
{
|
||||
int faces;
|
||||
|
||||
|
|
|
@ -11,6 +11,12 @@ class IVertexBuffer;
|
|||
struct HWSkyPortal;
|
||||
struct HWDrawInfo;
|
||||
|
||||
// 57 world units roughly represent one sky texel for the glTranslate call.
|
||||
enum
|
||||
{
|
||||
skyoffsetfactor = 57
|
||||
};
|
||||
|
||||
struct FSkyVertex
|
||||
{
|
||||
float x, y, z, u, v;
|
||||
|
@ -55,7 +61,8 @@ public:
|
|||
IVertexBuffer *mVertexBuffer;
|
||||
|
||||
TArray<FSkyVertex> mVertices;
|
||||
TArray<unsigned int> mPrimStart;
|
||||
TArray<unsigned int> mPrimStartDoom;
|
||||
TArray<unsigned int> mPrimStartBuild;
|
||||
|
||||
int mRows, mColumns;
|
||||
|
||||
|
@ -63,15 +70,17 @@ public:
|
|||
int mFaceStart[7];
|
||||
int mSideStart;
|
||||
|
||||
void SkyVertex(int r, int c, bool yflip);
|
||||
void CreateSkyHemisphere(int hemi);
|
||||
void SkyVertexDoom(int r, int c, bool yflip);
|
||||
void SkyVertexBuild(int r, int c, bool yflip);
|
||||
void CreateSkyHemisphereDoom(int hemi);
|
||||
void CreateSkyHemisphereBuild(int hemi);
|
||||
void CreateDome();
|
||||
|
||||
public:
|
||||
|
||||
FSkyVertexBuffer();
|
||||
~FSkyVertexBuffer();
|
||||
void SetupMatrices(FGameTexture *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelmatrix, VSMatrix &textureMatrix, bool tiled);
|
||||
void SetupMatrices(FGameTexture *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelmatrix, VSMatrix &textureMatrix, bool tiled, float xscale = 0, float vertscale = 0);
|
||||
std::pair<IVertexBuffer *, IIndexBuffer *> GetBufferObjects() const
|
||||
{
|
||||
return std::make_pair(mVertexBuffer, nullptr);
|
||||
|
@ -83,8 +92,9 @@ public:
|
|||
else return mSideStart;
|
||||
}
|
||||
|
||||
void RenderRow(FRenderState& state, EDrawType prim, int row, bool apply = true);
|
||||
void RenderDome(FRenderState& state, FGameTexture* tex, float x_offset, float y_offset, bool mirror, int mode, bool tiled);
|
||||
void RenderBox(FRenderState& state, FTextureID texno, FSkyBox* tex, float x_offset, bool sky2, float stretch, const FVector3& skyrotatevector, const FVector3& skyrotatevector2);
|
||||
void RenderRow(FRenderState& state, EDrawType prim, int row, TArray<unsigned int>& mPrimStart, bool apply = true);
|
||||
void RenderDome(FRenderState& state, FGameTexture* tex, int mode, bool which);
|
||||
void RenderDome(FRenderState& state, FGameTexture* tex, float x_offset, float y_offset, bool mirror, int mode, bool tiled, float xscale = 0, float yscale = 0);
|
||||
void RenderBox(FRenderState& state, FSkyBox* tex, float x_offset, bool sky2, float stretch, const FVector3& skyrotatevector, const FVector3& skyrotatevector2);
|
||||
|
||||
};
|
||||
|
|
|
@ -60,7 +60,6 @@ static VRMode vrmi_checker = { 2, isqrt2, isqrt2, 1.f,{ { -.5f, 1.f },{ .5f, 1.f
|
|||
|
||||
const VRMode *VRMode::GetVRMode(bool toscreen)
|
||||
{
|
||||
#ifdef VR3D_ENABLED
|
||||
int mode = !toscreen || (sysCallbacks.DisableTextureFilter && sysCallbacks.DisableTextureFilter()) ? 0 : vr_mode;
|
||||
|
||||
switch (mode)
|
||||
|
@ -96,9 +95,6 @@ const VRMode *VRMode::GetVRMode(bool toscreen)
|
|||
case VR_CHECKERINTERLEAVED:
|
||||
return &vrmi_checker;
|
||||
}
|
||||
#else
|
||||
return &vrmi_mono;
|
||||
#endif
|
||||
}
|
||||
|
||||
void VRMode::AdjustViewport(DFrameBuffer *screen) const
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "hw_shadowmap.h"
|
||||
|
||||
|
||||
struct sector_t;
|
||||
struct FPortalSceneState;
|
||||
class FSkyVertexBuffer;
|
||||
class IIndexBuffer;
|
||||
|
|
|
@ -8706,7 +8706,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
|||
bool writable;
|
||||
ArgList[i] = ArgList[i]->Resolve(ctx); // must be resolved before the address is requested.
|
||||
|
||||
if (ArgList[i]->ValueType->isRealPointer())
|
||||
if (ArgList[i] && ArgList[i]->ValueType->isRealPointer())
|
||||
{
|
||||
auto pointedType = ArgList[i]->ValueType->toPointer()->PointedType;
|
||||
if (pointedType && pointedType->isDynArray())
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "dobject.h"
|
||||
#include "vm.h"
|
||||
#include "types.h"
|
||||
#include "v_draw.h"
|
||||
|
||||
// We need one specific type for each of the 8 integral VM types and instantiate the needed functions for each of them.
|
||||
// Dynamic arrays cannot hold structs because for every type there'd need to be an internal implementation which is impossible.
|
||||
|
@ -412,6 +413,28 @@ DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_I32, Push, ArrayPush<FDynArray_I32 COMMA
|
|||
ACTION_RETURN_INT(self->Push(val));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FDynArray_I32, PushV)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FDynArray_I32);
|
||||
PARAM_VA_POINTER(va_reginfo); // Get the hidden type information array
|
||||
VMVa_List args = { param + 1, 0, numparam - 2, va_reginfo + 1 };
|
||||
while (args.curindex < args.numargs)
|
||||
{
|
||||
if (args.reginfo[args.curindex] == REGT_INT)
|
||||
{
|
||||
self->Push(args.args[args.curindex++].i);
|
||||
}
|
||||
else if (args.reginfo[args.curindex] == REGT_FLOAT)
|
||||
{
|
||||
self->Push(int(args.args[args.curindex++].f));
|
||||
}
|
||||
else ThrowAbortException(X_OTHER, "Invalid parameter in pushv, int expected");
|
||||
}
|
||||
|
||||
|
||||
ACTION_RETURN_INT(self->Size()-1);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(FDynArray_I32, Pop, ArrayPop<FDynArray_I32>)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FDynArray_I32);
|
||||
|
|
|
@ -550,7 +550,21 @@ DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, ToDouble, StringToDbl)
|
|||
ACTION_RETURN_FLOAT(self->ToDouble());
|
||||
}
|
||||
|
||||
static void StringSplit(FString *self, TArray<FString> *tokens, const FString &delimiter, int keepEmpty)
|
||||
static void StringSubst(FString *self, const FString &substr, const FString& replc)
|
||||
{
|
||||
self->Substitute(substr, replc);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Substitute, StringSubst)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_STRING(substr);
|
||||
PARAM_STRING(replc);
|
||||
StringSubst(self, substr, replc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void StringSplit(FString* self, TArray<FString>* tokens, const FString& delimiter, int keepEmpty)
|
||||
{
|
||||
self->Split(*tokens, delimiter, static_cast<FString::EmptyTokenType>(keepEmpty));
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "s_music.h"
|
||||
#include "i_interface.h"
|
||||
#include "base_sbar.h"
|
||||
#include "image.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -80,10 +81,10 @@ DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, StatusbarToRealCoords, StatusbarTo
|
|||
return MIN(4, numret);
|
||||
}
|
||||
|
||||
void SBar_DrawTexture(DStatusBarCore* self, int texid, double x, double y, int flags, double alpha, double w, double h, double scaleX, double scaleY)
|
||||
void SBar_DrawTexture(DStatusBarCore* self, int texid, double x, double y, int flags, double alpha, double w, double h, double scaleX, double scaleY, int style)
|
||||
{
|
||||
if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
|
||||
self->DrawGraphic(FSetTextureID(texid), x, y, flags, alpha, w, h, scaleX, scaleY);
|
||||
self->DrawGraphic(FSetTextureID(texid), x, y, flags, alpha, w, h, scaleX, scaleY, ERenderStyle(style));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawTexture, SBar_DrawTexture)
|
||||
|
@ -98,14 +99,15 @@ DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawTexture, SBar_DrawTexture)
|
|||
PARAM_FLOAT(h);
|
||||
PARAM_FLOAT(scaleX);
|
||||
PARAM_FLOAT(scaleY);
|
||||
SBar_DrawTexture(self, texid, x, y, flags, alpha, w, h, scaleX, scaleY);
|
||||
PARAM_INT(style);
|
||||
SBar_DrawTexture(self, texid, x, y, flags, alpha, w, h, scaleX, scaleY, style);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SBar_DrawImage(DStatusBarCore* self, const FString& texid, double x, double y, int flags, double alpha, double w, double h, double scaleX, double scaleY)
|
||||
void SBar_DrawImage(DStatusBarCore* self, const FString& texid, double x, double y, int flags, double alpha, double w, double h, double scaleX, double scaleY, int style)
|
||||
{
|
||||
if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
|
||||
self->DrawGraphic(TexMan.CheckForTexture(texid, ETextureType::Any), x, y, flags, alpha, w, h, scaleX, scaleY);
|
||||
self->DrawGraphic(TexMan.CheckForTexture(texid, ETextureType::Any), x, y, flags, alpha, w, h, scaleX, scaleY, ERenderStyle(style));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawImage, SBar_DrawImage)
|
||||
|
@ -120,11 +122,12 @@ DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawImage, SBar_DrawImage)
|
|||
PARAM_FLOAT(h);
|
||||
PARAM_FLOAT(scaleX);
|
||||
PARAM_FLOAT(scaleY);
|
||||
SBar_DrawImage(self, texid, x, y, flags, alpha, w, h, scaleX, scaleY);
|
||||
PARAM_INT(style);
|
||||
SBar_DrawImage(self, texid, x, y, flags, alpha, w, h, scaleX, scaleY, style);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SBar_DrawString(DStatusBarCore* self, DHUDFont* font, const FString& string, double x, double y, int flags, int trans, double alpha, int wrapwidth, int linespacing, double scaleX, double scaleY, int translation);
|
||||
void SBar_DrawString(DStatusBarCore* self, DHUDFont* font, const FString& string, double x, double y, int flags, int trans, double alpha, int wrapwidth, int linespacing, double scaleX, double scaleY, int translation, int style);
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawString, SBar_DrawString)
|
||||
{
|
||||
|
@ -141,7 +144,8 @@ DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawString, SBar_DrawString)
|
|||
PARAM_FLOAT(scaleX);
|
||||
PARAM_FLOAT(scaleY);
|
||||
PARAM_INT(pt);
|
||||
SBar_DrawString(self, font, string, x, y, flags, trans, alpha, wrapwidth, linespacing, scaleX, scaleY, pt);
|
||||
PARAM_INT(style);
|
||||
SBar_DrawString(self, font, string, x, y, flags, trans, alpha, wrapwidth, linespacing, scaleX, scaleY, pt, style);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -336,8 +340,7 @@ DEFINE_ACTION_FUNCTION(_TexMan, GetName)
|
|||
|
||||
static int CheckForTexture(const FString& name, int type, int flags)
|
||||
{
|
||||
// ForceLookup is intentionally blocked here, this flag is for internal use only.
|
||||
return TexMan.CheckForTexture(name, static_cast<ETextureType>(type), (flags & ~FTextureManager::TEXMAN_ForceLookup)).GetIndex();
|
||||
return TexMan.CheckForTexture(name, static_cast<ETextureType>(type), flags).GetIndex();
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, CheckForTexture, CheckForTexture)
|
||||
|
@ -477,6 +480,20 @@ DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, OkForLocalization, OkForLocalization_)
|
|||
ACTION_RETURN_INT(OkForLocalization_(name, subst));
|
||||
}
|
||||
|
||||
static int UseGamePalette(int index)
|
||||
{
|
||||
auto tex = TexMan.GameByIndex(index, false);
|
||||
if (!tex) return false;
|
||||
auto image = tex->GetTexture()->GetImage();
|
||||
return image ? image->UseGamePalette() : false;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, UseGamePalette, UseGamePalette)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(texid);
|
||||
ACTION_RETURN_INT(UseGamePalette(texid));
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
//
|
||||
|
@ -867,6 +884,13 @@ DEFINE_ACTION_FUNCTION(FKeyBindings, GetAllKeysForCommand)
|
|||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FKeyBindings, GetBinding)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings);
|
||||
PARAM_INT(key);
|
||||
ACTION_RETURN_STRING(self->GetBinding(key));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FKeyBindings, UnbindACommand)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings);
|
||||
|
@ -914,6 +938,7 @@ DEFINE_GLOBAL_NAMED(mus_playing, musplaying);
|
|||
DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, name);
|
||||
DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, baseorder);
|
||||
DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, loop);
|
||||
DEFINE_FIELD_X(MusPlayingInfo, MusPlayingInfo, handle);
|
||||
|
||||
DEFINE_GLOBAL_NAMED(PClass::AllClasses, AllClasses)
|
||||
DEFINE_GLOBAL(Bindings)
|
||||
|
|
|
@ -452,16 +452,16 @@ void DStatusBarCore::StatusbarToRealCoords(double& x, double& y, double& w, doub
|
|||
//
|
||||
//============================================================================
|
||||
|
||||
void DStatusBarCore::DrawGraphic(FTextureID texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, PalEntry color, int translation, ERenderStyle style, double clipwidth)
|
||||
void DStatusBarCore::DrawGraphic(FTextureID texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, ERenderStyle style, PalEntry color, int translation, double clipwidth)
|
||||
{
|
||||
if (!texture.isValid())
|
||||
return;
|
||||
|
||||
FGameTexture* tex = TexMan.GetGameTexture(texture, !(flags & DI_DONTANIMATE));
|
||||
DrawGraphic(tex, x, y, flags, Alpha, boxwidth, boxheight, scaleX, scaleY, color, translation, style);
|
||||
DrawGraphic(tex, x, y, flags, Alpha, boxwidth, boxheight, scaleX, scaleY, style, color, translation);
|
||||
}
|
||||
|
||||
void DStatusBarCore::DrawGraphic(FGameTexture* tex, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, PalEntry color, int translation, ERenderStyle style, double clipwidth)
|
||||
void DStatusBarCore::DrawGraphic(FGameTexture* tex, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, ERenderStyle style, PalEntry color, int translation, double clipwidth)
|
||||
{
|
||||
double texwidth = tex->GetDisplayWidth() * scaleX;
|
||||
double texheight = tex->GetDisplayHeight() * scaleY;
|
||||
|
@ -695,7 +695,7 @@ void DStatusBarCore::DrawRotated(FGameTexture* tex, double x, double y, int flag
|
|||
//
|
||||
//============================================================================
|
||||
|
||||
void DStatusBarCore::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 DStatusBarCore::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, int style)
|
||||
{
|
||||
bool monospaced = monospacing != EMonospacing::Off;
|
||||
double dx = 0;
|
||||
|
@ -822,6 +822,7 @@ void DStatusBarCore::DrawString(FFont* font, const FString& cstring, double x, d
|
|||
DTA_DestHeightF, rh,
|
||||
DTA_Alpha, Alpha,
|
||||
DTA_TranslationIndex, pt,
|
||||
DTA_LegacyRenderStyle, ERenderStyle(style),
|
||||
TAG_DONE);
|
||||
|
||||
dx = monospaced
|
||||
|
@ -833,7 +834,7 @@ void DStatusBarCore::DrawString(FFont* font, const FString& cstring, double x, d
|
|||
}
|
||||
}
|
||||
|
||||
void SBar_DrawString(DStatusBarCore* self, DHUDFont* font, const FString& string, double x, double y, int flags, int trans, double alpha, int wrapwidth, int linespacing, double scaleX, double scaleY, int pt)
|
||||
void SBar_DrawString(DStatusBarCore* self, DHUDFont* font, const FString& string, double x, double y, int flags, int trans, double alpha, int wrapwidth, int linespacing, double scaleX, double scaleY, int pt, int style)
|
||||
{
|
||||
if (font == nullptr) ThrowAbortException(X_READ_NIL, nullptr);
|
||||
if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
|
||||
|
@ -852,13 +853,13 @@ void SBar_DrawString(DStatusBarCore* self, DHUDFont* font, const FString& string
|
|||
auto brk = V_BreakLines(font->mFont, int(wrapwidth * scaleX), string, true);
|
||||
for (auto& line : brk)
|
||||
{
|
||||
self->DrawString(font->mFont, line.Text, x, y, flags, alpha, trans, font->mSpacing, font->mMonospacing, font->mShadowX, font->mShadowY, scaleX, scaleY, pt);
|
||||
self->DrawString(font->mFont, line.Text, x, y, flags, alpha, trans, font->mSpacing, font->mMonospacing, font->mShadowX, font->mShadowY, scaleX, scaleY, pt, style);
|
||||
y += (font->mFont->GetHeight() + linespacing) * scaleY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self->DrawString(font->mFont, string, x, y, flags, alpha, trans, font->mSpacing, font->mMonospacing, font->mShadowX, font->mShadowY, scaleX, scaleY, pt);
|
||||
self->DrawString(font->mFont, string, x, y, flags, alpha, trans, font->mSpacing, font->mMonospacing, font->mShadowX, font->mShadowY, scaleX, scaleY, pt, style);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -184,11 +184,11 @@ public:
|
|||
virtual void SetScale();
|
||||
void ValidateResolution(int& hres, int& vres) const;
|
||||
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 DrawGraphic(FGameTexture* texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, ERenderStyle style = STYLE_Translucent, PalEntry color = 0xffffffff, int translation = 0, double clipwidth = -1.0);
|
||||
void DrawGraphic(FTextureID texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY, ERenderStyle style = STYLE_Translucent, PalEntry color = 0xffffffff, int translation = 0, double clipwidth = -1.0);
|
||||
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 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, int style);
|
||||
void TransformRect(double& x, double& y, double& w, double& h, int flags = 0);
|
||||
void Fill(PalEntry color, double x, double y, double w, double h, int flags = 0);
|
||||
void SetClipRect(double x, double y, double w, double h, int flags = 0);
|
||||
|
|
|
@ -231,6 +231,7 @@ public:
|
|||
void SetFullbright() { flags |= GTexf_RenderFullbright; }
|
||||
void SetDisableFullbright(bool on) { if (on) flags |= GTexf_DisableFullbrightSprites; else flags &= ~GTexf_DisableFullbrightSprites; }
|
||||
void SetGlowing(PalEntry color) { flags = (flags & ~GTexf_AutoGlowing) | GTexf_Glowing; GlowColor = color; }
|
||||
void SetDisableBrightmap() { flags |= GTexf_BrightmapChecked; Brightmap = nullptr; }
|
||||
|
||||
bool isUserContent() const;
|
||||
int CheckRealHeight() { return xs_RoundToInt(Base->CheckRealHeight() / ScaleY); }
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
|
||||
#define MAXWIDTH 12000
|
||||
#define MAXHEIGHT 5000
|
||||
|
@ -101,3 +102,6 @@ enum EStateUseFlags
|
|||
SUF_WEAPON = 4,
|
||||
SUF_ITEM = 8,
|
||||
};
|
||||
|
||||
using std::min;
|
||||
using std::max;
|
||||
|
|
|
@ -103,4 +103,14 @@ inline void fillshort(void* buff, size_t count, uint16_t clear)
|
|||
template<typename T> inline constexpr T Sgn(const T& val) { return (val > 0) - (val < 0); }
|
||||
|
||||
|
||||
inline int sizeToBits(int w)
|
||||
{
|
||||
int j = 15;
|
||||
|
||||
while ((j > 1) && ((1 << j) > w))
|
||||
j--;
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,9 +33,7 @@ class VSMatrix {
|
|||
|
||||
public:
|
||||
|
||||
VSMatrix()
|
||||
{
|
||||
}
|
||||
VSMatrix() = default;
|
||||
|
||||
VSMatrix(int)
|
||||
{
|
||||
|
|
|
@ -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"
|
||||
|
@ -44,6 +43,9 @@ Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au)
|
|||
#include "v_video.h"
|
||||
#include "gamestruct.h"
|
||||
#include "v_draw.h"
|
||||
#include "sectorgeometry.h"
|
||||
#include "gamefuncs.h"
|
||||
#include "hw_sections.h"
|
||||
|
||||
CVAR(Bool, am_followplayer, true, CVAR_ARCHIVE)
|
||||
CVAR(Bool, am_rotate, true, CVAR_ARCHIVE)
|
||||
|
@ -408,8 +410,6 @@ void drawredlines(int cposx, int cposy, int czoom, int cang)
|
|||
{
|
||||
int xvect = -bsin(cang) * czoom;
|
||||
int yvect = -bcos(cang) * czoom;
|
||||
int xvect2 = MulScale(xvect, yxaspect, 16);
|
||||
int yvect2 = MulScale(yvect, yxaspect, 16);
|
||||
int width = screen->GetWidth();
|
||||
int height = screen->GetHeight();
|
||||
|
||||
|
@ -441,13 +441,13 @@ void drawredlines(int cposx, int cposy, int czoom, int cang)
|
|||
int ox = wal->x - cposx;
|
||||
int oy = wal->y - cposy;
|
||||
int x1 = DMulScale(ox, xvect, -oy, yvect, 16) + (width << 11);
|
||||
int y1 = DMulScale(oy, xvect2, ox, yvect2, 16) + (height << 11);
|
||||
int y1 = DMulScale(oy, xvect, ox, yvect, 16) + (height << 11);
|
||||
|
||||
auto wal2 = &wall[wal->point2];
|
||||
ox = wal2->x - cposx;
|
||||
oy = wal2->y - cposy;
|
||||
int x2 = DMulScale(ox, xvect, -oy, yvect, 16) + (width << 11);
|
||||
int y2 = DMulScale(oy, xvect2, ox, yvect2, 16) + (height << 11);
|
||||
int y2 = DMulScale(oy, xvect, ox, yvect, 16) + (height << 11);
|
||||
|
||||
drawlinergb(x1, y1, x2, y2, RedLineColor());
|
||||
}
|
||||
|
@ -465,8 +465,6 @@ static void drawwhitelines(int cposx, int cposy, int czoom, int cang)
|
|||
{
|
||||
int xvect = -bsin(cang) * czoom;
|
||||
int yvect = -bcos(cang) * czoom;
|
||||
int xvect2 = MulScale(xvect, yxaspect, 16);
|
||||
int yvect2 = MulScale(yvect, yxaspect, 16);
|
||||
int width = screen->GetWidth();
|
||||
int height = screen->GetHeight();
|
||||
|
||||
|
@ -483,7 +481,7 @@ static void drawwhitelines(int cposx, int cposy, int czoom, int cang)
|
|||
for (j = startwall, wal = &wall[startwall]; j < endwall; j++, wal++)
|
||||
{
|
||||
if (wal->nextwall >= 0) continue;
|
||||
if (!tileGetTexture(wal->picnum)->isValid()) continue;
|
||||
if (!gFullMap && !tileGetTexture(wal->picnum)->isValid()) continue;
|
||||
|
||||
if ((g_gameType & GAMEFLAG_SW) && !gFullMap && !show2dwall[j])
|
||||
continue;
|
||||
|
@ -491,20 +489,25 @@ static void drawwhitelines(int cposx, int cposy, int czoom, int cang)
|
|||
int ox = wal->x - cposx;
|
||||
int oy = wal->y - cposy;
|
||||
int x1 = DMulScale(ox, xvect, -oy, yvect, 16) + (width << 11);
|
||||
int y1 = DMulScale(oy, xvect2, ox, yvect2, 16) + (height << 11);
|
||||
int y1 = DMulScale(oy, xvect, ox, yvect, 16) + (height << 11);
|
||||
|
||||
int k = wal->point2;
|
||||
auto wal2 = &wall[k];
|
||||
ox = wal2->x - cposx;
|
||||
oy = wal2->y - cposy;
|
||||
int x2 = DMulScale(ox, xvect, -oy, yvect, 16) + (width << 11);
|
||||
int y2 = DMulScale(oy, xvect2, ox, yvect2, 16) + (height << 11);
|
||||
int y2 = DMulScale(oy, xvect, ox, yvect, 16) + (height << 11);
|
||||
|
||||
drawlinergb(x1, y1, x2, y2, WhiteLineColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// player sprite fallback
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DrawPlayerArrow(int cposx, int cposy, int cang, int pl_x, int pl_y, int zoom, int pl_angle)
|
||||
{
|
||||
|
@ -517,8 +520,6 @@ void DrawPlayerArrow(int cposx, int cposy, int cang, int pl_x, int pl_y, int zoo
|
|||
|
||||
int xvect = -bsin(cang) * zoom;
|
||||
int yvect = -bcos(cang) * zoom;
|
||||
int xvect2 = MulScale(xvect, yxaspect, 16);
|
||||
int yvect2 = MulScale(yvect, yxaspect, 16);
|
||||
|
||||
int pxvect = -bsin(pl_angle);
|
||||
int pyvect = -bcos(pl_angle);
|
||||
|
@ -540,14 +541,124 @@ void DrawPlayerArrow(int cposx, int cposy, int cang, int pl_x, int pl_y, int zoo
|
|||
int oy2 = py2 - cposx;
|
||||
|
||||
int sx1 = DMulScale(ox1, xvect, -oy1, yvect, 16) + (width << 11);
|
||||
int sy1 = DMulScale(oy1, xvect2, ox1, yvect2, 16) + (height << 11);
|
||||
int sy1 = DMulScale(oy1, xvect, ox1, yvect, 16) + (height << 11);
|
||||
int sx2 = DMulScale(ox2, xvect, -oy2, yvect, 16) + (width << 11);
|
||||
int sy2 = DMulScale(oy2, xvect2, ox2, yvect2, 16) + (height << 11);
|
||||
int sy2 = DMulScale(oy2, xvect, ox2, yvect, 16) + (height << 11);
|
||||
|
||||
drawlinergb(sx1, sy1, sx2, sy2, WhiteLineColor());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// floor textures
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void renderDrawMapView(int cposx, int cposy, int czoom, int cang)
|
||||
{
|
||||
int xvect = -bsin(cang) * czoom;
|
||||
int yvect = -bcos(cang) * czoom;
|
||||
int width = screen->GetWidth();
|
||||
int height = screen->GetHeight();
|
||||
TArray<FVector4> vertices;
|
||||
TArray<int> floorsprites;
|
||||
|
||||
|
||||
for (int i = numsectors - 1; i >= 0; i--)
|
||||
{
|
||||
if (!gFullMap && !show2dsector[i]) continue;
|
||||
|
||||
//Collect floor sprites to draw
|
||||
SectIterator it(i);
|
||||
int s;
|
||||
while ((s = it.NextIndex()) >= 0)
|
||||
{
|
||||
if (sprite[s].cstat & CSTAT_SPRITE_INVISIBLE)
|
||||
continue;
|
||||
|
||||
if ((sprite[s].cstat & CSTAT_SPRITE_ALIGNMENT_MASK) == CSTAT_SPRITE_ALIGNMENT_FLOOR)
|
||||
{
|
||||
if ((sprite[s].cstat & (CSTAT_SPRITE_ONE_SIDED | CSTAT_SPRITE_YFLIP)) == (CSTAT_SPRITE_ONE_SIDED | CSTAT_SPRITE_YFLIP))
|
||||
continue; // upside down
|
||||
floorsprites.Push(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (sector[i].floorstat & CSTAT_SECTOR_SKY) continue;
|
||||
|
||||
int picnum = sector[i].floorpicnum;
|
||||
if ((unsigned)picnum >= (unsigned)MAXTILES) continue;
|
||||
|
||||
for (auto ii : sectionspersector[i])
|
||||
{
|
||||
auto mesh = sectorGeometry.get(ii, 0, { 0.f,0.f });
|
||||
vertices.Resize(mesh->vertices.Size());
|
||||
for (unsigned j = 0; j < mesh->vertices.Size(); j++)
|
||||
{
|
||||
int ox = int(mesh->vertices[j].X * 16.f) - cposx;
|
||||
int oy = int(mesh->vertices[j].Y * -16.f) - cposy;
|
||||
int x1 = DMulScale(ox, xvect, -oy, yvect, 16) + (width << 11);
|
||||
int y1 = DMulScale(oy, xvect, ox, yvect, 16) + (height << 11);
|
||||
vertices[j] = { x1 / 4096.f, y1 / 4096.f, mesh->texcoords[j].X, mesh->texcoords[j].Y };
|
||||
}
|
||||
}
|
||||
|
||||
int translation = TRANSLATION(Translation_Remap + curbasepal, sector[i].floorpal);
|
||||
setgotpic(picnum);
|
||||
twod->AddPoly(tileGetTexture(picnum, true), vertices.Data(), vertices.Size(), nullptr, 0, translation, shadeToLight(sector[i].floorshade),
|
||||
LegacyRenderStyles[STYLE_Translucent], windowxy1.x, windowxy1.y, windowxy2.x + 1, windowxy2.y + 1);
|
||||
|
||||
|
||||
}
|
||||
qsort(floorsprites.Data(), floorsprites.Size(), sizeof(int), [](const void* a, const void* b)
|
||||
{
|
||||
int A = *(int*)a;
|
||||
int B = *(int*)b;
|
||||
if (sprite[A].z != sprite[B].z) return sprite[B].z - sprite[A].z;
|
||||
return A - B; // ensures stable sort.
|
||||
});
|
||||
|
||||
vertices.Resize(4);
|
||||
for (auto sn : floorsprites)
|
||||
{
|
||||
if (!gFullMap && !show2dsprite[sn]) continue;
|
||||
auto spr = &sprite[sn];
|
||||
vec2_t pp[4];
|
||||
GetFlatSpritePosition(spr, spr->pos.vec2, pp, true);
|
||||
|
||||
for (unsigned j = 0; j < 4; j++)
|
||||
{
|
||||
int ox = pp[j].x - cposx;
|
||||
int oy = pp[j].y - cposy;
|
||||
int x1 = DMulScale(ox, xvect, -oy, yvect, 16) + (width << 11);
|
||||
int y1 = DMulScale(oy, xvect, ox, yvect, 16) + (height << 11);
|
||||
vertices[j] = { x1 / 4096.f, y1 / 4096.f, j == 1 || j == 2 ? 1.f : 0.f, j == 2 || j == 3 ? 1.f : 0.f };
|
||||
}
|
||||
int shade;
|
||||
if ((sector[spr->sectnum].ceilingstat & CSTAT_SECTOR_SKY)) shade = sector[spr->sectnum].ceilingshade;
|
||||
else shade = sector[spr->sectnum].floorshade;
|
||||
shade += spr->shade;
|
||||
PalEntry color = shadeToLight(shade);
|
||||
FRenderStyle rs = LegacyRenderStyles[STYLE_Translucent];
|
||||
float alpha = 1;
|
||||
if (spr->cstat & CSTAT_SPRITE_TRANSLUCENT)
|
||||
{
|
||||
rs = GetRenderStyle(0, !!(spr->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT));
|
||||
alpha = GetAlphaFromBlend((spr->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT) ? DAMETH_TRANS2 : DAMETH_TRANS1, 0);
|
||||
color.a = uint8_t(alpha * 255);
|
||||
}
|
||||
|
||||
int translation = TRANSLATION(Translation_Remap + curbasepal, spr->pal);
|
||||
int picnum = spr->picnum;
|
||||
setgotpic(picnum);
|
||||
const static unsigned indices[] = { 0, 1, 2, 0, 2, 3 };
|
||||
twod->AddPoly(tileGetTexture(picnum, true), vertices.Data(), vertices.Size(), indices, 6, translation, color, rs,
|
||||
windowxy1.x, windowxy1.y, windowxy2.x + 1, windowxy2.y + 1);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
|
@ -573,7 +684,6 @@ void DrawOverheadMap(int pl_x, int pl_y, int pl_angle, double const smoothratio)
|
|||
renderDrawMapView(x, y, gZoom, follow_a);
|
||||
}
|
||||
int32_t tmpydim = (width * 5) / 8;
|
||||
renderSetAspect(65536, DivScale(tmpydim * 320, width * 200, 16));
|
||||
|
||||
drawredlines(x, y, gZoom, follow_a);
|
||||
drawwhitelines(x, y, gZoom, follow_a);
|
||||
|
|
|
@ -40,8 +40,8 @@
|
|||
#include "m_fixed.h"
|
||||
#include "xs_Float.h" // needed for reliably overflowing float->int conversions.
|
||||
#include "serializer.h"
|
||||
#include "build.h"
|
||||
#include "math/cmath.h"
|
||||
#include "templates.h"
|
||||
|
||||
class FSerializer;
|
||||
|
||||
|
@ -59,9 +59,9 @@ enum
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
constexpr double BAngRadian = pi::pi() * (1. / 1024.);
|
||||
constexpr double BRadAngScale = 1. / BAngRadian;
|
||||
constexpr double BAngToDegree = 360. / 2048.;
|
||||
|
||||
extern int16_t sintable[2048];
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
|
@ -69,11 +69,11 @@ constexpr double BAngToDegree = 360. / 2048.;
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
inline int32_t bsin(const int ang, const int8_t shift = 0)
|
||||
inline int bsin(const int ang, const int shift = 0)
|
||||
{
|
||||
return shift < 0 ? sintable[ang & 2047] >> abs(shift) : sintable[ang & 2047] << shift;
|
||||
}
|
||||
inline double bsinf(const double ang, const int8_t shift = 0)
|
||||
inline double bsinf(const double ang, const int shift = 0)
|
||||
{
|
||||
return g_sin(ang * BAngRadian) * (shift >= -SINSHIFT ? uint64_t(1) << (SINSHIFT + shift) : 1. / (uint64_t(1) << abs(SINSHIFT + shift)));
|
||||
}
|
||||
|
@ -85,156 +85,16 @@ inline double bsinf(const double ang, const int8_t shift = 0)
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
inline int32_t bcos(const int ang, const int8_t shift = 0)
|
||||
inline int bcos(const int ang, const int shift = 0)
|
||||
{
|
||||
return shift < 0 ? sintable[(ang + 512) & 2047] >> abs(shift) : sintable[(ang + 512) & 2047] << shift;
|
||||
}
|
||||
inline double bcosf(const double ang, const int8_t shift = 0)
|
||||
inline double bcosf(const double ang, const int shift = 0)
|
||||
{
|
||||
return g_cos(ang * BAngRadian) * (shift >= -SINSHIFT ? uint64_t(1) << (SINSHIFT + shift) : 1. / (uint64_t(1) << abs(SINSHIFT + shift)));
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Shift a Build angle left by 21 bits.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
inline constexpr int64_t BAngToBAM(int ang)
|
||||
{
|
||||
return ang << BAMBITS;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class lookangle
|
||||
{
|
||||
int32_t value;
|
||||
|
||||
constexpr lookangle(int32_t v) : value(v) {}
|
||||
|
||||
friend constexpr lookangle bamlook(int32_t v);
|
||||
friend constexpr lookangle q16look(int32_t v);
|
||||
friend constexpr lookangle buildlook(int32_t v);
|
||||
friend lookangle buildflook(double v);
|
||||
friend lookangle radlook(double v);
|
||||
friend lookangle deglook(double v);
|
||||
|
||||
friend FSerializer &Serialize(FSerializer &arc, const char *key, lookangle &obj, lookangle *defval);
|
||||
|
||||
friend class binangle;
|
||||
|
||||
public:
|
||||
lookangle() = default;
|
||||
lookangle(const lookangle &other) = default;
|
||||
// This class intentionally makes no allowances for implicit type conversions because those would render it ineffective.
|
||||
constexpr short asbuild() const { return value >> 21; }
|
||||
constexpr double asbuildf() const { return value * (1. / BAMUNIT); }
|
||||
constexpr fixed_t asq16() const { return value >> 5; }
|
||||
constexpr double asrad() const { return value * (pi::pi() / 0x80000000u); }
|
||||
constexpr double asdeg() const { return AngleToFloat(value); }
|
||||
constexpr int32_t asbam() const { return value; }
|
||||
|
||||
double fsin() const { return g_sin(asrad()); }
|
||||
double fcos() const { return g_cos(asrad()); }
|
||||
double ftan() const { return g_tan(asrad()); }
|
||||
int bsin(const int8_t& shift = 0) const { return ::bsin(asbuild(), shift); }
|
||||
int bcos(const int8_t& shift = 0) const { return ::bcos(asbuild(), shift); }
|
||||
|
||||
bool operator< (lookangle other) const
|
||||
{
|
||||
return value < other.value;
|
||||
}
|
||||
|
||||
bool operator> (lookangle other) const
|
||||
{
|
||||
return value > other.value;
|
||||
}
|
||||
|
||||
bool operator<= (lookangle other) const
|
||||
{
|
||||
return value <= other.value;
|
||||
}
|
||||
|
||||
bool operator>= (lookangle other) const
|
||||
{
|
||||
return value >= other.value;
|
||||
}
|
||||
constexpr bool operator== (lookangle other) const
|
||||
{
|
||||
return value == other.value;
|
||||
}
|
||||
|
||||
constexpr bool operator!= (lookangle other) const
|
||||
{
|
||||
return value != other.value;
|
||||
}
|
||||
|
||||
constexpr lookangle &operator+= (lookangle other)
|
||||
{
|
||||
value += other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr lookangle &operator-= (lookangle other)
|
||||
{
|
||||
value -= other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr lookangle operator+ (lookangle other) const
|
||||
{
|
||||
return lookangle(value + other.value);
|
||||
}
|
||||
|
||||
constexpr lookangle operator- (lookangle other) const
|
||||
{
|
||||
return lookangle(value - other.value);
|
||||
}
|
||||
|
||||
constexpr lookangle &operator<<= (const uint8_t shift)
|
||||
{
|
||||
value <<= shift;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr lookangle &operator>>= (const uint8_t shift)
|
||||
{
|
||||
value >>= shift;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr lookangle operator<< (const uint8_t shift) const
|
||||
{
|
||||
return lookangle(value << shift);
|
||||
}
|
||||
|
||||
constexpr lookangle operator>> (const uint8_t shift) const
|
||||
{
|
||||
return lookangle(value >> shift);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline constexpr lookangle bamlook(int32_t v) { return lookangle(v); }
|
||||
inline constexpr lookangle q16look(int32_t v) { return lookangle(v << 5); }
|
||||
inline constexpr lookangle buildlook(int32_t v) { return lookangle(v << BAMBITS); }
|
||||
inline lookangle buildflook(double v) { return lookangle(xs_CRoundToInt(v * BAMUNIT)); }
|
||||
inline lookangle radlook(double v) { return lookangle(xs_CRoundToInt(v * (0x80000000u / pi::pi()))); }
|
||||
inline lookangle deglook(double v) { return lookangle(FloatToAngle(v)); }
|
||||
|
||||
inline FSerializer &Serialize(FSerializer &arc, const char *key, lookangle &obj, lookangle *defval)
|
||||
{
|
||||
return Serialize(arc, key, obj.value, defval ? &defval->value : nullptr);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
|
@ -260,12 +120,19 @@ public:
|
|||
binangle() = default;
|
||||
binangle(const binangle &other) = default;
|
||||
// This class intentionally makes no allowances for implicit type conversions because those would render it ineffective.
|
||||
constexpr short asbuild() const { return value >> 21; }
|
||||
constexpr int32_t tosigned() const { return value > INT32_MAX ? int64_t(value) - UINT32_MAX : value; }
|
||||
constexpr short asbuild() const { return value >> BAMBITS; }
|
||||
constexpr double asbuildf() const { return value * (1. / BAMUNIT); }
|
||||
constexpr fixed_t asq16() const { return value >> 5; }
|
||||
constexpr uint32_t asbam() const { return value; }
|
||||
constexpr double asrad() const { return value * (pi::pi() / 0x80000000u); }
|
||||
constexpr double asdeg() const { return AngleToFloat(value); }
|
||||
constexpr uint32_t asbam() const { return value; }
|
||||
constexpr short signedbuild() const { return tosigned() >> BAMBITS; }
|
||||
constexpr double signedbuildf() const { return tosigned() * (1. / BAMUNIT); }
|
||||
constexpr fixed_t signedq16() const { return tosigned() >> 5; }
|
||||
constexpr int32_t signedbam() const { return tosigned(); }
|
||||
constexpr double signedrad() const { return tosigned() * (pi::pi() / 0x80000000u); }
|
||||
constexpr double signeddeg() const { return AngleToFloat(tosigned()); }
|
||||
|
||||
double fsin() const { return g_sin(asrad()); }
|
||||
double fcos() const { return g_cos(asrad()); }
|
||||
|
@ -305,28 +172,6 @@ public:
|
|||
return binangle(value - other.value);
|
||||
}
|
||||
|
||||
constexpr binangle &operator+= (lookangle other)
|
||||
{
|
||||
value += other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr binangle &operator-= (lookangle other)
|
||||
{
|
||||
value -= other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr binangle operator+ (lookangle other) const
|
||||
{
|
||||
return binangle(value + other.value);
|
||||
}
|
||||
|
||||
constexpr binangle operator- (lookangle other) const
|
||||
{
|
||||
return binangle(value - other.value);
|
||||
}
|
||||
|
||||
constexpr binangle &operator<<= (const uint8_t shift)
|
||||
{
|
||||
value <<= shift;
|
||||
|
@ -348,7 +193,6 @@ public:
|
|||
{
|
||||
return binangle(value >> shift);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline constexpr binangle bamang(uint32_t v) { return binangle(v); }
|
||||
|
@ -366,24 +210,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 +346,38 @@ 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(const double& vect)
|
||||
inline binangle bvectangbam(int32_t x, int32_t y)
|
||||
{
|
||||
return atan(vect) * BRadAngScale;
|
||||
return radang(atan2(y, x));
|
||||
}
|
||||
inline double bvectangf(const int32_t& x, const int32_t& y)
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Interpolation functions for use throughout games.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
inline int32_t interpolatedvalue(int32_t oval, int32_t val, double const smoothratio, int const scale = 16)
|
||||
{
|
||||
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.);
|
||||
}
|
||||
return oval + MulScale(val - oval, smoothratio, scale);
|
||||
}
|
||||
inline int32_t bvectang(const int32_t& x, const int32_t& y)
|
||||
|
||||
inline double interpolatedvaluef(double oval, double val, double const smoothratio, int const scale = 16)
|
||||
{
|
||||
return xs_CRoundToInt(bvectangf(x, y));
|
||||
return oval + MulScaleF(val - oval, smoothratio, scale);
|
||||
}
|
||||
inline fixed_t bvectangq16(const int32_t& x, const int32_t& y)
|
||||
|
||||
inline int32_t interpolatedangle(int32_t oang, int32_t ang, double const smoothratio, int const scale = 16)
|
||||
{
|
||||
return FloatToFixed(bvectangf(x, y));
|
||||
return oang + MulScale(((ang + 1024 - oang) & 2047) - 1024, smoothratio, scale);
|
||||
}
|
||||
inline binangle bvectangbam(const int32_t& x, const int32_t& y)
|
||||
|
||||
inline binangle interpolatedangle(binangle oang, binangle ang, double const smoothratio, int const scale = 16)
|
||||
{
|
||||
return bamang(xs_CRoundToUInt(bvectangf(x, y) * BAMUNIT));
|
||||
return bamang(oang.asbam() + MulScale(((ang.asbam() + 0x80000000 - oang.asbam()) & 0xFFFFFFFF) - 0x80000000, smoothratio, scale));
|
||||
}
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
#include "c_dispatch.h"
|
||||
#include "d_net.h"
|
||||
#include "gamestate.h"
|
||||
#include "mmulti.h"
|
||||
#include "gstrings.h"
|
||||
#include "gamecontrol.h"
|
||||
#include "screenjob.h"
|
||||
|
@ -242,7 +241,7 @@ void changeMap(int player, uint8_t** stream, bool skip)
|
|||
|
||||
void endScreenJob(int player, uint8_t** stream, bool skip)
|
||||
{
|
||||
if (!skip) EndScreenJob();
|
||||
if (!skip) gameaction = ga_endscreenjob;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -280,6 +279,7 @@ void DeferedStartGame(MapRecord* map, int skill, bool nostopsound)
|
|||
static MapRecord* levelwarp_common(FCommandLine& argv, const char *cmdname, const char *t2)
|
||||
{
|
||||
int numparm = g_gameType & (GAMEFLAG_SW | GAMEFLAG_PSEXHUMED) ? 1 : 2; // Handle games with episodic and non-episodic level order.
|
||||
if (numparm == 2 && argv.argc() == 2) numparm = 1;
|
||||
if (argv.argc() <= numparm)
|
||||
{
|
||||
if (numparm == 2) Printf(PRINT_BOLD, "%s <e> <m>: %s episode 'e' and map 'm'\n", cmdname, t2);
|
||||
|
@ -294,7 +294,7 @@ static MapRecord* levelwarp_common(FCommandLine& argv, const char *cmdname, cons
|
|||
Printf(PRINT_BOLD, "Invalid level! Numbers must be > 0\n");
|
||||
return nullptr;
|
||||
}
|
||||
auto map = FindMapByLevelNum(numparm == 1 ? m : levelnum(e - 1, m - 1));
|
||||
auto map = FindMapByIndex(e, m);
|
||||
if (!map)
|
||||
{
|
||||
if (numparm == 2) Printf(PRINT_BOLD, "Level E%s L%s not found!\n", argv[1], argv[2]);
|
||||
|
|
|
@ -63,7 +63,6 @@
|
|||
#include "vm.h"
|
||||
#include "gstrings.h"
|
||||
#include "s_music.h"
|
||||
#include "mmulti.h"
|
||||
#include "printf.h"
|
||||
#include "i_time.h"
|
||||
#include "d_ticcmd.h"
|
||||
|
|
|
@ -10,6 +10,9 @@ enum
|
|||
MAXPLAYERS = 8
|
||||
};
|
||||
|
||||
extern int myconnectindex, numplayers;
|
||||
extern int connecthead, connectpoint2[MAXPLAYERS];
|
||||
|
||||
class FDynamicBuffer
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
** def.cpp
|
||||
** Rewritten .def parser free of Build license restrictions.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2020 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 OFf
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#include "build.h"
|
||||
#include "compat.h"
|
||||
|
||||
#include "mdsprite.h" // md3model_t
|
||||
#include "buildtiles.h"
|
||||
#include "bitmap.h"
|
||||
#include "m_argv.h"
|
||||
#include "gamecontrol.h"
|
||||
#include "palettecontainer.h"
|
||||
#include "mapinfo.h"
|
||||
#include "sc_man.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool ParseDefFile(const char* file, FScanner *parent)
|
||||
{
|
||||
int lump = fileSystem.FindFile(file);
|
||||
bool success = false;
|
||||
if (lump == -1)
|
||||
{
|
||||
if (!parent) Printf(PRINT_BOLD, "%sd: file not found\n", file);
|
||||
else parent->ScriptError("%s: file not found\n", file);
|
||||
return false;
|
||||
}
|
||||
FScanner sc;
|
||||
if (parent) sc.symbols = std::move(parent->symbols); // the child parser needs to add to the parent's symbol table so transfer its ownership for the parsing run.
|
||||
sc.OpenLumpNum(lump);
|
||||
sc.SetCMode(true);
|
||||
sc.SetNoOctals(true);
|
||||
sc.SetNoFatalErrors(true);
|
||||
FString str;
|
||||
|
||||
while (sc.GetString())
|
||||
{
|
||||
if (sc.Compare({"#include", "include"}))
|
||||
{
|
||||
if (!sc.MustGetString())
|
||||
ParseDefFile(sc.String, &sc);
|
||||
}
|
||||
else if (sc.Compare({"#includedefault", "includedefault"}))
|
||||
{
|
||||
ParseDefFile(G_DefaultDefFile(), &sc);
|
||||
}
|
||||
else if (sc.Compare({"#define", "define"}))
|
||||
{
|
||||
parseDefine(sc);
|
||||
}
|
||||
else if (sc.Compare("definetexture"))
|
||||
{
|
||||
parseDefineTexture(sc);
|
||||
}
|
||||
else if (sc.Compare("defineskybox"))
|
||||
{
|
||||
parseDefineSkybox(sc);
|
||||
}
|
||||
else if (sc.Compare("definetint"))
|
||||
{
|
||||
parseDefineTint(sc);
|
||||
}
|
||||
else if (sc.Compare("alphahack")) // why 'hack'?
|
||||
{
|
||||
parseAlphaHack(sc);
|
||||
}
|
||||
else if (sc.Compare("alphahackrange")) // why 'hack'?
|
||||
{
|
||||
parseAlphaHackRange(sc);
|
||||
}
|
||||
if (sc.Compare({"spritecol", "2dcolidxrange")) // only used by Mapster32 so just read over them and ignore the result
|
||||
{
|
||||
parseDiscard<3>(sc);
|
||||
}
|
||||
else if (sc.Compare("2dcol")) // same here
|
||||
{
|
||||
parseDiscard<4>(sc);
|
||||
}
|
||||
else if (sc.Compare("fogpal"))
|
||||
{
|
||||
parseFogPal(sc);
|
||||
}
|
||||
else if (sc.Compare("nofloorpalrange"))
|
||||
{
|
||||
parseNoFloorpalRange(sc);
|
||||
}
|
||||
else if (sc.Compare("loadgrp"))
|
||||
{
|
||||
parseLoadGrp(sc);
|
||||
}
|
||||
else if (sc.Compare("cachesize") || sc.Compare("shadefactor"))
|
||||
{
|
||||
parseDiscard<1>(sc);
|
||||
}
|
||||
else if (sc.Compare("artfile"))
|
||||
{
|
||||
parseArtFile(sc);
|
||||
}
|
||||
|
||||
}
|
||||
success = true;
|
||||
|
||||
if (parent) parent->symbols = std::move(sc.symbols);
|
||||
return success;
|
||||
}
|
2159
source/core/defparser.cpp
Normal file
2159
source/core/defparser.cpp
Normal file
File diff suppressed because it is too large
Load diff
1321
source/core/g_mapinfo.cpp
Normal file
1321
source/core/g_mapinfo.cpp
Normal file
File diff suppressed because it is too large
Load diff
108
source/core/g_mapinfo.h
Normal file
108
source/core/g_mapinfo.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
** g_level.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2006 Randy Heit
|
||||
** 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.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __G_LEVEL_H__
|
||||
#define __G_LEVEL_H__
|
||||
|
||||
#include "autosegs.h"
|
||||
#include "vectors.h"
|
||||
#include "sc_man.h"
|
||||
#include "file_zip.h"
|
||||
|
||||
struct FMapInfoParser
|
||||
{
|
||||
FScanner sc;
|
||||
bool Internal;
|
||||
MapRecord* defaultinfoptr;
|
||||
|
||||
FMapInfoParser(bool internal = false)
|
||||
{
|
||||
Internal = internal;
|
||||
}
|
||||
|
||||
bool CheckLegacyMapDefinition(FString& mapname);
|
||||
bool ParseLookupName(FString &dest);
|
||||
void ParseMusic(FString &name, int &order);
|
||||
void ParseLumpOrTextureName(FString &name);
|
||||
|
||||
void ParseCutscene(CutsceneDef& cdef);
|
||||
void ParseCluster();
|
||||
void ParseMapName(FString &mapname);
|
||||
MapRecord *ParseMapHeader(MapRecord &defaultinfo);
|
||||
void ParseMapDefinition(MapRecord &leveldef);
|
||||
void ParseEpisodeInfo ();
|
||||
void ParseCutsceneInfo();
|
||||
void ParseGameInfo();
|
||||
void ParseMapInfo (int lump, MapRecord &gamedefaults, MapRecord &defaultinfo);
|
||||
|
||||
void ParseOpenBrace();
|
||||
bool ParseCloseBrace();
|
||||
bool CheckAssign();
|
||||
void ParseAssign();
|
||||
void MustParseAssign();
|
||||
void ParseComma();
|
||||
bool CheckNumber();
|
||||
bool CheckFloat();
|
||||
void SkipToNext();
|
||||
void CheckEndOfFile(const char *block);
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma section(SECTION_YREG,read)
|
||||
#define MSVC_YSEG __declspec(allocate(SECTION_YREG))
|
||||
#define GCC_YSEG
|
||||
#else
|
||||
#define MSVC_YSEG
|
||||
#define GCC_YSEG __attribute__((section(SECTION_YREG))) __attribute__((used))
|
||||
#endif
|
||||
|
||||
#define DEFINE_MAP_OPTION(name, old) \
|
||||
static void MapOptHandler_##name(FMapInfoParser &parse, MapRecord *info); \
|
||||
static FMapOptInfo MapOpt_##name = \
|
||||
{ #name, MapOptHandler_##name, old }; \
|
||||
MSVC_YSEG FMapOptInfo *mapopt_##name GCC_YSEG = &MapOpt_##name; \
|
||||
static void MapOptHandler_##name(FMapInfoParser &parse, MapRecord *info)
|
||||
|
||||
|
||||
struct FMapOptInfo
|
||||
{
|
||||
const char *name;
|
||||
void (*handler) (FMapInfoParser &parse, MapRecord *levelinfo);
|
||||
bool old;
|
||||
};
|
||||
|
||||
|
||||
void G_ParseMapInfo();
|
||||
|
||||
|
||||
#endif //__G_LEVEL_H__
|
|
@ -57,7 +57,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "c_dispatch.h"
|
||||
#include "glbackend/glbackend.h"
|
||||
#include "engineerrors.h"
|
||||
#include "mmulti.h"
|
||||
#include "gamestate.h"
|
||||
#include "gstrings.h"
|
||||
#include "texturemanager.h"
|
||||
|
@ -73,6 +72,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "automap.h"
|
||||
#include "v_draw.h"
|
||||
#include "gi.h"
|
||||
#include "vm.h"
|
||||
#include "g_mapinfo.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)
|
||||
|
@ -101,7 +105,7 @@ CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG | CVAR_ARCHIVE)
|
|||
// The last remains of sdlayer.cpp
|
||||
GameInterface* gi;
|
||||
int myconnectindex, numplayers;
|
||||
int connecthead, connectpoint2[MAXMULTIPLAYERS];
|
||||
int connecthead, connectpoint2[MAXPLAYERS];
|
||||
auto vsnprintfptr = vsnprintf; // This is an inline in Visual Studio but we need an address for it to satisfy the MinGW compiled libraries.
|
||||
int lastTic;
|
||||
|
||||
|
@ -134,6 +138,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;
|
||||
|
||||
|
@ -224,14 +229,21 @@ static bool System_DisableTextureFilter()
|
|||
|
||||
static IntRect System_GetSceneRect()
|
||||
{
|
||||
// Special handling so the view with a visible status bar displays properly
|
||||
int height = windowxy2.y - windowxy1.y + 1, width = windowxy2.x - windowxy1.x + 1;
|
||||
int viewbottom = windowxy2.y + 1;
|
||||
int viewheight = viewbottom - windowxy1.y;
|
||||
int viewright = windowxy2.x + 1;
|
||||
int viewwidth = viewright - windowxy1.x;
|
||||
|
||||
int renderheight;
|
||||
|
||||
if (viewheight == screen->GetHeight()) renderheight = viewheight;
|
||||
else renderheight = (viewwidth * screen->GetHeight() / screen->GetWidth()) & ~7;
|
||||
|
||||
IntRect mSceneViewport;
|
||||
mSceneViewport.left = windowxy1.x;
|
||||
mSceneViewport.top = windowxy1.y;
|
||||
mSceneViewport.width = width;
|
||||
mSceneViewport.height = height;
|
||||
mSceneViewport.top = screen->GetHeight() - (renderheight + windowxy1.y - ((renderheight - viewheight) / 2));
|
||||
mSceneViewport.width = viewwidth;
|
||||
mSceneViewport.height = renderheight;
|
||||
return mSceneViewport;
|
||||
}
|
||||
|
||||
|
@ -275,6 +287,11 @@ void System_CrashInfo(char* buffer, size_t bufflen, const char *lfstr)
|
|||
|
||||
UserConfig userConfig;
|
||||
|
||||
DEFINE_GLOBAL(userConfig)
|
||||
DEFINE_FIELD_X(UserConfigStruct, UserConfig, nomonsters)
|
||||
DEFINE_FIELD_X(UserConfigStruct, UserConfig, nosound)
|
||||
DEFINE_FIELD_X(UserConfigStruct, UserConfig, nologo)
|
||||
|
||||
void UserConfig::ProcessOptions()
|
||||
{
|
||||
// -help etc are omitted
|
||||
|
@ -549,7 +566,7 @@ int GameMain()
|
|||
I_ShowFatalError(err.what());
|
||||
r = -1;
|
||||
}
|
||||
DeleteScreenJob();
|
||||
//DeleteScreenJob();
|
||||
DeinitMenus();
|
||||
if (StatusBar) StatusBar->Destroy();
|
||||
StatusBar = nullptr;
|
||||
|
@ -565,12 +582,12 @@ 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();
|
||||
engineUnInit();
|
||||
freeallmodels();
|
||||
if (gi)
|
||||
{
|
||||
delete gi;
|
||||
|
@ -590,13 +607,17 @@ int GameMain()
|
|||
|
||||
void SetDefaultStrings()
|
||||
{
|
||||
// Duke 1.3 does not define its episodes through CON.
|
||||
if ((g_gameType & GAMEFLAG_DUKE) && fileSystem.FindFile("E4L1.MAP") < 0)
|
||||
{
|
||||
auto vol0 = AllocateVolume(); vol0->index = 0;
|
||||
auto vol1 = AllocateVolume(); vol1->index = 1; vol1->flags = VF_SHAREWARELOCK;
|
||||
auto vol2 = AllocateVolume(); vol2->index = 2; vol1->flags = VF_SHAREWARELOCK;
|
||||
// Pre-Atomic releases do not define this.
|
||||
gVolumeNames[0] = "$L.A. Meltdown";
|
||||
gVolumeNames[1] = "$Lunar Apocalypse";
|
||||
gVolumeNames[2] = "$Shrapnel City";
|
||||
if (g_gameType & GAMEFLAG_SHAREWARE) gVolumeNames[3] = "$The Birth";
|
||||
vol0->name = "$L.A. Meltdown";
|
||||
vol1->name = "$Lunar Apocalypse";
|
||||
vol2->name = "$Shrapnel City";
|
||||
|
||||
gSkillNames[0] = "$Piece of Cake";
|
||||
gSkillNames[1] = "$Let's Rock";
|
||||
gSkillNames[2] = "$Come get Some";
|
||||
|
@ -648,13 +669,16 @@ static TArray<GrpEntry> SetupGame()
|
|||
{
|
||||
for (auto& str : game)
|
||||
{
|
||||
int g = 0;
|
||||
for (auto& grp : groups)
|
||||
{
|
||||
if (grp.FileInfo.gameid.CompareNoCase(str) == 0)
|
||||
{
|
||||
userConfig.gamegrp = grp.FileName;
|
||||
groupno = g;
|
||||
goto foundit;
|
||||
}
|
||||
g++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -662,16 +686,18 @@ static TArray<GrpEntry> SetupGame()
|
|||
|
||||
// If the user has specified a file name, let's see if we know it.
|
||||
//
|
||||
if (userConfig.gamegrp.Len())
|
||||
if (groupno == -1 && userConfig.gamegrp.Len())
|
||||
{
|
||||
FString gamegrplower = "/" + userConfig.gamegrp.MakeLower();
|
||||
FString gamegrplower = userConfig.gamegrp.MakeLower();
|
||||
if (gamegrplower[1] != ':' || gamegrplower[2] != '/') gamegrplower.Insert(0, "/");
|
||||
|
||||
int g = 0;
|
||||
for (auto& grp : groups)
|
||||
{
|
||||
auto grplower = grp.FileName.MakeLower();
|
||||
grplower.Substitute("\\", "/");
|
||||
if (grplower.LastIndexOf(gamegrplower) == grplower.Len() - gamegrplower.Len())
|
||||
FixPathSeperator(grplower);
|
||||
int pos = grplower.LastIndexOf(gamegrplower);
|
||||
if (pos >= 0 && pos == grplower.Len() - gamegrplower.Len())
|
||||
{
|
||||
groupno = g;
|
||||
break;
|
||||
|
@ -992,6 +1018,7 @@ int RunGame()
|
|||
LoadScripts();
|
||||
StartScreen->Progress();
|
||||
SetDefaultStrings();
|
||||
Job_Init();
|
||||
if (Args->CheckParm("-sounddebug"))
|
||||
C_DoCommand("stat sounddebug");
|
||||
|
||||
|
@ -999,8 +1026,15 @@ int RunGame()
|
|||
SetupGameButtons();
|
||||
gameinfo.mBackButton = "engine/graphics/m_back.png";
|
||||
StartScreen->Progress();
|
||||
|
||||
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();
|
||||
StartScreen->Progress();
|
||||
G_ParseMapInfo();
|
||||
CreateStatusBar();
|
||||
SetDefaultMenuColors();
|
||||
M_Init();
|
||||
|
@ -1012,9 +1046,24 @@ 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);
|
||||
if (GameStartupInfo.Name.IsNotEmpty()) I_SetWindowTitle(GameStartupInfo.Name);
|
||||
|
||||
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);
|
||||
MainLoop();
|
||||
|
@ -1061,7 +1110,7 @@ void updatePauseStatus()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PolymostProcessVoxels(void);
|
||||
void LoadVoxelModels(void);
|
||||
|
||||
void setVideoMode()
|
||||
{
|
||||
|
@ -1069,25 +1118,6 @@ void setVideoMode()
|
|||
ydim = screen->GetHeight();
|
||||
V_UpdateModeSize(xdim, ydim);
|
||||
videoSetViewableArea(0, 0, xdim - 1, ydim - 1);
|
||||
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);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1378,16 +1408,11 @@ void DrawCrosshair(int deftile, int health, double xdelta, double ydelta, double
|
|||
|
||||
void LoadDefinitions()
|
||||
{
|
||||
cycle_t deftimer;
|
||||
deftimer.Reset();
|
||||
deftimer.Clock();
|
||||
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.
|
||||
loaddefinitionsfile("engine/engine.def"); // Internal stuff that is required.
|
||||
|
||||
// check what we have.
|
||||
// user .defs override the default ones and are not cumulative.
|
||||
|
@ -1395,31 +1420,33 @@ void LoadDefinitions()
|
|||
// otherwise the default rules inherited from older ports apply.
|
||||
if (userConfig.UserDef.IsNotEmpty())
|
||||
{
|
||||
if (!loaddefinitionsfile(userConfig.UserDef, true, false)) loaded = userConfig.UserDef;
|
||||
loaddefinitionsfile(userConfig.UserDef, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fileSystem.FileExists(razedefsfile))
|
||||
{
|
||||
if (!loaddefinitionsfile(razedefsfile, true, true)) loaded = razedefsfile;
|
||||
loaddefinitionsfile(razedefsfile, true);
|
||||
}
|
||||
else
|
||||
else if (fileSystem.FileExists(defsfile))
|
||||
{
|
||||
if (!loaddefinitionsfile(defsfile, true, false)) loaded = defsfile;
|
||||
loaddefinitionsfile(defsfile, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (userConfig.AddDefs)
|
||||
{
|
||||
for (auto& m : *userConfig.AddDefs)
|
||||
{
|
||||
loaddefinitionsfile(m, false);
|
||||
}
|
||||
userConfig.AddDefs.reset();
|
||||
}
|
||||
|
||||
if (GameStartupInfo.def.IsNotEmpty())
|
||||
{
|
||||
loaddefinitionsfile(GameStartupInfo.def, false); // Stuff from gameinfo.
|
||||
loaddefinitionsfile(GameStartupInfo.def); // Stuff from gameinfo.
|
||||
}
|
||||
|
||||
if (loaded)
|
||||
{
|
||||
deftimer.Unclock();
|
||||
DPrintf(DMSG_SPAMMY, "Definitions file \"%s\" loaded, %f ms.\n", loaded, deftimer.TimeMS());
|
||||
}
|
||||
userConfig.AddDefs.reset();
|
||||
|
||||
// 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"))
|
||||
|
@ -1481,13 +1508,69 @@ DEFINE_ACTION_FUNCTION(_Screen, GetViewWindow)
|
|||
return MIN(numret, 4);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Build, ShadeToLight, shadeToLight)
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Raze, ShadeToLight, shadeToLight)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(shade);
|
||||
ACTION_RETURN_INT(shadeToLight(shade));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Raze, StopAllSounds, FX_StopAllSounds)
|
||||
{
|
||||
FX_StopAllSounds();
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Raze, StopMusic, Mus_Stop)
|
||||
{
|
||||
Mus_Stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Raze, SoundEnabled, SoundEnabled)
|
||||
{
|
||||
ACTION_RETURN_INT(SoundEnabled());
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Raze, MusicEnabled, MusicEnabled)
|
||||
{
|
||||
ACTION_RETURN_INT(MusicEnabled());
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Raze, GetTimeFrac, I_GetTimeFrac)
|
||||
{
|
||||
ACTION_RETURN_INT(I_GetTimeFrac());
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_Raze, PlayerName)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(index);
|
||||
ACTION_RETURN_STRING(unsigned(index) >= MAXPLAYERS ? "" : PlayerName(index));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Raze, bsin, bsin)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(v);
|
||||
PARAM_INT(shift);
|
||||
ACTION_RETURN_INT(bsin(v, shift));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Raze, bcos, bcos)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(v);
|
||||
PARAM_INT(shift);
|
||||
ACTION_RETURN_INT(bcos(v, shift));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_MapRecord, GetCluster)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(MapRecord);
|
||||
ACTION_RETURN_POINTER(FindCluster(self->cluster));
|
||||
}
|
||||
|
||||
extern bool demoplayback;
|
||||
DEFINE_GLOBAL(multiplayer)
|
||||
DEFINE_GLOBAL(netgame)
|
||||
|
@ -1495,3 +1578,41 @@ DEFINE_GLOBAL(gameaction)
|
|||
DEFINE_GLOBAL(gamestate)
|
||||
DEFINE_GLOBAL(demoplayback)
|
||||
DEFINE_GLOBAL(consoleplayer)
|
||||
DEFINE_GLOBAL(currentLevel)
|
||||
DEFINE_GLOBAL(paused)
|
||||
|
||||
DEFINE_FIELD_X(ClusterDef, ClusterDef, name)
|
||||
DEFINE_FIELD_X(ClusterDef, ClusterDef, InterBackground)
|
||||
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, parTime)
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, designerTime)
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, fileName)
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, labelName)
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, name)
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, music)
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, cdSongId)
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, flags)
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, levelNumber)
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, cluster)
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, NextMap)
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, NextSecret)
|
||||
//native readonly String messages[MAX_MESSAGES];
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, Author)
|
||||
DEFINE_FIELD_X(MapRecord, MapRecord, InterBackground)
|
||||
|
||||
DEFINE_FIELD_X(SummaryInfo, SummaryInfo, kills)
|
||||
DEFINE_FIELD_X(SummaryInfo, SummaryInfo, maxkills)
|
||||
DEFINE_FIELD_X(SummaryInfo, SummaryInfo, secrets)
|
||||
DEFINE_FIELD_X(SummaryInfo, SummaryInfo, maxsecrets)
|
||||
DEFINE_FIELD_X(SummaryInfo, SummaryInfo, supersecrets)
|
||||
DEFINE_FIELD_X(SummaryInfo, SummaryInfo, playercount)
|
||||
DEFINE_FIELD_X(SummaryInfo, SummaryInfo, time)
|
||||
DEFINE_FIELD_X(SummaryInfo, SummaryInfo, cheated)
|
||||
DEFINE_FIELD_X(SummaryInfo, SummaryInfo, endofgame)
|
||||
|
||||
|
||||
void InitBuildTiles()
|
||||
{
|
||||
// need to find a better way to handle this thing.
|
||||
}
|
||||
|
||||
|
|
|
@ -70,12 +70,12 @@ extern UserConfig userConfig;
|
|||
|
||||
extern int nomusic;
|
||||
extern bool nosound;
|
||||
inline bool MusicEnabled()
|
||||
inline int MusicEnabled() // int return is for scripting
|
||||
{
|
||||
return mus_enabled && !nomusic;
|
||||
}
|
||||
|
||||
inline bool SoundEnabled()
|
||||
inline int SoundEnabled()
|
||||
{
|
||||
return snd_enabled && !nosound;
|
||||
}
|
||||
|
@ -99,8 +99,15 @@ enum
|
|||
GAMEFLAG_POWERSLAVE = 0x00002000,
|
||||
GAMEFLAG_EXHUMED = 0x00004000,
|
||||
GAMEFLAG_PSEXHUMED = GAMEFLAG_POWERSLAVE | GAMEFLAG_EXHUMED, // the two games really are the same, except for the name and the publisher.
|
||||
GAMEFLAG_WORLDTOUR = 0x00008000,
|
||||
GAMEFLAG_DUKEDC = 0x00010000,
|
||||
GAMEFLAG_WORLDTOUR = 0x00008000,
|
||||
GAMEFLAG_DUKEDC = 0x00010000,
|
||||
GAMEFLAG_DUKENW = 0x00020000,
|
||||
GAMEFLAG_DUKEVACA = 0x00040000,
|
||||
GAMEFLAG_BLOODCP = 0x00080000,
|
||||
GAMEFLAG_ROUTE66 = 0x00100000,
|
||||
GAMEFLAG_SWWANTON = 0x00200000,
|
||||
GAMEFLAG_SWTWINDRAG = 0x00400000,
|
||||
|
||||
GAMEFLAG_DUKECOMPAT = GAMEFLAG_DUKE | GAMEFLAG_NAM | GAMEFLAG_NAPALM | GAMEFLAG_WW2GI | GAMEFLAG_RRALL,
|
||||
GAMEFLAGMASK = 0x0000FFFF, // flags allowed from grpinfo
|
||||
|
||||
|
@ -160,6 +167,11 @@ inline bool isWW2GI()
|
|||
return g_gameType & (GAMEFLAG_WW2GI);
|
||||
}
|
||||
|
||||
inline bool isDuke()
|
||||
{
|
||||
return g_gameType & (GAMEFLAG_DUKE);
|
||||
}
|
||||
|
||||
inline bool isRR()
|
||||
{
|
||||
return g_gameType & (GAMEFLAG_RRALL);
|
||||
|
@ -195,7 +207,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
|
||||
|
|
|
@ -81,6 +81,7 @@ CVARD(Bool, cl_smoothsway, false, CVAR_ARCHIVE, "move SW weapon left and right s
|
|||
CVARD(Bool, cl_showmagamt, false, CVAR_ARCHIVE, "show the amount of rounds left in the magazine of your weapon on the modern HUD")
|
||||
CVARD(Bool, cl_nomeleeblur, false, CVAR_ARCHIVE, "enable/disable blur effect with melee weapons in SW")
|
||||
CVARD(Bool, cl_exhumedoldturn, false, CVAR_ARCHIVE, "enable/disable legacy turning speed for Powerslave/Exhumed")
|
||||
CVARD(Bool, cl_hudinterpolation, true, CVAR_ARCHIVE, "enable/disable HUD (weapon drawer) interpolation")
|
||||
|
||||
|
||||
CUSTOM_CVARD(Int, cl_autoaim, 1, CVAR_ARCHIVE|CVAR_USERINFO, "enable/disable weapon autoaim")
|
||||
|
|
|
@ -26,6 +26,7 @@ EXTERN_CVAR(Bool, cl_smoothsway)
|
|||
EXTERN_CVAR(Bool, cl_showmagamt)
|
||||
EXTERN_CVAR(Bool, cl_nomeleeblur)
|
||||
EXTERN_CVAR(Bool, cl_exhumedoldturn)
|
||||
EXTERN_CVAR(Bool, cl_hudinterpolation)
|
||||
|
||||
EXTERN_CVAR(Bool, demorec_seeds_cvar)
|
||||
EXTERN_CVAR(Bool, demoplay_diffs)
|
||||
|
|
|
@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
|
||||
#include "gamefuncs.h"
|
||||
#include "gamestruct.h"
|
||||
#include "intvec.h"
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -146,3 +147,180 @@ bool calcChaseCamPos(int* px, int* py, int* pz, spritetype* pspr, short *psectnu
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// note that this returns values in renderer coordinate space with inverted sign!
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PlanesAtPoint(const sectortype* sec, float dax, float day, float* pceilz, float* pflorz)
|
||||
{
|
||||
float ceilz = float(sec->ceilingz);
|
||||
float florz = float(sec->floorz);
|
||||
|
||||
if (((sec->ceilingstat | sec->floorstat) & CSTAT_SECTOR_SLOPE) == CSTAT_SECTOR_SLOPE)
|
||||
{
|
||||
auto wal = &wall[sec->wallptr];
|
||||
auto wal2 = &wall[wal->point2];
|
||||
|
||||
float dx = wal2->x - wal->x;
|
||||
float dy = wal2->y - wal->y;
|
||||
|
||||
int i = (int)sqrt(dx * dx + dy * dy) << 5; // length of sector's first wall.
|
||||
if (i != 0)
|
||||
{
|
||||
float const j = (dx * (day - wal->y) - dy * (dax - wal->x)) * (1.f / 8.f);
|
||||
if (sec->ceilingstat & CSTAT_SECTOR_SLOPE) ceilz += (sec->ceilingheinum * j) / i;
|
||||
if (sec->floorstat & CSTAT_SECTOR_SLOPE) florz += (sec->floorheinum * j) / i;
|
||||
}
|
||||
}
|
||||
// Scale to render coordinates.
|
||||
if (pceilz) *pceilz = ceilz * -(1.f / 256.f);
|
||||
if (pflorz) *pflorz = florz * -(1.f / 256.f);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Calculate the position of a wall sprite in the world
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GetWallSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool render)
|
||||
{
|
||||
auto tex = tileGetTexture(spr->picnum);
|
||||
|
||||
int width, leftofs;
|
||||
if (render && hw_hightile && TileFiles.tiledata[spr->picnum].hiofs.xsize)
|
||||
{
|
||||
width = TileFiles.tiledata[spr->picnum].hiofs.xsize;
|
||||
leftofs = (TileFiles.tiledata[spr->picnum].hiofs.xoffs + spr->xoffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
width = (int)tex->GetDisplayWidth();
|
||||
leftofs = ((int)tex->GetDisplayLeftOffset() + spr->xoffset);
|
||||
}
|
||||
|
||||
int x = bsin(spr->ang) * spr->xrepeat;
|
||||
int y = -bcos(spr->ang) * spr->xrepeat;
|
||||
|
||||
int xoff = leftofs;
|
||||
if (spr->cstat & CSTAT_SPRITE_XFLIP) xoff = -xoff;
|
||||
int origin = (width >> 1) + xoff;
|
||||
|
||||
out[0].x = pos.x - MulScale(x, origin, 16);
|
||||
out[0].y = pos.y - MulScale(y, origin, 16);
|
||||
out[1].x = out[0].x + MulScale(x, width, 16);
|
||||
out[1].y = out[0].y + MulScale(y, width, 16);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Calculate the position of a wall sprite in the world
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GetFlatSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool render)
|
||||
{
|
||||
auto tex = tileGetTexture(spr->picnum);
|
||||
|
||||
int width, height, leftofs, topofs;
|
||||
if (render && hw_hightile && TileFiles.tiledata[spr->picnum].hiofs.xsize)
|
||||
{
|
||||
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
|
||||
{
|
||||
width = (int)tex->GetDisplayWidth() * spr->xrepeat;
|
||||
height = (int)tex->GetDisplayHeight() * spr->yrepeat;
|
||||
leftofs = ((int)tex->GetDisplayLeftOffset() + spr->xoffset) * spr->xrepeat;
|
||||
topofs = ((int)tex->GetDisplayTopOffset() + spr->yoffset) * spr->yrepeat;
|
||||
}
|
||||
|
||||
if (spr->cstat & CSTAT_SPRITE_XFLIP) leftofs = -leftofs;
|
||||
if (spr->cstat & CSTAT_SPRITE_YFLIP) topofs = -topofs;
|
||||
|
||||
int sprcenterx = (width >> 1) + leftofs;
|
||||
int sprcentery = (height >> 1) + topofs;
|
||||
|
||||
int cosang = bcos(spr->ang);
|
||||
int sinang = bsin(spr->ang);
|
||||
|
||||
out[0].x = pos.x + DMulScale(sinang, sprcenterx, cosang, sprcentery, 16);
|
||||
out[0].y = pos.y + DMulScale(sinang, sprcentery, -cosang, sprcenterx, 16);
|
||||
|
||||
out[1].x = out[0].x - MulScale(sinang, width, 16);
|
||||
out[1].y = out[0].y + MulScale(cosang, width, 16);
|
||||
|
||||
vec2_t sub = { MulScale(cosang, height, 16), MulScale(sinang, height, 16) };
|
||||
out[2] = out[1] - sub;
|
||||
out[3] = out[0] - sub;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Check if some walls are set to use rotated textures.
|
||||
// Ideally this should just have been done with texture rotation,
|
||||
// but the effects on the render code would be too severe due to the alignment mess.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void checkRotatedWalls()
|
||||
{
|
||||
for (int i = 0; i < numwalls; ++i)
|
||||
{
|
||||
if (wall[i].cstat & CSTAT_WALL_ROTATE_90)
|
||||
{
|
||||
auto& w = wall[i];
|
||||
auto& tile = RotTile(w.picnum + animateoffs(w.picnum, 16384));
|
||||
|
||||
if (tile.newtile == -1 && tile.owner == -1)
|
||||
{
|
||||
auto owner = w.picnum + animateoffs(w.picnum, 16384);
|
||||
|
||||
tile.newtile = TileFiles.tileCreateRotated(owner);
|
||||
assert(tile.newtile != -1);
|
||||
|
||||
RotTile(tile.newtile).owner = w.picnum + animateoffs(w.picnum, 16384);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// vector serializers
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FSerializer& Serialize(FSerializer& arc, const char* key, vec2_t& c, vec2_t* def)
|
||||
{
|
||||
if (def && !memcmp(&c, def, sizeof(c))) return arc;
|
||||
if (arc.BeginObject(key))
|
||||
{
|
||||
arc("x", c.x, def ? &def->x : nullptr)
|
||||
("y", c.y, def ? &def->y : nullptr)
|
||||
.EndObject();
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
|
||||
FSerializer& Serialize(FSerializer& arc, const char* key, vec3_t& c, vec3_t* def)
|
||||
{
|
||||
if (def && !memcmp(&c, def, sizeof(c))) return arc;
|
||||
if (arc.BeginObject(key))
|
||||
{
|
||||
arc("x", c.x, def ? &def->x : nullptr)
|
||||
("y", c.y, def ? &def->y : nullptr)
|
||||
("z", c.z, def ? &def->z : nullptr)
|
||||
.EndObject();
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,121 @@
|
|||
#pragma once
|
||||
|
||||
#include "gamecontrol.h"
|
||||
#include "buildtypes.h"
|
||||
#include "binaryangle.h"
|
||||
#include "build.h"
|
||||
|
||||
extern int cameradist, cameraclock;
|
||||
|
||||
bool calcChaseCamPos(int* px, int* py, int* pz, spritetype* pspr, short *psectnum, binangle ang, fixedhoriz horiz, double const smoothratio);
|
||||
void loaddefinitionsfile(const char* fn, bool cumulative = false);
|
||||
|
||||
bool calcChaseCamPos(int* px, int* py, int* pz, spritetype* pspr, short *psectnum, binangle ang, fixedhoriz horiz, double const smoothratio);
|
||||
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);
|
||||
void GetFlatSpritePosition(const spritetype* spr, vec2_t pos, vec2_t* out, bool render = false);
|
||||
void checkRotatedWalls();
|
||||
|
||||
// y is negated so that the orientation is the same as in GZDoom, in order to use its utilities.
|
||||
// The render code should NOT use Build coordinates for anything!
|
||||
|
||||
inline double WallStartX(int wallnum)
|
||||
{
|
||||
return wall[wallnum].x * (1 / 16.);
|
||||
}
|
||||
|
||||
inline double WallStartY(int wallnum)
|
||||
{
|
||||
return wall[wallnum].y * (1 / -16.);
|
||||
}
|
||||
|
||||
inline double WallEndX(int wallnum)
|
||||
{
|
||||
return wall[wall[wallnum].point2].x * (1 / 16.);
|
||||
}
|
||||
|
||||
inline double WallEndY(int wallnum)
|
||||
{
|
||||
return wall[wall[wallnum].point2].y * (1 / -16.);
|
||||
}
|
||||
|
||||
inline double WallStartX(const walltype* wallnum)
|
||||
{
|
||||
return wallnum->x * (1 / 16.);
|
||||
}
|
||||
|
||||
inline double WallStartY(const walltype* wallnum)
|
||||
{
|
||||
return wallnum->y * (1 / -16.);
|
||||
}
|
||||
|
||||
inline DVector2 WallStart(const walltype* wallnum)
|
||||
{
|
||||
return { WallStartX(wallnum), WallStartY(wallnum) };
|
||||
}
|
||||
|
||||
inline double WallEndX(const walltype* wallnum)
|
||||
{
|
||||
return wall[wallnum->point2].x * (1 / 16.);
|
||||
}
|
||||
|
||||
inline double WallEndY(const walltype* wallnum)
|
||||
{
|
||||
return wall[wallnum->point2].y * (1 / -16.);
|
||||
}
|
||||
|
||||
inline DVector2 WallEnd(const walltype* wallnum)
|
||||
{
|
||||
return { WallEndX(wallnum), WallEndY(wallnum) };
|
||||
}
|
||||
|
||||
inline DVector2 WallDelta(const walltype* wallnum)
|
||||
{
|
||||
return WallEnd(wallnum) - WallStart(wallnum);
|
||||
}
|
||||
|
||||
inline double SpriteX(int wallnum)
|
||||
{
|
||||
return sprite[wallnum].x * (1 / 16.);
|
||||
}
|
||||
|
||||
inline double SpriteY(int wallnum)
|
||||
{
|
||||
return sprite[wallnum].y * (1 / -16.);
|
||||
}
|
||||
|
||||
inline double PointOnLineSide(double x, double y, double linex, double liney, double deltax, double deltay)
|
||||
{
|
||||
return (x - linex) * deltay - (y - liney) * deltax;
|
||||
}
|
||||
|
||||
inline double PointOnLineSide(const DVector2 &pos, const walltype *line)
|
||||
{
|
||||
return (pos.X - WallStartX(line)) * WallDelta(line).Y - (pos.Y - WallStartY(line)) * WallDelta(line).X;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline double PointOnLineSide(const TVector2<T>& pos, const TVector2<T>& linestart, const TVector2<T>& lineend)
|
||||
{
|
||||
return (pos.X - linestart.X) * (lineend.Y - linestart.Y) - (pos.Y - linestart.Y) * (lineend.X - linestart.X);
|
||||
}
|
||||
|
||||
inline int sectorofwall(int wallNum)
|
||||
{
|
||||
if ((unsigned)wallNum < (unsigned)numwalls) return wall[wallNum].sector;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern int numshades;
|
||||
|
||||
// Return type is int because this gets passed to variadic functions where structs may produce undefined behavior.
|
||||
inline int shadeToLight(int shade)
|
||||
{
|
||||
shade = clamp(shade, 0, numshades - 1);
|
||||
int light = Scale(numshades - 1 - shade, 255, numshades - 1);
|
||||
return PalEntry(255, light, light, light);
|
||||
}
|
||||
|
||||
inline void copyfloorpal(spritetype* spr, const sectortype* sect)
|
||||
{
|
||||
if (!lookups.noFloorPal(sect->floorpal)) spr->pal = sect->floorpal;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "v_draw.h"
|
||||
#include "v_font.h"
|
||||
#include "gamestruct.h"
|
||||
#include "gamefuncs.h"
|
||||
|
||||
F2DDrawer twodpsp;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "gameinput.h"
|
||||
#include "gamestruct.h"
|
||||
#include "serializer.h"
|
||||
#include "build.h"
|
||||
|
||||
CVARD(Bool, invertmousex, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "invert horizontal mouse movement")
|
||||
CVARD(Bool, invertmouse, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "invert vertical mouse movement")
|
||||
|
@ -49,46 +50,18 @@ int getincangle(int a, int na)
|
|||
return na-a;
|
||||
}
|
||||
|
||||
double getincanglef(double a, double na)
|
||||
binangle getincanglebam(binangle a, binangle na)
|
||||
{
|
||||
a = fmod(a, 2048.);
|
||||
na = fmod(na, 2048.);
|
||||
int64_t cura = a.asbam();
|
||||
int64_t newa = na.asbam();
|
||||
|
||||
if(fabs(a-na) >= 1024)
|
||||
if(abs(cura-newa) > INT32_MAX)
|
||||
{
|
||||
if(na > 1024) na -= 2048;
|
||||
if(a > 1024) a -= 2048;
|
||||
if(newa > INT32_MAX) newa -= UINT32_MAX;
|
||||
if(cura > INT32_MAX) cura -= UINT32_MAX;
|
||||
}
|
||||
|
||||
return na-a;
|
||||
}
|
||||
|
||||
fixed_t getincangleq16(fixed_t a, fixed_t na)
|
||||
{
|
||||
a &= 0x7FFFFFF;
|
||||
na &= 0x7FFFFFF;
|
||||
|
||||
if(abs(a-na) >= IntToFixed(1024))
|
||||
{
|
||||
if(na > IntToFixed(1024)) na -= IntToFixed(2048);
|
||||
if(a > IntToFixed(1024)) a -= IntToFixed(2048);
|
||||
}
|
||||
|
||||
return na-a;
|
||||
}
|
||||
|
||||
lookangle getincanglebam(binangle a, binangle na)
|
||||
{
|
||||
int64_t cura = a.asbam() & 0xFFFFFFFF;
|
||||
int64_t newa = na.asbam() & 0xFFFFFFFF;
|
||||
|
||||
if(abs(cura-newa) >= BAngToBAM(1024))
|
||||
{
|
||||
if(newa > BAngToBAM(1024)) newa -= BAngToBAM(2048);
|
||||
if(cura > BAngToBAM(1024)) cura -= BAngToBAM(2048);
|
||||
}
|
||||
|
||||
return bamlook(newa-cura);
|
||||
return bamang(newa-cura);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -271,13 +244,13 @@ void processMovement(InputPacket* currInput, InputPacket* inputBuffer, ControlIn
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void sethorizon(PlayerHorizon* horizon, float const horz, ESyncBits* actions, double const scaleAdjust)
|
||||
void PlayerHorizon::applyinput(float const horz, ESyncBits* actions, double const scaleAdjust)
|
||||
{
|
||||
// Process only if no targeted horizon set.
|
||||
if (!horizon->targetset())
|
||||
if (!targetset())
|
||||
{
|
||||
// Store current horizon as true pitch.
|
||||
double pitch = horizon->horiz.aspitch();
|
||||
double pitch = horiz.aspitch();
|
||||
|
||||
if (horz)
|
||||
{
|
||||
|
@ -312,20 +285,17 @@ void sethorizon(PlayerHorizon* horizon, float const horz, ESyncBits* actions, do
|
|||
}
|
||||
|
||||
// clamp before converting back to horizon
|
||||
horizon->horiz = q16horiz(clamp(PitchToHoriz(pitch), gi->playerHorizMin(), gi->playerHorizMax()));
|
||||
horiz = q16horiz(clamp(PitchToHoriz(pitch), gi->playerHorizMin(), gi->playerHorizMax()));
|
||||
|
||||
// return to center if conditions met.
|
||||
if ((*actions & SB_CENTERVIEW) && !(*actions & (SB_LOOK_UP|SB_LOOK_DOWN)))
|
||||
if ((*actions & SB_CENTERVIEW) && !(*actions & (SB_LOOK_UP|SB_LOOK_DOWN)) && horiz.asq16())
|
||||
{
|
||||
if (abs(horizon->horiz.asq16()) > FloatToFixed(0.25))
|
||||
{
|
||||
// move horiz back to 0
|
||||
horizon->horiz -= q16horiz(xs_CRoundToInt(scaleAdjust * horizon->horiz.asq16() * (10. / GameTicRate)));
|
||||
}
|
||||
else
|
||||
// move horiz back to 0
|
||||
horiz -= buildfhoriz(scaleAdjust * horiz.asbuildf() * (10. / GameTicRate));
|
||||
if (abs(horiz.asq16()) < (FRACUNIT >> 2))
|
||||
{
|
||||
// not looking anymore because horiz is back at 0
|
||||
horizon->horiz = q16horiz(0);
|
||||
horiz = q16horiz(0);
|
||||
*actions &= ~SB_CENTERVIEW;
|
||||
}
|
||||
}
|
||||
|
@ -342,66 +312,72 @@ void sethorizon(PlayerHorizon* horizon, float const horz, ESyncBits* actions, do
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void applylook(PlayerAngle* angle, float const avel, ESyncBits* actions, double const scaleAdjust)
|
||||
void PlayerAngle::applyinput(float const avel, ESyncBits* actions, double const scaleAdjust)
|
||||
{
|
||||
// return q16rotscrnang to 0 and set to 0 if less than a quarter of a unit
|
||||
angle->rotscrnang -= bamlook(xs_CRoundToInt(scaleAdjust * angle->rotscrnang.asbam() * (15. / GameTicRate)));
|
||||
if (abs(angle->rotscrnang.asbam()) < (BAMUNIT >> 2)) angle->rotscrnang = bamlook(0);
|
||||
if (rotscrnang.asbam())
|
||||
{
|
||||
// return rotscrnang to 0
|
||||
rotscrnang -= buildfang(scaleAdjust * rotscrnang.signedbuildf() * (15. / GameTicRate));
|
||||
if (abs(rotscrnang.signedbam()) < (BAMUNIT >> 2)) rotscrnang = bamang(0);
|
||||
}
|
||||
|
||||
// return q16look_ang to 0 and set to 0 if less than a quarter of a unit
|
||||
angle->look_ang -= bamlook(xs_CRoundToInt(scaleAdjust * angle->look_ang.asbam() * (7.5 / GameTicRate)));
|
||||
if (abs(angle->look_ang.asbam()) < (BAMUNIT >> 2)) angle->look_ang = bamlook(0);
|
||||
if (look_ang.asbam())
|
||||
{
|
||||
// return look_ang to 0
|
||||
look_ang -= buildfang(scaleAdjust * look_ang.signedbuildf() * (7.5 / GameTicRate));
|
||||
if (abs(look_ang.signedbam()) < (BAMUNIT >> 2)) look_ang = bamang(0);
|
||||
}
|
||||
|
||||
if (*actions & SB_LOOK_LEFT)
|
||||
{
|
||||
// start looking left
|
||||
angle->look_ang -= bamlook(xs_CRoundToInt(scaleAdjust * (4560. / GameTicRate) * BAMUNIT));
|
||||
angle->rotscrnang += bamlook(xs_CRoundToInt(scaleAdjust * (720. / GameTicRate) * BAMUNIT));
|
||||
look_ang += buildfang(scaleAdjust * -(4560. / GameTicRate));
|
||||
rotscrnang += buildfang(scaleAdjust * (720. / GameTicRate));
|
||||
}
|
||||
|
||||
if (*actions & SB_LOOK_RIGHT)
|
||||
{
|
||||
// start looking right
|
||||
angle->look_ang += bamlook(xs_CRoundToInt(scaleAdjust * (4560. / GameTicRate) * BAMUNIT));
|
||||
angle->rotscrnang -= bamlook(xs_CRoundToInt(scaleAdjust * (720. / GameTicRate) * BAMUNIT));
|
||||
look_ang += buildfang(scaleAdjust * (4560. / GameTicRate));
|
||||
rotscrnang += buildfang(scaleAdjust * -(720. / GameTicRate));
|
||||
}
|
||||
|
||||
if (!angle->targetset())
|
||||
if (!targetset())
|
||||
{
|
||||
if (*actions & SB_TURNAROUND)
|
||||
{
|
||||
if (angle->spin.asbam() == 0)
|
||||
if (spin == 0)
|
||||
{
|
||||
// currently not spinning, so start a spin
|
||||
angle->spin = buildlook(-1024);
|
||||
spin = -1024.;
|
||||
}
|
||||
*actions &= ~SB_TURNAROUND;
|
||||
}
|
||||
|
||||
if (angle->spin.asbam() < 0)
|
||||
{
|
||||
// return spin to 0
|
||||
lookangle add = bamlook(xs_CRoundToUInt(scaleAdjust * ((!(*actions & SB_CROUCH) ? 3840. : 1920.) / GameTicRate) * BAMUNIT));
|
||||
angle->spin += add;
|
||||
if (angle->spin.asbam() > 0)
|
||||
{
|
||||
// Don't overshoot our target. With variable factor this is possible.
|
||||
add -= angle->spin;
|
||||
angle->spin = bamlook(0);
|
||||
}
|
||||
angle->ang += bamang(add.asbam());
|
||||
}
|
||||
|
||||
if (avel)
|
||||
{
|
||||
// add player's input
|
||||
angle->ang += degang(avel);
|
||||
angle->spin = bamlook(0);
|
||||
ang += degang(avel);
|
||||
spin = 0;
|
||||
}
|
||||
|
||||
if (spin < 0)
|
||||
{
|
||||
// return spin to 0
|
||||
double add = scaleAdjust * ((!(*actions & SB_CROUCH) ? 3840. : 1920.) / GameTicRate);
|
||||
spin += add;
|
||||
if (spin > 0)
|
||||
{
|
||||
// Don't overshoot our target. With variable factor this is possible.
|
||||
add -= spin;
|
||||
spin = 0;
|
||||
}
|
||||
ang += buildfang(add);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
angle->spin = bamlook(0);
|
||||
spin = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -411,7 +387,7 @@ void applylook(PlayerAngle* angle, float const avel, ESyncBits* actions, double
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void calcviewpitch(vec2_t const pos, fixedhoriz* horizoff, binangle const ang, bool const aimmode, bool const canslopetilt, int const cursectnum, double const scaleAdjust, bool const climbing)
|
||||
void PlayerHorizon::calcviewpitch(vec2_t const pos, binangle const ang, bool const aimmode, bool const canslopetilt, int const cursectnum, double const scaleAdjust, bool const climbing)
|
||||
{
|
||||
if (cl_slopetilting)
|
||||
{
|
||||
|
@ -438,7 +414,7 @@ void calcviewpitch(vec2_t const pos, fixedhoriz* horizoff, binangle const ang, b
|
|||
// accordingly
|
||||
if (cursectnum == tempsect || (!isBlood() && abs(getflorzofslope(tempsect, x, y) - k) <= (4 << 8)))
|
||||
{
|
||||
*horizoff += q16horiz(xs_CRoundToInt(scaleAdjust * ((j - k) * (!isBlood() ? 160 : 1408))));
|
||||
horizoff += q16horiz(xs_CRoundToInt(scaleAdjust * ((j - k) * (!isBlood() ? 160 : 1408))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -446,21 +422,21 @@ void calcviewpitch(vec2_t const pos, fixedhoriz* horizoff, binangle const ang, b
|
|||
if (climbing)
|
||||
{
|
||||
// tilt when climbing but you can't even really tell it.
|
||||
if (horizoff->asq16() < IntToFixed(100))
|
||||
*horizoff += q16horiz(xs_CRoundToInt(scaleAdjust * (((IntToFixed(100) - horizoff->asq16()) >> 3) + FRACUNIT)));
|
||||
if (horizoff.asq16() < IntToFixed(100))
|
||||
horizoff += q16horiz(xs_CRoundToInt(scaleAdjust * (((IntToFixed(100) - horizoff.asq16()) >> 3) + FRACUNIT)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make horizoff grow towards 0 since horizoff is not modified when you're not on a slope.
|
||||
if (horizoff->asq16() > 0)
|
||||
if (horizoff.asq16() > 0)
|
||||
{
|
||||
*horizoff += q16horiz(xs_CRoundToInt(-scaleAdjust * ((horizoff->asq16() >> 3) + FRACUNIT)));
|
||||
if (horizoff->asq16() < 0) *horizoff = q16horiz(0);
|
||||
horizoff += q16horiz(xs_CRoundToInt(-scaleAdjust * ((horizoff.asq16() >> 3) + FRACUNIT)));
|
||||
if (horizoff.asq16() < 0) horizoff = q16horiz(0);
|
||||
}
|
||||
if (horizoff->asq16() < 0)
|
||||
if (horizoff.asq16() < 0)
|
||||
{
|
||||
*horizoff += q16horiz(xs_CRoundToInt(-scaleAdjust * ((horizoff->asq16() >> 3) - FRACUNIT)));
|
||||
if (horizoff->asq16() > 0) *horizoff = q16horiz(0);
|
||||
horizoff += q16horiz(xs_CRoundToInt(-scaleAdjust * ((horizoff.asq16() >> 3) - FRACUNIT)));
|
||||
if (horizoff.asq16() > 0) horizoff = q16horiz(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
#include "packet.h"
|
||||
|
||||
int getincangle(int a, int na);
|
||||
double getincanglef(double a, double na);
|
||||
fixed_t getincangleq16(fixed_t a, fixed_t na);
|
||||
lookangle getincanglebam(binangle a, binangle na);
|
||||
binangle getincanglebam(binangle a, binangle na);
|
||||
|
||||
struct PlayerHorizon
|
||||
{
|
||||
|
@ -29,7 +27,12 @@ struct PlayerHorizon
|
|||
|
||||
void addadjustment(double value)
|
||||
{
|
||||
__addadjustment(q16horiz(FloatToFixed(value)));
|
||||
__addadjustment(buildfhoriz(value));
|
||||
}
|
||||
|
||||
void addadjustment(fixedhoriz value)
|
||||
{
|
||||
__addadjustment(value);
|
||||
}
|
||||
|
||||
void resetadjustment()
|
||||
|
@ -37,19 +40,14 @@ struct PlayerHorizon
|
|||
adjustment = 0;
|
||||
}
|
||||
|
||||
void settarget(int value, bool backup = false)
|
||||
{
|
||||
__settarget(buildhoriz(clamp(value, FixedToInt(gi->playerHorizMin()), FixedToInt(gi->playerHorizMax()))), backup);
|
||||
}
|
||||
|
||||
void settarget(double value, bool backup = false)
|
||||
{
|
||||
__settarget(buildfhoriz(clamp(value, FixedToFloat(gi->playerHorizMin()), FixedToFloat(gi->playerHorizMax()))), backup);
|
||||
__settarget(buildfhoriz(value), backup);
|
||||
}
|
||||
|
||||
void settarget(fixedhoriz value, bool backup = false)
|
||||
{
|
||||
__settarget(q16horiz(clamp(value.asq16(), gi->playerHorizMin(), gi->playerHorizMax())), backup);
|
||||
__settarget(value, backup);
|
||||
}
|
||||
|
||||
bool targetset()
|
||||
|
@ -61,11 +59,11 @@ struct PlayerHorizon
|
|||
{
|
||||
if (targetset())
|
||||
{
|
||||
auto delta = (target - horiz).asq16();
|
||||
auto delta = (target - horiz).asbuildf();
|
||||
|
||||
if (abs(delta) > FRACUNIT)
|
||||
if (abs(delta) > 1)
|
||||
{
|
||||
horiz += q16horiz(xs_CRoundToInt(scaleAdjust * delta));
|
||||
horiz += buildfhoriz(scaleAdjust * delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -75,7 +73,7 @@ struct PlayerHorizon
|
|||
}
|
||||
else if (adjustment)
|
||||
{
|
||||
horiz += q16horiz(xs_CRoundToInt(scaleAdjust * adjustment));
|
||||
horiz += buildfhoriz(scaleAdjust * adjustment);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,12 +89,17 @@ struct PlayerHorizon
|
|||
|
||||
fixedhoriz interpolatedsum(double const smoothratio)
|
||||
{
|
||||
double const ratio = smoothratio * (1. / FRACUNIT);
|
||||
fixed_t const prev = osum().asq16();
|
||||
fixed_t const curr = sum().asq16();
|
||||
return q16horiz(prev + xs_CRoundToInt(ratio * (curr - prev)));
|
||||
return q16horiz(interpolatedvalue(osum().asq16(), sum().asq16(), smoothratio));
|
||||
}
|
||||
|
||||
double horizsumfrac(double const smoothratio)
|
||||
{
|
||||
return (!SyncInput() ? sum() : interpolatedsum(smoothratio)).asbuildf() * (1. / 16.); // Used within draw code for Duke.
|
||||
}
|
||||
|
||||
void applyinput(float const horz, ESyncBits* actions, double const scaleAdjust = 1);
|
||||
void calcviewpitch(vec2_t const pos, binangle const ang, bool const aimmode, bool const canslopetilt, int const cursectnum, double const scaleAdjust = 1, bool const climbing = false);
|
||||
|
||||
private:
|
||||
fixedhoriz target;
|
||||
double adjustment;
|
||||
|
@ -105,7 +108,7 @@ private:
|
|||
{
|
||||
if (!SyncInput())
|
||||
{
|
||||
adjustment += value.asq16();
|
||||
adjustment += value.asbuildf();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -113,8 +116,10 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void __settarget(fixedhoriz value, bool backup = false)
|
||||
void __settarget(fixedhoriz value, bool backup)
|
||||
{
|
||||
value = q16horiz(clamp(value.asq16(), gi->playerHorizMin(), gi->playerHorizMax()));
|
||||
|
||||
if (!SyncInput() && !backup)
|
||||
{
|
||||
target = value;
|
||||
|
@ -130,8 +135,8 @@ private:
|
|||
|
||||
struct PlayerAngle
|
||||
{
|
||||
binangle ang, oang;
|
||||
lookangle look_ang, olook_ang, rotscrnang, orotscrnang, spin;
|
||||
binangle ang, oang, look_ang, olook_ang, rotscrnang, orotscrnang;
|
||||
double spin;
|
||||
|
||||
void backup()
|
||||
{
|
||||
|
@ -147,24 +152,14 @@ struct PlayerAngle
|
|||
rotscrnang = orotscrnang;
|
||||
}
|
||||
|
||||
void addadjustment(int value)
|
||||
{
|
||||
__addadjustment(buildlook(value));
|
||||
}
|
||||
|
||||
void addadjustment(double value)
|
||||
{
|
||||
__addadjustment(buildflook(value));
|
||||
}
|
||||
|
||||
void addadjustment(lookangle value)
|
||||
{
|
||||
__addadjustment(value);
|
||||
__addadjustment(buildfang(value));
|
||||
}
|
||||
|
||||
void addadjustment(binangle value)
|
||||
{
|
||||
__addadjustment(bamlook(value.asbam()));
|
||||
__addadjustment(value);
|
||||
}
|
||||
|
||||
void resetadjustment()
|
||||
|
@ -172,14 +167,9 @@ struct PlayerAngle
|
|||
adjustment = 0;
|
||||
}
|
||||
|
||||
void settarget(int value, bool backup = false)
|
||||
{
|
||||
__settarget(buildang(value & 2047), backup);
|
||||
}
|
||||
|
||||
void settarget(double value, bool backup = false)
|
||||
{
|
||||
__settarget(buildfang(fmod(value, 2048)), backup);
|
||||
__settarget(buildfang(value), backup);
|
||||
}
|
||||
|
||||
void settarget(binangle value, bool backup = false)
|
||||
|
@ -196,11 +186,11 @@ struct PlayerAngle
|
|||
{
|
||||
if (targetset())
|
||||
{
|
||||
auto delta = getincanglebam(ang, target).asbam();
|
||||
auto delta = getincanglebam(ang, target).signedbuildf();
|
||||
|
||||
if (delta > BAMUNIT)
|
||||
if (abs(delta) > 1)
|
||||
{
|
||||
ang += bamang(xs_CRoundToUInt(scaleAdjust * delta));
|
||||
ang += buildfang(scaleAdjust * delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -210,7 +200,7 @@ struct PlayerAngle
|
|||
}
|
||||
else if (adjustment)
|
||||
{
|
||||
ang += bamang(xs_CRoundToUInt(scaleAdjust * adjustment));
|
||||
ang += buildfang(scaleAdjust * adjustment);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,39 +216,40 @@ struct PlayerAngle
|
|||
|
||||
binangle interpolatedsum(double const smoothratio)
|
||||
{
|
||||
double const ratio = smoothratio * (1. / FRACUNIT);
|
||||
uint32_t const dang = UINT32_MAX >> 1;
|
||||
int64_t const prev = osum().asbam();
|
||||
int64_t const curr = sum().asbam();
|
||||
return bamang(prev + xs_CRoundToUInt(ratio * (((curr + dang - prev) & 0xFFFFFFFF) - dang)));
|
||||
return interpolatedangle(osum(), sum(), smoothratio);
|
||||
}
|
||||
|
||||
lookangle interpolatedlookang(double const smoothratio)
|
||||
binangle interpolatedlookang(double const smoothratio)
|
||||
{
|
||||
double const ratio = smoothratio * (1. / FRACUNIT);
|
||||
return bamlook(olook_ang.asbam() + xs_CRoundToInt(ratio * (look_ang - olook_ang).asbam()));
|
||||
return interpolatedangle(olook_ang, look_ang, smoothratio);
|
||||
}
|
||||
|
||||
lookangle interpolatedrotscrn(double const smoothratio)
|
||||
binangle interpolatedrotscrn(double const smoothratio)
|
||||
{
|
||||
double const ratio = smoothratio * (1. / FRACUNIT);
|
||||
return bamlook(orotscrnang.asbam() + xs_CRoundToInt(ratio * (rotscrnang - orotscrnang).asbam()));
|
||||
return interpolatedangle(orotscrnang, rotscrnang, smoothratio);
|
||||
}
|
||||
|
||||
double look_anghalf(double const smoothratio)
|
||||
{
|
||||
return (!SyncInput() ? look_ang : interpolatedlookang(smoothratio)).asbam() * (0.5 / BAMUNIT); // Used within draw code for weapon and crosshair when looking left/right.
|
||||
return (!SyncInput() ? look_ang : interpolatedlookang(smoothratio)).signedbuildf() * 0.5; // Used within draw code for weapon and crosshair when looking left/right.
|
||||
}
|
||||
|
||||
double looking_arc(double const smoothratio)
|
||||
{
|
||||
return fabs((!SyncInput() ? look_ang : interpolatedlookang(smoothratio)).signedbuildf()) * (1. / 9.); // Used within draw code for weapon and crosshair when looking left/right.
|
||||
}
|
||||
|
||||
void applyinput(float const avel, ESyncBits* actions, double const scaleAdjust = 1);
|
||||
|
||||
private:
|
||||
binangle target;
|
||||
double adjustment;
|
||||
|
||||
void __addadjustment(lookangle value)
|
||||
void __addadjustment(binangle value)
|
||||
{
|
||||
if (!SyncInput())
|
||||
{
|
||||
adjustment += value.asbam();
|
||||
adjustment += value.signedbuildf();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -266,7 +257,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void __settarget(binangle value, bool backup = false)
|
||||
void __settarget(binangle value, bool backup)
|
||||
{
|
||||
if (!SyncInput() && !backup)
|
||||
{
|
||||
|
@ -290,6 +281,3 @@ void updateTurnHeldAmt(double const scaleAdjust);
|
|||
bool const isTurboTurnTime();
|
||||
void resetTurnHeldAmt();
|
||||
void processMovement(InputPacket* currInput, InputPacket* inputBuffer, ControlInfo* const hidInput, double const scaleAdjust, int const drink_amt = 0, bool const allowstrafe = true, double const turnscale = 1);
|
||||
void sethorizon(PlayerHorizon* horizon, float const horz, ESyncBits* actions, double const scaleAdjust = 1);
|
||||
void applylook(PlayerAngle* angle, float const avel, ESyncBits* actions, double const scaleAdjust = 1);
|
||||
void calcviewpitch(vec2_t const pos, fixedhoriz* horizoff, binangle const ang, bool const aimmode, bool const canslopetilt, int const cursectnum, double const scaleAdjust = 1, bool const climbing = false);
|
||||
|
|
|
@ -43,8 +43,10 @@ enum gameaction_t : int
|
|||
ga_nextlevel, // Actually start the next level.
|
||||
ga_loadgamehidecon,
|
||||
ga_newgamenostopsound, // start a new game
|
||||
ga_endscreenjob,
|
||||
|
||||
ga_fullconsole,
|
||||
};
|
||||
extern gamestate_t gamestate;
|
||||
extern gameaction_t gameaction;
|
||||
extern int intermissiondelay;
|
||||
|
|
|
@ -11,6 +11,8 @@ bool System_WantGuiCapture(); // During playing this tells us whether the game m
|
|||
#include "inputstate.h"
|
||||
|
||||
class FSerializer;
|
||||
struct FRenderViewpoint;
|
||||
struct spritetype;
|
||||
|
||||
struct GameStats
|
||||
{
|
||||
|
@ -45,6 +47,19 @@ struct MapRecord;
|
|||
|
||||
extern cycle_t drawtime, actortime, thinktime, gameupdatetime;
|
||||
|
||||
struct GeoEffect
|
||||
{
|
||||
int* geosectorwarp;
|
||||
int* geosectorwarp2;
|
||||
int* geosector;
|
||||
int* geox;
|
||||
int* geoy;
|
||||
int* geox2;
|
||||
int* geoy2;
|
||||
int geocnt;
|
||||
|
||||
};
|
||||
|
||||
struct GameInterface
|
||||
{
|
||||
virtual const char* Name() { return "$"; }
|
||||
|
@ -64,12 +79,11 @@ struct GameInterface
|
|||
virtual void MenuSound(EMenuSounds snd) {}
|
||||
virtual bool CanSave() { return true; }
|
||||
virtual void CustomMenuSelection(int menu, int item) {}
|
||||
virtual bool StartGame(FNewGameStartup& gs) { return false; }
|
||||
virtual bool StartGame(FNewGameStartup& gs) { return true; }
|
||||
virtual FSavegameInfo GetSaveSig() { return { "", 0, 0}; }
|
||||
virtual double SmallFontScale() { return 1; }
|
||||
virtual void SerializeGameState(FSerializer& arc) {}
|
||||
virtual void DrawPlayerSprite(const DVector2& origin, bool onteam) {}
|
||||
virtual void QuitToTitle() {}
|
||||
virtual void SetAmbience(bool on) {}
|
||||
virtual FString GetCoordString() { return "'stat coord' not implemented"; }
|
||||
virtual void ExitFromMenu() { throw CExitEvent(0); }
|
||||
|
@ -99,6 +113,11 @@ struct GameInterface
|
|||
virtual int chaseCamX(binangle ang) { return 0; }
|
||||
virtual int chaseCamY(binangle ang) { return 0; }
|
||||
virtual int chaseCamZ(fixedhoriz horiz) { return 0; }
|
||||
virtual void processSprites(spritetype* tsprite, int& spritesortcnt, int viewx, int viewy, int viewz, binangle viewang, double smoothRatio) = 0;
|
||||
virtual void UpdateCameras(double smoothratio) {}
|
||||
virtual void EnterPortal(spritetype* viewer, int type) {}
|
||||
virtual void LeavePortal(spritetype* viewer, int type) {}
|
||||
virtual bool GetGeoEffect(GeoEffect* eff, int viewsector) { return false; }
|
||||
virtual int Voxelize(int sprnum) { return -1; }
|
||||
|
||||
virtual FString statFPS()
|
||||
|
|
|
@ -61,6 +61,7 @@ double Get(int index, int type)
|
|||
|
||||
void Set(int index, int type, double val)
|
||||
{
|
||||
int old;
|
||||
switch(type)
|
||||
{
|
||||
case Interp_Sect_Floorz: sector[index].floorz = xs_CRoundToInt(val); break;
|
||||
|
@ -72,8 +73,8 @@ void Set(int index, int type, double val)
|
|||
case Interp_Sect_CeilingPanX: sector[index].ceilingxpan_ = float(val); break;
|
||||
case Interp_Sect_CeilingPanY: sector[index].ceilingypan_ = float(val); break;
|
||||
|
||||
case Interp_Wall_X: wall[index].x = xs_CRoundToInt(val); break;
|
||||
case Interp_Wall_Y: wall[index].y = xs_CRoundToInt(val); break;
|
||||
case Interp_Wall_X: old = wall[index].x; wall[index].x = xs_CRoundToInt(val); if (wall[index].x != old) sector[wall[index].sector].dirty = 255; break;
|
||||
case Interp_Wall_Y: old = wall[index].y; wall[index].y = xs_CRoundToInt(val); if (wall[index].y != old) sector[wall[index].sector].dirty = 255; break;
|
||||
case Interp_Wall_PanX: wall[index].xpan_ = float(val); break;
|
||||
case Interp_Wall_PanY: wall[index].ypan_ = float(val); break;
|
||||
|
||||
|
|
|
@ -1,37 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
class FSerializer;
|
||||
|
||||
struct vec2_16_t
|
||||
{
|
||||
int16_t x, y;
|
||||
};
|
||||
|
||||
|
||||
#if 0
|
||||
struct vec2_t
|
||||
struct vec2_t
|
||||
{
|
||||
int32_t x, y;
|
||||
};
|
||||
|
||||
struct vec2f_t
|
||||
{
|
||||
float x, y;
|
||||
};
|
||||
|
||||
struct vec2d_t
|
||||
{
|
||||
double x, y;
|
||||
vec2_t() = default;
|
||||
vec2_t(const vec2_t&) = default;
|
||||
vec2_t(int x_, int y_) : x(x_), y(y_) {}
|
||||
vec2_t operator+(const vec2_t& other) const { return { x + other.x, y + other.y }; }
|
||||
vec2_t operator-(const vec2_t& other) const { return { x - other.x, y - other.y }; }
|
||||
vec2_t& operator+=(const vec2_t& other) { x += other.x; y += other.y; return *this; };
|
||||
vec2_t& operator-=(const vec2_t& other) { x -= other.x; y -= other.y; return *this; };
|
||||
bool operator == (const vec2_t& other) const { return x == other.x && y == other.y; };
|
||||
};
|
||||
|
||||
struct vec3_t
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int32_t x, y, z;
|
||||
};
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int32_t x, y, z;
|
||||
};
|
||||
vec2_t vec2;
|
||||
};
|
||||
|
||||
vec3_t() = default;
|
||||
vec3_t(const vec3_t&) = default;
|
||||
vec3_t(int x_, int y_, int z_) : x(x_), y(y_), z(z_) {}
|
||||
vec3_t operator+(const vec3_t& other) const { return { x + other.x, y + other.y, z + other.z }; }
|
||||
vec3_t operator-(const vec3_t& other) const { return { x - other.x, y - other.y, z - other.z }; }
|
||||
vec3_t& operator+=(const vec3_t & other) { x += other.x; y += other.y; z += other.z; return *this; };
|
||||
vec3_t& operator-=(const vec3_t & other) { x -= other.x; y -= other.y; z += other.z; return *this; };
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
struct vec2f_t
|
||||
{
|
||||
float x, y;
|
||||
};
|
||||
|
||||
struct vec3_16_t
|
||||
|
@ -46,3 +63,6 @@ struct vec3_16_t
|
|||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
FSerializer& Serialize(FSerializer& arc, const char* key, vec2_t& c, vec2_t* def);
|
||||
FSerializer& Serialize(FSerializer& arc, const char* key, vec3_t& c, vec3_t* def);
|
||||
|
|
|
@ -74,7 +74,6 @@
|
|||
#include "vm.h"
|
||||
#include "gamestate.h"
|
||||
#include "screenjob.h"
|
||||
#include "mmulti.h"
|
||||
#include "c_console.h"
|
||||
#include "uiinput.h"
|
||||
#include "v_video.h"
|
||||
|
@ -105,6 +104,7 @@ bool r_NoInterpolate;
|
|||
int entertic;
|
||||
int oldentertics;
|
||||
int gametic;
|
||||
int intermissiondelay;
|
||||
|
||||
FString BackupSaveGame;
|
||||
|
||||
|
@ -133,6 +133,20 @@ void G_BuildTiccmd(ticcmd_t* cmd)
|
|||
//==========================================================================
|
||||
bool newGameStarted;
|
||||
|
||||
void NewGame(MapRecord* map, int skill, bool ns = false)
|
||||
{
|
||||
newGameStarted = true;
|
||||
ShowIntermission(nullptr, map, nullptr, [=](bool) {
|
||||
gi->NewGame(map, skill, ns);
|
||||
});
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void GameTicker()
|
||||
{
|
||||
int i;
|
||||
|
@ -159,7 +173,7 @@ static void GameTicker()
|
|||
FX_SetReverb(0);
|
||||
gi->FreeLevelData();
|
||||
gameaction = ga_level;
|
||||
gi->NewGame(g_nextmap, -1);
|
||||
NewGame(g_nextmap, -1);
|
||||
BackupSaveGame = "";
|
||||
}
|
||||
break;
|
||||
|
@ -191,13 +205,12 @@ static void GameTicker()
|
|||
FX_StopAllSounds();
|
||||
case ga_newgamenostopsound:
|
||||
DeleteScreenJob();
|
||||
newGameStarted = true;
|
||||
FX_SetReverb(0);
|
||||
gi->FreeLevelData();
|
||||
C_FlushDisplay();
|
||||
gameaction = ga_level;
|
||||
BackupSaveGame = "";
|
||||
gi->NewGame(g_nextmap, g_nextskill, ga == ga_newgamenostopsound);
|
||||
NewGame(g_nextmap, g_nextskill, ga == ga_newgamenostopsound);
|
||||
break;
|
||||
|
||||
case ga_startup:
|
||||
|
@ -209,6 +222,7 @@ static void GameTicker()
|
|||
|
||||
case ga_mainmenu:
|
||||
FX_StopAllSounds();
|
||||
if (isBlood()) Mus_Stop();
|
||||
case ga_mainmenunostopsound:
|
||||
gi->FreeLevelData();
|
||||
gamestate = GS_MENUSCREEN;
|
||||
|
@ -253,6 +267,10 @@ static void GameTicker()
|
|||
gameaction = ga_nothing;
|
||||
break;
|
||||
|
||||
case ga_endscreenjob:
|
||||
EndScreenJob();
|
||||
break;
|
||||
|
||||
// for later
|
||||
// case ga_recordgame, // start a new demo recording (later)
|
||||
// case ga_loadgameplaydemo, // load a savegame and play a demo.
|
||||
|
@ -331,7 +349,16 @@ static void GameTicker()
|
|||
break;
|
||||
case GS_INTERMISSION:
|
||||
case GS_INTRO:
|
||||
ScreenJobTick();
|
||||
if (intermissiondelay > 0)
|
||||
{
|
||||
intermissiondelay--;
|
||||
break;
|
||||
}
|
||||
if (ScreenJobTick())
|
||||
{
|
||||
// synchronize termination with the playsim.
|
||||
Net_WriteByte(DEM_ENDSCREENJOB);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -371,7 +398,7 @@ void Display()
|
|||
case GS_INTRO:
|
||||
case GS_INTERMISSION:
|
||||
// screen jobs are not bound by the game ticker so they need to be ticked in the display loop.
|
||||
ScreenJobDraw();
|
||||
if (intermissiondelay <= 0) ScreenJobDraw();
|
||||
break;
|
||||
|
||||
case GS_LEVEL:
|
||||
|
@ -633,6 +660,16 @@ void MainLoop ()
|
|||
// Clamp the timer to TICRATE until the playloop has been entered.
|
||||
r_NoInterpolate = true;
|
||||
|
||||
if (userConfig.CommandMap.IsNotEmpty())
|
||||
{
|
||||
auto maprecord = FindMapByName(userConfig.CommandMap);
|
||||
userConfig.CommandMap = "";
|
||||
if (maprecord)
|
||||
{
|
||||
NewGame(maprecord, /*userConfig.skill*/2); // todo: fix the skill.
|
||||
}
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -35,8 +35,12 @@
|
|||
#include "build.h"
|
||||
#include "sc_man.h"
|
||||
#include "printf.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "md4.h"
|
||||
#include "hw_sections.h"
|
||||
|
||||
static TArray<usermaphack_t> usermaphacks;
|
||||
TArray<int> blockingpairs[MAXWALLS];
|
||||
|
||||
void AddUserMapHack(usermaphack_t& mhk)
|
||||
{
|
||||
|
@ -45,7 +49,9 @@ void AddUserMapHack(usermaphack_t& mhk)
|
|||
|
||||
static int32_t LoadMapHack(const char *filename)
|
||||
{
|
||||
int32_t currentsprite = -1;
|
||||
int currentsprite = -1;
|
||||
int currentwall = -1;
|
||||
int currentsector = -1;
|
||||
|
||||
FScanner sc;
|
||||
int lump = fileSystem.FindFile(filename);
|
||||
|
@ -68,8 +74,30 @@ static int32_t LoadMapHack(const char *filename)
|
|||
return true;
|
||||
};
|
||||
|
||||
auto validateWall = [&]()
|
||||
{
|
||||
if (currentwall < 0)
|
||||
{
|
||||
sc.ScriptMessage("Using %s without a valid wall", token.GetChars());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
auto validateSector = [&]()
|
||||
{
|
||||
if (currentsector < 0)
|
||||
{
|
||||
sc.ScriptMessage("Using %s without a valid sector", token.GetChars());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (sc.Compare("sprite"))
|
||||
{
|
||||
currentwall = -1;
|
||||
currentsector = -1;
|
||||
if (sc.CheckNumber())
|
||||
{
|
||||
currentsprite = sc.Number;
|
||||
|
@ -81,6 +109,137 @@ static int32_t LoadMapHack(const char *filename)
|
|||
}
|
||||
else currentsprite = -1;
|
||||
}
|
||||
if (sc.Compare("wall"))
|
||||
{
|
||||
currentsprite = -1;
|
||||
currentsector = -1;
|
||||
if (sc.CheckNumber())
|
||||
{
|
||||
currentwall = sc.Number;
|
||||
if (currentwall < 0 || currentwall >= MAXWALLS)
|
||||
{
|
||||
sc.ScriptMessage("Invalid wall number %d", currentwall);
|
||||
currentwall = -1;
|
||||
}
|
||||
}
|
||||
else currentwall = -1;
|
||||
}
|
||||
if (sc.Compare("sector"))
|
||||
{
|
||||
currentsprite = -1;
|
||||
currentwall = -1;
|
||||
if (sc.CheckNumber())
|
||||
{
|
||||
currentsector = sc.Number;
|
||||
if (currentsector < 0 || currentsector >= MAXSECTORS)
|
||||
{
|
||||
sc.ScriptMessage("Invalid sector number %d", currentsector);
|
||||
currentsector = -1;
|
||||
}
|
||||
}
|
||||
else currentsector = -1;
|
||||
}
|
||||
else if (sc.Compare("blocks"))
|
||||
{
|
||||
if (sc.CheckNumber() && validateWall())
|
||||
{
|
||||
blockingpairs[currentwall].Push(sc.Number);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("picnum"))
|
||||
{
|
||||
if (sc.CheckNumber())
|
||||
{
|
||||
if (currentwall != -1 && validateWall())
|
||||
{
|
||||
wall[currentwall].picnum = sc.Number;
|
||||
}
|
||||
else if (currentsprite != -1 && validateSprite())
|
||||
{
|
||||
sprite[currentsprite].picnum = sc.Number;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("overpicnum"))
|
||||
{
|
||||
if (sc.CheckNumber() && validateWall())
|
||||
{
|
||||
wall[currentwall].overpicnum = sc.Number;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("overpicnum"))
|
||||
{
|
||||
if (sc.CheckNumber() && validateWall())
|
||||
{
|
||||
wall[currentwall].overpicnum = sc.Number;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("split"))
|
||||
{
|
||||
int start = -1, end = -1;
|
||||
if (sc.CheckNumber()) start = sc.Number;
|
||||
if (sc.CheckNumber()) end = sc.Number;
|
||||
if (end >= 0 && validateSector())
|
||||
{
|
||||
hw_SetSplitSector(currentsector, start, end);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("clearflags"))
|
||||
{
|
||||
if (currentsector != -1 && validateSector())
|
||||
{
|
||||
sc.GetString();
|
||||
if (sc.Compare("floor") && sc.CheckNumber())
|
||||
{
|
||||
sector[currentsector].floorstat &= ~sc.Number;
|
||||
}
|
||||
else if (sc.Compare("ceiling") && sc.CheckNumber())
|
||||
{
|
||||
sector[currentsector].ceilingstat &= ~sc.Number;
|
||||
}
|
||||
else sc.ScriptError("Bad token %s", sc.String);
|
||||
}
|
||||
else if (sc.CheckNumber())
|
||||
{
|
||||
if (currentwall != -1 && validateWall())
|
||||
{
|
||||
wall[currentwall].cstat &= ~sc.Number;
|
||||
}
|
||||
else if (currentsprite != -1 && validateSprite())
|
||||
{
|
||||
sprite[currentsprite].cstat &= ~sc.Number;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("setflags"))
|
||||
{
|
||||
if (sc.CheckNumber())
|
||||
{
|
||||
if (currentwall != -1 && validateWall())
|
||||
{
|
||||
wall[currentwall].cstat |= sc.Number;
|
||||
}
|
||||
else if (currentsprite != -1 && validateSprite())
|
||||
{
|
||||
sprite[currentsprite].cstat |= sc.Number;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("lotag"))
|
||||
{
|
||||
if (sc.CheckNumber())
|
||||
{
|
||||
if (currentwall != -1 && validateWall())
|
||||
{
|
||||
wall[currentwall].lotag = sc.Number;
|
||||
}
|
||||
else if (currentsprite != -1 && validateSprite())
|
||||
{
|
||||
sprite[currentsprite].lotag = sc.Number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (sc.Compare("angleoff") || sc.Compare("angoff"))
|
||||
{
|
||||
if (sc.CheckNumber() && validateSprite())
|
||||
|
@ -201,6 +360,13 @@ static int32_t LoadMapHack(const char *filename)
|
|||
|
||||
void G_LoadMapHack(const char* filename, const unsigned char* md4)
|
||||
{
|
||||
for (auto& p : blockingpairs) p.Clear();
|
||||
FString internal = "engine/compatibility/";
|
||||
for (int j = 0; j < 16; ++j)
|
||||
{
|
||||
internal.AppendFormat("%02x", md4[j]);
|
||||
}
|
||||
LoadMapHack(internal + ".mhk");
|
||||
FString hack = StripExtension(filename) + ".mhk";
|
||||
|
||||
if (LoadMapHack(hack))
|
||||
|
@ -215,3 +381,31 @@ void G_LoadMapHack(const char* filename, const unsigned char* md4)
|
|||
}
|
||||
}
|
||||
|
||||
// Map hacks use MD4 instead of MD5. Oh, well...
|
||||
CCMD(md4sum)
|
||||
{
|
||||
if (argv.argc() < 2)
|
||||
{
|
||||
Printf("Usage: md4sum <file> ...\n");
|
||||
}
|
||||
for (int i = 1; i < argv.argc(); ++i)
|
||||
{
|
||||
FileReader fr = fileSystem.OpenFileReader(argv[i]);
|
||||
if (!fr.isOpen())
|
||||
{
|
||||
Printf("%s: %s\n", argv[i], strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto data = fr.Read();
|
||||
uint8_t digest[16];
|
||||
md4once(data.Data(), data.Size(), digest);
|
||||
for (int j = 0; j < 16; ++j)
|
||||
{
|
||||
Printf("%02x", digest[j]);
|
||||
}
|
||||
Printf(" //*%s\n", argv[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,43 +41,49 @@
|
|||
#include "raze_sound.h"
|
||||
|
||||
FString gSkillNames[MAXSKILLS];
|
||||
FString gVolumeNames[MAXVOLUMES];
|
||||
FString gVolumeSubtitles[MAXVOLUMES];
|
||||
int32_t gVolumeFlags[MAXVOLUMES];
|
||||
int gDefaultVolume = 0, gDefaultSkill = 1;
|
||||
|
||||
MapRecord mapList[512]; // Due to how this gets used it needs to be static. EDuke defines 7 episode plus one spare episode with 64 potential levels each and relies on the static array which is freely accessible by scripts.
|
||||
MapRecord *currentLevel; // level that is currently played. (The real level, not what script hacks modfifying the current level index can pretend.)
|
||||
GlobalCutscenes globalCutscenes;
|
||||
TArray<ClusterDef> clusters;
|
||||
TArray<VolumeRecord> volumes;
|
||||
TArray<TPointer<MapRecord>> mapList; // must be allocated as pointers because it can whack the currentlLevel pointer if this was a flat array.
|
||||
MapRecord *currentLevel; // level that is currently played.
|
||||
MapRecord* lastLevel; // Same here, for the last level.
|
||||
unsigned int numUsedSlots;
|
||||
|
||||
|
||||
CCMD(listmaps)
|
||||
{
|
||||
for (unsigned int i = 0; i < numUsedSlots; i++)
|
||||
for (auto& map : mapList)
|
||||
{
|
||||
int lump = fileSystem.FindFile(mapList[i].fileName);
|
||||
int lump = fileSystem.FindFile(map->fileName);
|
||||
if (lump >= 0)
|
||||
{
|
||||
int rfnum = fileSystem.GetFileContainer(lump);
|
||||
Printf("%s - %s (%s)\n", mapList[i].fileName.GetChars(), mapList[i].DisplayName(), fileSystem.GetResourceFileName(rfnum));
|
||||
Printf("%s - %s (%s)\n", map->LabelName(), map->DisplayName(), fileSystem.GetResourceFileName(rfnum));
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("%s - %s (defined but does not exist)\n", mapList[i].fileName.GetChars(), mapList[i].DisplayName());
|
||||
Printf("%s - %s (defined but does not exist)\n", map->fileName.GetChars(), map->DisplayName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CutsceneDef::GetSound()
|
||||
{
|
||||
int id;
|
||||
if (soundName.IsNotEmpty()) id = soundEngine->FindSound(soundName);
|
||||
if (id <= 0) id = soundEngine->FindSoundByResID(soundID);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
MapRecord *FindMapByName(const char *nm)
|
||||
{
|
||||
for (unsigned i = 0; i < numUsedSlots; i++)
|
||||
for (auto& map : mapList)
|
||||
{
|
||||
auto &map = mapList[i];
|
||||
if (map.labelName.CompareNoCase(nm) == 0)
|
||||
if (map->labelName.CompareNoCase(nm) == 0)
|
||||
{
|
||||
return ↦
|
||||
return map.Data();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -86,23 +92,79 @@ MapRecord *FindMapByName(const char *nm)
|
|||
|
||||
MapRecord *FindMapByLevelNum(int num)
|
||||
{
|
||||
for (unsigned i = 0; i < numUsedSlots; i++)
|
||||
for (auto& map : mapList)
|
||||
{
|
||||
auto &map = mapList[i];
|
||||
if (map.levelNumber == num)
|
||||
if (map->levelNumber == num)
|
||||
{
|
||||
return ↦
|
||||
return map.Data();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MapRecord *FindNextMap(MapRecord *thismap)
|
||||
VolumeRecord* FindVolume(int index)
|
||||
{
|
||||
if (thismap->nextLevel != -1) return FindMapByLevelNum(thismap->nextLevel);
|
||||
return FindMapByLevelNum(thismap->levelNumber+1);
|
||||
for (auto& vol : volumes)
|
||||
{
|
||||
if (vol.index == index) return &vol;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ClusterDef* FindCluster(int index)
|
||||
{
|
||||
for (auto& vol : clusters)
|
||||
{
|
||||
if (vol.index == index) return &vol;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ClusterDef* AllocateCluster()
|
||||
{
|
||||
return &clusters[clusters.Reserve(1)];
|
||||
}
|
||||
|
||||
VolumeRecord* AllocateVolume()
|
||||
{
|
||||
return &volumes[volumes.Reserve(1)];
|
||||
}
|
||||
|
||||
MapRecord* FindMapByIndexOnly(int cluster, int num)
|
||||
{
|
||||
int levelnum = makelevelnum(cluster, num);
|
||||
for (auto& map : mapList)
|
||||
{
|
||||
if (map->levelNumber == levelnum) return map.Data();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MapRecord* FindMapByIndex(int cluster, int num)
|
||||
{
|
||||
auto map = FindMapByLevelNum(num);
|
||||
if (!map && num < 1000) map = FindMapByLevelNum(makelevelnum(cluster, num));
|
||||
return map;
|
||||
}
|
||||
|
||||
MapRecord* FindNextMap(MapRecord* thismap)
|
||||
{
|
||||
MapRecord* next = nullptr;
|
||||
if (!thismap->NextMap.Compare("-")) return nullptr; // '-' means to forcibly end the game here.
|
||||
if (thismap->NextMap.IsNotEmpty()) next = FindMapByName(thismap->NextMap);
|
||||
if (!next) next = FindMapByLevelNum(thismap->levelNumber + 1);
|
||||
return next;
|
||||
}
|
||||
|
||||
MapRecord* FindNextSecretMap(MapRecord* thismap)
|
||||
{
|
||||
MapRecord* next = nullptr;
|
||||
if (!thismap->NextSecret.Compare("-")) return nullptr; // '-' means to forcibly end the game here.
|
||||
if (thismap->NextSecret.IsNotEmpty()) next = FindMapByName(thismap->NextSecret);
|
||||
return next? next : FindNextMap(thismap);
|
||||
}
|
||||
|
||||
|
||||
bool SetMusicForMap(const char* mapname, const char* music, bool namehack)
|
||||
{
|
||||
static const char* specials[] = { "intro", "briefing", "loading" };
|
||||
|
@ -129,7 +191,7 @@ bool SetMusicForMap(const char* mapname, const char* music, bool namehack)
|
|||
if (numMatches != 4 || toupper(b1) != 'E' || toupper(b2) != 'L')
|
||||
return false;
|
||||
|
||||
index = FindMapByLevelNum(levelnum(ep - 1, lev - 1));
|
||||
index = FindMapByIndexOnly(ep, lev);
|
||||
|
||||
}
|
||||
if (index != nullptr)
|
||||
|
@ -142,18 +204,19 @@ bool SetMusicForMap(const char* mapname, const char* music, bool namehack)
|
|||
|
||||
MapRecord *AllocateMap()
|
||||
{
|
||||
return &mapList[numUsedSlots++];
|
||||
auto&p = mapList[mapList.Reserve(1)];
|
||||
p.Alloc();
|
||||
return p.Data();
|
||||
}
|
||||
|
||||
|
||||
MapRecord* SetupUserMap(const char* boardfilename, const char *defaultmusic)
|
||||
{
|
||||
for (unsigned i = 0; i < numUsedSlots; i++)
|
||||
for (auto& map : mapList)
|
||||
{
|
||||
auto &map = mapList[i];
|
||||
if (map.fileName.CompareNoCase(boardfilename) == 0)
|
||||
if (map->fileName.CompareNoCase(boardfilename) == 0)
|
||||
{
|
||||
return ↦
|
||||
return map.Data();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,28 +3,58 @@
|
|||
#include "gstrings.h"
|
||||
#include "cmdlib.h"
|
||||
#include "quotemgr.h"
|
||||
#include "palentry.h"
|
||||
#include "vectors.h"
|
||||
#ifdef GetMessage
|
||||
#undef GetMessage // Windows strikes...
|
||||
#endif
|
||||
|
||||
|
||||
enum EMax
|
||||
{
|
||||
MAXSKILLS = 7,
|
||||
MAXVOLUMES = 7,
|
||||
MAXMENUGAMEPLAYENTRIES = 7,
|
||||
};
|
||||
|
||||
enum EVolFlags
|
||||
{
|
||||
EF_HIDEFROMSP = 1,
|
||||
VF_HIDEFROMSP = 1,
|
||||
VF_OPTIONAL = 2,
|
||||
VF_SHAREWARELOCK = 4, // show in shareware but lock access.
|
||||
VF_NOSKILL = 8,
|
||||
};
|
||||
|
||||
enum EMapFlags
|
||||
{
|
||||
LEVEL_NOINTERMISSION = 1,
|
||||
LEVEL_SECRETEXITOVERRIDE = 2, // when given an explicit level number, override with secret exit in the map, mainly for compiling episodes out of single levels.
|
||||
LEVEL_CLEARINVENTORY = 4,
|
||||
LEVEL_CLEARWEAPONS = 8,
|
||||
LEVEL_FORCENOEOG = 16, // RR E1L7 needs this to override its boss's death ending the game.
|
||||
};
|
||||
|
||||
enum EMapGameFlags
|
||||
{
|
||||
LEVEL_RR_HULKSPAWN = 1,
|
||||
LEVEL_RR_CLEARMOONSHINE = 2,
|
||||
|
||||
LEVEL_EX_COUNTDOWN = 4,
|
||||
LEVEL_EX_TRAINING = 8,
|
||||
LEVEL_EX_ALTSOUND = 16,
|
||||
LEVEL_EX_MULTI = 32,
|
||||
|
||||
LEVEL_SW_SPAWNMINES = 64,
|
||||
LEVEL_SW_BOSSMETER_SERPENT = 128,
|
||||
LEVEL_SW_BOSSMETER_SUMO = 256,
|
||||
LEVEL_SW_BOSSMETER_ZILLA = 512,
|
||||
LEVEL_SW_DEATHEXIT_SERPENT = 1024,
|
||||
LEVEL_SW_DEATHEXIT_SUMO = 2048,
|
||||
LEVEL_SW_DEATHEXIT_ZILLA = 4096,
|
||||
|
||||
|
||||
};
|
||||
|
||||
// These get filled in by the map definition parsers of the front ends.
|
||||
extern FString gSkillNames[MAXSKILLS];
|
||||
extern FString gVolumeNames[MAXVOLUMES];
|
||||
extern FString gVolumeSubtitles[MAXVOLUMES];
|
||||
extern int32_t gVolumeFlags[MAXVOLUMES];
|
||||
extern int gDefaultVolume, gDefaultSkill;
|
||||
|
||||
|
||||
|
@ -46,6 +76,57 @@ enum {
|
|||
MAX_MESSAGES = 32
|
||||
};
|
||||
|
||||
class DObject;
|
||||
struct MapRecord;
|
||||
|
||||
struct CutsceneDef
|
||||
{
|
||||
FString video;
|
||||
FString function;
|
||||
FString soundName;
|
||||
int soundID = -1; // ResID not SoundID!
|
||||
int framespersec = 0; // only relevant for ANM.
|
||||
bool transitiononly = false; // only play when transitioning between maps, but not when starting on a map or ending a game.
|
||||
|
||||
void Create(DObject* runner);
|
||||
bool Create(DObject* runner, MapRecord* map, bool transition);
|
||||
bool isdefined() { return video.IsNotEmpty() || function.IsNotEmpty(); }
|
||||
int GetSound();
|
||||
};
|
||||
|
||||
struct GlobalCutscenes
|
||||
{
|
||||
CutsceneDef Intro;
|
||||
CutsceneDef DefaultMapIntro;
|
||||
CutsceneDef DefaultMapOutro;
|
||||
CutsceneDef DefaultGameover;
|
||||
CutsceneDef SharewareEnd;
|
||||
CutsceneDef LoadingScreen;
|
||||
FString MPSummaryScreen;
|
||||
FString SummaryScreen;
|
||||
};
|
||||
|
||||
struct ClusterDef
|
||||
{
|
||||
FString name; // What gets displayed for this cluster. In Duke this is normally the corresponding volume name but does not have to be.
|
||||
CutsceneDef intro; // plays when entering this cluster
|
||||
CutsceneDef outro; // plays when leaving this cluster
|
||||
CutsceneDef gameover; // when defined, plays when the player dies in this cluster
|
||||
FString InterBackground;
|
||||
int index = -1;
|
||||
int flags = 0; // engine and common flags
|
||||
};
|
||||
|
||||
struct VolumeRecord // episodes
|
||||
{
|
||||
FString startmap;
|
||||
FString name;
|
||||
FString subtitle;
|
||||
int index = -1;
|
||||
int flags = 0;
|
||||
int shortcut = 0;
|
||||
};
|
||||
|
||||
struct MapRecord
|
||||
{
|
||||
int parTime = 0;
|
||||
|
@ -54,16 +135,38 @@ struct MapRecord
|
|||
FString labelName;
|
||||
FString name;
|
||||
FString music;
|
||||
FString Author;
|
||||
FString NextMap;
|
||||
FString NextSecret;
|
||||
int cdSongId = -1;
|
||||
int musicorder = -1;
|
||||
|
||||
CutsceneDef intro;
|
||||
CutsceneDef outro;
|
||||
int flags = 0;
|
||||
int gameflags = 0;
|
||||
int levelNumber = -1;
|
||||
int cluster = -1;
|
||||
|
||||
PalEntry fadeto = 0;
|
||||
int fogdensity = 0;
|
||||
int skyfog = 0;
|
||||
FString BorderTexture;
|
||||
FString InterBackground;
|
||||
TArray<FString> PrecacheTextures;
|
||||
FVector4 skyrotatevector;
|
||||
|
||||
// The rest is only used by Blood
|
||||
int nextLevel = -1;
|
||||
int nextSecret = -1;
|
||||
FString messages[MAX_MESSAGES];
|
||||
FString author;
|
||||
int8_t fog = -1, weather = -1; // Blood defines these but they aren't used.
|
||||
|
||||
// game specific stuff
|
||||
int rr_startsound = 0;
|
||||
int rr_mamaspawn = 15;
|
||||
int ex_ramses_horiz = 11;
|
||||
int ex_ramses_cdtrack = -1; // this is not music, it is the actual dialogue!
|
||||
FString ex_ramses_pup;
|
||||
FString ex_ramses_text;
|
||||
|
||||
const char* LabelName() const
|
||||
{
|
||||
|
@ -97,39 +200,65 @@ struct MapRecord
|
|||
{
|
||||
messages[num] = msg;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
struct SummaryInfo
|
||||
{
|
||||
int kills;
|
||||
int maxkills;
|
||||
int secrets;
|
||||
int maxsecrets;
|
||||
int supersecrets;
|
||||
int time;
|
||||
int playercount;
|
||||
bool cheated;
|
||||
bool endofgame;
|
||||
};
|
||||
|
||||
extern MapRecord mapList[512];
|
||||
extern GlobalCutscenes globalCutscenes;
|
||||
extern MapRecord *currentLevel;
|
||||
|
||||
bool SetMusicForMap(const char* mapname, const char* music, bool namehack = false);
|
||||
|
||||
MapRecord *FindMapByName(const char *nm);
|
||||
MapRecord *FindMapByLevelNum(int num);
|
||||
MapRecord* FindMapByIndexOnly(int clst, int num); // this is for map setup where fallbacks are undesirable.
|
||||
MapRecord* FindMapByIndex(int clst, int num);
|
||||
MapRecord *FindNextMap(MapRecord *thismap);
|
||||
MapRecord* FindNextSecretMap(MapRecord* thismap);
|
||||
MapRecord* SetupUserMap(const char* boardfilename, const char *defaultmusic = nullptr);
|
||||
MapRecord* AllocateMap();
|
||||
|
||||
VolumeRecord* FindVolume(int index);
|
||||
ClusterDef* FindCluster(int index);
|
||||
ClusterDef* AllocateCluster();
|
||||
VolumeRecord* AllocateVolume();
|
||||
void SetLevelNum(MapRecord* info, int num);
|
||||
|
||||
inline VolumeRecord* MustFindVolume(int index)
|
||||
{
|
||||
auto r = FindVolume(index);
|
||||
if (r) return r;
|
||||
r = AllocateVolume();
|
||||
r->index = index;
|
||||
return r;
|
||||
}
|
||||
inline ClusterDef* MustFindCluster(int index)
|
||||
{
|
||||
auto r = FindCluster(index);
|
||||
if (r) return r;
|
||||
r = AllocateCluster();
|
||||
r->index = index;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
// These should be the only places converting between level numbers and volume/map pairs
|
||||
constexpr inline int levelnum(int vol, int map)
|
||||
constexpr inline int makelevelnum(int vol, int map)
|
||||
{
|
||||
return vol * 1000 + map;
|
||||
}
|
||||
|
||||
constexpr inline int volfromlevelnum(int num)
|
||||
{
|
||||
return num >= 0 ? num / 1000 : 0;
|
||||
}
|
||||
|
||||
constexpr inline int mapfromlevelnum(int num)
|
||||
{
|
||||
return num >= 0 ? num % 1000 : -1;
|
||||
}
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
RRENDSLOT = 127
|
||||
|
|
|
@ -41,7 +41,10 @@
|
|||
#include "inputstate.h"
|
||||
#include "md4.h"
|
||||
#include "gamecontrol.h"
|
||||
|
||||
#include "gamefuncs.h"
|
||||
#include "sectorgeometry.h"
|
||||
#include "render.h"
|
||||
#include "hw_sections.h"
|
||||
|
||||
static void ReadSectorV7(FileReader& fr, sectortype& sect)
|
||||
{
|
||||
|
@ -368,10 +371,14 @@ static void insertAllSprites(const char* filename, const vec3_t* pos, int16_t* c
|
|||
assert(realnumsprites == Numsprites);
|
||||
}
|
||||
|
||||
void addBlockingPairs();
|
||||
|
||||
void engineLoadBoard(const char* filename, int flags, vec3_t* pos, int16_t* ang, int16_t* cursectnum)
|
||||
{
|
||||
inputState.ClearAllInput();
|
||||
memset(sector, 0, sizeof(*sector) * MAXSECTORS);
|
||||
memset(wall, 0, sizeof(*wall) * MAXWALLS);
|
||||
memset(sprite, 0, sizeof(*sector) * MAXSPRITES);
|
||||
|
||||
FileReader fr = fileSystem.OpenFileReader(filename);
|
||||
if (!fr.isOpen()) I_Error("Unable to open map %s", filename);
|
||||
|
@ -385,7 +392,7 @@ void engineLoadBoard(const char* filename, int flags, vec3_t* pos, int16_t* ang,
|
|||
memset(spritesmooth, 0, sizeof(spritesmooth_t) * (MAXSPRITES + MAXUNIQHUDID));
|
||||
initspritelists();
|
||||
ClearAutomap();
|
||||
Polymost_prepare_loadboard();
|
||||
Polymost::Polymost_prepare_loadboard();
|
||||
|
||||
pos->x = fr.ReadInt32();
|
||||
pos->y = fr.ReadInt32();
|
||||
|
@ -444,6 +451,10 @@ void engineLoadBoard(const char* filename, int flags, vec3_t* pos, int16_t* ang,
|
|||
unsigned char md4[16];
|
||||
md4once(buffer.Data(), buffer.Size(), md4);
|
||||
G_LoadMapHack(filename, md4);
|
||||
setWallSectors();
|
||||
hw_BuildSections();
|
||||
sectorGeometry.SetSize(numsections);
|
||||
|
||||
|
||||
memcpy(wallbackup, wall, sizeof(wallbackup));
|
||||
memcpy(sectorbackup, sector, sizeof(sectorbackup));
|
||||
|
@ -468,4 +479,18 @@ void loadMapBackup(const char* filename)
|
|||
engineLoadBoard(filename, 0, &pos, &scratch, &scratch);
|
||||
initspritelists();
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the sector reference for each wall. We need this for the triangulation cache.
|
||||
void setWallSectors()
|
||||
{
|
||||
for (int i = 0; i < numsectors; i++)
|
||||
{
|
||||
sector[i].dirty = 255;
|
||||
sector[i].exflags = 0;
|
||||
for (int w = 0; w < sector[i].wallnum; w++)
|
||||
{
|
||||
wall[sector[i].wallptr + w].sector = i;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -64,6 +64,7 @@
|
|||
#include "i_net.h"
|
||||
#include "savegamehelp.h"
|
||||
#include "gi.h"
|
||||
#include "raze_music.h"
|
||||
|
||||
EXTERN_CVAR(Int, cl_gfxlocalization)
|
||||
EXTERN_CVAR(Bool, m_quickexit)
|
||||
|
@ -83,8 +84,31 @@ bool help_disabled;
|
|||
FNewGameStartup NewGameStartupInfo;
|
||||
|
||||
|
||||
|
||||
//FNewGameStartup NewGameStartupInfo;
|
||||
|
||||
static bool DoStartGame(FNewGameStartup& gs)
|
||||
{
|
||||
auto vol = FindVolume(gs.Episode);
|
||||
if (!vol) return false;
|
||||
|
||||
if (isShareware() && (vol->flags & VF_SHAREWARELOCK))
|
||||
{
|
||||
M_StartMessage(GStrings("SHAREWARELOCK"), 1, NAME_None);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto map = FindMapByName(vol->startmap);
|
||||
if (!map) return false;
|
||||
soundEngine->StopAllChannels();
|
||||
|
||||
gi->StartGame(gs); // play game specific effects (like Duke/RR/SW's voice lines when starting a game.)
|
||||
|
||||
DeferedStartGame(map, gs.Skill);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool M_SetSpecialMenu(FName& menu, int param)
|
||||
{
|
||||
|
@ -115,13 +139,19 @@ bool M_SetSpecialMenu(FName& menu, int param)
|
|||
|
||||
case NAME_Startgame:
|
||||
case NAME_StartgameNoSkill:
|
||||
menu = NAME_Startgame;
|
||||
NewGameStartupInfo.Skill = param;
|
||||
if (menu == NAME_StartgameNoSkill) NewGameStartupInfo.Episode = param;
|
||||
if (gi->StartGame(NewGameStartupInfo))
|
||||
if (menu == NAME_StartgameNoSkill)
|
||||
{
|
||||
menu = NAME_Startgame;
|
||||
NewGameStartupInfo.Episode = param;
|
||||
NewGameStartupInfo.Skill = 1;
|
||||
}
|
||||
if (DoStartGame(NewGameStartupInfo))
|
||||
{
|
||||
M_ClearMenus();
|
||||
STAT_StartNewGame(gVolumeNames[NewGameStartupInfo.Episode], NewGameStartupInfo.Skill);
|
||||
int ep = NewGameStartupInfo.Episode;
|
||||
auto vol = FindVolume(ep);
|
||||
if (vol) STAT_StartNewGame(vol->name, NewGameStartupInfo.Skill);
|
||||
inputState.ClearAllInput();
|
||||
}
|
||||
return false;
|
||||
|
@ -243,7 +273,8 @@ CCMD(menu_endgame)
|
|||
{
|
||||
STAT_Cancel();
|
||||
M_ClearMenus();
|
||||
gi->QuitToTitle();
|
||||
Mus_Stop();
|
||||
gameaction = ga_mainmenu;
|
||||
});
|
||||
|
||||
M_ActivateMenu(newmenu);
|
||||
|
@ -365,6 +396,7 @@ static DMenuItemBase* CreateCustomListMenuItemText(double x, double y, int heigh
|
|||
// Creates the episode menu
|
||||
//
|
||||
//=============================================================================
|
||||
extern TArray<VolumeRecord> volumes;
|
||||
|
||||
static void BuildEpisodeMenu()
|
||||
{
|
||||
|
@ -385,22 +417,22 @@ static void BuildEpisodeMenu()
|
|||
ld->mSelectedItem = gDefaultVolume + ld->mItems.Size(); // account for pre-added items
|
||||
int y = ld->mYpos;
|
||||
|
||||
for (int i = 0; i < MAXVOLUMES; i++)
|
||||
// Volume definitions should be sorted by intended menu order.
|
||||
for (auto &vol : volumes)
|
||||
{
|
||||
if (gVolumeNames[i].IsNotEmpty() && !(gVolumeFlags[i] & EF_HIDEFROMSP))
|
||||
|
||||
if (vol.name.IsNotEmpty() && !(vol.flags & VF_HIDEFROMSP))
|
||||
{
|
||||
int isShareware = ((g_gameType & GAMEFLAG_DUKE) && (g_gameType & GAMEFLAG_SHAREWARE) && i > 0);
|
||||
auto it = CreateCustomListMenuItemText(ld->mXpos, y, ld->mLinespacing, gVolumeNames[i][0],
|
||||
gVolumeNames[i], ld->mFont, CR_UNTRANSLATED, isShareware, NAME_Skillmenu, i); // font colors are not used, so hijack one for the shareware flag.
|
||||
int isShareware = ((g_gameType & GAMEFLAG_DUKE) && (g_gameType & GAMEFLAG_SHAREWARE) && (vol.flags & VF_SHAREWARELOCK));
|
||||
auto it = CreateCustomListMenuItemText(ld->mXpos, y, ld->mLinespacing, vol.name[0],
|
||||
vol.name, ld->mFont, CR_UNTRANSLATED, isShareware, NAME_Skillmenu, vol.index); // font colors are not used, so hijack one for the shareware flag.
|
||||
|
||||
y += ld->mLinespacing;
|
||||
ld->mItems.Push(it);
|
||||
addedVolumes++;
|
||||
if (gVolumeSubtitles[i].IsNotEmpty())
|
||||
if (vol.subtitle.IsNotEmpty())
|
||||
{
|
||||
auto it = CreateCustomListMenuItemText(ld->mXpos, y, ld->mLinespacing * 6 / 10, 1,
|
||||
gVolumeSubtitles[i], SmallFont, CR_GRAY, false, NAME_None, i);
|
||||
vol.subtitle, SmallFont, CR_GRAY, false, NAME_None, vol.index);
|
||||
y += ld->mLinespacing * 6 / 10;
|
||||
ld->mItems.Push(it);
|
||||
textadded = true;
|
||||
|
@ -731,3 +763,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;
|
||||
}
|
||||
|
|
|
@ -49,15 +49,25 @@
|
|||
#include <vpx/vpx_decoder.h>
|
||||
#include <vpx/vp8dx.h>
|
||||
#include "raze_music.h"
|
||||
#include "vm.h"
|
||||
|
||||
|
||||
class MoviePlayer
|
||||
{
|
||||
protected:
|
||||
enum EMovieFlags
|
||||
{
|
||||
NOSOUNDCUTOFF = 1,
|
||||
FIXEDVIEWPORT = 2, // Forces fixed 640x480 screen size like for Blood's intros.
|
||||
};
|
||||
|
||||
int flags;
|
||||
public:
|
||||
virtual void Start() {}
|
||||
virtual bool Frame(uint64_t clock) = 0;
|
||||
virtual void Stop() {}
|
||||
virtual ~MoviePlayer() = default;
|
||||
virtual FTextureID GetTexture() = 0;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -76,16 +86,17 @@ class AnmPlayer : public MoviePlayer
|
|||
int frametime = 0;
|
||||
int nextframetime = 0;
|
||||
AnimTextures animtex;
|
||||
const AnimSound* animSnd;
|
||||
const int* frameTicks;
|
||||
bool nostopsound;
|
||||
const TArray<int> animSnd;
|
||||
int frameTicks[3];
|
||||
|
||||
public:
|
||||
bool isvalid() { return numframes > 0; }
|
||||
|
||||
AnmPlayer(FileReader& fr, const AnimSound* ans, const int *frameticks, bool nosoundcutoff)
|
||||
: animSnd(ans), frameTicks(frameticks), nostopsound(nosoundcutoff)
|
||||
AnmPlayer(FileReader& fr, TArray<int>& ans, const int *frameticks, int flags_)
|
||||
: animSnd(std::move(ans))
|
||||
{
|
||||
memcpy(frameTicks, frameticks, 3 * sizeof(int));
|
||||
flags = flags_;
|
||||
buffer = fr.ReadPadded(1);
|
||||
fr.Close();
|
||||
|
||||
|
@ -109,17 +120,12 @@ public:
|
|||
|
||||
if (currentclock < nextframetime - 1)
|
||||
{
|
||||
twod->ClearScreen();
|
||||
DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_Masked, false, TAG_DONE);
|
||||
return true;
|
||||
}
|
||||
|
||||
animtex.SetFrame(ANIM_GetPalette(&anim), ANIM_DrawFrame(&anim, curframe));
|
||||
frametime = currentclock;
|
||||
|
||||
twod->ClearScreen();
|
||||
DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_Masked, false, TAG_DONE);
|
||||
|
||||
int delay = 20;
|
||||
if (frameTicks)
|
||||
{
|
||||
|
@ -129,11 +135,12 @@ public:
|
|||
}
|
||||
nextframetime += delay;
|
||||
|
||||
if (animSnd) for (int i = 0; animSnd[i].framenum >= 0; i++)
|
||||
bool nostopsound = (flags & NOSOUNDCUTOFF);
|
||||
for (unsigned i = 0; i < animSnd.Size(); i+=2)
|
||||
{
|
||||
if (animSnd[i].framenum == curframe)
|
||||
if (animSnd[i] == curframe)
|
||||
{
|
||||
int sound = animSnd[i].soundnum;
|
||||
int sound = animSnd[i+1];
|
||||
if (sound == -1)
|
||||
soundEngine->StopAllChannels();
|
||||
else if (SoundEnabled())
|
||||
|
@ -147,6 +154,7 @@ public:
|
|||
|
||||
void Stop() override
|
||||
{
|
||||
bool nostopsound = (flags & NOSOUNDCUTOFF);
|
||||
if (!nostopsound) soundEngine->StopAllChannels();
|
||||
}
|
||||
|
||||
|
@ -156,6 +164,11 @@ public:
|
|||
buffer.Reset();
|
||||
animtex.Clean();
|
||||
}
|
||||
|
||||
FTextureID GetTexture() override
|
||||
{
|
||||
return animtex.GetFrameID();
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -187,8 +200,6 @@ public:
|
|||
{
|
||||
if (failed) return false;
|
||||
bool playon = decoder.RunFrame(clock);
|
||||
twod->ClearScreen();
|
||||
DrawTexture(twod, decoder.animTex().GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE);
|
||||
return playon;
|
||||
}
|
||||
|
||||
|
@ -196,6 +207,11 @@ public:
|
|||
{
|
||||
decoder.Close();
|
||||
}
|
||||
|
||||
FTextureID GetTexture() override
|
||||
{
|
||||
return decoder.animTex().GetFrameID();
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -209,7 +225,7 @@ class VpxPlayer : public MoviePlayer
|
|||
bool failed = false;
|
||||
FileReader fr;
|
||||
AnimTextures animtex;
|
||||
const AnimSound* animSnd;
|
||||
const TArray<int> animSnd;
|
||||
|
||||
unsigned width, height;
|
||||
TArray<uint8_t> Pic;
|
||||
|
@ -234,10 +250,10 @@ public:
|
|||
public:
|
||||
bool isvalid() { return !failed; }
|
||||
|
||||
VpxPlayer(FileReader& fr_, const AnimSound* animSnd_, int origframedelay, FString& error)
|
||||
VpxPlayer(FileReader& fr_, TArray<int>& animSnd_, int flags_, int origframedelay, FString& error) : animSnd(std::move(animSnd_))
|
||||
{
|
||||
fr = std::move(fr_);
|
||||
animSnd = animSnd_;
|
||||
flags = flags_;
|
||||
|
||||
if (!ReadIVFHeader(origframedelay))
|
||||
{
|
||||
|
@ -433,30 +449,35 @@ public:
|
|||
framenum++;
|
||||
if (framenum >= numframes) stop = true;
|
||||
|
||||
bool nostopsound = (flags & NOSOUNDCUTOFF);
|
||||
int soundframe = convdenom ? Scale(framenum, convnumer, convdenom) : framenum;
|
||||
if (soundframe > lastsoundframe)
|
||||
{
|
||||
if (animSnd && soundtrack == -1) for (int i = 0; animSnd[i].framenum >= 0; i++)
|
||||
if (soundtrack == -1)
|
||||
{
|
||||
if (animSnd[i].framenum == soundframe)
|
||||
for (unsigned i = 0; i < animSnd.Size(); i += 2)
|
||||
{
|
||||
int sound = animSnd[i].soundnum;
|
||||
if (sound == -1)
|
||||
soundEngine->StopAllChannels();
|
||||
else if (SoundEnabled())
|
||||
soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_NONE, sound, 1.f, ATTN_NONE);
|
||||
if (animSnd[i] == soundframe)
|
||||
{
|
||||
int sound = animSnd[i + 1];
|
||||
if (sound == -1)
|
||||
soundEngine->StopAllChannels();
|
||||
else if (SoundEnabled())
|
||||
soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, nostopsound ? CHANF_UI : CHANF_NONE, sound, 1.f, ATTN_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
lastsoundframe = soundframe;
|
||||
}
|
||||
}
|
||||
DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit, TAG_DONE);
|
||||
return !stop;
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
Mus_Stop();
|
||||
bool nostopsound = (flags & NOSOUNDCUTOFF);
|
||||
if (!nostopsound) soundEngine->StopAllChannels();
|
||||
}
|
||||
|
||||
~VpxPlayer()
|
||||
|
@ -464,6 +485,11 @@ public:
|
|||
vpx_codec_destroy(&codec);
|
||||
animtex.Clean();
|
||||
}
|
||||
|
||||
FTextureID GetTexture() override
|
||||
{
|
||||
return animtex.GetFrameID();
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -498,9 +524,10 @@ class SmkPlayer : public MoviePlayer
|
|||
bool fullscreenScale;
|
||||
uint64_t nFrameNs;
|
||||
int nFrame = 0;
|
||||
const AnimSound* animSnd;
|
||||
const TArray<int> animSnd;
|
||||
FString filename;
|
||||
SoundStream* stream = nullptr;
|
||||
bool hassound = false;
|
||||
|
||||
public:
|
||||
bool isvalid() { return hSMK.isValid; }
|
||||
|
@ -534,22 +561,21 @@ public:
|
|||
}
|
||||
|
||||
|
||||
SmkPlayer(const char *fn, const AnimSound* ans, bool fixedviewport)
|
||||
SmkPlayer(const char *fn, TArray<int>& ans, int flags_) : animSnd(std::move(ans))
|
||||
{
|
||||
hSMK = Smacker_Open(fn);
|
||||
if (!hSMK.isValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
flags = flags_;
|
||||
Smacker_GetFrameSize(hSMK, nWidth, nHeight);
|
||||
pFrame.Resize(nWidth * nHeight + std::max(nWidth, nHeight));
|
||||
nFrameRate = Smacker_GetFrameRate(hSMK);
|
||||
nFrameNs = 1'000'000'000 / nFrameRate;
|
||||
nFrames = Smacker_GetNumFrames(hSMK);
|
||||
Smacker_GetPalette(hSMK, palette);
|
||||
fullscreenScale = (!fixedviewport || (nWidth <= 320 && nHeight <= 200) || nWidth >= 640 || nHeight >= 480);
|
||||
|
||||
bool hassound = false;
|
||||
numAudioTracks = Smacker_GetNumAudioTracks(hSMK);
|
||||
if (numAudioTracks)
|
||||
{
|
||||
|
@ -562,14 +588,12 @@ public:
|
|||
auto read = Smacker_GetAudioData(hSMK, 0, (int16_t*)audioBuffer.Data());
|
||||
if (adata.inf.bitsPerSample == 8) copy8bitSamples(read);
|
||||
else copy16bitSamples(read);
|
||||
animSnd = nullptr;
|
||||
hassound = true;
|
||||
}
|
||||
}
|
||||
if (!hassound)
|
||||
{
|
||||
adata.inf = {};
|
||||
animSnd = ans;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -612,27 +636,21 @@ public:
|
|||
}
|
||||
|
||||
}
|
||||
if (fullscreenScale)
|
||||
{
|
||||
DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawTexture(twod, animtex.GetFrame(), 320, 240, DTA_VirtualWidth, 640, DTA_VirtualHeight, 480, DTA_CenterOffset, true, TAG_DONE);
|
||||
}
|
||||
|
||||
if (frame > nFrame)
|
||||
{
|
||||
nFrame++;
|
||||
Smacker_GetNextFrame(hSMK);
|
||||
if (animSnd) for (int i = 0; animSnd[i].framenum >= 0; i++)
|
||||
bool nostopsound = (flags & NOSOUNDCUTOFF);
|
||||
if (!hassound) for (unsigned i = 0; i < animSnd.Size(); i += 2)
|
||||
{
|
||||
if (animSnd[i].framenum == nFrame)
|
||||
if (animSnd[i] == nFrame)
|
||||
{
|
||||
int sound = animSnd[i].soundnum;
|
||||
int sound = animSnd[i + 1];
|
||||
if (sound == -1)
|
||||
soundEngine->StopAllChannels();
|
||||
else if (SoundEnabled())
|
||||
soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_NONE, sound, 1.f, ATTN_NONE);
|
||||
soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, nostopsound ? CHANF_UI : CHANF_NONE, sound, 1.f, ATTN_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -640,13 +658,24 @@ public:
|
|||
return nFrame < nFrames;
|
||||
}
|
||||
|
||||
void Stop() override
|
||||
{
|
||||
if (stream) S_StopCustomStream(stream);
|
||||
bool nostopsound = (flags & NOSOUNDCUTOFF);
|
||||
if (!nostopsound && !hassound) soundEngine->StopAllChannels();
|
||||
}
|
||||
|
||||
~SmkPlayer()
|
||||
{
|
||||
Smacker_Close(hSMK);
|
||||
if (stream) S_StopCustomStream(stream);
|
||||
soundEngine->StopAllChannels();
|
||||
animtex.Clean();
|
||||
}
|
||||
|
||||
FTextureID GetTexture() override
|
||||
{
|
||||
return animtex.GetFrameID();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -655,61 +684,11 @@ public:
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class DMoviePlayer : public DSkippableScreenJob
|
||||
{
|
||||
MoviePlayer* player;
|
||||
bool started = false;
|
||||
|
||||
public:
|
||||
DMoviePlayer(MoviePlayer* mp)
|
||||
{
|
||||
player = mp;
|
||||
pausable = false;
|
||||
}
|
||||
|
||||
|
||||
void Draw(double smoothratio) override
|
||||
{
|
||||
if (!player)
|
||||
{
|
||||
state = stopped;
|
||||
return;
|
||||
}
|
||||
if (!started)
|
||||
{
|
||||
started = true;
|
||||
player->Start();
|
||||
}
|
||||
uint64_t clock = (ticks + smoothratio) * 1'000'000'000. / GameTicRate;
|
||||
if (state == running && !player->Frame(clock))
|
||||
{
|
||||
state = finished;
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy() override
|
||||
{
|
||||
if (player)
|
||||
{
|
||||
player->Stop();
|
||||
delete player;
|
||||
}
|
||||
player = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
MoviePlayer* OpenMovie(const char* filename, const AnimSound* ans, const int* frameticks, bool nosoundcutoff, FString& error)
|
||||
MoviePlayer* OpenMovie(const char* filename, TArray<int>& ans, const int* frameticks, int flags, FString& error)
|
||||
{
|
||||
FileReader fr;
|
||||
// first try as .ivf - but only if sounds are provided - the decoder is video only.
|
||||
if (ans)
|
||||
if (ans.Size())
|
||||
{
|
||||
auto fn = StripExtension(filename);
|
||||
DefaultExtension(fn, ".ivf");
|
||||
|
@ -739,7 +718,7 @@ MoviePlayer* OpenMovie(const char* filename, const AnimSound* ans, const int* fr
|
|||
|
||||
if (!memcmp(id, "LPF ", 4))
|
||||
{
|
||||
auto anm = new AnmPlayer(fr, ans, frameticks, nosoundcutoff);
|
||||
auto anm = new AnmPlayer(fr, ans, frameticks, flags);
|
||||
if (!anm->isvalid())
|
||||
{
|
||||
error.Format("%s: invalid ANM file.\n", filename);
|
||||
|
@ -751,7 +730,7 @@ MoviePlayer* OpenMovie(const char* filename, const AnimSound* ans, const int* fr
|
|||
else if (!memcmp(id, "SMK2", 4))
|
||||
{
|
||||
fr.Close();
|
||||
auto anm = new SmkPlayer(filename, ans, true); // Fixme: Handle Blood's video scaling behavior more intelligently.
|
||||
auto anm = new SmkPlayer(filename, ans, flags);
|
||||
if (!anm->isvalid())
|
||||
{
|
||||
error.Format("%s: invalid SMK file.\n", filename);
|
||||
|
@ -772,7 +751,7 @@ MoviePlayer* OpenMovie(const char* filename, const AnimSound* ans, const int* fr
|
|||
}
|
||||
else if (!memcmp(id, "DKIF\0\0 \0VP80", 12))
|
||||
{
|
||||
auto anm = new VpxPlayer(fr, ans, frameticks ? frameticks[1] : 0, error);
|
||||
auto anm = new VpxPlayer(fr, ans, frameticks ? frameticks[1] : 0, flags, error);
|
||||
if (!anm->isvalid())
|
||||
{
|
||||
delete anm;
|
||||
|
@ -795,20 +774,53 @@ MoviePlayer* OpenMovie(const char* filename, const AnimSound* ans, const int* fr
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* frameticks, bool nosoundcutoff)
|
||||
DEFINE_ACTION_FUNCTION(_MoviePlayer, Create)
|
||||
{
|
||||
if (!filename)
|
||||
{
|
||||
return Create<DBlackScreen>(1);
|
||||
}
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_STRING(filename);
|
||||
PARAM_POINTER(sndinf, TArray<int>);
|
||||
PARAM_INT(flags);
|
||||
PARAM_INT(frametime);
|
||||
PARAM_INT(firstframetime);
|
||||
PARAM_INT(lastframetime);
|
||||
|
||||
FString error;
|
||||
auto movie = OpenMovie(filename, ans, frameticks, nosoundcutoff, error);
|
||||
if (firstframetime == -1) firstframetime = frametime;
|
||||
if (lastframetime == -1) lastframetime = frametime;
|
||||
int frametimes[] = { firstframetime, frametime, lastframetime };
|
||||
auto movie = OpenMovie(filename, *sndinf, frametime == -1? nullptr : frametimes, flags, error);
|
||||
if (!movie)
|
||||
{
|
||||
Printf(TEXTCOLOR_YELLOW, "%s", error.GetChars());
|
||||
return Create<DBlackScreen>(1);
|
||||
}
|
||||
return Create<DMoviePlayer>(movie);
|
||||
ACTION_RETURN_POINTER(movie);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_MoviePlayer, Start)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(MoviePlayer);
|
||||
self->Start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_MoviePlayer, Frame)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(MoviePlayer);
|
||||
PARAM_FLOAT(clock);
|
||||
ACTION_RETURN_INT(self->Frame(int64_t(clock)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_MoviePlayer, Destroy)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(MoviePlayer);
|
||||
self->Stop();
|
||||
delete self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_MoviePlayer, GetTexture)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(MoviePlayer);
|
||||
ACTION_RETURN_INT(self->GetTexture().GetIndex());
|
||||
}
|
||||
|
|
1059
source/core/nodebuilder/nodebuild.cpp
Normal file
1059
source/core/nodebuilder/nodebuild.cpp
Normal file
File diff suppressed because it is too large
Load diff
470
source/core/nodebuilder/nodebuild.h
Normal file
470
source/core/nodebuilder/nodebuild.h
Normal file
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
** nodebuild.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2016 Randy Heit
|
||||
** 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.
|
||||
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation; either version 2 of the License, or (at
|
||||
** your option) any later version.
|
||||
**
|
||||
** 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.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "tarray.h"
|
||||
#include "x86.h"
|
||||
#include "build.h"
|
||||
|
||||
struct FPolySeg;
|
||||
struct FMiniBSP;
|
||||
struct FLevelLocals;
|
||||
|
||||
struct FEventInfo
|
||||
{
|
||||
int Vertex;
|
||||
uint32_t FrontSeg;
|
||||
};
|
||||
|
||||
struct FEvent
|
||||
{
|
||||
FEvent *Parent, *Left, *Right;
|
||||
double Distance;
|
||||
FEventInfo Info;
|
||||
};
|
||||
|
||||
class FEventTree
|
||||
{
|
||||
public:
|
||||
FEventTree ();
|
||||
~FEventTree ();
|
||||
|
||||
FEvent *GetMinimum ();
|
||||
FEvent *GetSuccessor (FEvent *event) const { FEvent *node = Successor(event); return node == &Nil ? NULL : node; }
|
||||
FEvent *GetPredecessor (FEvent *event) const { FEvent *node = Predecessor(event); return node == &Nil ? NULL : node; }
|
||||
|
||||
FEvent *GetNewNode ();
|
||||
void Insert (FEvent *event);
|
||||
FEvent *FindEvent (double distance) const;
|
||||
void DeleteAll ();
|
||||
|
||||
void PrintTree () const { PrintTree (Root); }
|
||||
|
||||
private:
|
||||
FEvent Nil;
|
||||
FEvent *Root;
|
||||
FEvent *Spare;
|
||||
|
||||
void DeletionTraverser (FEvent *event);
|
||||
FEvent *Successor (FEvent *event) const;
|
||||
FEvent *Predecessor (FEvent *event) const;
|
||||
|
||||
void PrintTree (const FEvent *event) const;
|
||||
};
|
||||
|
||||
struct FSimpleVert
|
||||
{
|
||||
fixed_t x, y;
|
||||
};
|
||||
|
||||
typedef int64_t fixed64_t;
|
||||
|
||||
struct vertex_t
|
||||
{
|
||||
DVector2 p;
|
||||
|
||||
void set(fixed_t x, fixed_t y)
|
||||
{
|
||||
p.X = x / 65536.;
|
||||
p.Y = y / 65536.;
|
||||
}
|
||||
|
||||
double fX() const
|
||||
{
|
||||
return p.X;
|
||||
}
|
||||
|
||||
double fY() const
|
||||
{
|
||||
return p.Y;
|
||||
}
|
||||
|
||||
fixed_t fixX() const
|
||||
{
|
||||
return FLOAT2FIXED(p.X);
|
||||
}
|
||||
|
||||
fixed_t fixY() const
|
||||
{
|
||||
return FLOAT2FIXED(p.Y);
|
||||
}
|
||||
};
|
||||
|
||||
struct side_t;
|
||||
|
||||
struct line_t
|
||||
{
|
||||
vertex_t* v1, * v2; // vertices, from v1 to v2
|
||||
side_t* sidedef[2];
|
||||
sectortype* frontsector, * backsector;
|
||||
int linenum;
|
||||
|
||||
int Index() const { return linenum; }
|
||||
|
||||
};
|
||||
|
||||
struct side_t
|
||||
{
|
||||
sectortype* sector; // Sector the SideDef is facing.
|
||||
int sidenum;
|
||||
int Index() const { return sidenum; }
|
||||
};
|
||||
|
||||
struct subsector_t;
|
||||
struct seg_t
|
||||
{
|
||||
vertex_t* v1;
|
||||
vertex_t* v2;
|
||||
|
||||
side_t* sidedef;
|
||||
line_t* linedef;
|
||||
|
||||
// Sector references. Could be retrieved from linedef, too.
|
||||
sectortype* frontsector;
|
||||
sectortype* backsector; // NULL for one-sided lines
|
||||
|
||||
seg_t* PartnerSeg;
|
||||
subsector_t* Subsector;
|
||||
|
||||
int segnum;
|
||||
|
||||
int Index() const { return segnum; }
|
||||
};
|
||||
|
||||
struct glseg_t : public seg_t
|
||||
{
|
||||
uint32_t Partner;
|
||||
};
|
||||
|
||||
struct subsector_t
|
||||
{
|
||||
sectortype* sector;
|
||||
seg_t* firstline;
|
||||
uint32_t numlines;
|
||||
};
|
||||
|
||||
struct node_t
|
||||
{
|
||||
// Partition line.
|
||||
fixed_t x;
|
||||
fixed_t y;
|
||||
fixed_t dx;
|
||||
fixed_t dy;
|
||||
union
|
||||
{
|
||||
float bbox[2][4]; // Bounding box for each child.
|
||||
fixed_t nb_bbox[2][4]; // Used by nodebuilder.
|
||||
};
|
||||
float len;
|
||||
int nodenum;
|
||||
union
|
||||
{
|
||||
void* children[2]; // If bit 0 is set, it's a subsector.
|
||||
int intchildren[2]; // Used by nodebuilder.
|
||||
};
|
||||
|
||||
int Index() const { return nodenum; }
|
||||
};
|
||||
|
||||
struct FLevelLocals
|
||||
{
|
||||
TArray<vertex_t> vertexes;
|
||||
TArray<subsector_t> subsectors;
|
||||
TArray<node_t> nodes;
|
||||
TArray<seg_t> segs;
|
||||
};
|
||||
|
||||
enum { NO_SIDE = 0x7fffffff };
|
||||
|
||||
|
||||
class FNodeBuilder
|
||||
{
|
||||
struct FPrivSeg
|
||||
{
|
||||
int v1, v2;
|
||||
int sidedef;
|
||||
int linedef;
|
||||
sectortype *frontsector;
|
||||
sectortype *backsector;
|
||||
uint32_t next;
|
||||
uint32_t nextforvert;
|
||||
uint32_t nextforvert2;
|
||||
int loopnum; // loop number for split avoidance (0 means splitting is okay)
|
||||
uint32_t partner; // seg on back side
|
||||
uint32_t storedseg; // seg # in the GL_SEGS lump
|
||||
|
||||
int planenum;
|
||||
bool planefront;
|
||||
FPrivSeg *hashnext;
|
||||
};
|
||||
struct FPrivVert : FSimpleVert
|
||||
{
|
||||
uint32_t segs; // segs that use this vertex as v1
|
||||
uint32_t segs2; // segs that use this vertex as v2
|
||||
|
||||
bool operator== (const FPrivVert &other)
|
||||
{
|
||||
return x == other.x && y == other.y;
|
||||
}
|
||||
};
|
||||
struct FSimpleLine
|
||||
{
|
||||
fixed_t x, y, dx, dy;
|
||||
};
|
||||
union USegPtr
|
||||
{
|
||||
uint32_t SegNum;
|
||||
FPrivSeg *SegPtr;
|
||||
};
|
||||
struct FSplitSharer
|
||||
{
|
||||
double Distance;
|
||||
uint32_t Seg;
|
||||
bool Forward;
|
||||
};
|
||||
|
||||
// Like a blockmap, but for vertices instead of lines
|
||||
class IVertexMap
|
||||
{
|
||||
public:
|
||||
virtual ~IVertexMap();
|
||||
virtual int SelectVertexExact(FPrivVert &vert) = 0;
|
||||
virtual int SelectVertexClose(FPrivVert &vert) = 0;
|
||||
private:
|
||||
IVertexMap &operator=(const IVertexMap &);
|
||||
};
|
||||
|
||||
class FVertexMap : public IVertexMap
|
||||
{
|
||||
public:
|
||||
FVertexMap (FNodeBuilder &builder, fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy);
|
||||
~FVertexMap ();
|
||||
|
||||
int SelectVertexExact (FPrivVert &vert);
|
||||
int SelectVertexClose (FPrivVert &vert);
|
||||
|
||||
private:
|
||||
FNodeBuilder &MyBuilder;
|
||||
TArray<int> *VertexGrid;
|
||||
|
||||
fixed64_t MinX, MinY, MaxX, MaxY;
|
||||
int BlocksWide, BlocksTall;
|
||||
|
||||
enum { BLOCK_SHIFT = 8 + FRACBITS };
|
||||
enum { BLOCK_SIZE = 1 << BLOCK_SHIFT };
|
||||
|
||||
int InsertVertex (FPrivVert &vert);
|
||||
inline int GetBlock (fixed64_t x, fixed64_t y)
|
||||
{
|
||||
assert (x >= MinX);
|
||||
assert (y >= MinY);
|
||||
assert (x <= MaxX);
|
||||
assert (y <= MaxY);
|
||||
return (unsigned(x - MinX) >> BLOCK_SHIFT) + (unsigned(y - MinY) >> BLOCK_SHIFT) * BlocksWide;
|
||||
}
|
||||
};
|
||||
|
||||
class FVertexMapSimple : public IVertexMap
|
||||
{
|
||||
public:
|
||||
FVertexMapSimple(FNodeBuilder &builder);
|
||||
|
||||
int SelectVertexExact(FPrivVert &vert);
|
||||
int SelectVertexClose(FPrivVert &vert);
|
||||
private:
|
||||
int InsertVertex(FPrivVert &vert);
|
||||
|
||||
FNodeBuilder &MyBuilder;
|
||||
};
|
||||
|
||||
friend class FVertexMap;
|
||||
friend class FVertexMapSimple;
|
||||
|
||||
public:
|
||||
struct FLevel
|
||||
{
|
||||
vertex_t *Vertices; int NumVertices;
|
||||
side_t *Sides; int NumSides;
|
||||
line_t *Lines; int NumLines;
|
||||
|
||||
fixed_t MinX, MinY, MaxX, MaxY;
|
||||
|
||||
void FindMapBounds();
|
||||
void ResetMapBounds()
|
||||
{
|
||||
MinX = FIXED_MAX;
|
||||
MinY = FIXED_MAX;
|
||||
MaxX = FIXED_MIN;
|
||||
MaxY = FIXED_MIN;
|
||||
}
|
||||
};
|
||||
|
||||
struct FPolyStart
|
||||
{
|
||||
int polynum;
|
||||
fixed_t x, y;
|
||||
};
|
||||
|
||||
FNodeBuilder (FLevel &lev);
|
||||
~FNodeBuilder ();
|
||||
|
||||
void Extract(FLevelLocals &lev);
|
||||
const int *GetOldVertexTable();
|
||||
|
||||
// These are used for building sub-BSP trees for polyobjects.
|
||||
void Clear();
|
||||
void AddSegs(seg_t *segs, int numsegs);
|
||||
void BuildMini(bool makeGLNodes);
|
||||
|
||||
static angle_t PointToAngle (fixed_t dx, fixed_t dy);
|
||||
|
||||
// < 0 : in front of line
|
||||
// == 0 : on line
|
||||
// > 0 : behind line
|
||||
|
||||
static inline int PointOnSide (int x, int y, int x1, int y1, int dx, int dy);
|
||||
|
||||
private:
|
||||
IVertexMap *VertexMap;
|
||||
int *OldVertexTable;
|
||||
|
||||
TArray<node_t> Nodes;
|
||||
TArray<subsector_t> Subsectors;
|
||||
TArray<uint32_t> SubsectorSets;
|
||||
TArray<FPrivSeg> Segs;
|
||||
TArray<FPrivVert> Vertices;
|
||||
TArray<USegPtr> SegList;
|
||||
TArray<uint8_t> PlaneChecked;
|
||||
TArray<FSimpleLine> Planes;
|
||||
|
||||
TArray<int> Touched; // Loops a splitter touches on a vertex
|
||||
TArray<int> Colinear; // Loops with edges colinear to a splitter
|
||||
FEventTree Events; // Vertices intersected by the current splitter
|
||||
|
||||
TArray<FSplitSharer> SplitSharers; // Segs colinear with the current splitter
|
||||
|
||||
uint32_t HackSeg; // Seg to force to back of splitter
|
||||
uint32_t HackMate; // Seg to use in front of hack seg
|
||||
FLevel &Level;
|
||||
bool GLNodes; // Add minisegs to make GL nodes?
|
||||
|
||||
// Progress meter stuff
|
||||
int SegsStuffed;
|
||||
|
||||
void FindUsedVertices (vertex_t *vertices, int max);
|
||||
void BuildTree ();
|
||||
void MakeSegsFromSides ();
|
||||
int CreateSeg (int linenum, int sidenum);
|
||||
void GroupSegPlanes ();
|
||||
void GroupSegPlanesSimple ();
|
||||
void AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg);
|
||||
int CreateNode (uint32_t set, unsigned int count, fixed_t bbox[4]);
|
||||
int CreateSubsector (uint32_t set, fixed_t bbox[4]);
|
||||
void CreateSubsectorsForReal ();
|
||||
bool CheckSubsector (uint32_t set, node_t &node, uint32_t &splitseg);
|
||||
bool CheckSubsectorOverlappingSegs (uint32_t set, node_t &node, uint32_t &splitseg);
|
||||
bool ShoveSegBehind (uint32_t set, node_t &node, uint32_t seg, uint32_t mate); int SelectSplitter (uint32_t set, node_t &node, uint32_t &splitseg, int step, bool nosplit);
|
||||
void SplitSegs (uint32_t set, node_t &node, uint32_t splitseg, uint32_t &outset0, uint32_t &outset1, unsigned int &count0, unsigned int &count1);
|
||||
uint32_t SplitSeg (uint32_t segnum, int splitvert, int v1InFront);
|
||||
int Heuristic (node_t &node, uint32_t set, bool honorNoSplit);
|
||||
|
||||
// Returns:
|
||||
// 0 = seg is in front
|
||||
// 1 = seg is in back
|
||||
// -1 = seg cuts the node
|
||||
|
||||
int ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]);
|
||||
|
||||
void FixSplitSharers (const node_t &node);
|
||||
double AddIntersection (const node_t &node, int vertex);
|
||||
void AddMinisegs (const node_t &node, uint32_t splitseg, uint32_t &fset, uint32_t &rset);
|
||||
uint32_t CheckLoopStart (fixed_t dx, fixed_t dy, int vertex1, int vertex2);
|
||||
uint32_t CheckLoopEnd (fixed_t dx, fixed_t dy, int vertex2);
|
||||
void RemoveSegFromVert1 (uint32_t segnum, int vertnum);
|
||||
void RemoveSegFromVert2 (uint32_t segnum, int vertnum);
|
||||
uint32_t AddMiniseg (int v1, int v2, uint32_t partner, uint32_t seg1, uint32_t splitseg);
|
||||
void SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const;
|
||||
|
||||
int CloseSubsector (TArray<glseg_t> &segs, int subsector, vertex_t *outVerts);
|
||||
uint32_t PushGLSeg (TArray<glseg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts);
|
||||
void PushConnectingGLSeg (int subsector, TArray<glseg_t> &segs, vertex_t *v1, vertex_t *v2);
|
||||
int OutputDegenerateSubsector (TArray<glseg_t> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts);
|
||||
|
||||
static int SortSegs (const void *a, const void *b);
|
||||
|
||||
double InterceptVector (const node_t &splitter, const FPrivSeg &seg);
|
||||
|
||||
void PrintSet (int l, uint32_t set);
|
||||
|
||||
FNodeBuilder &operator= (const FNodeBuilder &) { return *this; }
|
||||
};
|
||||
|
||||
// Points within this distance of a line will be considered on the line.
|
||||
// Units are in fixed_ts.
|
||||
const double SIDE_EPSILON = 6.5536;
|
||||
|
||||
// Vertices within this distance of each other will be considered as the same vertex.
|
||||
#define VERTEX_EPSILON 6 // This is a fixed_t value
|
||||
|
||||
inline int FNodeBuilder::PointOnSide (int x, int y, int x1, int y1, int dx, int dy)
|
||||
{
|
||||
// For most cases, a simple dot product is enough.
|
||||
double d_dx = double(dx);
|
||||
double d_dy = double(dy);
|
||||
double d_x = double(x);
|
||||
double d_y = double(y);
|
||||
double d_x1 = double(x1);
|
||||
double d_y1 = double(y1);
|
||||
|
||||
double s_num = (d_y1-d_y)*d_dx - (d_x1-d_x)*d_dy;
|
||||
|
||||
if (fabs(s_num) < 17179869184.f) // 4<<32
|
||||
{
|
||||
// Either the point is very near the line, or the segment defining
|
||||
// the line is very short: Do a more expensive test to determine
|
||||
// just how far from the line the point is.
|
||||
double l = d_dx*d_dx + d_dy*d_dy; // double l = sqrt(d_dx*d_dx+d_dy*d_dy);
|
||||
double dist = s_num * s_num / l; // double dist = fabs(s_num)/l;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON) // if (dist < SIDE_EPSILON)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return s_num > 0.0 ? -1 : 1;
|
||||
}
|
||||
|
||||
using sector_t = sectortype;
|
135
source/core/nodebuilder/nodebuild_classify_nosse2.cpp
Normal file
135
source/core/nodebuilder/nodebuild_classify_nosse2.cpp
Normal file
|
@ -0,0 +1,135 @@
|
|||
#include "nodebuild.h"
|
||||
|
||||
#define FAR_ENOUGH 17179869184.f // 4<<32
|
||||
|
||||
int FNodeBuilder::ClassifyLine(node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2])
|
||||
{
|
||||
double d_x1 = double(node.x);
|
||||
double d_y1 = double(node.y);
|
||||
double d_dx = double(node.dx);
|
||||
double d_dy = double(node.dy);
|
||||
double d_xv1 = double(v1->x);
|
||||
double d_xv2 = double(v2->x);
|
||||
double d_yv1 = double(v1->y);
|
||||
double d_yv2 = double(v2->y);
|
||||
|
||||
double s_num1 = (d_y1 - d_yv1) * d_dx - (d_x1 - d_xv1) * d_dy;
|
||||
double s_num2 = (d_y1 - d_yv2) * d_dx - (d_x1 - d_xv2) * d_dy;
|
||||
|
||||
int nears = 0;
|
||||
|
||||
if (s_num1 <= -FAR_ENOUGH)
|
||||
{
|
||||
if (s_num2 <= -FAR_ENOUGH)
|
||||
{
|
||||
sidev[0] = sidev[1] = 1;
|
||||
return 1;
|
||||
}
|
||||
if (s_num2 >= FAR_ENOUGH)
|
||||
{
|
||||
sidev[0] = 1;
|
||||
sidev[1] = -1;
|
||||
return -1;
|
||||
}
|
||||
nears = 1;
|
||||
}
|
||||
else if (s_num1 >= FAR_ENOUGH)
|
||||
{
|
||||
if (s_num2 >= FAR_ENOUGH)
|
||||
{
|
||||
sidev[0] = sidev[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if (s_num2 <= -FAR_ENOUGH)
|
||||
{
|
||||
sidev[0] = -1;
|
||||
sidev[1] = 1;
|
||||
return -1;
|
||||
}
|
||||
nears = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nears = 2 | int(fabs(s_num2) < FAR_ENOUGH);
|
||||
}
|
||||
|
||||
if (nears)
|
||||
{
|
||||
double l = 1.f / (d_dx*d_dx + d_dy*d_dy);
|
||||
if (nears & 2)
|
||||
{
|
||||
double dist = s_num1 * s_num1 * l;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||
{
|
||||
sidev[0] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||
}
|
||||
if (nears & 1)
|
||||
{
|
||||
double dist = s_num2 * s_num2 * l;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||
{
|
||||
sidev[1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||
}
|
||||
|
||||
if ((sidev[0] | sidev[1]) == 0)
|
||||
{ // seg is coplanar with the splitter, so use its orientation to determine
|
||||
// which child it ends up in. If it faces the same direction as the splitter,
|
||||
// it goes in front. Otherwise, it goes in back.
|
||||
|
||||
if (node.dx != 0)
|
||||
{
|
||||
if ((node.dx > 0 && v2->x > v1->x) || (node.dx < 0 && v2->x < v1->x))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((node.dy > 0 && v2->y > v1->y) || (node.dy < 0 && v2->y < v1->y))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sidev[0] <= 0 && sidev[1] <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (sidev[0] >= 0 && sidev[1] >= 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
226
source/core/nodebuilder/nodebuild_events.cpp
Normal file
226
source/core/nodebuilder/nodebuild_events.cpp
Normal file
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
** nodebuild_events.cpp
|
||||
**
|
||||
** A red-black tree for keeping track of segs that get touched by a splitter.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2006 Randy Heit
|
||||
** 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.
|
||||
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation; either version 2 of the License, or (at
|
||||
** your option) any later version.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "nodebuild.h"
|
||||
#include "printf.h"
|
||||
|
||||
FEventTree::FEventTree ()
|
||||
: Root (&Nil), Spare (NULL)
|
||||
{
|
||||
memset (&Nil, 0, sizeof(Nil));
|
||||
}
|
||||
|
||||
FEventTree::~FEventTree ()
|
||||
{
|
||||
FEvent *probe;
|
||||
|
||||
DeleteAll ();
|
||||
probe = Spare;
|
||||
while (probe != NULL)
|
||||
{
|
||||
FEvent *next = probe->Left;
|
||||
delete probe;
|
||||
probe = next;
|
||||
}
|
||||
}
|
||||
|
||||
void FEventTree::DeleteAll ()
|
||||
{
|
||||
DeletionTraverser (Root);
|
||||
Root = &Nil;
|
||||
}
|
||||
|
||||
void FEventTree::DeletionTraverser (FEvent *node)
|
||||
{
|
||||
if (node != &Nil && node != NULL)
|
||||
{
|
||||
DeletionTraverser (node->Left);
|
||||
DeletionTraverser (node->Right);
|
||||
node->Left = Spare;
|
||||
Spare = node;
|
||||
}
|
||||
}
|
||||
|
||||
FEvent *FEventTree::GetNewNode ()
|
||||
{
|
||||
FEvent *node;
|
||||
|
||||
if (Spare != NULL)
|
||||
{
|
||||
node = Spare;
|
||||
Spare = node->Left;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = new FEvent;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void FEventTree::Insert (FEvent *z)
|
||||
{
|
||||
FEvent *y = &Nil;
|
||||
FEvent *x = Root;
|
||||
|
||||
while (x != &Nil)
|
||||
{
|
||||
y = x;
|
||||
if (z->Distance < x->Distance)
|
||||
{
|
||||
x = x->Left;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = x->Right;
|
||||
}
|
||||
}
|
||||
z->Parent = y;
|
||||
if (y == &Nil)
|
||||
{
|
||||
Root = z;
|
||||
}
|
||||
else if (z->Distance < y->Distance)
|
||||
{
|
||||
y->Left = z;
|
||||
}
|
||||
else
|
||||
{
|
||||
y->Right = z;
|
||||
}
|
||||
z->Left = &Nil;
|
||||
z->Right = &Nil;
|
||||
}
|
||||
|
||||
FEvent *FEventTree::Successor (FEvent *event) const
|
||||
{
|
||||
if (event->Right != &Nil)
|
||||
{
|
||||
event = event->Right;
|
||||
while (event->Left != &Nil)
|
||||
{
|
||||
event = event->Left;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
else
|
||||
{
|
||||
FEvent *y = event->Parent;
|
||||
while (y != &Nil && event == y->Right)
|
||||
{
|
||||
event = y;
|
||||
y = y->Parent;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
FEvent *FEventTree::Predecessor (FEvent *event) const
|
||||
{
|
||||
if (event->Left != &Nil)
|
||||
{
|
||||
event = event->Left;
|
||||
while (event->Right != &Nil)
|
||||
{
|
||||
event = event->Right;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
else
|
||||
{
|
||||
FEvent *y = event->Parent;
|
||||
while (y != &Nil && event == y->Left)
|
||||
{
|
||||
event = y;
|
||||
y = y->Parent;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
FEvent *FEventTree::FindEvent (double key) const
|
||||
{
|
||||
FEvent *node = Root;
|
||||
|
||||
while (node != &Nil)
|
||||
{
|
||||
if (node->Distance == key)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
else if (node->Distance > key)
|
||||
{
|
||||
node = node->Left;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node->Right;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FEvent *FEventTree::GetMinimum ()
|
||||
{
|
||||
FEvent *node = Root;
|
||||
|
||||
if (node == &Nil)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
while (node->Left != &Nil)
|
||||
{
|
||||
node = node->Left;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void FEventTree::PrintTree (const FEvent *event) const
|
||||
{
|
||||
// Use the CRT's sprintf so that it shares the same formatting as ZDBSP's output.
|
||||
char buff[100];
|
||||
if (event != &Nil)
|
||||
{
|
||||
PrintTree(event->Left);
|
||||
sprintf(buff, " Distance %g, vertex %d, seg %u\n",
|
||||
g_sqrt(event->Distance/4294967296.0), event->Info.Vertex, (unsigned)event->Info.FrontSeg);
|
||||
Printf(PRINT_LOG, "%s", buff);
|
||||
PrintTree(event->Right);
|
||||
}
|
||||
}
|
440
source/core/nodebuilder/nodebuild_extract.cpp
Normal file
440
source/core/nodebuilder/nodebuild_extract.cpp
Normal file
|
@ -0,0 +1,440 @@
|
|||
/*
|
||||
** nodebuild_extract.cpp
|
||||
**
|
||||
** Converts the nodes, segs, and subsectors from the node builder's
|
||||
** internal format to the format used by the rest of the game.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2006 Randy Heit
|
||||
** 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.
|
||||
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation; either version 2 of the License, or (at
|
||||
** your option) any later version.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "nodebuild.h"
|
||||
|
||||
#if 0
|
||||
#define D(x) x
|
||||
#define DD 1
|
||||
#else
|
||||
#define D(x) do{}while(0)
|
||||
#undef DD
|
||||
#endif
|
||||
|
||||
|
||||
void FNodeBuilder::Extract (FLevelLocals &theLevel)
|
||||
{
|
||||
int i;
|
||||
|
||||
auto &outVerts = theLevel.vertexes;
|
||||
int vertCount = Vertices.Size ();
|
||||
outVerts.Alloc(vertCount);
|
||||
|
||||
for (i = 0; i < vertCount; ++i)
|
||||
{
|
||||
outVerts[i].set(Vertices[i].x, Vertices[i].y);
|
||||
}
|
||||
|
||||
auto &outSubs = theLevel.subsectors;
|
||||
auto subCount = Subsectors.Size();
|
||||
outSubs.Alloc(subCount);
|
||||
memset(&outSubs[0], 0, subCount * sizeof(subsector_t));
|
||||
|
||||
auto &outNodes = theLevel.nodes;
|
||||
auto nodeCount = Nodes.Size ();
|
||||
outNodes.Alloc(nodeCount);
|
||||
|
||||
memcpy (&outNodes[0], &Nodes[0], nodeCount*sizeof(node_t));
|
||||
for (unsigned i = 0; i < nodeCount; ++i)
|
||||
{
|
||||
D(Printf(PRINT_LOG, "Node %d: Splitter[%08x,%08x] [%08x,%08x]\n", i,
|
||||
outNodes[i].x, outNodes[i].y, outNodes[i].dx, outNodes[i].dy));
|
||||
// Go backwards because on 64-bit systems, both of the intchildren are
|
||||
// inside the first in-game child.
|
||||
for (int j = 1; j >= 0; --j)
|
||||
{
|
||||
if (outNodes[i].intchildren[j] & 0x80000000)
|
||||
{
|
||||
D(Printf(PRINT_LOG, " subsector %d\n", outNodes[i].intchildren[j] & 0x7FFFFFFF));
|
||||
outNodes[i].children[j] = (uint8_t *)(&outSubs[(outNodes[i].intchildren[j] & 0x7fffffff)]) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
D(Printf(PRINT_LOG, " node %d\n", outNodes[i].intchildren[j]));
|
||||
outNodes[i].children[j] = &outNodes[outNodes[i].intchildren[j]];
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < 2; ++j)
|
||||
{
|
||||
for (int k = 0; k < 4; ++k)
|
||||
{
|
||||
outNodes[i].bbox[j][k] = FIXED2FLOAT(outNodes[i].nb_bbox[j][k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto &outSegs = theLevel.segs;
|
||||
if (GLNodes)
|
||||
{
|
||||
TArray<glseg_t> segs (Segs.Size()*5/4);
|
||||
|
||||
for (unsigned i = 0; i < subCount; ++i)
|
||||
{
|
||||
uint32_t numsegs = CloseSubsector (segs, i, &outVerts[0]);
|
||||
outSubs[i].numlines = numsegs;
|
||||
outSubs[i].firstline = (seg_t *)(size_t)(segs.Size() - numsegs);
|
||||
}
|
||||
|
||||
auto segCount = segs.Size ();
|
||||
outSegs.Alloc(segCount);
|
||||
|
||||
for (unsigned i = 0; i < segCount; ++i)
|
||||
{
|
||||
outSegs[i] = *(seg_t *)&segs[i];
|
||||
|
||||
if (segs[i].Partner != UINT_MAX)
|
||||
{
|
||||
const uint32_t storedseg = Segs[segs[i].Partner].storedseg;
|
||||
outSegs[i].PartnerSeg = UINT_MAX == storedseg ? nullptr : &outSegs[storedseg];
|
||||
}
|
||||
else
|
||||
{
|
||||
outSegs[i].PartnerSeg = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (&outSubs[0], &Subsectors[0], subCount*sizeof(subsector_t));
|
||||
auto segCount = Segs.Size ();
|
||||
outSegs.Alloc(segCount);
|
||||
for (unsigned i = 0; i < segCount; ++i)
|
||||
{
|
||||
const FPrivSeg *org = &Segs[SegList[i].SegNum];
|
||||
seg_t *out = &outSegs[i];
|
||||
|
||||
D(Printf(PRINT_LOG, "Seg %d: v1(%d) -> v2(%d)\n", i, org->v1, org->v2));
|
||||
|
||||
out->v1 = &outVerts[org->v1];
|
||||
out->v2 = &outVerts[org->v2];
|
||||
out->backsector = org->backsector;
|
||||
out->frontsector = org->frontsector;
|
||||
out->linedef = Level.Lines + org->linedef;
|
||||
out->sidedef = Level.Sides + org->sidedef;
|
||||
out->PartnerSeg = nullptr;
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < subCount; ++i)
|
||||
{
|
||||
outSubs[i].firstline = &outSegs[(size_t)outSubs[i].firstline];
|
||||
}
|
||||
|
||||
D(Printf("%i segs, %i nodes, %i subsectors\n", segCount, nodeCount, subCount));
|
||||
|
||||
for (i = 0; i < Level.NumLines; ++i)
|
||||
{
|
||||
Level.Lines[i].v1 = &outVerts[(size_t)Level.Lines[i].v1];
|
||||
Level.Lines[i].v2 = &outVerts[(size_t)Level.Lines[i].v2];
|
||||
}
|
||||
}
|
||||
|
||||
int FNodeBuilder::CloseSubsector (TArray<glseg_t> &segs, int subsector, vertex_t *outVerts)
|
||||
{
|
||||
FPrivSeg *seg, *prev;
|
||||
angle_t prevAngle;
|
||||
double accumx, accumy;
|
||||
fixed_t midx, midy;
|
||||
int firstVert;
|
||||
uint32_t first, max, count, i, j;
|
||||
bool diffplanes;
|
||||
int firstplane;
|
||||
|
||||
first = (uint32_t)(size_t)Subsectors[subsector].firstline;
|
||||
max = first + Subsectors[subsector].numlines;
|
||||
count = 0;
|
||||
|
||||
accumx = accumy = 0.0;
|
||||
diffplanes = false;
|
||||
firstplane = Segs[SegList[first].SegNum].planenum;
|
||||
|
||||
// Calculate the midpoint of the subsector and also check for degenerate subsectors.
|
||||
// A subsector is degenerate if it exists in only one dimension, which can be
|
||||
// detected when all the segs lie in the same plane. This can happen if you have
|
||||
// outward-facing lines in the void that don't point toward any sector. (Some of the
|
||||
// polyobjects in Hexen are constructed like this.)
|
||||
for (i = first; i < max; ++i)
|
||||
{
|
||||
seg = &Segs[SegList[i].SegNum];
|
||||
accumx += double(Vertices[seg->v1].x) + double(Vertices[seg->v2].x);
|
||||
accumy += double(Vertices[seg->v1].y) + double(Vertices[seg->v2].y);
|
||||
if (firstplane != seg->planenum)
|
||||
{
|
||||
diffplanes = true;
|
||||
}
|
||||
}
|
||||
|
||||
midx = fixed_t(accumx / (max - first) / 2);
|
||||
midy = fixed_t(accumy / (max - first) / 2);
|
||||
|
||||
seg = &Segs[SegList[first].SegNum];
|
||||
prevAngle = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy);
|
||||
seg->storedseg = PushGLSeg (segs, seg, outVerts);
|
||||
count = 1;
|
||||
prev = seg;
|
||||
firstVert = seg->v1;
|
||||
|
||||
#ifdef DD
|
||||
Printf(PRINT_LOG, "--%d--\n", subsector);
|
||||
for (j = first; j < max; ++j)
|
||||
{
|
||||
seg = &Segs[SegList[j].SegNum];
|
||||
angle_t ang = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy);
|
||||
Printf(PRINT_LOG, "%d%c %5d(%5d,%5d)->%5d(%5d,%5d) - %3.5f %d,%d [%08x,%08x]-[%08x,%08x]\n", j,
|
||||
seg->linedef == -1 ? '+' : ':',
|
||||
seg->v1, Vertices[seg->v1].x>>16, Vertices[seg->v1].y>>16,
|
||||
seg->v2, Vertices[seg->v2].x>>16, Vertices[seg->v2].y>>16,
|
||||
double(ang/2)*180/(1<<30),
|
||||
seg->planenum, seg->planefront,
|
||||
Vertices[seg->v1].x, Vertices[seg->v1].y,
|
||||
Vertices[seg->v2].x, Vertices[seg->v2].y);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (diffplanes)
|
||||
{ // A well-behaved subsector. Output the segs sorted by the angle formed by connecting
|
||||
// the subsector's center to their first vertex.
|
||||
|
||||
D(Printf(PRINT_LOG, "Well behaved subsector\n"));
|
||||
for (i = first + 1; i < max; ++i)
|
||||
{
|
||||
angle_t bestdiff = ANGLE_MAX;
|
||||
FPrivSeg *bestseg = NULL;
|
||||
uint32_t bestj = UINT_MAX;
|
||||
j = first;
|
||||
do
|
||||
{
|
||||
seg = &Segs[SegList[j].SegNum];
|
||||
angle_t ang = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy);
|
||||
angle_t diff = prevAngle - ang;
|
||||
if (seg->v1 == prev->v2)
|
||||
{
|
||||
bestdiff = diff;
|
||||
bestseg = seg;
|
||||
bestj = j;
|
||||
break;
|
||||
}
|
||||
if (diff < bestdiff && diff > 0)
|
||||
{
|
||||
bestdiff = diff;
|
||||
bestseg = seg;
|
||||
bestj = j;
|
||||
}
|
||||
}
|
||||
while (++j < max);
|
||||
// Is a NULL bestseg actually okay?
|
||||
if (bestseg != NULL)
|
||||
{
|
||||
seg = bestseg;
|
||||
}
|
||||
if (prev->v2 != seg->v1)
|
||||
{
|
||||
// Add a new miniseg to connect the two segs
|
||||
PushConnectingGLSeg (subsector, segs, &outVerts[prev->v2], &outVerts[seg->v1]);
|
||||
count++;
|
||||
}
|
||||
#ifdef DD
|
||||
Printf(PRINT_LOG, "+%d\n", bestj);
|
||||
#endif
|
||||
prevAngle -= bestdiff;
|
||||
seg->storedseg = PushGLSeg (segs, seg, outVerts);
|
||||
count++;
|
||||
prev = seg;
|
||||
if (seg->v2 == firstVert)
|
||||
{
|
||||
prev = seg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DD
|
||||
Printf(PRINT_LOG, "\n");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{ // A degenerate subsector. These are handled in three stages:
|
||||
// Stage 1. Proceed in the same direction as the start seg until we
|
||||
// hit the seg furthest from it.
|
||||
// Stage 2. Reverse direction and proceed until we hit the seg
|
||||
// furthest from the start seg.
|
||||
// Stage 3. Reverse direction again and insert segs until we get
|
||||
// to the start seg.
|
||||
// A dot product serves to determine distance from the start seg.
|
||||
|
||||
D(Printf(PRINT_LOG, "degenerate subsector\n"));
|
||||
|
||||
// Stage 1. Go forward.
|
||||
count += OutputDegenerateSubsector (segs, subsector, true, 0, prev, outVerts);
|
||||
|
||||
// Stage 2. Go backward.
|
||||
count += OutputDegenerateSubsector (segs, subsector, false, DBL_MAX, prev, outVerts);
|
||||
|
||||
// Stage 3. Go forward again.
|
||||
count += OutputDegenerateSubsector (segs, subsector, true, -DBL_MAX, prev, outVerts);
|
||||
}
|
||||
|
||||
if (prev->v2 != firstVert)
|
||||
{
|
||||
PushConnectingGLSeg (subsector, segs, &outVerts[prev->v2], &outVerts[firstVert]);
|
||||
count++;
|
||||
}
|
||||
#ifdef DD
|
||||
Printf(PRINT_LOG, "Output GL subsector %d:\n", subsector);
|
||||
for (i = segs.Size() - count; i < (int)segs.Size(); ++i)
|
||||
{
|
||||
Printf(PRINT_LOG, " Seg %5d%c(%5d,%5d)-(%5d,%5d) [%08x,%08x]-[%08x,%08x]\n", i,
|
||||
segs[i].linedef == NULL ? '+' : ' ',
|
||||
segs[i].v1->fixX()>>16,
|
||||
segs[i].v1->fixY()>>16,
|
||||
segs[i].v2->fixX()>>16,
|
||||
segs[i].v2->fixY()>>16,
|
||||
segs[i].v1->fixX(),
|
||||
segs[i].v1->fixY(),
|
||||
segs[i].v2->fixX(),
|
||||
segs[i].v2->fixY());
|
||||
}
|
||||
#endif
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int FNodeBuilder::OutputDegenerateSubsector (TArray<glseg_t> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts)
|
||||
{
|
||||
static const double bestinit[2] = { -DBL_MAX, DBL_MAX };
|
||||
FPrivSeg *seg;
|
||||
int i, j, first, max, count;
|
||||
double dot, x1, y1, dx, dy, dx2, dy2;
|
||||
bool wantside;
|
||||
|
||||
first = (uint32_t)(size_t)Subsectors[subsector].firstline;
|
||||
max = first + Subsectors[subsector].numlines;
|
||||
count = 0;
|
||||
|
||||
seg = &Segs[SegList[first].SegNum];
|
||||
x1 = Vertices[seg->v1].x;
|
||||
y1 = Vertices[seg->v1].y;
|
||||
dx = Vertices[seg->v2].x - x1;
|
||||
dy = Vertices[seg->v2].y - y1;
|
||||
wantside = seg->planefront ^ !bForward;
|
||||
|
||||
for (i = first + 1; i < max; ++i)
|
||||
{
|
||||
double bestdot = bestinit[bForward];
|
||||
FPrivSeg *bestseg = NULL;
|
||||
for (j = first + 1; j < max; ++j)
|
||||
{
|
||||
seg = &Segs[SegList[j].SegNum];
|
||||
if (seg->planefront != wantside)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
dx2 = Vertices[seg->v1].x - x1;
|
||||
dy2 = Vertices[seg->v1].y - y1;
|
||||
dot = dx*dx2 + dy*dy2;
|
||||
|
||||
if (bForward)
|
||||
{
|
||||
if (dot < bestdot && dot > lastdot)
|
||||
{
|
||||
bestdot = dot;
|
||||
bestseg = seg;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dot > bestdot && dot < lastdot)
|
||||
{
|
||||
bestdot = dot;
|
||||
bestseg = seg;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bestseg != NULL)
|
||||
{
|
||||
if (prev->v2 != bestseg->v1)
|
||||
{
|
||||
PushConnectingGLSeg (subsector, segs, &outVerts[prev->v2], &outVerts[bestseg->v1]);
|
||||
count++;
|
||||
}
|
||||
seg->storedseg = PushGLSeg (segs, bestseg, outVerts);
|
||||
count++;
|
||||
prev = bestseg;
|
||||
lastdot = bestdot;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32_t FNodeBuilder::PushGLSeg (TArray<glseg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts)
|
||||
{
|
||||
glseg_t newseg;
|
||||
|
||||
newseg.v1 = outVerts + seg->v1;
|
||||
newseg.v2 = outVerts + seg->v2;
|
||||
newseg.backsector = seg->backsector;
|
||||
newseg.frontsector = seg->frontsector;
|
||||
if (seg->linedef != -1)
|
||||
{
|
||||
newseg.linedef = Level.Lines + seg->linedef;
|
||||
newseg.sidedef = Level.Sides + seg->sidedef;
|
||||
}
|
||||
else
|
||||
{
|
||||
newseg.linedef = NULL;
|
||||
newseg.sidedef = NULL;
|
||||
}
|
||||
newseg.Partner = seg->partner;
|
||||
return (uint32_t)segs.Push (newseg);
|
||||
}
|
||||
|
||||
void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray<glseg_t> &segs, vertex_t *v1, vertex_t *v2)
|
||||
{
|
||||
glseg_t newseg;
|
||||
|
||||
newseg.v1 = v1;
|
||||
newseg.v2 = v2;
|
||||
newseg.backsector = NULL;
|
||||
newseg.frontsector = NULL;
|
||||
newseg.linedef = NULL;
|
||||
newseg.sidedef = NULL;
|
||||
newseg.Partner = UINT_MAX;
|
||||
segs.Push (newseg);
|
||||
}
|
397
source/core/nodebuilder/nodebuild_gl.cpp
Normal file
397
source/core/nodebuilder/nodebuild_gl.cpp
Normal file
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
** nodebuild_gl.cpp
|
||||
**
|
||||
** Extra functions for the node builder to create minisegs.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2006 Randy Heit
|
||||
** 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.
|
||||
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation; either version 2 of the License, or (at
|
||||
** your option) any later version.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "nodebuild.h"
|
||||
|
||||
static inline void Warn (const char *format, ...)
|
||||
{
|
||||
}
|
||||
|
||||
static const angle_t ANGLE_EPSILON = 5000;
|
||||
|
||||
#if 0
|
||||
#define D(x) x
|
||||
#else
|
||||
#define D(x) do{}while(0)
|
||||
#endif
|
||||
|
||||
double FNodeBuilder::AddIntersection (const node_t &node, int vertex)
|
||||
{
|
||||
static const FEventInfo defaultInfo =
|
||||
{
|
||||
-1, UINT_MAX
|
||||
};
|
||||
|
||||
// Calculate signed distance of intersection vertex from start of splitter.
|
||||
// Only ordering is important, so we don't need a sqrt.
|
||||
FPrivVert *v = &Vertices[vertex];
|
||||
double dist = (double(v->x) - node.x)*(node.dx) + (double(v->y) - node.y)*(node.dy);
|
||||
|
||||
FEvent *event = Events.FindEvent (dist);
|
||||
if (event == NULL)
|
||||
{
|
||||
event = Events.GetNewNode ();
|
||||
event->Distance = dist;
|
||||
event->Info = defaultInfo;
|
||||
event->Info.Vertex = vertex;
|
||||
Events.Insert (event);
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
// If there are any segs on the splitter that span more than two events, they
|
||||
// must be split. Alien Vendetta is one example wad that is quite bad about
|
||||
// having overlapping lines. If we skip this step, these segs will still be
|
||||
// split later, but minisegs will erroneously be added for them, and partner
|
||||
// seg information will be messed up in the generated tree.
|
||||
void FNodeBuilder::FixSplitSharers (const node_t &node)
|
||||
{
|
||||
D(Printf(PRINT_LOG, "events:\n"));
|
||||
D(Events.PrintTree());
|
||||
for (unsigned int i = 0; i < SplitSharers.Size(); ++i)
|
||||
{
|
||||
uint32_t seg = SplitSharers[i].Seg;
|
||||
int v2 = Segs[seg].v2;
|
||||
FEvent *event = Events.FindEvent (SplitSharers[i].Distance);
|
||||
FEvent *next;
|
||||
|
||||
if (event == NULL)
|
||||
{ // Should not happen
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use the CRT's printf so the formatting matches ZDBSP's
|
||||
D(char buff[200]);
|
||||
D(sprintf(buff, "Considering events on seg %d(%d[%d,%d]->%d[%d,%d]) [%g:%g]\n", seg,
|
||||
Segs[seg].v1,
|
||||
Vertices[Segs[seg].v1].x>>16,
|
||||
Vertices[Segs[seg].v1].y>>16,
|
||||
Segs[seg].v2,
|
||||
Vertices[Segs[seg].v2].x>>16,
|
||||
Vertices[Segs[seg].v2].y>>16,
|
||||
SplitSharers[i].Distance, event->Distance));
|
||||
D(Printf(PRINT_LOG, "%s", buff));
|
||||
|
||||
if (SplitSharers[i].Forward)
|
||||
{
|
||||
event = Events.GetSuccessor (event);
|
||||
if (event == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
next = Events.GetSuccessor (event);
|
||||
}
|
||||
else
|
||||
{
|
||||
event = Events.GetPredecessor (event);
|
||||
if (event == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
next = Events.GetPredecessor (event);
|
||||
}
|
||||
|
||||
while (event != NULL && next != NULL && event->Info.Vertex != v2)
|
||||
{
|
||||
D(Printf(PRINT_LOG, "Forced split of seg %d(%d->%d) at %d(%d,%d)\n", seg,
|
||||
Segs[seg].v1, Segs[seg].v2,
|
||||
event->Info.Vertex,
|
||||
Vertices[event->Info.Vertex].x>>16,
|
||||
Vertices[event->Info.Vertex].y>>16));
|
||||
|
||||
uint32_t newseg = SplitSeg (seg, event->Info.Vertex, 1);
|
||||
|
||||
Segs[newseg].next = Segs[seg].next;
|
||||
Segs[seg].next = newseg;
|
||||
|
||||
uint32_t partner = Segs[seg].partner;
|
||||
if (partner != UINT_MAX)
|
||||
{
|
||||
int endpartner = SplitSeg (partner, event->Info.Vertex, 1);
|
||||
|
||||
Segs[endpartner].next = Segs[partner].next;
|
||||
Segs[partner].next = endpartner;
|
||||
|
||||
Segs[seg].partner = endpartner;
|
||||
Segs[partner].partner = newseg;
|
||||
}
|
||||
|
||||
seg = newseg;
|
||||
if (SplitSharers[i].Forward)
|
||||
{
|
||||
event = next;
|
||||
next = Events.GetSuccessor (next);
|
||||
}
|
||||
else
|
||||
{
|
||||
event = next;
|
||||
next = Events.GetPredecessor (next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FNodeBuilder::AddMinisegs (const node_t &node, uint32_t splitseg, uint32_t &fset, uint32_t &bset)
|
||||
{
|
||||
FEvent *event = Events.GetMinimum (), *prev = NULL;
|
||||
|
||||
while (event != NULL)
|
||||
{
|
||||
if (prev != NULL)
|
||||
{
|
||||
uint32_t fseg1, bseg1, fseg2, bseg2;
|
||||
uint32_t fnseg, bnseg;
|
||||
|
||||
// Minisegs should only be added when they can create valid loops on both the front and
|
||||
// back of the splitter. This means some subsectors could be unclosed if their sectors
|
||||
// are unclosed, but at least we won't be needlessly creating subsectors in void space.
|
||||
// Unclosed subsectors can be closed trivially once the BSP tree is complete.
|
||||
|
||||
if ((fseg1 = CheckLoopStart (node.dx, node.dy, prev->Info.Vertex, event->Info.Vertex)) != UINT_MAX &&
|
||||
(bseg1 = CheckLoopStart (-node.dx, -node.dy, event->Info.Vertex, prev->Info.Vertex)) != UINT_MAX &&
|
||||
(fseg2 = CheckLoopEnd (node.dx, node.dy, event->Info.Vertex)) != UINT_MAX &&
|
||||
(bseg2 = CheckLoopEnd (-node.dx, -node.dy, prev->Info.Vertex)) != UINT_MAX)
|
||||
{
|
||||
// Add miniseg on the front side
|
||||
fnseg = AddMiniseg (prev->Info.Vertex, event->Info.Vertex, UINT_MAX, fseg1, splitseg);
|
||||
Segs[fnseg].next = fset;
|
||||
fset = fnseg;
|
||||
|
||||
// Add miniseg on the back side
|
||||
bnseg = AddMiniseg (event->Info.Vertex, prev->Info.Vertex, fnseg, bseg1, splitseg);
|
||||
Segs[bnseg].next = bset;
|
||||
bset = bnseg;
|
||||
|
||||
sector_t *fsector, *bsector;
|
||||
|
||||
fsector = Segs[fseg1].frontsector;
|
||||
bsector = Segs[bseg1].frontsector;
|
||||
|
||||
Segs[fnseg].frontsector = fsector;
|
||||
Segs[fnseg].backsector = bsector;
|
||||
Segs[bnseg].frontsector = bsector;
|
||||
Segs[bnseg].backsector = fsector;
|
||||
|
||||
// Only print the warning if this might be bad.
|
||||
if (fsector != bsector &&
|
||||
fsector != Segs[fseg1].backsector &&
|
||||
bsector != Segs[bseg1].backsector)
|
||||
{
|
||||
Warn ("Sectors %d at (%d,%d) and %d at (%d,%d) don't match.\n",
|
||||
Segs[fseg1].frontsector,
|
||||
Vertices[prev->Info.Vertex].x>>FRACBITS, Vertices[prev->Info.Vertex].y>>FRACBITS,
|
||||
Segs[bseg1].frontsector,
|
||||
Vertices[event->Info.Vertex].x>>FRACBITS, Vertices[event->Info.Vertex].y>>FRACBITS
|
||||
);
|
||||
}
|
||||
|
||||
D(Printf (PRINT_LOG, "**Minisegs** %d/%d added %d(%d,%d)->%d(%d,%d)\n", fnseg, bnseg,
|
||||
prev->Info.Vertex,
|
||||
Vertices[prev->Info.Vertex].x>>16, Vertices[prev->Info.Vertex].y>>16,
|
||||
event->Info.Vertex,
|
||||
Vertices[event->Info.Vertex].x>>16, Vertices[event->Info.Vertex].y>>16));
|
||||
}
|
||||
}
|
||||
prev = event;
|
||||
event = Events.GetSuccessor (event);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t FNodeBuilder::AddMiniseg (int v1, int v2, uint32_t partner, uint32_t seg1, uint32_t splitseg)
|
||||
{
|
||||
uint32_t nseg;
|
||||
FPrivSeg *seg = &Segs[seg1];
|
||||
FPrivSeg newseg;
|
||||
|
||||
newseg.sidedef = NO_SIDE;
|
||||
newseg.linedef = -1;
|
||||
newseg.loopnum = 0;
|
||||
newseg.next = UINT_MAX;
|
||||
newseg.planefront = true;
|
||||
newseg.hashnext = NULL;
|
||||
newseg.storedseg = UINT_MAX;
|
||||
newseg.frontsector = NULL;
|
||||
newseg.backsector = NULL;
|
||||
|
||||
if (splitseg != UINT_MAX)
|
||||
{
|
||||
newseg.planenum = Segs[splitseg].planenum;
|
||||
}
|
||||
else
|
||||
{
|
||||
newseg.planenum = -1;
|
||||
}
|
||||
|
||||
newseg.v1 = v1;
|
||||
newseg.v2 = v2;
|
||||
newseg.nextforvert = Vertices[v1].segs;
|
||||
newseg.nextforvert2 = Vertices[v2].segs2;
|
||||
newseg.next = seg->next;
|
||||
if (partner != UINT_MAX)
|
||||
{
|
||||
newseg.partner = partner;
|
||||
}
|
||||
else
|
||||
{
|
||||
newseg.partner = UINT_MAX;
|
||||
}
|
||||
nseg = Segs.Push (newseg);
|
||||
if (newseg.partner != UINT_MAX)
|
||||
{
|
||||
Segs[partner].partner = nseg;
|
||||
}
|
||||
Vertices[v1].segs = nseg;
|
||||
Vertices[v2].segs2 = nseg;
|
||||
//Printf ("Between %d and %d::::\n", seg1, seg2);
|
||||
return nseg;
|
||||
}
|
||||
|
||||
uint32_t FNodeBuilder::CheckLoopStart (fixed_t dx, fixed_t dy, int vertex, int vertex2)
|
||||
{
|
||||
FPrivVert *v = &Vertices[vertex];
|
||||
angle_t splitAngle = PointToAngle (dx, dy);
|
||||
uint32_t segnum;
|
||||
angle_t bestang;
|
||||
uint32_t bestseg;
|
||||
|
||||
// Find the seg ending at this vertex that forms the smallest angle
|
||||
// to the splitter.
|
||||
segnum = v->segs2;
|
||||
bestang = ANGLE_MAX;
|
||||
bestseg = UINT_MAX;
|
||||
while (segnum != UINT_MAX)
|
||||
{
|
||||
FPrivSeg *seg = &Segs[segnum];
|
||||
angle_t segAngle = PointToAngle (Vertices[seg->v1].x - v->x, Vertices[seg->v1].y - v->y);
|
||||
angle_t diff = splitAngle - segAngle;
|
||||
|
||||
if (diff < ANGLE_EPSILON &&
|
||||
PointOnSide (Vertices[seg->v1].x, Vertices[seg->v1].y, v->x, v->y, dx, dy) == 0)
|
||||
{
|
||||
// If a seg lies right on the splitter, don't count it
|
||||
}
|
||||
else
|
||||
{
|
||||
if (diff <= bestang)
|
||||
{
|
||||
bestang = diff;
|
||||
bestseg = segnum;
|
||||
}
|
||||
}
|
||||
segnum = seg->nextforvert2;
|
||||
}
|
||||
if (bestseg == UINT_MAX)
|
||||
{
|
||||
return UINT_MAX;
|
||||
}
|
||||
// Now make sure there are no segs starting at this vertex that form
|
||||
// an even smaller angle to the splitter.
|
||||
segnum = v->segs;
|
||||
while (segnum != UINT_MAX)
|
||||
{
|
||||
FPrivSeg *seg = &Segs[segnum];
|
||||
if (seg->v2 == vertex2)
|
||||
{
|
||||
return UINT_MAX;
|
||||
}
|
||||
angle_t segAngle = PointToAngle (Vertices[seg->v2].x - v->x, Vertices[seg->v2].y - v->y);
|
||||
angle_t diff = splitAngle - segAngle;
|
||||
if (diff < bestang && seg->partner != bestseg)
|
||||
{
|
||||
return UINT_MAX;
|
||||
}
|
||||
segnum = seg->nextforvert;
|
||||
}
|
||||
return bestseg;
|
||||
}
|
||||
|
||||
uint32_t FNodeBuilder::CheckLoopEnd (fixed_t dx, fixed_t dy, int vertex)
|
||||
{
|
||||
FPrivVert *v = &Vertices[vertex];
|
||||
angle_t splitAngle = PointToAngle (dx, dy) + ANGLE_180;
|
||||
uint32_t segnum;
|
||||
angle_t bestang;
|
||||
uint32_t bestseg;
|
||||
|
||||
// Find the seg starting at this vertex that forms the smallest angle
|
||||
// to the splitter.
|
||||
segnum = v->segs;
|
||||
bestang = ANGLE_MAX;
|
||||
bestseg = UINT_MAX;
|
||||
while (segnum != UINT_MAX)
|
||||
{
|
||||
FPrivSeg *seg = &Segs[segnum];
|
||||
angle_t segAngle = PointToAngle (Vertices[seg->v2].x - v->x, Vertices[seg->v2].y - v->y);
|
||||
angle_t diff = segAngle - splitAngle;
|
||||
|
||||
if (diff < ANGLE_EPSILON &&
|
||||
PointOnSide (Vertices[seg->v1].x, Vertices[seg->v1].y, v->x, v->y, dx, dy) == 0)
|
||||
{
|
||||
// If a seg lies right on the splitter, don't count it
|
||||
}
|
||||
else
|
||||
{
|
||||
if (diff <= bestang)
|
||||
{
|
||||
bestang = diff;
|
||||
bestseg = segnum;
|
||||
}
|
||||
}
|
||||
segnum = seg->nextforvert;
|
||||
}
|
||||
if (bestseg == UINT_MAX)
|
||||
{
|
||||
return UINT_MAX;
|
||||
}
|
||||
// Now make sure there are no segs ending at this vertex that form
|
||||
// an even smaller angle to the splitter.
|
||||
segnum = v->segs2;
|
||||
while (segnum != UINT_MAX)
|
||||
{
|
||||
FPrivSeg *seg = &Segs[segnum];
|
||||
angle_t segAngle = PointToAngle (Vertices[seg->v1].x - v->x, Vertices[seg->v1].y - v->y);
|
||||
angle_t diff = segAngle - splitAngle;
|
||||
if (diff < bestang && seg->partner != bestseg)
|
||||
{
|
||||
return UINT_MAX;
|
||||
}
|
||||
segnum = seg->nextforvert2;
|
||||
}
|
||||
return bestseg;
|
||||
}
|
535
source/core/nodebuilder/nodebuild_utility.cpp
Normal file
535
source/core/nodebuilder/nodebuild_utility.cpp
Normal file
|
@ -0,0 +1,535 @@
|
|||
/*
|
||||
** nodebuild_utility.cpp
|
||||
**
|
||||
** Miscellaneous node builder utility functions.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2006 Randy Heit
|
||||
** 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.
|
||||
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation; either version 2 of the License, or (at
|
||||
** your option) any later version.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include "nodebuild.h"
|
||||
#include "printf.h"
|
||||
#include "m_fixed.h"
|
||||
#include "m_bbox.h"
|
||||
|
||||
#if 0
|
||||
#define D(x) x
|
||||
#else
|
||||
#define D(x) do{}while(0)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define P(x) x
|
||||
#else
|
||||
#define P(x) do{}while(0)
|
||||
#endif
|
||||
|
||||
angle_t FNodeBuilder::PointToAngle (fixed_t x, fixed_t y)
|
||||
{
|
||||
const double rad2bam = double(1<<30) / M_PI;
|
||||
double ang = g_atan2 (double(y), double(x));
|
||||
// Convert to signed first since negative double to unsigned is undefined.
|
||||
return angle_t(int(ang * rad2bam)) << 1;
|
||||
}
|
||||
|
||||
void FNodeBuilder::FindUsedVertices (vertex_t *oldverts, int max)
|
||||
{
|
||||
int *map = new int[max];
|
||||
int i;
|
||||
FPrivVert newvert;
|
||||
|
||||
memset (&map[0], -1, sizeof(int)*max);
|
||||
|
||||
for (i = 0; i < Level.NumLines; ++i)
|
||||
{
|
||||
ptrdiff_t v1 = Level.Lines[i].v1 - oldverts;
|
||||
ptrdiff_t v2 = Level.Lines[i].v2 - oldverts;
|
||||
|
||||
if (map[v1] == -1)
|
||||
{
|
||||
newvert.x = oldverts[v1].fixX();
|
||||
newvert.y = oldverts[v1].fixY();
|
||||
map[v1] = VertexMap->SelectVertexExact (newvert);
|
||||
}
|
||||
if (map[v2] == -1)
|
||||
{
|
||||
newvert.x = oldverts[v2].fixX();
|
||||
newvert.y = oldverts[v2].fixY();
|
||||
map[v2] = VertexMap->SelectVertexExact (newvert);
|
||||
}
|
||||
|
||||
Level.Lines[i].v1 = (vertex_t *)(size_t)map[v1];
|
||||
Level.Lines[i].v2 = (vertex_t *)(size_t)map[v2];
|
||||
}
|
||||
OldVertexTable = map;
|
||||
}
|
||||
|
||||
// Retrieves the original vertex -> current vertex table.
|
||||
// Doing so prevents the node builder from freeing it.
|
||||
|
||||
const int *FNodeBuilder::GetOldVertexTable()
|
||||
{
|
||||
int *table = OldVertexTable;
|
||||
OldVertexTable = NULL;
|
||||
return table;
|
||||
}
|
||||
|
||||
// For every sidedef in the map, create a corresponding seg.
|
||||
|
||||
void FNodeBuilder::MakeSegsFromSides ()
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (Level.NumLines == 0)
|
||||
{
|
||||
I_Error ("Map is empty.\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < Level.NumLines; ++i)
|
||||
{
|
||||
if (Level.Lines[i].sidedef[0] != NULL)
|
||||
{
|
||||
CreateSeg (i, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Linedef %d does not have a front side.\n", i);
|
||||
}
|
||||
|
||||
if (Level.Lines[i].sidedef[1] != NULL)
|
||||
{
|
||||
j = CreateSeg (i, 1);
|
||||
if (Level.Lines[i].sidedef[0] != NULL)
|
||||
{
|
||||
Segs[j-1].partner = j;
|
||||
Segs[j].partner = j-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int FNodeBuilder::CreateSeg (int linenum, int sidenum)
|
||||
{
|
||||
FPrivSeg seg;
|
||||
int segnum;
|
||||
|
||||
seg.next = UINT_MAX;
|
||||
seg.loopnum = 0;
|
||||
seg.partner = UINT_MAX;
|
||||
seg.hashnext = NULL;
|
||||
seg.planefront = false;
|
||||
seg.planenum = UINT_MAX;
|
||||
seg.storedseg = UINT_MAX;
|
||||
|
||||
if (sidenum == 0)
|
||||
{ // front
|
||||
seg.frontsector = Level.Lines[linenum].frontsector;
|
||||
seg.backsector = Level.Lines[linenum].backsector;
|
||||
seg.v1 = (int)(size_t)Level.Lines[linenum].v1;
|
||||
seg.v2 = (int)(size_t)Level.Lines[linenum].v2;
|
||||
}
|
||||
else
|
||||
{ // back
|
||||
seg.frontsector = Level.Lines[linenum].backsector;
|
||||
seg.backsector = Level.Lines[linenum].frontsector;
|
||||
seg.v2 = (int)(size_t)Level.Lines[linenum].v1;
|
||||
seg.v1 = (int)(size_t)Level.Lines[linenum].v2;
|
||||
}
|
||||
seg.linedef = linenum;
|
||||
side_t *sd = Level.Lines[linenum].sidedef[sidenum];
|
||||
seg.sidedef = sd != NULL? sd->Index() : int(NO_SIDE);
|
||||
seg.nextforvert = Vertices[seg.v1].segs;
|
||||
seg.nextforvert2 = Vertices[seg.v2].segs2;
|
||||
|
||||
segnum = (int)Segs.Push (seg);
|
||||
Vertices[seg.v1].segs = segnum;
|
||||
Vertices[seg.v2].segs2 = segnum;
|
||||
D(Printf(PRINT_LOG, "Seg %4d: From line %d, side %s (%5d,%5d)-(%5d,%5d) [%08x,%08x]-[%08x,%08x]\n", segnum, linenum, sidenum ? "back " : "front",
|
||||
Vertices[seg.v1].x>>16, Vertices[seg.v1].y>>16, Vertices[seg.v2].x>>16, Vertices[seg.v2].y>>16,
|
||||
Vertices[seg.v1].x, Vertices[seg.v1].y, Vertices[seg.v2].x, Vertices[seg.v2].y));
|
||||
|
||||
return segnum;
|
||||
}
|
||||
|
||||
// For every seg, create FPrivSegs and FPrivVerts.
|
||||
|
||||
void FNodeBuilder::AddSegs(seg_t *segs, int numsegs)
|
||||
{
|
||||
assert(numsegs > 0);
|
||||
|
||||
for (int i = 0; i < numsegs; ++i)
|
||||
{
|
||||
FPrivSeg seg;
|
||||
FPrivVert vert;
|
||||
int segnum;
|
||||
|
||||
seg.next = UINT_MAX;
|
||||
seg.loopnum = 0;
|
||||
seg.partner = UINT_MAX;
|
||||
seg.hashnext = NULL;
|
||||
seg.planefront = false;
|
||||
seg.planenum = UINT_MAX;
|
||||
seg.storedseg = UINT_MAX;
|
||||
|
||||
seg.frontsector = segs[i].frontsector;
|
||||
seg.backsector = segs[i].backsector;
|
||||
vert.x = segs[i].v1->fixX();
|
||||
vert.y = segs[i].v1->fixY();
|
||||
seg.v1 = VertexMap->SelectVertexExact(vert);
|
||||
vert.x = segs[i].v2->fixX();
|
||||
vert.y = segs[i].v2->fixY();
|
||||
seg.v2 = VertexMap->SelectVertexExact(vert);
|
||||
seg.linedef = segs[i].linedef->Index();
|
||||
seg.sidedef = segs[i].sidedef != NULL ? segs[i].sidedef->Index() : int(NO_SIDE);
|
||||
seg.nextforvert = Vertices[seg.v1].segs;
|
||||
seg.nextforvert2 = Vertices[seg.v2].segs2;
|
||||
|
||||
segnum = (int)Segs.Push(seg);
|
||||
Vertices[seg.v1].segs = segnum;
|
||||
Vertices[seg.v2].segs2 = segnum;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Group colinear segs together so that only one seg per line needs to be checked
|
||||
// by SelectSplitter().
|
||||
|
||||
void FNodeBuilder::GroupSegPlanes ()
|
||||
{
|
||||
const int bucketbits = 12;
|
||||
FPrivSeg *buckets[1<<bucketbits] = { 0 };
|
||||
int i, planenum;
|
||||
|
||||
for (i = 0; i < (int)Segs.Size(); ++i)
|
||||
{
|
||||
FPrivSeg *seg = &Segs[i];
|
||||
seg->next = i+1;
|
||||
seg->hashnext = NULL;
|
||||
}
|
||||
|
||||
Segs[Segs.Size()-1].next = UINT_MAX;
|
||||
|
||||
for (i = planenum = 0; i < (int)Segs.Size(); ++i)
|
||||
{
|
||||
FPrivSeg *seg = &Segs[i];
|
||||
fixed_t x1 = Vertices[seg->v1].x;
|
||||
fixed_t y1 = Vertices[seg->v1].y;
|
||||
fixed_t x2 = Vertices[seg->v2].x;
|
||||
fixed_t y2 = Vertices[seg->v2].y;
|
||||
angle_t ang = PointToAngle (x2 - x1, y2 - y1);
|
||||
|
||||
if (ang >= 1u<<31)
|
||||
ang += 1u<<31;
|
||||
|
||||
FPrivSeg *check = buckets[ang >>= 31-bucketbits];
|
||||
|
||||
while (check != NULL)
|
||||
{
|
||||
fixed_t cx1 = Vertices[check->v1].x;
|
||||
fixed_t cy1 = Vertices[check->v1].y;
|
||||
fixed_t cdx = Vertices[check->v2].x - cx1;
|
||||
fixed_t cdy = Vertices[check->v2].y - cy1;
|
||||
if (PointOnSide (x1, y1, cx1, cy1, cdx, cdy) == 0 &&
|
||||
PointOnSide (x2, y2, cx1, cy1, cdx, cdy) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
check = check->hashnext;
|
||||
}
|
||||
if (check != NULL)
|
||||
{
|
||||
seg->planenum = check->planenum;
|
||||
const FSimpleLine *line = &Planes[seg->planenum];
|
||||
if (line->dx != 0)
|
||||
{
|
||||
if ((line->dx > 0 && x2 > x1) || (line->dx < 0 && x2 < x1))
|
||||
{
|
||||
seg->planefront = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
seg->planefront = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((line->dy > 0 && y2 > y1) || (line->dy < 0 && y2 < y1))
|
||||
{
|
||||
seg->planefront = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
seg->planefront = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
seg->hashnext = buckets[ang];
|
||||
buckets[ang] = seg;
|
||||
seg->planenum = planenum++;
|
||||
seg->planefront = true;
|
||||
|
||||
FSimpleLine pline = { Vertices[seg->v1].x,
|
||||
Vertices[seg->v1].y,
|
||||
Vertices[seg->v2].x - Vertices[seg->v1].x,
|
||||
Vertices[seg->v2].y - Vertices[seg->v1].y };
|
||||
Planes.Push (pline);
|
||||
}
|
||||
}
|
||||
|
||||
D(Printf ("%d planes from %d segs\n", planenum, Segs.Size()));
|
||||
|
||||
PlaneChecked.Reserve ((planenum + 7) / 8);
|
||||
}
|
||||
|
||||
// Just create one plane per seg. Should be good enough for mini BSPs.
|
||||
void FNodeBuilder::GroupSegPlanesSimple()
|
||||
{
|
||||
Planes.Resize(Segs.Size());
|
||||
for (int i = 0; i < (int)Segs.Size(); ++i)
|
||||
{
|
||||
FPrivSeg *seg = &Segs[i];
|
||||
FSimpleLine *pline = &Planes[i];
|
||||
seg->next = i+1;
|
||||
seg->hashnext = NULL;
|
||||
seg->planenum = i;
|
||||
seg->planefront = true;
|
||||
pline->x = Vertices[seg->v1].x;
|
||||
pline->y = Vertices[seg->v1].y;
|
||||
pline->dx = Vertices[seg->v2].x - Vertices[seg->v1].x;
|
||||
pline->dy = Vertices[seg->v2].y - Vertices[seg->v1].y;
|
||||
}
|
||||
Segs.Last().next = UINT_MAX;
|
||||
PlaneChecked.Reserve((Segs.Size() + 7) / 8);
|
||||
}
|
||||
|
||||
void FNodeBuilder::AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg)
|
||||
{
|
||||
FPrivVert *v1 = &Vertices[seg->v1];
|
||||
FPrivVert *v2 = &Vertices[seg->v2];
|
||||
|
||||
if (v1->x < bbox[BOXLEFT]) bbox[BOXLEFT] = v1->x;
|
||||
if (v1->x > bbox[BOXRIGHT]) bbox[BOXRIGHT] = v1->x;
|
||||
if (v1->y < bbox[BOXBOTTOM]) bbox[BOXBOTTOM] = v1->y;
|
||||
if (v1->y > bbox[BOXTOP]) bbox[BOXTOP] = v1->y;
|
||||
|
||||
if (v2->x < bbox[BOXLEFT]) bbox[BOXLEFT] = v2->x;
|
||||
if (v2->x > bbox[BOXRIGHT]) bbox[BOXRIGHT] = v2->x;
|
||||
if (v2->y < bbox[BOXBOTTOM]) bbox[BOXBOTTOM] = v2->y;
|
||||
if (v2->y > bbox[BOXTOP]) bbox[BOXTOP] = v2->y;
|
||||
}
|
||||
|
||||
void FNodeBuilder::FLevel::FindMapBounds()
|
||||
{
|
||||
double minx, maxx, miny, maxy;
|
||||
|
||||
minx = maxx = Vertices[0].fX();
|
||||
miny = maxy = Vertices[0].fY();
|
||||
|
||||
for (int i = 1; i < NumLines; ++i)
|
||||
{
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
vertex_t *v = (j == 0 ? Lines[i].v1 : Lines[i].v2);
|
||||
if (v->fX() < minx) minx = v->fX();
|
||||
else if (v->fX() > maxx) maxx = v->fX();
|
||||
if (v->fY() < miny) miny = v->fY();
|
||||
else if (v->fY() > maxy) maxy = v->fY();
|
||||
}
|
||||
}
|
||||
|
||||
MinX = FLOAT2FIXED(minx);
|
||||
MinY = FLOAT2FIXED(miny);
|
||||
MaxX = FLOAT2FIXED(maxx);
|
||||
MaxY = FLOAT2FIXED(maxy);
|
||||
}
|
||||
|
||||
FNodeBuilder::IVertexMap::~IVertexMap()
|
||||
{
|
||||
}
|
||||
|
||||
FNodeBuilder::FVertexMap::FVertexMap (FNodeBuilder &builder,
|
||||
fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy)
|
||||
: MyBuilder(builder)
|
||||
{
|
||||
MinX = minx;
|
||||
MinY = miny;
|
||||
BlocksWide = int(((double(maxx) - minx + 1) + (BLOCK_SIZE - 1)) / BLOCK_SIZE);
|
||||
BlocksTall = int(((double(maxy) - miny + 1) + (BLOCK_SIZE - 1)) / BLOCK_SIZE);
|
||||
MaxX = MinX + fixed64_t(BlocksWide) * BLOCK_SIZE - 1;
|
||||
MaxY = MinY + fixed64_t(BlocksTall) * BLOCK_SIZE - 1;
|
||||
VertexGrid = new TArray<int>[BlocksWide * BlocksTall];
|
||||
}
|
||||
|
||||
FNodeBuilder::FVertexMap::~FVertexMap ()
|
||||
{
|
||||
delete[] VertexGrid;
|
||||
}
|
||||
|
||||
int FNodeBuilder::FVertexMap::SelectVertexExact (FNodeBuilder::FPrivVert &vert)
|
||||
{
|
||||
TArray<int> &block = VertexGrid[GetBlock (vert.x, vert.y)];
|
||||
FPrivVert *vertices = &MyBuilder.Vertices[0];
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < block.Size(); ++i)
|
||||
{
|
||||
if (vertices[block[i]].x == vert.x && vertices[block[i]].y == vert.y)
|
||||
{
|
||||
return block[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Not present: add it!
|
||||
return InsertVertex (vert);
|
||||
}
|
||||
|
||||
int FNodeBuilder::FVertexMap::SelectVertexClose (FNodeBuilder::FPrivVert &vert)
|
||||
{
|
||||
TArray<int> &block = VertexGrid[GetBlock (vert.x, vert.y)];
|
||||
FPrivVert *vertices = &MyBuilder.Vertices[0];
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < block.Size(); ++i)
|
||||
{
|
||||
#if VERTEX_EPSILON <= 1
|
||||
if (vertices[block[i]].x == vert.x && vertices[block[i]].y == vert.y)
|
||||
#else
|
||||
if (abs(vertices[block[i]].x - vert.x) < VERTEX_EPSILON &&
|
||||
abs(vertices[block[i]].y - vert.y) < VERTEX_EPSILON)
|
||||
#endif
|
||||
{
|
||||
return block[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Not present: add it!
|
||||
return InsertVertex (vert);
|
||||
}
|
||||
|
||||
int FNodeBuilder::FVertexMap::InsertVertex (FNodeBuilder::FPrivVert &vert)
|
||||
{
|
||||
int vertnum;
|
||||
|
||||
vert.segs = UINT_MAX;
|
||||
vert.segs2 = UINT_MAX;
|
||||
vertnum = (int)MyBuilder.Vertices.Push (vert);
|
||||
|
||||
// If a vertex is near a block boundary, then it will be inserted on
|
||||
// both sides of the boundary so that SelectVertexClose can find
|
||||
// it by checking in only one block.
|
||||
fixed64_t minx = MAX (MinX, fixed64_t(vert.x) - VERTEX_EPSILON);
|
||||
fixed64_t maxx = MIN (MaxX, fixed64_t(vert.x) + VERTEX_EPSILON);
|
||||
fixed64_t miny = MAX (MinY, fixed64_t(vert.y) - VERTEX_EPSILON);
|
||||
fixed64_t maxy = MIN (MaxY, fixed64_t(vert.y) + VERTEX_EPSILON);
|
||||
|
||||
int blk[4] =
|
||||
{
|
||||
GetBlock (minx, miny),
|
||||
GetBlock (maxx, miny),
|
||||
GetBlock (minx, maxy),
|
||||
GetBlock (maxx, maxy)
|
||||
};
|
||||
unsigned int blkcount[4] =
|
||||
{
|
||||
VertexGrid[blk[0]].Size(),
|
||||
VertexGrid[blk[1]].Size(),
|
||||
VertexGrid[blk[2]].Size(),
|
||||
VertexGrid[blk[3]].Size()
|
||||
};
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (VertexGrid[blk[i]].Size() == blkcount[i])
|
||||
{
|
||||
VertexGrid[blk[i]].Push (vertnum);
|
||||
}
|
||||
}
|
||||
|
||||
return vertnum;
|
||||
}
|
||||
|
||||
FNodeBuilder::FVertexMapSimple::FVertexMapSimple(FNodeBuilder &builder)
|
||||
: MyBuilder(builder)
|
||||
{
|
||||
}
|
||||
|
||||
int FNodeBuilder::FVertexMapSimple::SelectVertexExact(FNodeBuilder::FPrivVert &vert)
|
||||
{
|
||||
FPrivVert *verts = &MyBuilder.Vertices[0];
|
||||
unsigned int stop = MyBuilder.Vertices.Size();
|
||||
|
||||
for (unsigned int i = 0; i < stop; ++i)
|
||||
{
|
||||
if (verts[i].x == vert.x && verts[i].y == vert.y)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// Not present: add it!
|
||||
return InsertVertex(vert);
|
||||
}
|
||||
|
||||
int FNodeBuilder::FVertexMapSimple::SelectVertexClose(FNodeBuilder::FPrivVert &vert)
|
||||
{
|
||||
FPrivVert *verts = &MyBuilder.Vertices[0];
|
||||
unsigned int stop = MyBuilder.Vertices.Size();
|
||||
|
||||
for (unsigned int i = 0; i < stop; ++i)
|
||||
{
|
||||
#if VERTEX_EPSILON <= 1
|
||||
if (verts[i].x == vert.x && verts[i].y == y)
|
||||
#else
|
||||
if (abs(verts[i].x - vert.x) < VERTEX_EPSILON &&
|
||||
abs(verts[i].y - vert.y) < VERTEX_EPSILON)
|
||||
#endif
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// Not present: add it!
|
||||
return InsertVertex (vert);
|
||||
}
|
||||
|
||||
int FNodeBuilder::FVertexMapSimple::InsertVertex (FNodeBuilder::FPrivVert &vert)
|
||||
{
|
||||
vert.segs = UINT_MAX;
|
||||
vert.segs2 = UINT_MAX;
|
||||
return (int)MyBuilder.Vertices.Push (vert);
|
||||
}
|
|
@ -48,6 +48,7 @@
|
|||
#include "../../glbackend/glbackend.h"
|
||||
|
||||
LookupTableInfo lookups;
|
||||
int numshades;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -136,7 +137,6 @@ void paletteLoadFromDisk(void)
|
|||
|
||||
void LookupTableInfo::postLoadTables(void)
|
||||
{
|
||||
globalpal = 0;
|
||||
GPalette.GenerateGlobalBrightmapFromColormap(getTable(0), numshades);
|
||||
|
||||
// Try to detect fullbright translations. Unfortunately this cannot be used to detect fade strength because of loss of color precision in the palette map.
|
||||
|
|
|
@ -17,16 +17,21 @@
|
|||
#include "palentry.h"
|
||||
#include "templates.h"
|
||||
|
||||
#define MAXBASEPALS 256
|
||||
#define MAXPALOOKUPS 256
|
||||
#define MAXBLENDTABS 256
|
||||
enum
|
||||
{
|
||||
MAXBASEPALS = 256,
|
||||
MAXPALOOKUPS = 256,
|
||||
MAXBLENDTABS = 256,
|
||||
|
||||
RESERVEDPALS = 4, // don't forget to increment this when adding reserved pals
|
||||
DETAILPAL = (MAXPALOOKUPS - 1),
|
||||
GLOWPAL = (MAXPALOOKUPS - 2),
|
||||
SPECULARPAL = (MAXPALOOKUPS - 3),
|
||||
NORMALPAL = (MAXPALOOKUPS - 4),
|
||||
BRIGHTPAL = (MAXPALOOKUPS),
|
||||
|
||||
#define RESERVEDPALS 4 // don't forget to increment this when adding reserved pals
|
||||
#define DETAILPAL (MAXPALOOKUPS - 1)
|
||||
#define GLOWPAL (MAXPALOOKUPS - 2)
|
||||
#define SPECULARPAL (MAXPALOOKUPS - 3)
|
||||
#define NORMALPAL (MAXPALOOKUPS - 4)
|
||||
#define BRIGHTPAL (MAXPALOOKUPS)
|
||||
MAXREALPAL = MAXPALOOKUPS - RESERVEDPALS
|
||||
};
|
||||
|
||||
// fixme: should use the flags from the PRSFlags enum directly
|
||||
enum
|
||||
|
@ -165,7 +170,7 @@ inline void videoclearFade()
|
|||
|
||||
void videoTintBlood(int32_t r, int32_t g, int32_t b);
|
||||
|
||||
extern int32_t globalpal, globalfloorpal;
|
||||
extern int numshades;
|
||||
extern void paletteLoadFromDisk(void);
|
||||
|
||||
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
|
||||
/*
|
||||
** 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.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -39,7 +39,10 @@
|
|||
#include "hw_material.h"
|
||||
#include "gamestruct.h"
|
||||
#include "gamecontrol.h"
|
||||
#include "glbackend/gl_models.h"
|
||||
#include "texturemanager.h"
|
||||
#include "hw_models.h"
|
||||
#include "hw_voxels.h"
|
||||
#include "mapinfo.h"
|
||||
|
||||
BEGIN_BLD_NS
|
||||
extern short voxelIndex[MAXTILES];
|
||||
|
@ -128,6 +131,19 @@ void precacheMarkedTiles()
|
|||
int dapalnum = pair->Key >> 32;
|
||||
doprecache(dapicnum, dapalnum);
|
||||
}
|
||||
|
||||
// Cache everything the map explicitly declares.
|
||||
TMap<FString, bool> cachetexmap;
|
||||
for (auto& tex : currentLevel->PrecacheTextures) cachetexmap.Insert(tex, true);
|
||||
|
||||
decltype(cachetexmap)::Iterator it2(cachetexmap);
|
||||
decltype(cachetexmap)::Pair* pair2;
|
||||
while (it2.NextPair(pair2))
|
||||
{
|
||||
auto tex = TexMan.FindGameTexture(pair2->Key, ETextureType::Any);
|
||||
if (tex) PrecacheTex(tex, 0);
|
||||
}
|
||||
|
||||
cachemap.Clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
|
||||
void PrecacheHardwareTextures(int nTile);
|
||||
void markTileForPrecache(int tilenum, int palnum);
|
||||
void markTextureForPrecache(const char* texname);
|
||||
void markVoxelForPrecache(int voxnum);
|
||||
void precacheMarkedTiles();
|
||||
|
|
400
source/core/rendering/hw_entrypoint.cpp
Normal file
400
source/core/rendering/hw_entrypoint.cpp
Normal file
|
@ -0,0 +1,400 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2004-2016 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_scene.cpp
|
||||
** manages the rendering of the player's view
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gi.h"
|
||||
#include "build.h"
|
||||
#include "v_draw.h"
|
||||
//#include "a_dynlight.h"
|
||||
#include "v_video.h"
|
||||
#include "m_png.h"
|
||||
#include "i_time.h"
|
||||
#include "hw_dynlightdata.h"
|
||||
#include "hw_clock.h"
|
||||
#include "flatvertices.h"
|
||||
|
||||
#include "hw_renderstate.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "hw_viewpointbuffer.h"
|
||||
#include "hw_clipper.h"
|
||||
//#include "hwrenderer/scene/hw_portal.h"
|
||||
#include "hw_vrmodes.h"
|
||||
|
||||
#include "hw_drawstructs.h"
|
||||
#include "hw_drawlist.h"
|
||||
#include "hw_drawinfo.h"
|
||||
#include "gamecvars.h"
|
||||
#include "render.h"
|
||||
#include "gamestruct.h"
|
||||
#include "gamehud.h"
|
||||
|
||||
EXTERN_CVAR(Bool, cl_capfps)
|
||||
|
||||
PalEntry GlobalMapFog;
|
||||
float GlobalFogDensity = 350.f;
|
||||
TArray<PortalDesc> allPortals;
|
||||
|
||||
|
||||
#if 0
|
||||
void CollectLights(FLevelLocals* Level)
|
||||
{
|
||||
IShadowMap* sm = &screen->mShadowMap;
|
||||
int lightindex = 0;
|
||||
|
||||
// Todo: this should go through the blockmap in a spiral pattern around the player so that closer lights are preferred.
|
||||
for (auto light = Level->lights; light; light = light->next)
|
||||
{
|
||||
IShadowMap::LightsProcessed++;
|
||||
if (light->shadowmapped && light->IsActive() && lightindex < 1024)
|
||||
{
|
||||
IShadowMap::LightsShadowmapped++;
|
||||
|
||||
light->mShadowmapIndex = lightindex;
|
||||
sm->SetLight(lightindex, (float)light->X(), (float)light->Y(), (float)light->Z(), light->GetRadius());
|
||||
lightindex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
light->mShadowmapIndex = 1024;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (; lightindex < 1024; lightindex++)
|
||||
{
|
||||
sm->SetLight(lightindex, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Renders one viewpoint in a scene
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void RenderViewpoint(FRenderViewpoint& mainvp, IntRect* bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen)
|
||||
{
|
||||
auto& RenderState = *screen->RenderState();
|
||||
|
||||
/*
|
||||
if (mainview && toscreen)
|
||||
{
|
||||
screen->SetAABBTree(camera->Level->aabbTree);
|
||||
screen->mShadowMap.SetCollectLights([=] {
|
||||
CollectLights(camera->Level);
|
||||
});
|
||||
screen->UpdateShadowMap();
|
||||
}
|
||||
*/
|
||||
|
||||
// Render (potentially) multiple views for stereo 3d
|
||||
// Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode.
|
||||
auto vrmode = VRMode::GetVRMode(mainview && toscreen);
|
||||
const int eyeCount = vrmode->mEyeCount;
|
||||
screen->FirstEye();
|
||||
hw_int_useindexedcolortextures = eyeCount > 1? false : *hw_useindexedcolortextures;
|
||||
|
||||
for (int eye_ix = 0; eye_ix < eyeCount; ++eye_ix)
|
||||
{
|
||||
const auto& eye = vrmode->mEyes[eye_ix];
|
||||
screen->SetViewportRects(bounds);
|
||||
|
||||
if (mainview) // Bind the scene frame buffer and turn on draw buffers used by ssao
|
||||
{
|
||||
bool useSSAO = (gl_ssao != 0);
|
||||
screen->SetSceneRenderTarget(useSSAO);
|
||||
RenderState.SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS);
|
||||
RenderState.EnableDrawBuffers(RenderState.GetPassDrawBufferCount(), true);
|
||||
}
|
||||
|
||||
auto di = HWDrawInfo::StartDrawInfo(nullptr, mainvp, nullptr);
|
||||
auto& vp = di->Viewpoint;
|
||||
vp = mainvp;
|
||||
|
||||
di->Set3DViewport(RenderState);
|
||||
float flash = 1.f;
|
||||
di->Viewpoint.FieldOfView = fov; // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint)
|
||||
|
||||
// Stereo mode specific perspective projection
|
||||
di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio);
|
||||
// Stereo mode specific viewpoint adjustment
|
||||
vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees);
|
||||
di->SetupView(RenderState, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false);
|
||||
|
||||
di->ProcessScene(toscreen);
|
||||
|
||||
if (mainview)
|
||||
{
|
||||
PostProcess.Clock();
|
||||
if (toscreen) di->EndDrawScene(RenderState); // do not call this for camera textures.
|
||||
|
||||
if (RenderState.GetPassType() == GBUFFER_PASS) // Turn off ssao draw buffers
|
||||
{
|
||||
RenderState.SetPassType(NORMAL_PASS);
|
||||
RenderState.EnableDrawBuffers(1);
|
||||
}
|
||||
|
||||
screen->PostProcessScene(false, CM_DEFAULT, flash, [&]() { });
|
||||
PostProcess.Unclock();
|
||||
}
|
||||
di->EndDrawInfo();
|
||||
if (eyeCount - eye_ix > 1)
|
||||
screen->NextEye(eyeCount);
|
||||
}
|
||||
hw_int_useindexedcolortextures = false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Set up the view point.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FRenderViewpoint SetupViewpoint(spritetype* cam, const vec3_t& position, int sectnum, binangle angle, fixedhoriz horizon, binangle rollang)
|
||||
{
|
||||
FRenderViewpoint r_viewpoint{};
|
||||
r_viewpoint.CameraSprite = cam;
|
||||
r_viewpoint.SectNums = nullptr;
|
||||
r_viewpoint.SectCount = sectnum;
|
||||
r_viewpoint.Pos = { position.x / 16.f, position.y / -16.f, position.z / -256.f };
|
||||
r_viewpoint.HWAngles.Yaw = -90.f + angle.asdeg();
|
||||
r_viewpoint.HWAngles.Pitch = -horizon.aspitch();
|
||||
r_viewpoint.HWAngles.Roll = -rollang.asdeg();
|
||||
r_viewpoint.FieldOfView = (float)r_fov;
|
||||
r_viewpoint.RotAngle = angle.asbam();
|
||||
double FocalTangent = tan(r_viewpoint.FieldOfView.Radians() / 2);
|
||||
DAngle an = 270. - r_viewpoint.HWAngles.Yaw.Degrees;
|
||||
r_viewpoint.TanSin = FocalTangent * an.Sin();
|
||||
r_viewpoint.TanCos = FocalTangent * an.Cos();
|
||||
r_viewpoint.ViewVector = an.ToVector();
|
||||
return r_viewpoint;
|
||||
}
|
||||
|
||||
|
||||
void DoWriteSavePic(FileWriter* file, uint8_t* scr, int width, int height, bool upsidedown)
|
||||
{
|
||||
int pixelsize = 3;
|
||||
|
||||
int pitch = width * pixelsize;
|
||||
if (upsidedown)
|
||||
{
|
||||
scr += ((height - 1) * width * pixelsize);
|
||||
pitch *= -1;
|
||||
}
|
||||
|
||||
M_CreatePNG(file, scr, nullptr, SS_RGB, width, height, pitch, vid_gamma);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Render the view to a savegame picture
|
||||
//
|
||||
// Currently a bit messy because the game side still needs to be able to
|
||||
// handle Polymost.
|
||||
//
|
||||
//===========================================================================
|
||||
bool writingsavepic;
|
||||
FileWriter* savefile;
|
||||
int savewidth, saveheight;
|
||||
void PM_WriteSavePic(FileWriter* file, int width, int height);
|
||||
EXTERN_CVAR(Bool, testnewrenderer);
|
||||
|
||||
void WriteSavePic(FileWriter* file, int width, int height)
|
||||
{
|
||||
if (!testnewrenderer)
|
||||
{
|
||||
PM_WriteSavePic(file, width, height);
|
||||
return;
|
||||
}
|
||||
int oldx = xdim;
|
||||
int oldy = ydim;
|
||||
auto oldwindowxy1 = windowxy1;
|
||||
auto oldwindowxy2 = windowxy2;
|
||||
|
||||
xdim = width;
|
||||
ydim = height;
|
||||
videoSetViewableArea(0, 0, width - 1, height - 1);
|
||||
|
||||
writingsavepic = true;
|
||||
savefile = file;
|
||||
savewidth = width;
|
||||
saveheight = height;
|
||||
bool didit = gi->GenerateSavePic();
|
||||
writingsavepic = false;
|
||||
xdim = oldx;
|
||||
ydim = oldy;
|
||||
videoSetViewableArea(oldwindowxy1.x, oldwindowxy1.y, oldwindowxy2.x, oldwindowxy2.y);
|
||||
}
|
||||
|
||||
void RenderToSavePic(FRenderViewpoint& vp, FileWriter* file, int width, int height)
|
||||
{
|
||||
IntRect bounds;
|
||||
bounds.left = 0;
|
||||
bounds.top = 0;
|
||||
bounds.width = width;
|
||||
bounds.height = height;
|
||||
auto& RenderState = *screen->RenderState();
|
||||
|
||||
// we must be sure the GPU finished reading from the buffer before we fill it with new data.
|
||||
screen->WaitForCommands(false);
|
||||
|
||||
// Switch to render buffers dimensioned for the savepic
|
||||
screen->SetSaveBuffers(true);
|
||||
screen->ImageTransitionScene(true);
|
||||
|
||||
RenderState.SetVertexBuffer(screen->mVertexData);
|
||||
screen->mVertexData->Reset();
|
||||
screen->mLights->Clear();
|
||||
screen->mViewpoints->Clear();
|
||||
|
||||
twodpsp.Clear();
|
||||
|
||||
RenderViewpoint(vp, &bounds, vp.FieldOfView.Degrees, 1.333f, 1.333f, true, false);
|
||||
|
||||
|
||||
int numpixels = width * height;
|
||||
uint8_t* scr = (uint8_t*)M_Malloc(numpixels * 3);
|
||||
screen->CopyScreenToBuffer(width, height, scr);
|
||||
|
||||
DoWriteSavePic(file, scr, width, height, screen->FlipSavePic());
|
||||
M_Free(scr);
|
||||
|
||||
// Switch back the screen render buffers
|
||||
screen->SetViewportRects(nullptr);
|
||||
screen->SetSaveBuffers(false);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Renders the main view
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
static void CheckTimer(FRenderState &state, uint64_t ShaderStartTime)
|
||||
{
|
||||
// if firstFrame is not yet initialized, initialize it to current time
|
||||
// if we're going to overflow a float (after ~4.6 hours, or 24 bits), re-init to regain precision
|
||||
if ((state.firstFrame == 0) || (screen->FrameTime - state.firstFrame >= 1 << 24) || ShaderStartTime >= state.firstFrame)
|
||||
state.firstFrame = screen->FrameTime;
|
||||
}
|
||||
|
||||
|
||||
void animatecamsprite(double s);
|
||||
|
||||
void render_drawrooms(spritetype* playersprite, const vec3_t& position, int sectnum, binangle angle, fixedhoriz horizon, binangle rollang, double smoothratio)
|
||||
{
|
||||
checkRotatedWalls();
|
||||
|
||||
if (gl_fogmode == 1) gl_fogmode = 2; // still needed?
|
||||
|
||||
int16_t sect = sectnum;
|
||||
updatesector(position.x, position.y, §);
|
||||
if (sect >= 0) sectnum = sect;
|
||||
if (sectnum < 0) return;
|
||||
|
||||
iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0;
|
||||
checkBenchActive();
|
||||
|
||||
// reset statistics counters
|
||||
ResetProfilingData();
|
||||
|
||||
// Get this before everything else
|
||||
FRenderViewpoint r_viewpoint = SetupViewpoint(playersprite, position, sectnum, angle, horizon, rollang);
|
||||
if (cl_capfps) r_viewpoint.TicFrac = 1.;
|
||||
else r_viewpoint.TicFrac = smoothratio * (1/65536.);
|
||||
|
||||
screen->mLights->Clear();
|
||||
screen->mViewpoints->Clear();
|
||||
screen->mVertexData->Reset();
|
||||
|
||||
if (writingsavepic) // hack alert! The save code should not go through render_drawrooms, but we can only clean up the game side when Polymost is gone for good.
|
||||
{
|
||||
RenderToSavePic(r_viewpoint, savefile, savewidth, saveheight);
|
||||
return;
|
||||
}
|
||||
|
||||
// Shader start time does not need to be handled per level. Just use the one from the camera to render from.
|
||||
auto RenderState = screen->RenderState();
|
||||
CheckTimer(*RenderState, 0/*ShaderStartTime*/);
|
||||
|
||||
// prepare all camera textures that have been used in the last frame.
|
||||
gi->UpdateCameras(r_viewpoint.TicFrac);
|
||||
|
||||
RenderState->SetVertexBuffer(screen->mVertexData);
|
||||
|
||||
// now render the main view
|
||||
float fovratio;
|
||||
float ratio = ActiveRatio(screen->GetWidth(), screen->GetHeight());
|
||||
if (ratio >= 1.33f)
|
||||
{
|
||||
fovratio = 1.33f;
|
||||
}
|
||||
else
|
||||
{
|
||||
fovratio = ratio;
|
||||
}
|
||||
|
||||
screen->ImageTransitionScene(true); // Only relevant for Vulkan.
|
||||
|
||||
RenderViewpoint(r_viewpoint, nullptr, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true);
|
||||
All.Unclock();
|
||||
}
|
||||
|
||||
void render_camtex(spritetype* playersprite, const vec3_t& position, int sectnum, binangle angle, fixedhoriz horizon, binangle rollang, FGameTexture* camtex, IntRect& rect, double smoothratio)
|
||||
{
|
||||
int16_t sect = sectnum;
|
||||
updatesector(position.x, position.y, §);
|
||||
if (sect >= 0) sectnum = sect;
|
||||
if (sectnum < 0) return;
|
||||
|
||||
screen->RenderState()->SetVertexBuffer(screen->mVertexData);
|
||||
|
||||
// now render the main view
|
||||
float ratio = camtex->GetDisplayWidth() / camtex->GetDisplayHeight();
|
||||
|
||||
FRenderViewpoint r_viewpoint = SetupViewpoint(playersprite, position, sectnum, angle, horizon, rollang);
|
||||
if (cl_capfps) r_viewpoint.TicFrac = smoothratio;
|
||||
|
||||
RenderViewpoint(r_viewpoint, &rect, r_viewpoint.FieldOfView.Degrees, ratio, ratio, false, false);
|
||||
All.Unclock();
|
||||
}
|
||||
|
||||
FSerializer& Serialize(FSerializer& arc, const char* key, PortalDesc& obj, PortalDesc* defval)
|
||||
{
|
||||
if (arc.BeginObject(key))
|
||||
{
|
||||
arc("type", obj.type)
|
||||
("dx", obj.dx)
|
||||
("dy", obj.dy)
|
||||
("dz", obj.dz)
|
||||
("targets", obj.targets)
|
||||
.EndObject();
|
||||
}
|
||||
return arc;
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// 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,
|
||||
|
@ -33,7 +33,7 @@
|
|||
#include "hwrenderer/data/buffers.h"
|
||||
#include "flatvertices.h"
|
||||
#include "hw_renderstate.h"
|
||||
#include "gl_models.h"
|
||||
#include "hw_models.h"
|
||||
|
||||
//CVAR(Bool, gl_light_models, true, CVAR_ARCHIVE)
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// 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,
|
|
@ -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;
|
||||
}
|
24
source/core/rendering/hw_palmanager.h
Normal file
24
source/core/rendering/hw_palmanager.h
Normal 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();
|
||||
|
221
source/core/rendering/hw_sections.cpp
Normal file
221
source/core/rendering/hw_sections.cpp
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
** hw_sectiona.cpp
|
||||
** For decoupling the renderer from internal Build structures
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** 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.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
** The sole reason for existence of this file is that Build's sector setup
|
||||
** does not allow for easy splitting of sectors, either for having disjoint parts
|
||||
** or requiring partial rendering. So we need to add a superstructure
|
||||
** where we can shuffle around some content without disturbing the original
|
||||
** order...
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#include "hw_sections.h"
|
||||
|
||||
|
||||
SectionLine sectionLines[MAXWALLS + (MAXWALLS >> 2)];
|
||||
Section sections[MAXSECTORS + (MAXSECTORS >> 2)];
|
||||
TArray<int> sectionspersector[MAXSECTORS]; // reverse map, mainly for the automap
|
||||
int numsections;
|
||||
int numsectionlines;
|
||||
|
||||
void hw_SplitSector(int sector, int startpos, int endpos);
|
||||
|
||||
TArray<int> splits;
|
||||
|
||||
|
||||
void hw_BuildSections()
|
||||
{
|
||||
// Initial setup just creates a 1:1 mapping of walls to section lines and sectors to sections.
|
||||
numsectionlines = numwalls;
|
||||
numsections = numsectors;
|
||||
for (int i = 0; i < numwalls; i++)
|
||||
{
|
||||
sectionLines[i].startpoint = sectionLines[i].wall = i;
|
||||
sectionLines[i].endpoint = wall[i].point2;
|
||||
sectionLines[i].partner = wall[i].nextwall;
|
||||
sectionLines[i].section = wall[i].sector;
|
||||
sectionLines[i].partnersection = wall[i].nextsector;
|
||||
sectionLines[i].point2index = wall[i].point2 - sector[wall[i].sector].wallptr;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numsectors; i++)
|
||||
{
|
||||
sections[i].sector = i;
|
||||
sections[i].lines.Resize(sector[i].wallnum);
|
||||
for (int j = 0; j < sector[i].wallnum; j++) sections[i].lines[j] = sector[i].wallptr + j;
|
||||
sectionspersector[i].Resize(1);
|
||||
sectionspersector[i][0] = i;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < splits.Size(); i += 3)
|
||||
hw_SplitSector(splits[i], splits[i + 1], splits[i + 2]);
|
||||
}
|
||||
|
||||
|
||||
static void SplitSection(int section, int start, int end)
|
||||
{
|
||||
// note: to do this, the sector's lines must be well ordered and there must only be one outline and no holes.
|
||||
// This also can only apply a single split to a given sector.
|
||||
int firstsection = numsections++;
|
||||
int secondsection = numsections++;
|
||||
|
||||
auto& sect = sections[section];
|
||||
Section* sect1 = §ions[firstsection];
|
||||
Section* sect2 = §ions[secondsection];
|
||||
sect1->sector = sect.sector;
|
||||
sect2->sector = sect.sector;
|
||||
sect1->lines.Clear();
|
||||
sect2->lines.Clear();
|
||||
for (int aline : sect.lines)
|
||||
{
|
||||
int line = sectionLines[aline].wall;
|
||||
if (line < start || line >= end)
|
||||
{
|
||||
sect1->lines.Push(aline);
|
||||
}
|
||||
if (line == start)
|
||||
{
|
||||
sect1->lines.Push(-1);
|
||||
sect2->lines.Push(-1);
|
||||
}
|
||||
if (line >= start && line < end)
|
||||
{
|
||||
sect2->lines.Push(aline);
|
||||
}
|
||||
}
|
||||
|
||||
int firstnewline = numsectionlines;
|
||||
int thisline = numsectionlines;
|
||||
int splitline1, splitline2;
|
||||
//numsectionlines += sect1->lines.Size() + 1;
|
||||
for (unsigned i = 0; i < sect1->lines.Size(); i++)// auto& sline : sect1->lines)
|
||||
{
|
||||
int sline = sect1->lines[i];
|
||||
sect1->lines[i] = thisline;
|
||||
if (sline != -1)
|
||||
{
|
||||
SectionLine& newline = sectionLines[thisline];
|
||||
newline = sectionLines[sline];
|
||||
newline.section = int16_t(sect1 - sections);
|
||||
if (i != sect1->lines.Size() - 1) newline.point2index = thisline + 1 - firstnewline;
|
||||
else newline.point2index = 0;
|
||||
assert(newline.point2index >= 0);
|
||||
|
||||
// relink the partner
|
||||
auto& partnerline = sectionLines[newline.partner];
|
||||
partnerline.partner = thisline;
|
||||
partnerline.partnersection = newline.section;
|
||||
thisline++;
|
||||
}
|
||||
else
|
||||
{
|
||||
splitline1 = thisline++;
|
||||
sectionLines[splitline1].wall = -1;
|
||||
sectionLines[splitline1].section = int16_t(sect1 - sections);
|
||||
sectionLines[splitline1].partnersection = int16_t(sect2 - sections);
|
||||
sectionLines[splitline1].startpoint = start;
|
||||
sectionLines[splitline1].endpoint = end;
|
||||
sectionLines[splitline1].point2index = splitline1 + 1 - firstnewline;
|
||||
}
|
||||
}
|
||||
|
||||
firstnewline = thisline;
|
||||
for (unsigned i = 0; i < sect2->lines.Size(); i++)// auto& sline : sect1->lines)
|
||||
{
|
||||
int sline = sect2->lines[i];
|
||||
sect2->lines[i] = thisline;
|
||||
if (sline != -1)
|
||||
{
|
||||
SectionLine& newline = sectionLines[thisline];
|
||||
newline = sectionLines[sline];
|
||||
newline.section = int16_t(sect2 - sections);
|
||||
if (i != sect2->lines.Size() - 1) newline.point2index = thisline + 1 - firstnewline;
|
||||
else newline.point2index = 0;
|
||||
assert(newline.point2index >= 0);
|
||||
|
||||
// relink the partner
|
||||
auto& partnerline = sectionLines[newline.partner];
|
||||
partnerline.partner = thisline;
|
||||
partnerline.partnersection = newline.section;
|
||||
thisline++;
|
||||
}
|
||||
else
|
||||
{
|
||||
splitline2 = thisline++;
|
||||
sectionLines[splitline2].wall = -1;
|
||||
sectionLines[splitline2].section = int16_t(sect2 - sections);
|
||||
sectionLines[splitline2].partnersection = int16_t(sect1 - sections);
|
||||
sectionLines[splitline2].startpoint = end;
|
||||
sectionLines[splitline2].endpoint = start;
|
||||
sectionLines[splitline2].point2index = splitline2 + 1 - firstnewline;
|
||||
}
|
||||
}
|
||||
sectionLines[splitline1].partner = splitline2;
|
||||
sectionLines[splitline2].partner = splitline1;
|
||||
|
||||
sectionspersector[sect.sector].Resize(2);
|
||||
sectionspersector[sect.sector][0] = int16_t(sect1 - sections);
|
||||
sectionspersector[sect.sector][1] = int16_t(sect2 - sections);
|
||||
}
|
||||
|
||||
void hw_SplitSector(int sectnum, int start, int end)
|
||||
{
|
||||
int wallstart = sector[sectnum].wallptr;
|
||||
int wallend = wallstart + sector[sectnum].wallnum;
|
||||
if (start < wallstart || start >= wallend || end < wallstart || end >= wallend || end < start) return;
|
||||
|
||||
for (unsigned i = 0; i < sectionspersector[sectnum].Size(); i++)
|
||||
{
|
||||
int sect = sectionspersector[sectnum][i];
|
||||
bool foundstart = false, foundend = false;
|
||||
for (int aline : sections[sect].lines)
|
||||
{
|
||||
int line = sectionLines[aline].wall;
|
||||
if (line == start) foundstart = true;
|
||||
if (line == end) foundend = true;
|
||||
}
|
||||
if (foundstart && foundend)
|
||||
{
|
||||
sectionspersector->Delete(i);
|
||||
SplitSection(sect, start, end);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hw_SetSplitSector(int sectnum, int start, int end)
|
||||
{
|
||||
splits.Push(sectnum);
|
||||
splits.Push(start);
|
||||
splits.Push(end);
|
||||
}
|
32
source/core/rendering/hw_sections.h
Normal file
32
source/core/rendering/hw_sections.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include "build.h"
|
||||
|
||||
struct SectionLine
|
||||
{
|
||||
int16_t section;
|
||||
int16_t partnersection;
|
||||
int16_t startpoint;
|
||||
int16_t endpoint;
|
||||
int16_t wall;
|
||||
int16_t partner;
|
||||
int16_t point2index;
|
||||
};
|
||||
|
||||
struct Section
|
||||
{
|
||||
int sector;
|
||||
// this is the whole point of sections - instead of just having a start index and count, we have an explicit list of lines that's a lot easier to change when needed.
|
||||
TArray<int16_t> lines;
|
||||
};
|
||||
|
||||
// giving 25% more may be a bit high as normally this should be small numbers only.
|
||||
extern SectionLine sectionLines[MAXWALLS + (MAXWALLS >> 2)];
|
||||
extern Section sections[MAXSECTORS + (MAXSECTORS >> 2)];
|
||||
extern TArray<int> sectionspersector[MAXSECTORS]; // reverse map, mainly for the automap
|
||||
extern int numsections;
|
||||
extern int numsectionlines;
|
||||
|
||||
|
||||
void hw_BuildSections();
|
||||
void hw_SetSplitSector(int sector, int startpos, int endpos);
|
114
source/core/rendering/hw_voxels.cpp
Normal file
114
source/core/rendering/hw_voxels.cpp
Normal 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).GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto index = fileSystem.FindResource(i, "KVX");
|
||||
if (index >= 0)
|
||||
{
|
||||
voxmodels[i] = voxload(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
24
source/core/rendering/hw_voxels.h
Normal file
24
source/core/rendering/hw_voxels.h
Normal 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);
|
78
source/core/rendering/render.h
Normal file
78
source/core/rendering/render.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
#pragma once
|
||||
#include "build.h"
|
||||
|
||||
class FSerializer;
|
||||
struct IntRect;
|
||||
|
||||
void render_drawrooms(spritetype* playersprite, const vec3_t& position, int sectnum, binangle angle, fixedhoriz horizon, binangle rollang, double smoothratio);
|
||||
void render_camtex(spritetype* playersprite, const vec3_t& position, int sectnum, binangle angle, fixedhoriz horizon, binangle rollang, FGameTexture* camtex, IntRect& rect, double smoothratio);
|
||||
|
||||
struct PortalDesc
|
||||
{
|
||||
int type;
|
||||
int dx, dy, dz;
|
||||
TArray<int> targets;
|
||||
};
|
||||
|
||||
FSerializer& Serialize(FSerializer& arc, const char* key, PortalDesc& obj, PortalDesc* defval);
|
||||
|
||||
|
||||
extern TArray<PortalDesc> allPortals;
|
||||
|
||||
inline void portalClear()
|
||||
{
|
||||
allPortals.Clear();
|
||||
}
|
||||
|
||||
inline int portalAdd(int type, int target, int dx = 0, int dy = 0, int dz = 0)
|
||||
{
|
||||
auto& pt = allPortals[allPortals.Reserve(1)];
|
||||
pt.type = type;
|
||||
if (target >= 0) pt.targets.Push(target);
|
||||
pt.dx = dx;
|
||||
pt.dy = dy;
|
||||
pt.dz = dz;
|
||||
return allPortals.Size() - 1;
|
||||
}
|
||||
|
||||
// merges portals in adjoining sectors.
|
||||
inline void mergePortals()
|
||||
{
|
||||
//Printf("Have %d portals\n", allPortals.Size());
|
||||
bool didsomething = true;
|
||||
while (didsomething)
|
||||
{
|
||||
didsomething = false;
|
||||
for (unsigned i = 0; i < allPortals.Size(); i++)
|
||||
{
|
||||
auto& pt1 = allPortals[i];
|
||||
if (pt1.type == PORTAL_SECTOR_CEILING || pt1.type == PORTAL_SECTOR_FLOOR)
|
||||
{
|
||||
for (unsigned j = i + 1; j < allPortals.Size(); j++)
|
||||
{
|
||||
auto& pt2 = allPortals[j];
|
||||
if (pt1.type != pt2.type || pt1.dx != pt2.dx || pt1.dy != pt2.dy || pt1.dz != pt2.dz) continue;
|
||||
for (unsigned s = 0; s < pt1.targets.Size() && pt2.targets.Size(); s++)
|
||||
{
|
||||
for (unsigned t = 0; t < pt2.targets.Size(); t++)
|
||||
{
|
||||
if (findwallbetweensectors(pt1.targets[s], pt2.targets[t]) >= 0)
|
||||
{
|
||||
pt1.targets.Append(pt2.targets);
|
||||
pt2.targets.Reset();
|
||||
pt2.type = -1;
|
||||
for (int n = 0; n < numsectors; n++)
|
||||
{
|
||||
//Printf("Merged %d and %d\n", i, j);
|
||||
if (sector[n].portalnum == j) sector[n].portalnum = i;
|
||||
}
|
||||
didsomething = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
633
source/core/rendering/scene/hw_bunchdrawer.cpp
Normal file
633
source/core/rendering/scene/hw_bunchdrawer.cpp
Normal file
|
@ -0,0 +1,633 @@
|
|||
/*
|
||||
** hw_bunchdrawer.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2008-2021 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "hw_drawinfo.h"
|
||||
#include "hw_bunchdrawer.h"
|
||||
#include "hw_clipper.h"
|
||||
#include "hw_clock.h"
|
||||
#include "hw_drawstructs.h"
|
||||
#include "automap.h"
|
||||
#include "gamefuncs.h"
|
||||
#include "hw_portal.h"
|
||||
#include "gamestruct.h"
|
||||
#include "hw_voxels.h"
|
||||
#include "mapinfo.h"
|
||||
#include "gamecontrol.h"
|
||||
#include "hw_sections.h"
|
||||
|
||||
extern TArray<int> blockingpairs[MAXWALLS];
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
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);
|
||||
viewy = view.y * -(1/ 16.f);
|
||||
iview = view;
|
||||
StartScene();
|
||||
clipper->SetViewpoint(view);
|
||||
|
||||
gcosang = bamang(di->Viewpoint.RotAngle).fcos();
|
||||
gsinang = bamang(di->Viewpoint.RotAngle).fsin();
|
||||
|
||||
for (int i = 0; i < numwalls; i++)
|
||||
{
|
||||
// Precalculate the clip angles to avoid doing this repeatedly during level traversal.
|
||||
// Reverse the orientation so that startangle and endangle are properly ordered.
|
||||
wall[i].clipangle = clipper->PointToAngle(wall[i].pos);
|
||||
}
|
||||
memset(sectionstartang, -1, sizeof(sectionstartang));
|
||||
memset(sectionendang, -1, sizeof(sectionendang));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BunchDrawer::StartScene()
|
||||
{
|
||||
LastBunch = 0;
|
||||
StartTime = I_msTime();
|
||||
Bunches.Clear();
|
||||
CompareData.Clear();
|
||||
gotsector.Zero();
|
||||
gotsection2.Zero();
|
||||
gotwall.Zero();
|
||||
blockwall.Zero();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
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.asbam() - ang1.asbam()) > ANGLE_180? ang1 :startan;
|
||||
bunch->endangle = (endan.asbam() - ang2.asbam()) < ANGLE_180 ? ang2 : endan;
|
||||
bunch->portal = portal;
|
||||
return bunch->endangle != ang2;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool BunchDrawer::AddLineToBunch(int line, binangle newan)
|
||||
{
|
||||
Bunches[LastBunch].endline++;
|
||||
Bunches[LastBunch].endangle = (newan.asbam() - ang2.asbam()) < ANGLE_180 ? ang2 : newan;
|
||||
return Bunches[LastBunch].endangle != ang2;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BunchDrawer::DeleteBunch(int index)
|
||||
{
|
||||
Bunches[index] = Bunches.Last();
|
||||
Bunches.Pop();
|
||||
}
|
||||
|
||||
bool BunchDrawer::CheckClip(walltype* wal)
|
||||
{
|
||||
auto pt2 = &wall[wal->point2];
|
||||
sectortype* backsector = §or[wal->nextsector];
|
||||
sectortype* frontsector = §or[wall[wal->nextwall].nextsector];
|
||||
|
||||
// if one plane is sky on both sides, the line must not clip.
|
||||
if (frontsector->ceilingstat & backsector->ceilingstat & CSTAT_SECTOR_SKY) return false;
|
||||
if (frontsector->floorstat & backsector->floorstat & CSTAT_SECTOR_SKY) return false;
|
||||
|
||||
float bs_floorheight1;
|
||||
float bs_floorheight2;
|
||||
float bs_ceilingheight1;
|
||||
float bs_ceilingheight2;
|
||||
float fs_floorheight1;
|
||||
float fs_floorheight2;
|
||||
float fs_ceilingheight1;
|
||||
float fs_ceilingheight2;
|
||||
|
||||
// Mirrors and horizons always block the view
|
||||
//if (linedef->special==Line_Mirror || linedef->special==Line_Horizon) return true;
|
||||
|
||||
PlanesAtPoint(frontsector, wal->x, wal->y, &fs_ceilingheight1, &fs_floorheight1);
|
||||
PlanesAtPoint(frontsector, pt2->x, pt2->y, &fs_ceilingheight2, &fs_floorheight2);
|
||||
|
||||
PlanesAtPoint(backsector, wal->x, wal->y, &bs_ceilingheight1, &bs_floorheight1);
|
||||
PlanesAtPoint(backsector, pt2->x, pt2->y, &bs_ceilingheight2, &bs_floorheight2);
|
||||
|
||||
// now check for closed sectors! No idea if we really need the sky checks. We'll see.
|
||||
if (bs_ceilingheight1 <= fs_floorheight1 && bs_ceilingheight2 <= fs_floorheight2)
|
||||
{
|
||||
// backsector's ceiling is below frontsector's floor.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fs_ceilingheight1 <= bs_floorheight1 && fs_ceilingheight2 <= bs_floorheight2)
|
||||
{
|
||||
// backsector's floor is above frontsector's ceiling
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bs_ceilingheight1 <= bs_floorheight1 && bs_ceilingheight2 <= bs_floorheight2)
|
||||
{
|
||||
// backsector is closed
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ClipLine
|
||||
// Clips the given segment
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int BunchDrawer::ClipLine(int aline, bool portal)
|
||||
{
|
||||
auto cline = §ionLines[aline];
|
||||
int section = cline->section;
|
||||
int line = cline->wall;
|
||||
|
||||
auto startAngleBam = wall[cline->startpoint].clipangle;
|
||||
auto endAngleBam = wall[cline->endpoint].clipangle;
|
||||
|
||||
// Back side, i.e. backface culling - read: endAngle <= startAngle!
|
||||
if (startAngleBam.asbam() - endAngleBam.asbam() < ANGLE_180)
|
||||
{
|
||||
return CL_Skip;
|
||||
}
|
||||
if (line >= 0 && blockwall[line]) return CL_Draw;
|
||||
|
||||
// convert to clipper coordinates and clamp to valid range.
|
||||
int startAngle = startAngleBam.asbam() - ang1.asbam();
|
||||
int endAngle = endAngleBam.asbam() - ang1.asbam();
|
||||
if (startAngle < 0) startAngle = 0;
|
||||
if (endAngle < 0) endAngle = INT_MAX;
|
||||
|
||||
// since these values are derived from previous calls of this function they cannot be out of range.
|
||||
int sectStartAngle = sectionstartang[section];
|
||||
auto sectEndAngle = sectionendang[section];
|
||||
|
||||
// check against the maximum possible viewing range of the sector.
|
||||
// Todo: check if this is sufficient or if we really have to do a more costly check against the single visible segments.
|
||||
if (sectStartAngle != -1)
|
||||
{
|
||||
if (sectStartAngle > endAngle || sectEndAngle < startAngle)
|
||||
return CL_Skip; // completely outside the valid range for this sector.
|
||||
if (sectStartAngle > startAngle) startAngle = sectStartAngle;
|
||||
if (sectEndAngle < endAngle) endAngle = sectEndAngle;
|
||||
if (endAngle <= startAngle) return CL_Skip; // can this even happen?
|
||||
}
|
||||
|
||||
if (!portal && !clipper->IsRangeVisible(startAngle, endAngle))
|
||||
{
|
||||
return CL_Skip;
|
||||
}
|
||||
|
||||
auto wal = &wall[line];
|
||||
if (cline->partner == -1 || (wal->cstat & CSTAT_WALL_1WAY) || CheckClip(wal))
|
||||
{
|
||||
// one-sided
|
||||
if (!portal) clipper->AddClipRange(startAngle, endAngle);
|
||||
return CL_Draw;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (portal) clipper->RemoveClipRange(startAngle, endAngle);
|
||||
|
||||
// set potentially visible viewing range for this line's back sector.
|
||||
int nsection = cline->partnersection;
|
||||
if (sectionstartang[nsection] == -1)
|
||||
{
|
||||
sectionstartang[nsection] = startAngle;
|
||||
sectionendang[nsection] = endAngle;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (startAngle < sectionstartang[nsection]) sectionstartang[nsection] = startAngle;
|
||||
if (endAngle > sectionendang[nsection]) sectionendang[nsection] = endAngle;
|
||||
}
|
||||
|
||||
return CL_Draw | CL_Pass;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BunchDrawer::ProcessBunch(int bnch)
|
||||
{
|
||||
FBunch* bunch = &Bunches[bnch];
|
||||
|
||||
ClipWall.Clock();
|
||||
for (int i = bunch->startline; i <= bunch->endline; i++)
|
||||
{
|
||||
int clipped = ClipLine(i, bunch->portal);
|
||||
|
||||
if (clipped & CL_Draw)
|
||||
{
|
||||
int ww = sectionLines[i].wall;
|
||||
if (ww != -1)
|
||||
{
|
||||
for (auto p : blockingpairs[ww]) blockwall.Set(sectionLines[p].wall);
|
||||
show2dwall.Set(ww);
|
||||
|
||||
if (!gotwall[i])
|
||||
{
|
||||
gotwall.Set(i);
|
||||
ClipWall.Unclock();
|
||||
Bsp.Unclock();
|
||||
SetupWall.Clock();
|
||||
|
||||
HWWall hwwall;
|
||||
hwwall.Process(di, &wall[ww], §or[bunch->sectnum], wall[ww].nextsector < 0 ? nullptr : §or[wall[ww].nextsector]);
|
||||
rendered_lines++;
|
||||
|
||||
SetupWall.Unclock();
|
||||
Bsp.Clock();
|
||||
ClipWall.Clock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clipped & CL_Pass)
|
||||
{
|
||||
ClipWall.Unclock();
|
||||
ProcessSection(sectionLines[i].partnersection, false);
|
||||
ClipWall.Clock();
|
||||
}
|
||||
}
|
||||
ClipWall.Unclock();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int BunchDrawer::WallInFront(int line1, int line2)
|
||||
{
|
||||
int wall1s = sectionLines[line1].startpoint;
|
||||
int wall1e = sectionLines[line1].endpoint;
|
||||
int wall2s = sectionLines[line2].startpoint;
|
||||
int wall2e = sectionLines[line2].endpoint;
|
||||
|
||||
double x1s = WallStartX(wall1s);
|
||||
double y1s = WallStartY(wall1s);
|
||||
double x1e = WallStartX(wall1e);
|
||||
double y1e = WallStartY(wall1e);
|
||||
double x2s = WallStartX(wall2s);
|
||||
double y2s = WallStartY(wall2s);
|
||||
double x2e = WallStartX(wall2e);
|
||||
double y2e = WallStartY(wall2e);
|
||||
|
||||
double dx = x1e - x1s;
|
||||
double dy = y1e - y1s;
|
||||
|
||||
double t1 = PointOnLineSide(x2s, y2s, x1s, y1s, dx, dy);
|
||||
double t2 = PointOnLineSide(x2e, y2e, x1s, y1s, dx, dy);
|
||||
if (t1 == 0)
|
||||
{
|
||||
if (t2 == 0) return(-1);
|
||||
t1 = t2;
|
||||
}
|
||||
if (t2 == 0) t2 = t1;
|
||||
|
||||
if ((t1 * t2) >= 0)
|
||||
{
|
||||
t2 = PointOnLineSide(viewx, viewy, x1s, y1s, dx, dy);
|
||||
return((t2 * t1) <= 0);
|
||||
}
|
||||
|
||||
dx = x2e - x2s;
|
||||
dy = y2e - y2s;
|
||||
t1 = PointOnLineSide(x1s, y1s, x2s, y2s, dx, dy);
|
||||
t2 = PointOnLineSide(x1e, y1e, x2s, y2s, dx, dy);
|
||||
if (t1 == 0)
|
||||
{
|
||||
if (t2 == 0) return(-1);
|
||||
t1 = t2;
|
||||
}
|
||||
if (t2 == 0) t2 = t1;
|
||||
if ((t1 * t2) >= 0)
|
||||
{
|
||||
t2 = PointOnLineSide(viewx, viewy, x2s, y2s, dx, dy);
|
||||
return((t2 * t1) > 0);
|
||||
}
|
||||
return(-2);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// This is a bit more complicated than it looks because angles can wrap
|
||||
// around so we can only compare angle differences.
|
||||
//
|
||||
// Rules:
|
||||
// 1. Any bunch can span at most 180°.
|
||||
// 2. 2 bunches can never overlap at both ends
|
||||
// 3. if there is an overlap one of the 2 starting points must be in the
|
||||
// overlapping area.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int BunchDrawer::BunchInFront(FBunch* b1, FBunch* b2)
|
||||
{
|
||||
binangle anglecheck, endang;
|
||||
|
||||
if (b2->startangle.asbam() - b1->startangle.asbam() < b1->endangle.asbam() - b1->startangle.asbam())
|
||||
{
|
||||
// we have an overlap at b2->startangle
|
||||
anglecheck = b2->startangle - b1->startangle;
|
||||
|
||||
// Find the wall in b1 that overlaps b2->startangle
|
||||
for (int i = b1->startline; i <= b1->endline; i++)
|
||||
{
|
||||
endang = wall[wall[i].point2].clipangle - b1->startangle;
|
||||
if (endang.asbam() > anglecheck.asbam())
|
||||
{
|
||||
// found a line
|
||||
int ret = WallInFront(b2->startline, i);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (b1->startangle.asbam() - b2->startangle.asbam() < b2->endangle.asbam() - b2->startangle.asbam())
|
||||
{
|
||||
// we have an overlap at b1->startangle
|
||||
anglecheck = b1->startangle - b2->startangle;
|
||||
|
||||
// Find the wall in b2 that overlaps b1->startangle
|
||||
for (int i = b2->startline; i <= b2->endline; i++)
|
||||
{
|
||||
endang = wall[wall[i].point2].clipangle - b2->startangle;
|
||||
if (endang.asbam() > anglecheck.asbam())
|
||||
{
|
||||
// found a line
|
||||
int ret = WallInFront(i, b1->startline);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
// we have no overlap
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int BunchDrawer::FindClosestBunch()
|
||||
{
|
||||
int closest = 0; //Almost works, but not quite :(
|
||||
|
||||
CompareData.Clear();
|
||||
for (unsigned i = 1; i < Bunches.Size(); i++)
|
||||
{
|
||||
switch (BunchInFront(&Bunches[i], &Bunches[closest]))
|
||||
{
|
||||
case 0: // i is in front
|
||||
closest = i;
|
||||
continue;
|
||||
|
||||
case 1: // i is behind
|
||||
continue;
|
||||
|
||||
default: // can't determine
|
||||
CompareData.Push(i); // mark for later comparison
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// we need to do a second pass to see how the marked bunches relate to the currently closest one.
|
||||
for (unsigned i = 0; i < CompareData.Size(); i++)
|
||||
{
|
||||
switch (BunchInFront(&Bunches[CompareData[i]], &Bunches[closest]))
|
||||
{
|
||||
case 0: // is in front
|
||||
closest = CompareData[i];
|
||||
CompareData[i] = CompareData.Last();
|
||||
CompareData.Pop();
|
||||
i = -1; // we need to recheck everything that's still marked. -1 because this will get incremented before being used.
|
||||
continue;
|
||||
|
||||
case 1: // is behind
|
||||
CompareData[i] = CompareData.Last();
|
||||
CompareData.Pop();
|
||||
i--;
|
||||
continue;
|
||||
|
||||
default:
|
||||
continue;
|
||||
|
||||
}
|
||||
}
|
||||
//Printf("picked bunch starting at %d\n", Bunches[closest].startline);
|
||||
return closest;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BunchDrawer::ProcessSection(int sectionnum, bool portal)
|
||||
{
|
||||
if (gotsection2[sectionnum]) return;
|
||||
gotsection2.Set(sectionnum);
|
||||
|
||||
bool inbunch;
|
||||
binangle startangle;
|
||||
|
||||
SetupSprite.Clock();
|
||||
|
||||
int z;
|
||||
int sectnum = sections[sectionnum].sector;
|
||||
if (!gotsector[sectnum])
|
||||
{
|
||||
gotsector.Set(sectnum);
|
||||
SectIterator it(sectnum);
|
||||
while ((z = it.NextIndex()) >= 0)
|
||||
{
|
||||
auto const spr = (uspriteptr_t)&sprite[z];
|
||||
|
||||
if ((spr->cstat & CSTAT_SPRITE_INVISIBLE) || spr->xrepeat == 0 || spr->yrepeat == 0) // skip invisible sprites
|
||||
continue;
|
||||
|
||||
int sx = spr->x - iview.x, sy = spr->y - int(iview.y);
|
||||
|
||||
// this checks if the sprite is it behind the camera, which will not work if the pitch is high enough to necessitate a FOV of more than 180°.
|
||||
//if ((spr->cstat & CSTAT_SPRITE_ALIGNMENT_MASK) || (hw_models && tile2model[spr->picnum].modelid >= 0) || ((sx * gcosang) + (sy * gsinang) > 0))
|
||||
{
|
||||
if ((spr->cstat & (CSTAT_SPRITE_ONE_SIDED | CSTAT_SPRITE_ALIGNMENT_MASK)) != (CSTAT_SPRITE_ONE_SIDED | CSTAT_SPRITE_ALIGNMENT_WALL) ||
|
||||
(r_voxels && tiletovox[spr->picnum] >= 0 && voxmodels[tiletovox[spr->picnum]]) ||
|
||||
(r_voxels && gi->Voxelize(spr->picnum) > -1) ||
|
||||
DMulScale(bcos(spr->ang), -sx, bsin(spr->ang), -sy, 6) > 0)
|
||||
if (renderAddTsprite(di->tsprite, di->spritesortcnt, z, sectnum))
|
||||
break;
|
||||
}
|
||||
}
|
||||
SetupSprite.Unclock();
|
||||
}
|
||||
|
||||
if (automapping)
|
||||
show2dsector.Set(sectnum);
|
||||
|
||||
SetupFlat.Clock();
|
||||
HWFlat flat;
|
||||
flat.ProcessSector(di, §or[sectnum], sectionnum);
|
||||
SetupFlat.Unclock();
|
||||
|
||||
//Todo: process subsectors
|
||||
inbunch = false;
|
||||
auto section = §ions[sectionnum];
|
||||
for (unsigned i = 0; i < section->lines.Size(); i++)
|
||||
{
|
||||
auto thisline = §ionLines[section->lines[i]];
|
||||
|
||||
#ifdef _DEBUG
|
||||
// For displaying positions in debugger
|
||||
//DVector2 start = { WallStartX(thiswall), WallStartY(thiswall) };
|
||||
//DVector2 end = { WallStartX(thiswall->point2), WallStartY(thiswall->point2) };
|
||||
#endif
|
||||
binangle walang1 = wall[thisline->startpoint].clipangle;
|
||||
binangle walang2 = wall[thisline->endpoint].clipangle;
|
||||
|
||||
// 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))
|
||||
{
|
||||
inbunch = false;
|
||||
}
|
||||
else if (!inbunch)
|
||||
{
|
||||
startangle = walang1;
|
||||
//Printf("Starting bunch:\n\tWall %d\n", sect->wallptr + i);
|
||||
inbunch = StartBunch(sectnum, section->lines[i], walang1, walang2, portal);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Printf("\tWall %d\n", sect->wallptr + i);
|
||||
inbunch = AddLineToBunch(section->lines[i], walang2);
|
||||
}
|
||||
if (thisline->endpoint != section->lines[i] + 1) inbunch = false;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BunchDrawer::RenderScene(const int* viewsectors, unsigned sectcount, bool portal)
|
||||
{
|
||||
//Printf("----------------------------------------- \nstart at sector %d\n", viewsectors[0]);
|
||||
auto process = [&]()
|
||||
{
|
||||
clipper->Clear(ang1);
|
||||
|
||||
for (unsigned i = 0; i < sectcount; i++)
|
||||
{
|
||||
for (auto j : sectionspersector[viewsectors[i]])
|
||||
{
|
||||
sectionstartang[j] = 0;
|
||||
sectionendang[j] = int(ang2.asbam() - ang1.asbam());
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < sectcount; i++)
|
||||
{
|
||||
for (auto j : sectionspersector[viewsectors[i]])
|
||||
{
|
||||
ProcessSection(j, 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 - 1);
|
||||
process();
|
||||
gotsection2.Zero();
|
||||
ang1 = bamang(rotang + ANGLE_90);
|
||||
ang2 = bamang(rotang - ANGLE_90 - 1);
|
||||
process();
|
||||
}
|
||||
Bsp.Unclock();
|
||||
}
|
63
source/core/rendering/scene/hw_bunchdrawer.h
Normal file
63
source/core/rendering/scene/hw_bunchdrawer.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include "tarray.h"
|
||||
#include "basics.h"
|
||||
|
||||
struct HWDrawInfo;
|
||||
class Clipper;
|
||||
|
||||
struct FBunch
|
||||
{
|
||||
int sectnum;
|
||||
int startline;
|
||||
int endline;
|
||||
bool portal;
|
||||
binangle startangle;
|
||||
binangle endangle;
|
||||
};
|
||||
|
||||
class BunchDrawer
|
||||
{
|
||||
HWDrawInfo *di;
|
||||
Clipper *clipper;
|
||||
int LastBunch;
|
||||
int StartTime;
|
||||
TArray<FBunch> Bunches;
|
||||
TArray<int> CompareData;
|
||||
double viewx, viewy;
|
||||
vec2_t iview;
|
||||
float gcosang, gsinang;
|
||||
FixedBitArray<MAXSECTORS> gotsector;
|
||||
FixedBitArray<MAXSECTORS*5/4> gotsection2;
|
||||
FixedBitArray<MAXWALLS> gotwall;
|
||||
FixedBitArray<MAXWALLS> blockwall;
|
||||
binangle ang1, ang2;
|
||||
|
||||
int sectionstartang[MAXSECTORS*5/4], sectionendang[MAXSECTORS*5/4];
|
||||
|
||||
private:
|
||||
|
||||
enum
|
||||
{
|
||||
CL_Skip = 0,
|
||||
CL_Draw = 1,
|
||||
CL_Pass = 2,
|
||||
};
|
||||
|
||||
void StartScene();
|
||||
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, bool portal);
|
||||
void ProcessBunch(int bnch);
|
||||
int WallInFront(int wall1, int wall2);
|
||||
int BunchInFront(FBunch* b1, FBunch* b2);
|
||||
int FindClosestBunch();
|
||||
void ProcessSection(int sectnum, bool portal);
|
||||
|
||||
public:
|
||||
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; }
|
||||
};
|
294
source/core/rendering/scene/hw_clipper.cpp
Normal file
294
source/core/rendering/scene/hw_clipper.cpp
Normal file
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
*
|
||||
** gl_clipper.cpp
|
||||
**
|
||||
** Handles visibility checks.
|
||||
** Loosely based on the JDoom clipper.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2003 Tim Stump
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "hw_clipper.h"
|
||||
#include "basics.h"
|
||||
#include "build.h"
|
||||
#include "printf.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RemoveRange
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::RemoveRange(ClipNode * range)
|
||||
{
|
||||
if (range == cliphead)
|
||||
{
|
||||
cliphead = cliphead->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (range->prev) range->prev->next = range->next;
|
||||
if (range->next) range->next->prev = range->prev;
|
||||
}
|
||||
|
||||
Free(range);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Clear
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::Clear(binangle rangestart)
|
||||
{
|
||||
ClipNode *node = cliphead;
|
||||
ClipNode *temp;
|
||||
|
||||
while (node != nullptr)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
Free(temp);
|
||||
}
|
||||
|
||||
cliphead = nullptr;
|
||||
|
||||
if (visibleStart.asbam() != 0 || visibleEnd.asbam() != 0)
|
||||
{
|
||||
int vstart = int(visibleStart.asbam() - rangestart.asbam());
|
||||
if (vstart > 1) AddClipRange(0, vstart - 1);
|
||||
|
||||
int vend = int(visibleEnd.asbam() - rangestart.asbam());
|
||||
if (vend > 0 && vend < INT_MAX - 1) AddClipRange(vend + 1, INT_MAX);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// IsRangeVisible
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool Clipper::IsRangeVisible(int startAngle, int endAngle)
|
||||
{
|
||||
ClipNode *ci;
|
||||
ci = cliphead;
|
||||
|
||||
if (endAngle == 0 && ci && ci->start==0) return false;
|
||||
|
||||
while (ci != nullptr && ci->start < endAngle)
|
||||
{
|
||||
if (startAngle >= ci->start && endAngle <= ci->end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ci = ci->next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// AddClipRange
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::AddClipRange(int start, int end)
|
||||
{
|
||||
ClipNode *node, *temp, *prevNode;
|
||||
|
||||
if (cliphead)
|
||||
{
|
||||
//check to see if range contains any old ranges
|
||||
node = cliphead;
|
||||
while (node != nullptr && node->start < end)
|
||||
{
|
||||
if (node->start >= start && node->end <= end)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
RemoveRange(temp);
|
||||
}
|
||||
else if (node->start<=start && node->end>=end)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
//check to see if range overlaps a range (or possibly 2)
|
||||
node = cliphead;
|
||||
while (node != nullptr && node->start <= end)
|
||||
{
|
||||
if (node->end >= start)
|
||||
{
|
||||
// we found the first overlapping node
|
||||
if (node->start > start)
|
||||
{
|
||||
// the new range overlaps with this node's start point
|
||||
node->start = start;
|
||||
}
|
||||
|
||||
if (node->end < end)
|
||||
{
|
||||
node->end = end;
|
||||
}
|
||||
|
||||
ClipNode *node2 = node->next;
|
||||
while (node2 && node2->start <= node->end)
|
||||
{
|
||||
if (node2->end > node->end) node->end = node2->end;
|
||||
ClipNode *delnode = node2;
|
||||
node2 = node2->next;
|
||||
RemoveRange(delnode);
|
||||
}
|
||||
return;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
//just add range
|
||||
node = cliphead;
|
||||
prevNode = nullptr;
|
||||
temp = NewRange(start, end);
|
||||
|
||||
while (node != nullptr && node->start < end)
|
||||
{
|
||||
prevNode = node;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
temp->next = node;
|
||||
if (node == nullptr)
|
||||
{
|
||||
temp->prev = prevNode;
|
||||
if (prevNode) prevNode->next = temp;
|
||||
if (!cliphead) cliphead = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node == cliphead)
|
||||
{
|
||||
cliphead->prev = temp;
|
||||
cliphead = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp->prev = prevNode;
|
||||
prevNode->next = temp;
|
||||
node->prev = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = NewRange(start, end);
|
||||
cliphead = temp;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RemoveClipRange
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::RemoveClipRange(int start, int end)
|
||||
{
|
||||
ClipNode *node, *temp;
|
||||
|
||||
if (cliphead)
|
||||
{
|
||||
//check to see if range contains any old ranges
|
||||
node = cliphead;
|
||||
while (node != nullptr && node->start < end)
|
||||
{
|
||||
if (node->start >= start && node->end <= end)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
RemoveRange(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
//check to see if range overlaps a range (or possibly 2)
|
||||
node = cliphead;
|
||||
while (node != nullptr)
|
||||
{
|
||||
if (node->start >= start && node->start <= end)
|
||||
{
|
||||
node->start = end;
|
||||
break;
|
||||
}
|
||||
else if (node->end >= start && node->end <= end)
|
||||
{
|
||||
node->end=start;
|
||||
}
|
||||
else if (node->start < start && node->end > end)
|
||||
{
|
||||
temp = NewRange(end, node->end);
|
||||
node->end=start;
|
||||
temp->next=node->next;
|
||||
temp->prev=node;
|
||||
node->next=temp;
|
||||
if (temp->next) temp->next->prev=temp;
|
||||
break;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::DumpClipper()
|
||||
{
|
||||
for (auto node = cliphead; node; node = node->next)
|
||||
{
|
||||
Printf("Range from %f to %f\n", bamang(node->start).asdeg(), bamang(node->end).asdeg());
|
||||
}
|
||||
}
|
115
source/core/rendering/scene/hw_clipper.h
Normal file
115
source/core/rendering/scene/hw_clipper.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
#ifndef __GL_CLIPPER
|
||||
#define __GL_CLIPPER
|
||||
|
||||
#include "xs_Float.h"
|
||||
#include "memarena.h"
|
||||
#include "basics.h"
|
||||
#include "vectors.h"
|
||||
#include "binaryangle.h"
|
||||
#include "intvec.h"
|
||||
|
||||
class ClipNode
|
||||
{
|
||||
friend class Clipper;
|
||||
|
||||
ClipNode *prev, *next;
|
||||
int start, end;
|
||||
|
||||
bool operator== (const ClipNode &other)
|
||||
{
|
||||
return other.start == start && other.end == end;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Clipper
|
||||
{
|
||||
FMemArena nodearena;
|
||||
ClipNode * freelist = nullptr;
|
||||
|
||||
ClipNode * clipnodes = nullptr;
|
||||
ClipNode * cliphead = nullptr;
|
||||
vec2_t viewpoint;
|
||||
void RemoveRange(ClipNode* cn);
|
||||
binangle visibleStart, visibleEnd;
|
||||
|
||||
public:
|
||||
bool IsRangeVisible(int startangle, int endangle);
|
||||
void AddClipRange(int startangle, int endangle);
|
||||
void RemoveClipRange(int startangle, int endangle);
|
||||
|
||||
public:
|
||||
|
||||
void Clear(binangle rangestart);
|
||||
|
||||
void Free(ClipNode *node)
|
||||
{
|
||||
node->next = freelist;
|
||||
freelist = node;
|
||||
}
|
||||
|
||||
private:
|
||||
ClipNode * GetNew()
|
||||
{
|
||||
if (freelist)
|
||||
{
|
||||
ClipNode * p = freelist;
|
||||
freelist = p->next;
|
||||
return p;
|
||||
}
|
||||
else return (ClipNode*)nodearena.Alloc(sizeof(ClipNode));
|
||||
}
|
||||
|
||||
ClipNode * NewRange(int start, int end)
|
||||
{
|
||||
ClipNode * c = GetNew();
|
||||
|
||||
c->start = start;
|
||||
c->end = end;
|
||||
c->next = c->prev = NULL;
|
||||
return c;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void SetViewpoint(const vec2_t &vp)
|
||||
{
|
||||
viewpoint = vp;
|
||||
}
|
||||
|
||||
void SetVisibleRange(angle_t a1, angle_t a2)
|
||||
{
|
||||
if (a2 != 0xffffffff)
|
||||
{
|
||||
visibleStart = bamang(a1 - a2);
|
||||
visibleEnd = bamang(a1 + a2);
|
||||
}
|
||||
else visibleStart = visibleEnd = bamang(0);
|
||||
}
|
||||
|
||||
void RestrictVisibleRange(binangle a1, binangle a2)
|
||||
{
|
||||
if (visibleStart == visibleEnd)
|
||||
{
|
||||
visibleStart = a1;
|
||||
visibleEnd = a2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a1.asbam() - visibleStart.asbam() < visibleEnd.asbam() - visibleStart.asbam()) visibleStart = a1;
|
||||
if (a2.asbam() - visibleStart.asbam() < visibleEnd.asbam() - visibleStart.asbam()) visibleStart = a2;
|
||||
}
|
||||
}
|
||||
|
||||
void DumpClipper();
|
||||
|
||||
binangle PointToAngle(const vec2_t& pos)
|
||||
{
|
||||
vec2_t vec = pos - viewpoint;
|
||||
return bvectangbam(vec.x, vec.y);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
734
source/core/rendering/scene/hw_drawinfo.cpp
Normal file
734
source/core/rendering/scene/hw_drawinfo.cpp
Normal file
|
@ -0,0 +1,734 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2000-2018 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 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/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_drawinfo.cpp
|
||||
** Basic scene draw info management class
|
||||
**
|
||||
*/
|
||||
|
||||
#include "hw_portal.h"
|
||||
#include "build.h"
|
||||
#include "hw_renderstate.h"
|
||||
#include "hw_drawinfo.h"
|
||||
//#include "models.h"
|
||||
#include "hw_clock.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "hw_viewpointbuffer.h"
|
||||
#include "flatvertices.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "hw_vrmodes.h"
|
||||
#include "hw_clipper.h"
|
||||
#include "v_draw.h"
|
||||
#include "gamecvars.h"
|
||||
#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)
|
||||
|
||||
CVAR(Bool, gl_texture, true, 0)
|
||||
CVAR(Float, gl_mask_threshold, 0.5f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Float, gl_mask_sprite_threshold, 0.5f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
FixedBitArray<MAXSECTORS> gotsector;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FDrawInfoList
|
||||
{
|
||||
public:
|
||||
TDeletingArray<HWDrawInfo *> mList;
|
||||
|
||||
HWDrawInfo * GetNew();
|
||||
void Release(HWDrawInfo *);
|
||||
};
|
||||
|
||||
|
||||
FDrawInfoList di_list;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Try to reuse the lists as often as possible as they contain resources that
|
||||
// are expensive to create and delete.
|
||||
//
|
||||
// Note: If multithreading gets used, this class needs synchronization.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
HWDrawInfo *FDrawInfoList::GetNew()
|
||||
{
|
||||
if (mList.Size() > 0)
|
||||
{
|
||||
HWDrawInfo *di;
|
||||
mList.Pop(di);
|
||||
return di;
|
||||
}
|
||||
return new HWDrawInfo();
|
||||
}
|
||||
|
||||
void FDrawInfoList::Release(HWDrawInfo * di)
|
||||
{
|
||||
di->ClearBuffers();
|
||||
mList.Push(di);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sets up a new drawinfo struct
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
HWDrawInfo *HWDrawInfo::StartDrawInfo(HWDrawInfo *parent, FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms)
|
||||
{
|
||||
HWDrawInfo *di = di_list.GetNew();
|
||||
di->StartScene(parentvp, uniforms);
|
||||
return di;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static Clipper staticClipper; // Since all scenes are processed sequentially we only need one clipper.
|
||||
static HWDrawInfo * gl_drawinfo; // This is a linked list of all active DrawInfos and needed to free the memory arena after the last one goes out of scope.
|
||||
|
||||
void HWDrawInfo::StartScene(FRenderViewpoint& parentvp, HWViewpointUniforms* uniforms)
|
||||
{
|
||||
mClipper = &staticClipper;
|
||||
|
||||
Viewpoint = parentvp;
|
||||
//lightmode = Level->lightMode;
|
||||
if (uniforms)
|
||||
{
|
||||
VPUniforms = *uniforms;
|
||||
// The clip planes will never be inherited from the parent drawinfo.
|
||||
VPUniforms.mClipLine.X = -1000001.f;
|
||||
VPUniforms.mClipHeight = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
VPUniforms.mProjectionMatrix.loadIdentity();
|
||||
VPUniforms.mViewMatrix.loadIdentity();
|
||||
VPUniforms.mNormalViewMatrix.loadIdentity();
|
||||
//VPUniforms.mViewHeight = viewheight;
|
||||
VPUniforms.mGlobVis = (2 / 65536.f) * g_visibility / r_ambientlight;
|
||||
VPUniforms.mPalLightLevels = numshades | (static_cast<int>(gl_fogmode) << 8) | (5 << 16);
|
||||
|
||||
VPUniforms.mClipLine.X = -10000000.0f;
|
||||
VPUniforms.mShadowmapFilter = gl_shadowmap_filter;
|
||||
}
|
||||
vec2_t view = { int(Viewpoint.Pos.X * 16), int(Viewpoint.Pos.Y * -16) };
|
||||
mClipper->SetViewpoint(view);
|
||||
|
||||
ClearBuffers();
|
||||
|
||||
for (int i = 0; i < GLDL_TYPES; i++) drawlists[i].Reset();
|
||||
vpIndex = 0;
|
||||
|
||||
// Fullbright information needs to be propagated from the main view.
|
||||
if (outer != nullptr) FullbrightFlags = outer->FullbrightFlags;
|
||||
else FullbrightFlags = 0;
|
||||
|
||||
outer = gl_drawinfo;
|
||||
gl_drawinfo = this;
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
HWDrawInfo *HWDrawInfo::EndDrawInfo()
|
||||
{
|
||||
assert(this == gl_drawinfo);
|
||||
for (int i = 0; i < GLDL_TYPES; i++) drawlists[i].Reset();
|
||||
gl_drawinfo = outer;
|
||||
di_list.Release(this);
|
||||
if (gl_drawinfo == nullptr)
|
||||
ResetRenderDataAllocator();
|
||||
return gl_drawinfo;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void HWDrawInfo::ClearBuffers()
|
||||
{
|
||||
spriteindex = 0;
|
||||
mClipPortal = nullptr;
|
||||
mCurrentPortal = nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// R_FrustumAngle
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
angle_t HWDrawInfo::FrustumAngle()
|
||||
{
|
||||
float WidescreenRatio = 1.6666f; // fixme - this is a placeholder.
|
||||
float tilt = fabs(Viewpoint.HWAngles.Pitch.Degrees);
|
||||
|
||||
// If the pitch is larger than this you can look all around at a FOV of 90°
|
||||
if (tilt > 46.0f) return 0xffffffff;
|
||||
|
||||
// ok, this is a gross hack that barely works...
|
||||
// but at least it doesn't overestimate too much...
|
||||
double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*Viewpoint.FieldOfView.Degrees*48.0 / AspectMultiplier(WidescreenRatio) / 90.0;
|
||||
angle_t a1 = DAngle(floatangle).BAMs();
|
||||
if (a1 >= ANGLE_90) return 0xffffffff; // it's either below 90 or bust.
|
||||
return a1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Setup the modelview matrix
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror)
|
||||
{
|
||||
float mult = mirror ? -1.f : 1.f;
|
||||
float planemult = planemirror ? -1 : 1;// Level->info->pixelstretch : Level->info->pixelstretch;
|
||||
|
||||
VPUniforms.mViewMatrix.loadIdentity();
|
||||
VPUniforms.mViewMatrix.rotate(angles.Roll.Degrees, 0.0f, 0.0f, 1.0f);
|
||||
VPUniforms.mViewMatrix.rotate(angles.Pitch.Degrees, 1.0f, 0.0f, 0.0f);
|
||||
VPUniforms.mViewMatrix.rotate(angles.Yaw.Degrees, 0.0f, mult, 0.0f);
|
||||
VPUniforms.mViewMatrix.translate(vx * mult, -vz * planemult, -vy);
|
||||
VPUniforms.mViewMatrix.scale(-mult, planemult, 1);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// SetupView
|
||||
// Setup the view rotation matrix for the given viewpoint
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void HWDrawInfo::SetupView(FRenderState &state, float vx, float vy, float vz, bool mirror, bool planemirror)
|
||||
{
|
||||
auto &vp = Viewpoint;
|
||||
//vp.SetViewAngle(r_viewwindow); // todo: need to pass in.
|
||||
SetViewMatrix(vp.HWAngles, vx, vy, vz, mirror, planemirror);
|
||||
SetCameraPos(vp.Pos);
|
||||
VPUniforms.CalcDependencies();
|
||||
vpIndex = screen->mViewpoints->SetViewpoint(state, &VPUniforms);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
HWPortal * HWDrawInfo::FindPortal(const void * src)
|
||||
{
|
||||
int i = Portals.Size() - 1;
|
||||
|
||||
while (i >= 0 && Portals[i] && Portals[i]->GetSource() != src) i--;
|
||||
return i >= 0 ? Portals[i] : nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::DispatchSprites()
|
||||
{
|
||||
for (int i = 0; i < spritesortcnt; i++)
|
||||
{
|
||||
auto tspr = &tsprite[i];
|
||||
int tilenum = tspr->picnum;
|
||||
int spritenum = tspr->owner;
|
||||
|
||||
if (spritenum < 0 || (unsigned)tilenum >= MAXTILES)
|
||||
continue;
|
||||
|
||||
if (automapping == 1 && (unsigned)spritenum < MAXSPRITES)
|
||||
show2dsprite.Set(spritenum);
|
||||
|
||||
setgotpic(tilenum);
|
||||
|
||||
if (!(spriteext[spritenum].flags & SPREXT_NOTMD))
|
||||
{
|
||||
int pt = Ptile2tile(tspr->picnum, tspr->pal);
|
||||
if (hw_models && tile2model[pt].modelid >= 0 && tile2model[pt].framenum >= 0)
|
||||
{
|
||||
//HWSprite hwsprite;
|
||||
//if (hwsprite.ProcessModel(pt, tspr)) continue;
|
||||
}
|
||||
if (r_voxels)
|
||||
{
|
||||
if ((tspr->cstat & CSTAT_SPRITE_ALIGNMENT) != CSTAT_SPRITE_ALIGNMENT_SLAB && tiletovox[tspr->picnum] >= 0 && voxmodels[tiletovox[tspr->picnum]])
|
||||
{
|
||||
HWSprite hwsprite;
|
||||
int num = tiletovox[tspr->picnum];
|
||||
if (hwsprite.ProcessVoxel(this, voxmodels[tiletovox[tspr->picnum]], tspr, §or[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, §or[tspr->sectnum], voxrotate[num]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (spriteext[spritenum].flags & SPREXT_AWAY1)
|
||||
{
|
||||
tspr->pos.x += bcos(tspr->ang, -13);
|
||||
tspr->pos.y += bsin(tspr->ang, -13);
|
||||
}
|
||||
else if (spriteext[spritenum].flags & SPREXT_AWAY2)
|
||||
{
|
||||
tspr->pos.x -= bcos(tspr->ang, -13);
|
||||
tspr->pos.y -= bsin(tspr->ang, -13);
|
||||
}
|
||||
|
||||
tileUpdatePicnum(&tilenum, sprite->owner + 32768, 0);
|
||||
tspr->picnum = tilenum;
|
||||
|
||||
switch (tspr->cstat & CSTAT_SPRITE_ALIGNMENT)
|
||||
{
|
||||
case CSTAT_SPRITE_ALIGNMENT_FACING:
|
||||
{
|
||||
HWSprite sprite;
|
||||
sprite.Process(this, tspr, §or[tspr->sectnum], false);
|
||||
break;
|
||||
}
|
||||
|
||||
case CSTAT_SPRITE_ALIGNMENT_WALL:
|
||||
{
|
||||
HWWall wall;
|
||||
wall.ProcessWallSprite(this, tspr, §or[tspr->sectnum]);
|
||||
break;
|
||||
}
|
||||
|
||||
case CSTAT_SPRITE_ALIGNMENT_FLOOR:
|
||||
{
|
||||
HWFlat flat;
|
||||
flat.ProcessFlatSprite(this, tspr, §or[tspr->sectnum]);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// CreateScene
|
||||
//
|
||||
// creates the draw lists for the current scene
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::CreateScene(bool portal)
|
||||
{
|
||||
const auto& vp = Viewpoint;
|
||||
|
||||
angle_t a1 = FrustumAngle();
|
||||
|
||||
// reset the portal manager
|
||||
portalState.StartFrame();
|
||||
|
||||
ProcessAll.Clock();
|
||||
|
||||
// clip the scene and fill the drawlists
|
||||
screen->mVertexData->Map();
|
||||
screen->mLights->Map();
|
||||
|
||||
spritesortcnt = 0;
|
||||
ingeo = false;
|
||||
geoofs = { 0,0 };
|
||||
|
||||
vec2_t view = { int(vp.Pos.X * 16), int(vp.Pos.Y * -16) };
|
||||
|
||||
if(!portal) mClipper->SetVisibleRange(vp.RotAngle, a1);
|
||||
|
||||
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, portal);
|
||||
else
|
||||
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);
|
||||
DispatchSprites();
|
||||
SetupSprite.Unclock();
|
||||
|
||||
GeoEffect eff;
|
||||
int effsect = vp.SectNums ? vp.SectNums[0] : vp.SectCount;
|
||||
int drawsect = effsect;
|
||||
// RR geometry hack. Ugh...
|
||||
// This just adds to the existing render list, so we must offset the effect areas to the same xy-space as the main one as we cannot change the view matrix.
|
||||
if (gi->GetGeoEffect(&eff, effsect))
|
||||
{
|
||||
ingeo = true;
|
||||
geoofs = { (float)eff.geox[0], (float)eff.geoy[0] };
|
||||
// process the first layer.
|
||||
for (int i = 0; i < eff.geocnt; i++)
|
||||
{
|
||||
auto sect = §or[eff.geosectorwarp[i]];
|
||||
for (auto w = 0; w < sect->wallnum; w++)
|
||||
{
|
||||
auto wal = &wall[sect->wallptr + w];
|
||||
wal->x += eff.geox[i];
|
||||
wal->y += eff.geoy[i];
|
||||
}
|
||||
sect->dirty = 255;
|
||||
if (eff.geosector[i] == effsect) drawsect = eff.geosectorwarp[i];
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
auto sect = §or[eff.geosectorwarp[i]];
|
||||
for (auto w = 0; w < sect->wallnum; w++)
|
||||
{
|
||||
auto wal = &wall[sect->wallptr + w];
|
||||
wal->x -= eff.geox[i];
|
||||
wal->y -= eff.geoy[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Now the second layer. Same shit, different arrays.
|
||||
geoofs = { (float)eff.geox2[0], (float)eff.geoy2[0] };
|
||||
for (int i = 0; i < eff.geocnt; i++)
|
||||
{
|
||||
auto sect = §or[eff.geosectorwarp2[i]];
|
||||
for (auto w = 0; w < sect->wallnum; w++)
|
||||
{
|
||||
auto wal = &wall[sect->wallptr + w];
|
||||
wal->x += eff.geox2[i];
|
||||
wal->y += eff.geoy2[i];
|
||||
}
|
||||
sect->dirty = 255;
|
||||
if (eff.geosector[i] == effsect) drawsect = eff.geosectorwarp2[i];
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
auto sect = §or[eff.geosectorwarp2[i]];
|
||||
for (auto w = 0; w < sect->wallnum; w++)
|
||||
{
|
||||
auto wal = &wall[sect->wallptr + w];
|
||||
wal->x -= eff.geox2[i];
|
||||
wal->y -= eff.geoy2[i];
|
||||
}
|
||||
}
|
||||
ingeo = false;
|
||||
}
|
||||
|
||||
|
||||
screen->mLights->Unmap();
|
||||
screen->mVertexData->Unmap();
|
||||
|
||||
ProcessAll.Unclock();
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RenderScene
|
||||
//
|
||||
// Draws the current draw lists for the non GLSL renderer
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::RenderScene(FRenderState &state)
|
||||
{
|
||||
const auto &vp = Viewpoint;
|
||||
RenderAll.Clock();
|
||||
|
||||
state.SetDepthMask(true);
|
||||
|
||||
state.EnableFog(true);
|
||||
state.SetRenderStyle(STYLE_Source);
|
||||
|
||||
|
||||
// Part 1: solid geometry. This is set up so that there are no transparent parts
|
||||
state.SetDepthFunc(DF_Less);
|
||||
state.AlphaFunc(Alpha_GEqual, 0.f);
|
||||
state.ClearDepthBias();
|
||||
|
||||
state.EnableTexture(gl_texture);
|
||||
state.EnableBrightmap(true);
|
||||
drawlists[GLDL_PLAINWALLS].DrawWalls(this, state, false);
|
||||
|
||||
drawlists[GLDL_PLAINFLATS].DrawFlats(this, state, false);
|
||||
|
||||
|
||||
// Part 2: masked geometry. This is set up so that only pixels with alpha>gl_mask_threshold will show
|
||||
state.AlphaFunc(Alpha_GEqual, gl_mask_threshold);
|
||||
|
||||
// This list is masked, non-translucent walls.
|
||||
drawlists[GLDL_MASKEDWALLS].DrawWalls(this, state, false);
|
||||
|
||||
// These lists must be drawn in two passes for color and depth to avoid depth fighting with overlapping entries
|
||||
drawlists[GLDL_MASKEDFLATS].SortFlats(this);
|
||||
drawlists[GLDL_MASKEDWALLSV].SortWallsHorz(this);
|
||||
drawlists[GLDL_MASKEDWALLSH].SortWallsVert(this);
|
||||
|
||||
state.SetDepthBias(-1, -128);
|
||||
|
||||
// these lists are only wall and floor sprites - often attached to walls and floors - so they need to be offset from the plane they may be attached to.
|
||||
drawlists[GLDL_MASKEDWALLSS].DrawWalls(this, state, false);
|
||||
|
||||
// Each list must draw both its passes before the next one to ensure proper depth buffer contents.
|
||||
state.SetDepthMask(false);
|
||||
drawlists[GLDL_MASKEDWALLSV].DrawWalls(this, state, false);
|
||||
state.SetDepthMask(true);
|
||||
state.SetColorMask(false);
|
||||
drawlists[GLDL_MASKEDWALLSV].DrawWalls(this, state, false);
|
||||
state.SetColorMask(true);
|
||||
|
||||
state.SetDepthMask(false);
|
||||
drawlists[GLDL_MASKEDWALLSH].DrawWalls(this, state, false);
|
||||
state.SetDepthMask(true);
|
||||
state.SetColorMask(false);
|
||||
drawlists[GLDL_MASKEDWALLSH].DrawWalls(this, state, false);
|
||||
state.SetColorMask(true);
|
||||
|
||||
state.SetDepthMask(false);
|
||||
drawlists[GLDL_MASKEDFLATS].DrawFlats(this, state, false);
|
||||
state.SetDepthMask(true);
|
||||
state.SetColorMask(false);
|
||||
drawlists[GLDL_MASKEDFLATS].DrawFlats(this, state, false);
|
||||
state.SetColorMask(true);
|
||||
state.ClearDepthBias();
|
||||
|
||||
drawlists[GLDL_MODELS].Draw(this, state, false);
|
||||
|
||||
state.SetRenderStyle(STYLE_Translucent);
|
||||
|
||||
state.SetDepthFunc(DF_LEqual);
|
||||
RenderAll.Unclock();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RenderTranslucent
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::RenderTranslucent(FRenderState &state)
|
||||
{
|
||||
RenderAll.Clock();
|
||||
|
||||
state.SetDepthBias(-1, -128);
|
||||
|
||||
// final pass: translucent stuff
|
||||
state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold);
|
||||
state.SetRenderStyle(STYLE_Translucent);
|
||||
|
||||
state.EnableBrightmap(true);
|
||||
drawlists[GLDL_TRANSLUCENTBORDER].Draw(this, state, true);
|
||||
state.SetDepthMask(false);
|
||||
|
||||
drawlists[GLDL_TRANSLUCENT].DrawSorted(this, state);
|
||||
state.EnableBrightmap(false);
|
||||
|
||||
state.ClearDepthBias();
|
||||
state.AlphaFunc(Alpha_GEqual, 0.5f);
|
||||
state.SetDepthMask(true);
|
||||
|
||||
RenderAll.Unclock();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RenderTranslucent
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::RenderPortal(HWPortal *p, FRenderState &state, bool usestencil)
|
||||
{
|
||||
auto gp = static_cast<HWPortal *>(p);
|
||||
gp->SetupStencil(this, state, usestencil);
|
||||
auto new_di = StartDrawInfo(this, Viewpoint, &VPUniforms);
|
||||
new_di->mCurrentPortal = gp;
|
||||
state.SetLightIndex(-1);
|
||||
gp->DrawContents(new_di, state);
|
||||
new_di->EndDrawInfo();
|
||||
state.SetVertexBuffer(screen->mVertexData);
|
||||
screen->mViewpoints->Bind(state, vpIndex);
|
||||
gp->RemoveStencil(this, state, usestencil);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Draws player sprites and color blend
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
void HWDrawInfo::EndDrawScene(FRenderState &state)
|
||||
{
|
||||
state.EnableFog(false);
|
||||
|
||||
#if 0
|
||||
// [BB] HUD models need to be rendered here.
|
||||
const bool renderHUDModel = IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player);
|
||||
if (renderHUDModel)
|
||||
{
|
||||
// [BB] The HUD model should be drawn over everything else already drawn.
|
||||
state.Clear(CT_Depth);
|
||||
DrawPlayerSprites(true, state);
|
||||
}
|
||||
#endif
|
||||
|
||||
state.EnableStencil(false);
|
||||
state.SetViewport(screen->mScreenViewport.left, screen->mScreenViewport.top, screen->mScreenViewport.width, screen->mScreenViewport.height);
|
||||
|
||||
// Restore standard rendering state
|
||||
state.SetRenderStyle(STYLE_Translucent);
|
||||
state.ResetColor();
|
||||
state.EnableTexture(true);
|
||||
state.SetScissor(0, 0, -1, -1);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// sets 3D viewport and initial state
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::Set3DViewport(FRenderState &state)
|
||||
{
|
||||
// Always clear all buffers with scissor test disabled.
|
||||
// This is faster on newer hardware because it allows the GPU to skip
|
||||
// reading from slower memory where the full buffers are stored.
|
||||
state.SetScissor(0, 0, -1, -1);
|
||||
state.Clear(CT_Color | CT_Depth | CT_Stencil);
|
||||
|
||||
const auto &bounds = screen->mSceneViewport;
|
||||
state.SetViewport(bounds.left, bounds.top, bounds.width, bounds.height);
|
||||
state.SetScissor(bounds.left, bounds.top, bounds.width, bounds.height);
|
||||
state.EnableMultisampling(true);
|
||||
state.EnableDepthTest(true);
|
||||
state.EnableStencil(true);
|
||||
state.SetStencil(0, SOP_Keep, SF_AllOn);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// gl_drawscene - this function renders the scene from the current
|
||||
// viewpoint, including mirrors and skyboxes and other portals
|
||||
// It is assumed that the HWPortal::EndFrame returns with the
|
||||
// stencil, z-buffer and the projection matrix intact!
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::DrawScene(int drawmode, bool portal)
|
||||
{
|
||||
static int recursion = 0;
|
||||
static int ssao_portals_available = 0;
|
||||
const auto& vp = Viewpoint;
|
||||
|
||||
bool applySSAO = false;
|
||||
if (drawmode == DM_MAINVIEW)
|
||||
{
|
||||
ssao_portals_available = gl_ssao_portals;
|
||||
applySSAO = true;
|
||||
}
|
||||
else if (drawmode == DM_OFFSCREEN)
|
||||
{
|
||||
ssao_portals_available = 0;
|
||||
}
|
||||
else if (drawmode == DM_PORTAL && ssao_portals_available > 0)
|
||||
{
|
||||
applySSAO = (mCurrentPortal->AllowSSAO()/* || Level->flags3&LEVEL3_SKYBOXAO*/);
|
||||
ssao_portals_available--;
|
||||
}
|
||||
|
||||
CreateScene(portal);
|
||||
auto& RenderState = *screen->RenderState();
|
||||
|
||||
RenderState.SetDepthMask(true);
|
||||
|
||||
if (!gl_no_skyclear) portalState.RenderFirstSkyPortal(recursion, this, RenderState);
|
||||
|
||||
RenderScene(RenderState);
|
||||
|
||||
if (applySSAO && RenderState.GetPassType() == GBUFFER_PASS)
|
||||
{
|
||||
screen->AmbientOccludeScene(VPUniforms.mProjectionMatrix.get()[5]);
|
||||
screen->mViewpoints->Bind(RenderState, vpIndex);
|
||||
}
|
||||
|
||||
// Handle all portals after rendering the opaque objects but before
|
||||
// doing all translucent stuff
|
||||
recursion++;
|
||||
portalState.EndFrame(this, RenderState);
|
||||
recursion--;
|
||||
RenderTranslucent(RenderState);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// R_RenderView - renders one view - either the screen or a camera texture
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::ProcessScene(bool toscreen)
|
||||
{
|
||||
portalState.BeginScene();
|
||||
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.
|
||||
}
|
||||
}
|
220
source/core/rendering/scene/hw_drawinfo.h
Normal file
220
source/core/rendering/scene/hw_drawinfo.h
Normal file
|
@ -0,0 +1,220 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include "build.h"
|
||||
#include "vectors.h"
|
||||
#include "hw_viewpointuniforms.h"
|
||||
#include "v_video.h"
|
||||
#include "hw_drawlist.h"
|
||||
#include "hw_bunchdrawer.h"
|
||||
//#include "r_viewpoint.h"
|
||||
|
||||
enum EDrawMode
|
||||
{
|
||||
DM_MAINVIEW,
|
||||
DM_OFFSCREEN,
|
||||
DM_PORTAL,
|
||||
DM_SKYPORTAL
|
||||
};
|
||||
|
||||
struct FSectorPortalGroup;
|
||||
struct FFlatVertex;
|
||||
class HWWall;
|
||||
class HWFlat;
|
||||
class HWSprite;
|
||||
class IShadowMap;
|
||||
struct FDynLightData;
|
||||
class Clipper;
|
||||
class HWPortal;
|
||||
class FFlatVertexBuffer;
|
||||
class IRenderQueue;
|
||||
class HWScenePortalBase;
|
||||
class FRenderState;
|
||||
|
||||
struct FRenderViewpoint
|
||||
{
|
||||
spritetype* CameraSprite;
|
||||
DVector3 Pos;
|
||||
FRotator HWAngles;
|
||||
FAngle FieldOfView;
|
||||
angle_t RotAngle;
|
||||
int* SectNums;
|
||||
int SectCount;
|
||||
double TicFrac;
|
||||
double TanCos, TanSin; // needed for calculating a sprite's screen depth.
|
||||
DVector2 ViewVector; // direction the camera is facing.
|
||||
};
|
||||
//==========================================================================
|
||||
//
|
||||
// these are used to link faked planes due to missing textures to a sector
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
enum SectorRenderFlags
|
||||
{
|
||||
// This is used to merge several subsectors into a single draw item
|
||||
SSRF_RENDERFLOOR = 1,
|
||||
SSRF_RENDERCEILING = 2,
|
||||
SSRF_RENDERALL = 7,
|
||||
SSRF_PROCESSED = 8,
|
||||
SSRF_SEEN = 16,
|
||||
};
|
||||
|
||||
enum EPortalClip
|
||||
{
|
||||
PClip_InFront,
|
||||
PClip_Inside,
|
||||
PClip_Behind,
|
||||
};
|
||||
|
||||
enum DrawListType
|
||||
{
|
||||
GLDL_PLAINWALLS,
|
||||
GLDL_PLAINFLATS,
|
||||
GLDL_MASKEDWALLS,
|
||||
GLDL_MASKEDWALLSS, // arbitrary wall sprites.
|
||||
GLDL_MASKEDWALLSV, // vertical wall sprites
|
||||
GLDL_MASKEDWALLSH, // horizontal wall sprites. These two lists merely exist for easier sorting.
|
||||
GLDL_MASKEDFLATS,
|
||||
GLDL_MODELS,
|
||||
|
||||
GLDL_TRANSLUCENT,
|
||||
GLDL_TRANSLUCENTBORDER,
|
||||
|
||||
GLDL_TYPES,
|
||||
};
|
||||
|
||||
|
||||
struct HWDrawInfo
|
||||
{
|
||||
struct wallseg
|
||||
{
|
||||
float x1, y1, z1, x2, y2, z2;
|
||||
};
|
||||
|
||||
HWDrawList drawlists[GLDL_TYPES];
|
||||
int vpIndex;
|
||||
//ELightMode lightmode;
|
||||
|
||||
HWDrawInfo * outer = nullptr;
|
||||
int FullbrightFlags;
|
||||
std::atomic<int> spriteindex;
|
||||
HWPortal *mClipPortal;
|
||||
HWPortal *mCurrentPortal;
|
||||
//FRotator mAngles;
|
||||
BunchDrawer mDrawer;
|
||||
Clipper *mClipper;
|
||||
FRenderViewpoint Viewpoint;
|
||||
HWViewpointUniforms VPUniforms; // per-viewpoint uniform state
|
||||
TArray<HWPortal *> Portals;
|
||||
spritetype tsprite[MAXSPRITESONSCREEN];
|
||||
int spritesortcnt;
|
||||
|
||||
// This is needed by the BSP traverser.
|
||||
bool multithread;
|
||||
bool ingeo;
|
||||
FVector2 geoofs;
|
||||
|
||||
private:
|
||||
bool inview;
|
||||
sectortype *currentsector;
|
||||
|
||||
void WorkerThread();
|
||||
|
||||
void UnclipSubsector(sectortype *sub);
|
||||
|
||||
void AddLine(walltype *seg, bool portalclip);
|
||||
void AddLines(sectortype* sector);
|
||||
void AddSpecialPortalLines(sectortype * sector, walltype* line);
|
||||
public:
|
||||
//void RenderThings(sectortype * sub, sectortype * sector);
|
||||
//void RenderParticles(sectortype *sub, sectortype *front);
|
||||
void SetColor(FRenderState &state, int sectorlightlevel, int rellight, bool fullbright, const FColormap &cm, float alpha, bool weapon = false);
|
||||
public:
|
||||
|
||||
void SetCameraPos(const DVector3 &pos)
|
||||
{
|
||||
VPUniforms.mCameraPos = { (float)pos.X, (float)pos.Z, (float)pos.Y, 0.f };
|
||||
}
|
||||
|
||||
void SetClipHeight(float h, float d)
|
||||
{
|
||||
VPUniforms.mClipHeight = h;
|
||||
VPUniforms.mClipHeightDirection = d;
|
||||
VPUniforms.mClipLine.X = -1000001.f;
|
||||
}
|
||||
|
||||
void SetClipLine(walltype *line)
|
||||
{
|
||||
//VPUniforms.mClipLine = { (float)line->v1->fX(), (float)line->v1->fY(), (float)line->Delta().X, (float)line->Delta().Y };
|
||||
VPUniforms.mClipHeight = 0;
|
||||
}
|
||||
|
||||
HWPortal * FindPortal(const void * src);
|
||||
|
||||
static HWDrawInfo *StartDrawInfo(HWDrawInfo *parent, FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms);
|
||||
void StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms);
|
||||
void ClearBuffers();
|
||||
HWDrawInfo *EndDrawInfo();
|
||||
|
||||
void DrawScene(int drawmode, bool portal);
|
||||
void CreateScene(bool portal);
|
||||
void DispatchSprites();
|
||||
void RenderScene(FRenderState &state);
|
||||
void RenderTranslucent(FRenderState &state);
|
||||
void RenderPortal(HWPortal *p, FRenderState &state, bool usestencil);
|
||||
void EndDrawScene(FRenderState &state);
|
||||
void Set3DViewport(FRenderState &state);
|
||||
void ProcessScene(bool toscreen);
|
||||
|
||||
//void GetDynSpriteLight(AActor *self, float x, float y, float z, FLightNode *node, int portalgroup, float *out);
|
||||
//void GetDynSpriteLight(AActor *thing, particle_t *particle, float *out);
|
||||
|
||||
void SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror);
|
||||
void SetupView(FRenderState &state, float vx, float vy, float vz, bool mirror, bool planemirror);
|
||||
angle_t FrustumAngle();
|
||||
|
||||
void DrawPlayerSprites(bool hudModelStep, FRenderState &state);
|
||||
|
||||
//void AddSubsectorToPortal(FSectorPortalGroup *portal, sectortype *sub);
|
||||
|
||||
void AddWall(HWWall *w);
|
||||
void AddMirrorSurface(HWWall *w);
|
||||
void AddFlat(HWFlat *flat);
|
||||
void AddSprite(HWSprite *sprite, bool translucent);
|
||||
|
||||
|
||||
bool isSoftwareLighting() const
|
||||
{
|
||||
return true;// lightmode == ELightMode::ZDoomSoftware || lightmode == ELightMode::DoomSoftware || lightmode == ELightMode::Build;
|
||||
}
|
||||
|
||||
bool isBuildSoftwareLighting() const
|
||||
{
|
||||
return true;// lightmode == ELightMode::Build;
|
||||
}
|
||||
|
||||
bool isDoomSoftwareLighting() const
|
||||
{
|
||||
return false;// lightmode == ELightMode::ZDoomSoftware || lightmode == ELightMode::DoomSoftware;
|
||||
}
|
||||
|
||||
bool isDarkLightMode() const
|
||||
{
|
||||
return false;// lightmode == ELightMode::Doom || lightmode == ELightMode::DoomDark;
|
||||
}
|
||||
|
||||
void SetFallbackLightMode()
|
||||
{
|
||||
//lightmode = ELightMode::Doom;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void CleanSWDrawer();
|
||||
//sectortype* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen);
|
||||
//void WriteSavePic(player_t* player, FileWriter* file, int width, int height);
|
||||
//sectortype* RenderView(player_t* player);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue