mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 19:45:05 +08:00
Compare commits
16 Commits
continuous
...
continuous
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98ff33d9e2 | ||
|
|
baa8fbaaec | ||
|
|
a0b46da04b | ||
|
|
e70ba7ad64 | ||
|
|
8a41be9d47 | ||
|
|
47aff9e30b | ||
|
|
ced8744ac9 | ||
|
|
734c07ddab | ||
|
|
ceb603488a | ||
|
|
80bac157eb | ||
|
|
b45581c630 | ||
|
|
d4fe3d6f8a | ||
|
|
1907485895 | ||
|
|
cfebb3e1d6 | ||
|
|
f9a0057c28 | ||
|
|
ceb2b0c5e4 |
2
.github/workflows/c-cpp.yml
vendored
2
.github/workflows/c-cpp.yml
vendored
@@ -66,7 +66,7 @@ jobs:
|
|||||||
targetos: apple
|
targetos: apple
|
||||||
targetarch: amd64
|
targetarch: amd64
|
||||||
env:
|
env:
|
||||||
SDL_VERSION: 2.30.10
|
SDL_VERSION: 2.30.11
|
||||||
GH_CPU_ARCH: ${{ matrix.targetarch }}
|
GH_CPU_ARCH: ${{ matrix.targetarch }}
|
||||||
GH_CROSSCOMPILING: ${{ matrix.cross }}
|
GH_CROSSCOMPILING: ${{ matrix.cross }}
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ These strings are specific to Xash3D FWGS.
|
|||||||
As Xash3D accidentally supports GoldSrc games, it also supports parsing liblist.gam.\
|
As Xash3D accidentally supports GoldSrc games, it also supports parsing liblist.gam.\
|
||||||
Xash3D will use this file if gameinfo.txt is absent, or if its modification timestamp is older than liblist.gam.
|
Xash3D will use this file if gameinfo.txt is absent, or if its modification timestamp is older than liblist.gam.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Starting from January 2025, Xash3D FWGS doesn't automatically generate gameinfo.txt from liblist.gam. The key conversion table still remains but if you wish to use gameinfo.txt instead of liblist.gam, you can execute `fs_make_gameinfo` in console.
|
||||||
|
|
||||||
For game creators who plan supporting only Xash3D, using this file is not recommended.
|
For game creators who plan supporting only Xash3D, using this file is not recommended.
|
||||||
|
|
||||||
The table below defines conversion rules from liblist.gam to gameinfo.txt. Some keys' interpretation does differ from `gameinfo.txt`, in this case a note will be left. If `liblist.gam` key isn't present in this table, it's ignored.
|
The table below defines conversion rules from liblist.gam to gameinfo.txt. Some keys' interpretation does differ from `gameinfo.txt`, in this case a note will be left. If `liblist.gam` key isn't present in this table, it's ignored.
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ GNU General Public License for more details.
|
|||||||
#ifndef BSPFILE_H
|
#ifndef BSPFILE_H
|
||||||
#define BSPFILE_H
|
#define BSPFILE_H
|
||||||
|
|
||||||
//#define SUPPORT_BSP2_FORMAT // allow to loading Darkplaces BSP2 maps (with broke binary compatibility)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============================================================================
|
==============================================================================
|
||||||
|
|
||||||
@@ -65,7 +63,6 @@ BRUSH MODELS
|
|||||||
#define MAX_MAP_CLIPNODES_BSP2 524288
|
#define MAX_MAP_CLIPNODES_BSP2 524288
|
||||||
|
|
||||||
// these limis not using by modelloader but only for displaying 'mapstats' correctly
|
// these limis not using by modelloader but only for displaying 'mapstats' correctly
|
||||||
#ifdef SUPPORT_BSP2_FORMAT
|
|
||||||
#define MAX_MAP_MODELS 2048 // embedded models
|
#define MAX_MAP_MODELS 2048 // embedded models
|
||||||
#define MAX_MAP_ENTSTRING 0x200000 // 2 Mb should be enough
|
#define MAX_MAP_ENTSTRING 0x200000 // 2 Mb should be enough
|
||||||
#define MAX_MAP_PLANES 131072 // can be increased without problems
|
#define MAX_MAP_PLANES 131072 // can be increased without problems
|
||||||
@@ -75,18 +72,6 @@ BRUSH MODELS
|
|||||||
#define MAX_MAP_VERTS 524288 // can be increased without problems
|
#define MAX_MAP_VERTS 524288 // can be increased without problems
|
||||||
#define MAX_MAP_FACES 262144 // can be increased without problems
|
#define MAX_MAP_FACES 262144 // can be increased without problems
|
||||||
#define MAX_MAP_MARKSURFACES 524288 // can be increased without problems
|
#define MAX_MAP_MARKSURFACES 524288 // can be increased without problems
|
||||||
#else
|
|
||||||
// increased to match PrimeXT compilers
|
|
||||||
#define MAX_MAP_MODELS 1024 // embedded models
|
|
||||||
#define MAX_MAP_ENTSTRING 0x100000 // 1 Mb should be enough
|
|
||||||
#define MAX_MAP_PLANES 65536 // can be increased without problems
|
|
||||||
#define MAX_MAP_NODES 32767 // because negative shorts are leafs
|
|
||||||
#define MAX_MAP_CLIPNODES MAX_MAP_CLIPNODES_HLBSP // because negative shorts are contents
|
|
||||||
#define MAX_MAP_LEAFS 32767 // signed short limit
|
|
||||||
#define MAX_MAP_VERTS 65535 // unsigned short limit
|
|
||||||
#define MAX_MAP_FACES 65535 // unsigned short limit
|
|
||||||
#define MAX_MAP_MARKSURFACES 65535 // unsigned short limit
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MAX_MAP_ENTITIES 8192 // network limit
|
#define MAX_MAP_ENTITIES 8192 // network limit
|
||||||
#define MAX_MAP_TEXINFO MAX_MAP_FACES // in theory each face may have personal texinfo
|
#define MAX_MAP_TEXINFO MAX_MAP_FACES // in theory each face may have personal texinfo
|
||||||
|
|||||||
@@ -60,26 +60,29 @@ typedef struct
|
|||||||
vec3_t position;
|
vec3_t position;
|
||||||
} mvertex_t;
|
} mvertex_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct mclipnode32_s
|
||||||
{
|
{
|
||||||
int planenum;
|
int planenum;
|
||||||
#ifdef SUPPORT_BSP2_FORMAT
|
int children[2]; // negative numbers are contents
|
||||||
int children[2]; // negative numbers are contents
|
} mclipnode32_t;
|
||||||
#else
|
|
||||||
short children[2]; // negative numbers are contents
|
typedef struct mclipnode16_s
|
||||||
#endif
|
{
|
||||||
} mclipnode_t;
|
int planenum;
|
||||||
|
short children[2]; // negative numbers are contents
|
||||||
|
} mclipnode16_t;
|
||||||
|
|
||||||
// size is matched but representation is not
|
// size is matched but representation is not
|
||||||
typedef struct
|
typedef struct medge32_s
|
||||||
{
|
{
|
||||||
#ifdef SUPPORT_BSP2_FORMAT
|
|
||||||
unsigned int v[2];
|
unsigned int v[2];
|
||||||
#else
|
} medge32_t;
|
||||||
|
|
||||||
|
typedef struct medge16_s
|
||||||
|
{
|
||||||
unsigned short v[2];
|
unsigned short v[2];
|
||||||
unsigned int cachededgeoffset;
|
unsigned int cachededgeoffset;
|
||||||
#endif
|
} medge16_t;
|
||||||
} medge_t;
|
|
||||||
|
|
||||||
typedef struct texture_s
|
typedef struct texture_s
|
||||||
{
|
{
|
||||||
@@ -156,13 +159,31 @@ typedef struct mnode_s
|
|||||||
|
|
||||||
// node specific
|
// node specific
|
||||||
mplane_t *plane;
|
mplane_t *plane;
|
||||||
struct mnode_s *children[2];
|
|
||||||
#ifdef SUPPORT_BSP2_FORMAT
|
#if !XASH_64BIT
|
||||||
int firstsurface;
|
union
|
||||||
int numsurfaces;
|
{
|
||||||
|
struct mnode_s *children_[2];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
// the ordering is important
|
||||||
|
int child_0_leaf : 1;
|
||||||
|
int child_0_off : 23;
|
||||||
|
int firstsurface_1 : 8;
|
||||||
|
int child_1_leaf : 1;
|
||||||
|
int child_1_off : 23;
|
||||||
|
int numsurfaces_1 : 8;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
unsigned short firstsurface_0;
|
||||||
|
unsigned short numsurfaces_0;
|
||||||
#else
|
#else
|
||||||
unsigned short firstsurface;
|
// in 64-bit ABI this struct has 4 more bytes of padding, let's use it!
|
||||||
unsigned short numsurfaces;
|
struct mnode_s *children_[2];
|
||||||
|
unsigned short firstsurface_0;
|
||||||
|
unsigned short numsurfaces_0;
|
||||||
|
unsigned short firstsurface_1;
|
||||||
|
unsigned short numsurfaces_1;
|
||||||
#endif
|
#endif
|
||||||
} mnode_t;
|
} mnode_t;
|
||||||
|
|
||||||
@@ -203,7 +224,6 @@ typedef struct mleaf_s
|
|||||||
int nummarksurfaces;
|
int nummarksurfaces;
|
||||||
int cluster; // helper to acess to uncompressed visdata
|
int cluster; // helper to acess to uncompressed visdata
|
||||||
byte ambient_sound_level[NUM_AMBIENTS];
|
byte ambient_sound_level[NUM_AMBIENTS];
|
||||||
|
|
||||||
} mleaf_t;
|
} mleaf_t;
|
||||||
|
|
||||||
// surface extradata
|
// surface extradata
|
||||||
@@ -291,7 +311,11 @@ struct msurface_s
|
|||||||
|
|
||||||
typedef struct hull_s
|
typedef struct hull_s
|
||||||
{
|
{
|
||||||
mclipnode_t *clipnodes;
|
union
|
||||||
|
{
|
||||||
|
mclipnode16_t *clipnodes16;
|
||||||
|
mclipnode32_t *clipnodes32;
|
||||||
|
};
|
||||||
mplane_t *planes;
|
mplane_t *planes;
|
||||||
int firstclipnode;
|
int firstclipnode;
|
||||||
int lastclipnode;
|
int lastclipnode;
|
||||||
@@ -341,7 +365,12 @@ typedef struct model_s
|
|||||||
mvertex_t *vertexes;
|
mvertex_t *vertexes;
|
||||||
|
|
||||||
int numedges;
|
int numedges;
|
||||||
medge_t *edges;
|
union
|
||||||
|
{
|
||||||
|
medge16_t *edges16;
|
||||||
|
medge32_t *edges32;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
int numnodes;
|
int numnodes;
|
||||||
mnode_t *nodes;
|
mnode_t *nodes;
|
||||||
@@ -356,7 +385,11 @@ typedef struct model_s
|
|||||||
int *surfedges;
|
int *surfedges;
|
||||||
|
|
||||||
int numclipnodes;
|
int numclipnodes;
|
||||||
mclipnode_t *clipnodes;
|
union
|
||||||
|
{
|
||||||
|
mclipnode16_t *clipnodes16;
|
||||||
|
mclipnode32_t *clipnodes32;
|
||||||
|
};
|
||||||
|
|
||||||
int nummarksurfaces;
|
int nummarksurfaces;
|
||||||
msurface_t **marksurfaces;
|
msurface_t **marksurfaces;
|
||||||
@@ -550,16 +583,68 @@ typedef struct
|
|||||||
#define ANIM_CYCLE 2
|
#define ANIM_CYCLE 2
|
||||||
#define MOD_FRAMES 20
|
#define MOD_FRAMES 20
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_DEMOS 32
|
#define MAX_DEMOS 32
|
||||||
#define MAX_MOVIES 8
|
#define MAX_MOVIES 8
|
||||||
#define MAX_CDTRACKS 32
|
#define MAX_CDTRACKS 32
|
||||||
#define MAX_CLIENT_SPRITES 512 // SpriteTextures (0-256 hud, 256-512 client)
|
#define MAX_CLIENT_SPRITES 512 // SpriteTextures (0-256 hud, 256-512 client)
|
||||||
#define MAX_REQUESTS 64
|
#define MAX_REQUESTS 64
|
||||||
|
|
||||||
|
STATIC_CHECK_SIZEOF( mnode_t, 52, 72 );
|
||||||
STATIC_CHECK_SIZEOF( mextrasurf_t, 324, 496 );
|
STATIC_CHECK_SIZEOF( mextrasurf_t, 324, 496 );
|
||||||
STATIC_CHECK_SIZEOF( decal_t, 60, 88 );
|
STATIC_CHECK_SIZEOF( decal_t, 60, 88 );
|
||||||
STATIC_CHECK_SIZEOF( mfaceinfo_t, 176, 304 );
|
STATIC_CHECK_SIZEOF( mfaceinfo_t, 176, 304 );
|
||||||
|
|
||||||
|
// model flags (stored in model_t->flags)
|
||||||
|
#define MODEL_QBSP2 BIT( 28 ) // uses 32-bit types
|
||||||
|
|
||||||
|
// access functions
|
||||||
|
static inline mnode_t *node_child( const mnode_t *n, int side, const model_t *mod )
|
||||||
|
{
|
||||||
|
#if !XASH_64BIT
|
||||||
|
if( unlikely( mod->flags & MODEL_QBSP2 )) // MODEL_QBSP2
|
||||||
|
{
|
||||||
|
if( side == 0 )
|
||||||
|
{
|
||||||
|
if( n->child_0_leaf )
|
||||||
|
return (mnode_t *)(mod->leafs + n->child_0_off);
|
||||||
|
else
|
||||||
|
return (mnode_t *)(mod->nodes + n->child_0_off);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( n->child_1_leaf )
|
||||||
|
return (mnode_t *)(mod->leafs + n->child_1_off);
|
||||||
|
else
|
||||||
|
return (mnode_t *)(mod->nodes + n->child_1_off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n->children_[side];
|
||||||
|
#else
|
||||||
|
return n->children_[side];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void node_children( mnode_t *children[2], const mnode_t *n, const model_t *mod )
|
||||||
|
{
|
||||||
|
children[0] = node_child( n, 0, mod );
|
||||||
|
children[1] = node_child( n, 1, mod );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int node_firstsurface( const mnode_t *n, const model_t *mod )
|
||||||
|
{
|
||||||
|
if( mod->flags & MODEL_QBSP2 )
|
||||||
|
return n->firstsurface_0 + ( n->firstsurface_1 << 16 );
|
||||||
|
else
|
||||||
|
return n->firstsurface_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int node_numsurfaces( const mnode_t *n, const model_t *mod )
|
||||||
|
{
|
||||||
|
if( mod->flags & MODEL_QBSP2 )
|
||||||
|
return n->numsurfaces_0 + ( n->numsurfaces_1 << 16 );
|
||||||
|
else
|
||||||
|
return n->numsurfaces_0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif//COM_MODEL_H
|
#endif//COM_MODEL_H
|
||||||
|
|||||||
@@ -127,8 +127,10 @@ static void R_SplitEntityOnNode( mnode_t *node )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// recurse down the contacted sides
|
// recurse down the contacted sides
|
||||||
if( sides & 1 ) R_SplitEntityOnNode( node->children[0] );
|
if( sides & 1 )
|
||||||
if( sides & 2 ) R_SplitEntityOnNode( node->children[1] );
|
R_SplitEntityOnNode( node_child( node, 0, cl.worldmodel ));
|
||||||
|
if( sides & 2 )
|
||||||
|
R_SplitEntityOnNode( node_child( node, 1, cl.worldmodel ));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -138,10 +138,7 @@ intptr_t CL_RenderGetParm( const int parm, const int arg, const qboolean checkRe
|
|||||||
switch( parm )
|
switch( parm )
|
||||||
{
|
{
|
||||||
case PARM_BSP2_SUPPORTED:
|
case PARM_BSP2_SUPPORTED:
|
||||||
#ifdef SUPPORT_BSP2_FORMAT
|
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
case PARAM_GAMEPAUSED:
|
case PARAM_GAMEPAUSED:
|
||||||
return cl.paused;
|
return cl.paused;
|
||||||
case PARM_CLIENT_INGAME:
|
case PARM_CLIENT_INGAME:
|
||||||
|
|||||||
@@ -466,8 +466,8 @@ static void R_ShowTree_r( mnode_t *node, float x, float y, float scale, int show
|
|||||||
R_DrawNodeConnection( x, y, x + scale, y + scale );
|
R_DrawNodeConnection( x, y, x + scale, y + scale );
|
||||||
}
|
}
|
||||||
|
|
||||||
R_ShowTree_r( node->children[1], x - scale, y + scale, downScale, shownodes, viewleaf );
|
R_ShowTree_r( node_child( node, 1, cl.worldmodel ), x - scale, y + scale, downScale, shownodes, viewleaf );
|
||||||
R_ShowTree_r( node->children[0], x + scale, y + scale, downScale, shownodes, viewleaf );
|
R_ShowTree_r( node_child( node, 0, cl.worldmodel ), x + scale, y + scale, downScale, shownodes, viewleaf );
|
||||||
|
|
||||||
world.recursion_level--;
|
world.recursion_level--;
|
||||||
}
|
}
|
||||||
@@ -482,7 +482,7 @@ static void R_ShowTree( void )
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
world.recursion_level = 0;
|
world.recursion_level = 0;
|
||||||
viewleaf = Mod_PointInLeaf( refState.vieworg, cl.worldmodel->nodes );
|
viewleaf = Mod_PointInLeaf( refState.vieworg, cl.worldmodel->nodes, cl.worldmodel );
|
||||||
|
|
||||||
ref.dllFuncs.TriRenderMode( kRenderTransTexture );
|
ref.dllFuncs.TriRenderMode( kRenderTransTexture );
|
||||||
|
|
||||||
|
|||||||
@@ -470,16 +470,16 @@ out_free:
|
|||||||
* This is a stack of the clipnodes we have traversed
|
* This is a stack of the clipnodes we have traversed
|
||||||
* "sides" indicates which side we went down each time
|
* "sides" indicates which side we went down each time
|
||||||
*/
|
*/
|
||||||
static mclipnode_t *node_stack[MAX_CLIPNODE_DEPTH];
|
static int node_stack[MAX_CLIPNODE_DEPTH];
|
||||||
static int side_stack[MAX_CLIPNODE_DEPTH];
|
static int side_stack[MAX_CLIPNODE_DEPTH];
|
||||||
static uint node_stack_depth;
|
static uint node_stack_depth;
|
||||||
|
|
||||||
static void push_node( mclipnode_t *node, int side )
|
static void push_node( int nodenum, int side )
|
||||||
{
|
{
|
||||||
if( node_stack_depth == MAX_CLIPNODE_DEPTH )
|
if( node_stack_depth == MAX_CLIPNODE_DEPTH )
|
||||||
Host_Error( "node stack overflow\n" );
|
Host_Error( "node stack overflow\n" );
|
||||||
|
|
||||||
node_stack[node_stack_depth] = node;
|
node_stack[node_stack_depth] = nodenum;
|
||||||
side_stack[node_stack_depth] = side;
|
side_stack[node_stack_depth] = side;
|
||||||
node_stack_depth++;
|
node_stack_depth++;
|
||||||
}
|
}
|
||||||
@@ -502,22 +502,27 @@ static void free_hull_polys( hullnode_t *hull_polys )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys, hull_model_t *model );
|
static void hull_windings_r( hull_t *hull, int nodenum, hullnode_t *polys, hull_model_t *model );
|
||||||
|
|
||||||
static void do_hull_recursion( hull_t *hull, mclipnode_t *node, int side, hullnode_t *polys, hull_model_t *model )
|
static void do_hull_recursion( hull_t *hull, int nodenum, int side, hullnode_t *polys, hull_model_t *model )
|
||||||
{
|
{
|
||||||
winding_t *w, *next;
|
winding_t *w, *next;
|
||||||
|
int childnum;
|
||||||
|
|
||||||
if( node->children[side] >= 0 )
|
if( world.version == QBSP2_VERSION )
|
||||||
|
childnum = hull->clipnodes32[nodenum].children[side];
|
||||||
|
else
|
||||||
|
childnum = hull->clipnodes16[nodenum].children[side];
|
||||||
|
|
||||||
|
if( childnum >= 0 )
|
||||||
{
|
{
|
||||||
mclipnode_t *child = hull->clipnodes + node->children[side];
|
push_node( nodenum, side );
|
||||||
push_node( node, side );
|
hull_windings_r( hull, childnum, polys, model );
|
||||||
hull_windings_r( hull, child, polys, model );
|
|
||||||
pop_node();
|
pop_node();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch( node->children[side] )
|
switch( childnum )
|
||||||
{
|
{
|
||||||
case CONTENTS_EMPTY:
|
case CONTENTS_EMPTY:
|
||||||
case CONTENTS_WATER:
|
case CONTENTS_WATER:
|
||||||
@@ -542,20 +547,25 @@ static void do_hull_recursion( hull_t *hull, mclipnode_t *node, int side, hullno
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Host_Error( "bad contents: %i\n", node->children[side] );
|
Host_Error( "bad contents: %i\n", childnum );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys, hull_model_t *model )
|
static void hull_windings_r( hull_t *hull, int nodenum, hullnode_t *polys, hull_model_t *model )
|
||||||
{
|
{
|
||||||
mplane_t *plane = hull->planes + node->planenum;
|
mplane_t *plane;
|
||||||
hullnode_t frontlist = LIST_HEAD_INIT( frontlist );
|
hullnode_t frontlist = LIST_HEAD_INIT( frontlist );
|
||||||
hullnode_t backlist = LIST_HEAD_INIT( backlist );
|
hullnode_t backlist = LIST_HEAD_INIT( backlist );
|
||||||
winding_t *w, *next, *front, *back;
|
winding_t *w, *next, *front, *back;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if( world.version == QBSP2_VERSION )
|
||||||
|
plane = hull->planes + hull->clipnodes32[nodenum].planenum;
|
||||||
|
else
|
||||||
|
plane = hull->planes + hull->clipnodes16[nodenum].planenum;
|
||||||
|
|
||||||
list_for_each_entry_safe( w, next, polys, chain )
|
list_for_each_entry_safe( w, next, polys, chain )
|
||||||
{
|
{
|
||||||
// PARANIOA - PAIR CHECK
|
// PARANIOA - PAIR CHECK
|
||||||
@@ -601,7 +611,13 @@ static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys,
|
|||||||
|
|
||||||
for( i = 0; w && i < node_stack_depth; i++ )
|
for( i = 0; w && i < node_stack_depth; i++ )
|
||||||
{
|
{
|
||||||
mplane_t *p = hull->planes + node_stack[i]->planenum;
|
mplane_t *p;
|
||||||
|
|
||||||
|
if( world.version == QBSP2_VERSION )
|
||||||
|
p = hull->planes + hull->clipnodes32[node_stack[i]].planenum;
|
||||||
|
else
|
||||||
|
p = hull->planes + hull->clipnodes16[node_stack[i]].planenum;
|
||||||
|
|
||||||
w = winding_clip( w, p, false, side_stack[i], 0.00001 );
|
w = winding_clip( w, p, false, side_stack[i], 0.00001 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -625,8 +641,8 @@ static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys,
|
|||||||
Con_Printf( S_WARN "new winding was clipped away!\n" );
|
Con_Printf( S_WARN "new winding was clipped away!\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
do_hull_recursion( hull, node, 0, &frontlist, model );
|
do_hull_recursion( hull, nodenum, 0, &frontlist, model );
|
||||||
do_hull_recursion( hull, node, 1, &backlist, model );
|
do_hull_recursion( hull, nodenum, 1, &backlist, model );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_paired_polys( hull_model_t *model )
|
static void remove_paired_polys( hull_model_t *model )
|
||||||
@@ -655,7 +671,7 @@ static void make_hull_windings( hull_t *hull, hull_model_t *model )
|
|||||||
|
|
||||||
if( hull->planes != NULL )
|
if( hull->planes != NULL )
|
||||||
{
|
{
|
||||||
hull_windings_r( hull, hull->clipnodes + hull->firstclipnode, &head, model );
|
hull_windings_r( hull, hull->firstclipnode, &head, model );
|
||||||
remove_paired_polys( model );
|
remove_paired_polys( model );
|
||||||
}
|
}
|
||||||
Con_Reportf( "%i hull polys\n", model->num_polys );
|
Con_Reportf( "%i hull polys\n", model->num_polys );
|
||||||
|
|||||||
@@ -300,6 +300,12 @@ static qboolean R_Init_Video_( const int type )
|
|||||||
return R_Init_Video( type );
|
return R_Init_Video( type );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static mleaf_t *pfnMod_PointInLeaf( const vec3_t p, mnode_t *node )
|
||||||
|
{
|
||||||
|
// FIXME: get rid of this on next RefAPI update
|
||||||
|
return Mod_PointInLeaf( p, node, cl.models[1] );
|
||||||
|
}
|
||||||
|
|
||||||
static const ref_api_t gEngfuncs =
|
static const ref_api_t gEngfuncs =
|
||||||
{
|
{
|
||||||
pfnEngineGetParm,
|
pfnEngineGetParm,
|
||||||
@@ -340,7 +346,7 @@ static const ref_api_t gEngfuncs =
|
|||||||
|
|
||||||
Mod_SampleSizeForFace,
|
Mod_SampleSizeForFace,
|
||||||
Mod_BoxVisible,
|
Mod_BoxVisible,
|
||||||
Mod_PointInLeaf,
|
pfnMod_PointInLeaf,
|
||||||
R_DrawWorldHull,
|
R_DrawWorldHull,
|
||||||
R_DrawModelHull,
|
R_DrawModelHull,
|
||||||
|
|
||||||
|
|||||||
@@ -996,7 +996,7 @@ static void S_UpdateAmbientSounds( void )
|
|||||||
// calc ambient sound levels
|
// calc ambient sound levels
|
||||||
if( !cl.worldmodel ) return;
|
if( !cl.worldmodel ) return;
|
||||||
|
|
||||||
leaf = Mod_PointInLeaf( s_listener.origin, cl.worldmodel->nodes );
|
leaf = Mod_PointInLeaf( s_listener.origin, cl.worldmodel->nodes, cl.worldmodel );
|
||||||
|
|
||||||
if( !leaf || !s_ambient_level.value )
|
if( !leaf || !s_ambient_level.value )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -72,8 +72,6 @@ GNU General Public License for more details.
|
|||||||
|
|
||||||
#define CVAR_GLCONFIG_DESCRIPTION "enable or disable %s"
|
#define CVAR_GLCONFIG_DESCRIPTION "enable or disable %s"
|
||||||
|
|
||||||
#define DEFAULT_BSP_BUILD_ERROR "%s can't be loaded in this build. Please rebuild engine with enabled SUPPORT_BSP2_FORMAT\n"
|
|
||||||
|
|
||||||
#define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest"
|
#define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest"
|
||||||
|
|
||||||
#define XASH_ENGINE_NAME "Xash3D FWGS"
|
#define XASH_ENGINE_NAME "Xash3D FWGS"
|
||||||
|
|||||||
@@ -84,6 +84,11 @@ static void FS_Path_f_( void )
|
|||||||
FS_Path_f();
|
FS_Path_f();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FS_MakeGameInfo_f( void )
|
||||||
|
{
|
||||||
|
g_fsapi.MakeGameInfo();
|
||||||
|
}
|
||||||
|
|
||||||
static const fs_interface_t fs_memfuncs =
|
static const fs_interface_t fs_memfuncs =
|
||||||
{
|
{
|
||||||
Con_Printf,
|
Con_Printf,
|
||||||
@@ -272,6 +277,7 @@ void FS_Init( const char *basedir )
|
|||||||
Cmd_AddRestrictedCommand( "fs_rescan", FS_Rescan_f, "rescan filesystem search pathes" );
|
Cmd_AddRestrictedCommand( "fs_rescan", FS_Rescan_f, "rescan filesystem search pathes" );
|
||||||
Cmd_AddRestrictedCommand( "fs_path", FS_Path_f_, "show filesystem search pathes" );
|
Cmd_AddRestrictedCommand( "fs_path", FS_Path_f_, "show filesystem search pathes" );
|
||||||
Cmd_AddRestrictedCommand( "fs_clearpaths", FS_ClearPaths_f, "clear filesystem search pathes" );
|
Cmd_AddRestrictedCommand( "fs_clearpaths", FS_ClearPaths_f, "clear filesystem search pathes" );
|
||||||
|
Cmd_AddRestrictedCommand( "fs_make_gameinfo", FS_MakeGameInfo_f, "create gameinfo.txt for current running game" );
|
||||||
|
|
||||||
if( !Sys_GetParmFromCmdLine( "-dll", host.gamedll ))
|
if( !Sys_GetParmFromCmdLine( "-dll", host.gamedll ))
|
||||||
host.gamedll[0] = 0;
|
host.gamedll[0] = 0;
|
||||||
|
|||||||
@@ -385,6 +385,35 @@ static const mlumpinfo_t extlumps[EXTRA_LUMPS] =
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define BOX_CLIPNODES_INITIALIZER \
|
||||||
|
{ \
|
||||||
|
.planenum = 0, \
|
||||||
|
.children = { CONTENTS_EMPTY, 1 }, \
|
||||||
|
}, \
|
||||||
|
{ \
|
||||||
|
.planenum = 1, \
|
||||||
|
.children = { 2, CONTENTS_EMPTY }, \
|
||||||
|
}, \
|
||||||
|
{ \
|
||||||
|
.planenum = 2, \
|
||||||
|
.children = { CONTENTS_EMPTY, 3 }, \
|
||||||
|
}, \
|
||||||
|
{ \
|
||||||
|
.planenum = 3, \
|
||||||
|
.children = { 4, CONTENTS_EMPTY }, \
|
||||||
|
}, \
|
||||||
|
{ \
|
||||||
|
.planenum = 4, \
|
||||||
|
.children = { CONTENTS_EMPTY, 5 }, \
|
||||||
|
}, \
|
||||||
|
{ \
|
||||||
|
.planenum = 5, \
|
||||||
|
.children = { CONTENTS_SOLID, CONTENTS_EMPTY }, \
|
||||||
|
}, \
|
||||||
|
|
||||||
|
const mclipnode16_t box_clipnodes16[6] = { BOX_CLIPNODES_INITIALIZER };
|
||||||
|
const mclipnode32_t box_clipnodes32[6] = { BOX_CLIPNODES_INITIALIZER };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============================================================================
|
===============================================================================
|
||||||
|
|
||||||
@@ -856,7 +885,7 @@ Mod_PointInLeaf
|
|||||||
|
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node )
|
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node, model_t *mod )
|
||||||
{
|
{
|
||||||
Assert( node != NULL );
|
Assert( node != NULL );
|
||||||
|
|
||||||
@@ -864,7 +893,7 @@ mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node )
|
|||||||
{
|
{
|
||||||
if( node->contents < 0 )
|
if( node->contents < 0 )
|
||||||
return (mleaf_t *)node;
|
return (mleaf_t *)node;
|
||||||
node = node->children[PlaneDiff( p, node->plane ) <= 0];
|
node = node_child( node, PlaneDiff( p, node->plane ) <= 0, mod );
|
||||||
}
|
}
|
||||||
|
|
||||||
// never reached
|
// never reached
|
||||||
@@ -885,7 +914,7 @@ byte *Mod_GetPVSForPoint( const vec3_t p )
|
|||||||
|
|
||||||
ASSERT( worldmodel != NULL );
|
ASSERT( worldmodel != NULL );
|
||||||
|
|
||||||
leaf = Mod_PointInLeaf( p, worldmodel->nodes );
|
leaf = Mod_PointInLeaf( p, worldmodel->nodes, worldmodel );
|
||||||
|
|
||||||
if( leaf && leaf->cluster >= 0 )
|
if( leaf && leaf->cluster >= 0 )
|
||||||
return Mod_DecompressPVS( leaf->compressed_vis, world.visbytes );
|
return Mod_DecompressPVS( leaf->compressed_vis, world.visbytes );
|
||||||
@@ -905,14 +934,14 @@ static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *v
|
|||||||
float d = PlaneDiff( org, node->plane );
|
float d = PlaneDiff( org, node->plane );
|
||||||
|
|
||||||
if( d > radius )
|
if( d > radius )
|
||||||
node = node->children[0];
|
node = node_child( node, 0, worldmodel );
|
||||||
else if( d < -radius )
|
else if( d < -radius )
|
||||||
node = node->children[1];
|
node = node_child( node, 1, worldmodel );
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// go down both sides
|
// go down both sides
|
||||||
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node->children[0], phs );
|
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node_child( node, 0, worldmodel ), phs );
|
||||||
node = node->children[1];
|
node = node_child( node, 1, worldmodel );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,7 +979,7 @@ int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, q
|
|||||||
|
|
||||||
ASSERT( worldmodel != NULL );
|
ASSERT( worldmodel != NULL );
|
||||||
|
|
||||||
leaf = Mod_PointInLeaf( org, worldmodel->nodes );
|
leaf = Mod_PointInLeaf( org, worldmodel->nodes, worldmodel );
|
||||||
bytes = Q_min( bytes, visbytes );
|
bytes = Q_min( bytes, visbytes );
|
||||||
|
|
||||||
// enable full visibility for some reasons
|
// enable full visibility for some reasons
|
||||||
@@ -1009,20 +1038,16 @@ static void Mod_BoxLeafnums_r( leaflist_t *ll, mnode_t *node )
|
|||||||
sides = BOX_ON_PLANE_SIDE( ll->mins, ll->maxs, node->plane );
|
sides = BOX_ON_PLANE_SIDE( ll->mins, ll->maxs, node->plane );
|
||||||
|
|
||||||
if( sides == 1 )
|
if( sides == 1 )
|
||||||
{
|
node = node_child( node, 0, worldmodel );
|
||||||
node = node->children[0];
|
|
||||||
}
|
|
||||||
else if( sides == 2 )
|
else if( sides == 2 )
|
||||||
{
|
node = node_child( node, 1, worldmodel );
|
||||||
node = node->children[1];
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// go down both
|
// go down both
|
||||||
if( ll->topnode == -1 )
|
if( ll->topnode == -1 )
|
||||||
ll->topnode = node - worldmodel->nodes;
|
ll->topnode = node - worldmodel->nodes;
|
||||||
Mod_BoxLeafnums_r( ll, node->children[0] );
|
Mod_BoxLeafnums_r( ll, node_child( node, 0, worldmodel ));
|
||||||
node = node->children[1];
|
node = node_child( node, 1, worldmodel );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1079,35 +1104,6 @@ qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbi
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
=============
|
|
||||||
Mod_HeadnodeVisible
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf )
|
|
||||||
{
|
|
||||||
if( !node || node->contents == CONTENTS_SOLID )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if( node->contents < 0 )
|
|
||||||
{
|
|
||||||
if( !CHECKVISBIT( visbits, ((mleaf_t *)node)->cluster ))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if( lastleaf )
|
|
||||||
*lastleaf = ((mleaf_t *)node)->cluster;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( Mod_HeadnodeVisible( node->children[0], visbits, lastleaf ))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if( Mod_HeadnodeVisible( node->children[1], visbits, lastleaf ))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Mod_FindModelOrigin
|
Mod_FindModelOrigin
|
||||||
@@ -1264,22 +1260,35 @@ Mod_GetFaceContents
|
|||||||
determine face contents by name
|
determine face contents by name
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
static mvertex_t *Mod_GetVertexByNumber( model_t *mod, int surfedge )
|
static mvertex_t *Mod_GetVertexByNumber( model_t *mod, int surfedge, const dbspmodel_t *bmod )
|
||||||
{
|
{
|
||||||
int lindex;
|
int lindex = mod->surfedges[surfedge];
|
||||||
medge_t *edge;
|
|
||||||
|
|
||||||
lindex = mod->surfedges[surfedge];
|
if( bmod->version == QBSP2_VERSION )
|
||||||
|
|
||||||
if( lindex > 0 )
|
|
||||||
{
|
{
|
||||||
edge = &mod->edges[lindex];
|
if( lindex > 0 )
|
||||||
return &mod->vertexes[edge->v[0]];
|
{
|
||||||
|
medge32_t *edge = &mod->edges32[lindex];
|
||||||
|
return &mod->vertexes[edge->v[0]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
medge32_t *edge = &mod->edges32[-lindex];
|
||||||
|
return &mod->vertexes[edge->v[1]];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
edge = &mod->edges[-lindex];
|
if( lindex > 0 )
|
||||||
return &mod->vertexes[edge->v[1]];
|
{
|
||||||
|
medge16_t *edge = &mod->edges16[lindex];
|
||||||
|
return &mod->vertexes[edge->v[0]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
medge16_t *edge = &mod->edges16[-lindex];
|
||||||
|
return &mod->vertexes[edge->v[1]];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1364,7 +1373,7 @@ Mod_CalcSurfaceExtents
|
|||||||
Fills in surf->texturemins[] and surf->extents[]
|
Fills in surf->texturemins[] and surf->extents[]
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
static void Mod_CalcSurfaceExtents( model_t *mod, msurface_t *surf )
|
static void Mod_CalcSurfaceExtents( model_t *mod, msurface_t *surf, const dbspmodel_t *bmod )
|
||||||
{
|
{
|
||||||
// this place is VERY critical to precision
|
// this place is VERY critical to precision
|
||||||
// keep it as float, don't use double, because it causes issues with lightmap
|
// keep it as float, don't use double, because it causes issues with lightmap
|
||||||
@@ -1391,8 +1400,16 @@ static void Mod_CalcSurfaceExtents( model_t *mod, msurface_t *surf )
|
|||||||
if( e >= mod->numedges || e <= -mod->numedges )
|
if( e >= mod->numedges || e <= -mod->numedges )
|
||||||
Host_Error( "%s: bad edge\n", __func__ );
|
Host_Error( "%s: bad edge\n", __func__ );
|
||||||
|
|
||||||
if( e >= 0 ) v = &mod->vertexes[mod->edges[e].v[0]];
|
if( bmod->version == QBSP2_VERSION )
|
||||||
else v = &mod->vertexes[mod->edges[-e].v[1]];
|
{
|
||||||
|
if( e >= 0 ) v = &mod->vertexes[mod->edges32[e].v[0]];
|
||||||
|
else v = &mod->vertexes[mod->edges32[-e].v[1]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( e >= 0 ) v = &mod->vertexes[mod->edges16[e].v[0]];
|
||||||
|
else v = &mod->vertexes[mod->edges16[-e].v[1]];
|
||||||
|
}
|
||||||
|
|
||||||
for( j = 0; j < 2; j++ )
|
for( j = 0; j < 2; j++ )
|
||||||
{
|
{
|
||||||
@@ -1446,7 +1463,7 @@ Mod_CalcSurfaceBounds
|
|||||||
fills in surf->mins and surf->maxs
|
fills in surf->mins and surf->maxs
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
static void Mod_CalcSurfaceBounds( model_t *mod, msurface_t *surf )
|
static void Mod_CalcSurfaceBounds( model_t *mod, msurface_t *surf, const dbspmodel_t *bmod )
|
||||||
{
|
{
|
||||||
int i, e;
|
int i, e;
|
||||||
mvertex_t *v;
|
mvertex_t *v;
|
||||||
@@ -1460,8 +1477,16 @@ static void Mod_CalcSurfaceBounds( model_t *mod, msurface_t *surf )
|
|||||||
if( e >= mod->numedges || e <= -mod->numedges )
|
if( e >= mod->numedges || e <= -mod->numedges )
|
||||||
Host_Error( "%s: bad edge\n", __func__ );
|
Host_Error( "%s: bad edge\n", __func__ );
|
||||||
|
|
||||||
if( e >= 0 ) v = &mod->vertexes[mod->edges[e].v[0]];
|
if( bmod->version == QBSP2_VERSION )
|
||||||
else v = &mod->vertexes[mod->edges[-e].v[1]];
|
{
|
||||||
|
if( e >= 0 ) v = &mod->vertexes[mod->edges32[e].v[0]];
|
||||||
|
else v = &mod->vertexes[mod->edges32[-e].v[1]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( e >= 0 ) v = &mod->vertexes[mod->edges16[e].v[0]];
|
||||||
|
else v = &mod->vertexes[mod->edges16[-e].v[1]];
|
||||||
|
}
|
||||||
AddPointToBounds( v->position, surf->info->mins, surf->info->maxs );
|
AddPointToBounds( v->position, surf->info->mins, surf->info->maxs );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1473,7 +1498,7 @@ static void Mod_CalcSurfaceBounds( model_t *mod, msurface_t *surf )
|
|||||||
Mod_CreateFaceBevels
|
Mod_CreateFaceBevels
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf )
|
static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf, const dbspmodel_t *bmod )
|
||||||
{
|
{
|
||||||
vec3_t delta, edgevec;
|
vec3_t delta, edgevec;
|
||||||
byte *facebevel;
|
byte *facebevel;
|
||||||
@@ -1506,8 +1531,8 @@ static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf )
|
|||||||
{
|
{
|
||||||
mplane_t *dest = &fb->edges[i];
|
mplane_t *dest = &fb->edges[i];
|
||||||
|
|
||||||
v0 = Mod_GetVertexByNumber( mod, surf->firstedge + i );
|
v0 = Mod_GetVertexByNumber( mod, surf->firstedge + i, bmod );
|
||||||
v1 = Mod_GetVertexByNumber( mod, surf->firstedge + (i + 1) % surf->numedges );
|
v1 = Mod_GetVertexByNumber( mod, surf->firstedge + (i + 1) % surf->numedges, bmod );
|
||||||
VectorSubtract( v1->position, v0->position, edgevec );
|
VectorSubtract( v1->position, v0->position, edgevec );
|
||||||
CrossProduct( faceNormal, edgevec, dest->normal );
|
CrossProduct( faceNormal, edgevec, dest->normal );
|
||||||
VectorNormalize( dest->normal );
|
VectorNormalize( dest->normal );
|
||||||
@@ -1521,7 +1546,7 @@ static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf )
|
|||||||
// compute face radius
|
// compute face radius
|
||||||
for( i = 0; i < surf->numedges; i++ )
|
for( i = 0; i < surf->numedges; i++ )
|
||||||
{
|
{
|
||||||
v0 = Mod_GetVertexByNumber( mod, surf->firstedge + i );
|
v0 = Mod_GetVertexByNumber( mod, surf->firstedge + i, bmod );
|
||||||
VectorSubtract( v0->position, fb->origin, delta );
|
VectorSubtract( v0->position, fb->origin, delta );
|
||||||
radius = DotProduct( delta, delta );
|
radius = DotProduct( delta, delta );
|
||||||
fb->radius = Q_max( radius, fb->radius );
|
fb->radius = Q_max( radius, fb->radius );
|
||||||
@@ -1533,13 +1558,15 @@ static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf )
|
|||||||
Mod_SetParent
|
Mod_SetParent
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
static void Mod_SetParent( mnode_t *node, mnode_t *parent )
|
static void Mod_SetParent( model_t *mod, mnode_t *node, mnode_t *parent )
|
||||||
{
|
{
|
||||||
node->parent = parent;
|
node->parent = parent;
|
||||||
|
|
||||||
if( node->contents < 0 ) return; // it's leaf
|
if( node->contents < 0 )
|
||||||
Mod_SetParent( node->children[0], node );
|
return; // it's leaf
|
||||||
Mod_SetParent( node->children[1], node );
|
|
||||||
|
Mod_SetParent( mod, node_child( node, 0, mod ), node );
|
||||||
|
Mod_SetParent( mod, node_child( node, 1, mod ), node );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1547,7 +1574,7 @@ static void Mod_SetParent( mnode_t *node, mnode_t *parent )
|
|||||||
CountClipNodes_r
|
CountClipNodes_r
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
static void CountClipNodes_r( mclipnode_t *src, hull_t *hull, int nodenum )
|
static void CountClipNodes16_r( mclipnode16_t *src, hull_t *hull, int nodenum )
|
||||||
{
|
{
|
||||||
// leaf?
|
// leaf?
|
||||||
if( nodenum < 0 ) return;
|
if( nodenum < 0 ) return;
|
||||||
@@ -1556,16 +1583,11 @@ static void CountClipNodes_r( mclipnode_t *src, hull_t *hull, int nodenum )
|
|||||||
Host_Error( "MAX_MAP_CLIPNODES limit exceeded\n" );
|
Host_Error( "MAX_MAP_CLIPNODES limit exceeded\n" );
|
||||||
hull->lastclipnode++;
|
hull->lastclipnode++;
|
||||||
|
|
||||||
CountClipNodes_r( src, hull, src[nodenum].children[0] );
|
CountClipNodes16_r( src, hull, src[nodenum].children[0] );
|
||||||
CountClipNodes_r( src, hull, src[nodenum].children[1] );
|
CountClipNodes16_r( src, hull, src[nodenum].children[1] );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void CountClipNodes32_r( mclipnode32_t *src, hull_t *hull, int nodenum )
|
||||||
==================
|
|
||||||
CountClipNodes32_r
|
|
||||||
==================
|
|
||||||
*/
|
|
||||||
static void CountClipNodes32_r( dclipnode32_t *src, hull_t *hull, int nodenum )
|
|
||||||
{
|
{
|
||||||
// leaf?
|
// leaf?
|
||||||
if( nodenum < 0 ) return;
|
if( nodenum < 0 ) return;
|
||||||
@@ -1578,15 +1600,27 @@ static void CountClipNodes32_r( dclipnode32_t *src, hull_t *hull, int nodenum )
|
|||||||
CountClipNodes32_r( src, hull, src[nodenum].children[1] );
|
CountClipNodes32_r( src, hull, src[nodenum].children[1] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CountDClipNodes_r( dclipnode32_t *src, hull_t *hull, int nodenum )
|
||||||
|
{
|
||||||
|
// leaf?
|
||||||
|
if( nodenum < 0 ) return;
|
||||||
|
|
||||||
|
if( hull->lastclipnode == MAX_MAP_CLIPNODES )
|
||||||
|
Host_Error( "MAX_MAP_CLIPNODES limit exceeded\n" );
|
||||||
|
hull->lastclipnode++;
|
||||||
|
|
||||||
|
CountDClipNodes_r( src, hull, src[nodenum].children[0] );
|
||||||
|
CountDClipNodes_r( src, hull, src[nodenum].children[1] );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
RemapClipNodes_r
|
RemapClipNodes_r
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
static int RemapClipNodes_r( dclipnode32_t *srcnodes, hull_t *hull, int nodenum )
|
static int RemapClipNodes_r( dbspmodel_t *bmod, dclipnode32_t *srcnodes, hull_t *hull, int nodenum )
|
||||||
{
|
{
|
||||||
dclipnode32_t *src;
|
dclipnode32_t *src;
|
||||||
mclipnode_t *out;
|
|
||||||
int i, c;
|
int i, c;
|
||||||
|
|
||||||
// leaf?
|
// leaf?
|
||||||
@@ -1599,13 +1633,22 @@ static int RemapClipNodes_r( dclipnode32_t *srcnodes, hull_t *hull, int nodenum
|
|||||||
src = srcnodes + nodenum;
|
src = srcnodes + nodenum;
|
||||||
|
|
||||||
c = hull->lastclipnode;
|
c = hull->lastclipnode;
|
||||||
out = &hull->clipnodes[c];
|
|
||||||
hull->lastclipnode++;
|
hull->lastclipnode++;
|
||||||
|
|
||||||
out->planenum = src->planenum;
|
if( bmod->version == QBSP2_VERSION )
|
||||||
|
{
|
||||||
for( i = 0; i < 2; i++ )
|
mclipnode32_t *out = &hull->clipnodes32[c];
|
||||||
out->children[i] = RemapClipNodes_r( srcnodes, hull, src->children[i] );
|
out->planenum = src->planenum;
|
||||||
|
for( i = 0; i < 2; i++ )
|
||||||
|
out->children[i] = RemapClipNodes_r( bmod, srcnodes, hull, src->children[i] );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mclipnode16_t *out = &hull->clipnodes16[c];
|
||||||
|
out->planenum = src->planenum;
|
||||||
|
for( i = 0; i < 2; i++ )
|
||||||
|
out->children[i] = RemapClipNodes_r( bmod, srcnodes, hull, src->children[i] );
|
||||||
|
}
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@@ -1617,34 +1660,64 @@ Mod_MakeHull0
|
|||||||
Duplicate the drawing hull structure as a clipping hull
|
Duplicate the drawing hull structure as a clipping hull
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
static void Mod_MakeHull0( model_t *mod )
|
static void Mod_MakeHull0( model_t *mod, const dbspmodel_t *bmod )
|
||||||
{
|
{
|
||||||
mnode_t *in, *child;
|
hull_t *hull = &mod->hulls[0];
|
||||||
mclipnode_t *out;
|
int i;
|
||||||
hull_t *hull;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
hull = &mod->hulls[0];
|
|
||||||
hull->clipnodes = out = Mem_Malloc( mod->mempool, mod->numnodes * sizeof( *out ));
|
|
||||||
in = mod->nodes;
|
|
||||||
|
|
||||||
hull->firstclipnode = 0;
|
hull->firstclipnode = 0;
|
||||||
hull->lastclipnode = mod->numnodes - 1;
|
hull->lastclipnode = mod->numnodes - 1;
|
||||||
hull->planes = mod->planes;
|
hull->planes = mod->planes;
|
||||||
|
|
||||||
for( i = 0; i < mod->numnodes; i++, out++, in++ )
|
if( bmod->version == QBSP2_VERSION )
|
||||||
{
|
{
|
||||||
out->planenum = in->plane - mod->planes;
|
mclipnode32_t *out;
|
||||||
|
mnode_t *in = mod->nodes;
|
||||||
|
|
||||||
for( j = 0; j < 2; j++ )
|
hull->clipnodes32 = out = Mem_Malloc( mod->mempool, mod->numnodes * sizeof( *hull->clipnodes32 ));
|
||||||
|
|
||||||
|
for( i = 0; i < mod->numnodes; i++, out++, in++ )
|
||||||
{
|
{
|
||||||
child = in->children[j];
|
int j;
|
||||||
|
|
||||||
if( child->contents < 0 )
|
out->planenum = in->plane - mod->planes;
|
||||||
out->children[j] = child->contents;
|
|
||||||
else out->children[j] = child - mod->nodes;
|
for( j = 0; j < 2; j++ )
|
||||||
|
{
|
||||||
|
mnode_t *child = node_child( in, j, mod );
|
||||||
|
|
||||||
|
if( child->contents < 0 )
|
||||||
|
out->children[j] = child->contents;
|
||||||
|
else
|
||||||
|
out->children[j] = child - mod->nodes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mclipnode16_t *out;
|
||||||
|
mnode_t *in = mod->nodes;
|
||||||
|
|
||||||
|
hull->clipnodes16 = out = Mem_Malloc( mod->mempool, mod->numnodes * sizeof( *hull->clipnodes16 ));
|
||||||
|
|
||||||
|
for( i = 0; i < mod->numnodes; i++, out++, in++ )
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
out->planenum = in->plane - mod->planes;
|
||||||
|
|
||||||
|
for( j = 0; j < 2; j++ )
|
||||||
|
{
|
||||||
|
mnode_t *child = node_child( in, j, mod );
|
||||||
|
|
||||||
|
if( child->contents < 0 )
|
||||||
|
out->children[j] = child->contents;
|
||||||
|
else
|
||||||
|
out->children[j] = child - mod->nodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1688,15 +1761,18 @@ static void Mod_SetupHull( dbspmodel_t *bmod, model_t *mod, poolhandle_t mempool
|
|||||||
if( VectorIsNull( hull->clip_mins ) && VectorIsNull( hull->clip_maxs ))
|
if( VectorIsNull( hull->clip_mins ) && VectorIsNull( hull->clip_maxs ))
|
||||||
return; // no hull specified
|
return; // no hull specified
|
||||||
|
|
||||||
CountClipNodes32_r( bmod->clipnodes_out, hull, headnode );
|
CountDClipNodes_r( bmod->clipnodes_out, hull, headnode );
|
||||||
|
|
||||||
// fit array to real count
|
// fit array to real count
|
||||||
hull->clipnodes = (mclipnode_t *)Mem_Malloc( mempool, sizeof( mclipnode_t ) * hull->lastclipnode );
|
if( bmod->version == QBSP2_VERSION )
|
||||||
|
hull->clipnodes32 = Mem_Malloc( mempool, sizeof( *hull->clipnodes32 ) * hull->lastclipnode );
|
||||||
|
else
|
||||||
|
hull->clipnodes16 = Mem_Malloc( mempool, sizeof( *hull->clipnodes16 ) * hull->lastclipnode );
|
||||||
|
|
||||||
hull->planes = mod->planes; // share planes
|
hull->planes = mod->planes; // share planes
|
||||||
hull->lastclipnode = 0; // restart counting
|
hull->lastclipnode = 0; // restart counting
|
||||||
|
|
||||||
// remap clipnodes to 16-bit indexes
|
RemapClipNodes_r( bmod, bmod->clipnodes_out, hull, headnode ); // remap clipnodes to 16-bit indexes
|
||||||
RemapClipNodes_r( bmod->clipnodes_out, hull, headnode );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static qboolean Mod_LoadLitfile( model_t *mod, const char *ext, size_t expected_size, color24 **out, size_t *outsize )
|
static qboolean Mod_LoadLitfile( model_t *mod, const char *ext, size_t expected_size, color24 **out, size_t *outsize )
|
||||||
@@ -1704,7 +1780,8 @@ static qboolean Mod_LoadLitfile( model_t *mod, const char *ext, size_t expected_
|
|||||||
char modelname[64], path[64];
|
char modelname[64], path[64];
|
||||||
int iCompare;
|
int iCompare;
|
||||||
fs_offset_t datasize;
|
fs_offset_t datasize;
|
||||||
byte *in;
|
file_t *f;
|
||||||
|
uint hdr[2];
|
||||||
|
|
||||||
COM_FileBase( mod->name, modelname, sizeof( modelname ));
|
COM_FileBase( mod->name, modelname, sizeof( modelname ));
|
||||||
Q_snprintf( path, sizeof( path ), "maps/%s.%s", modelname, ext );
|
Q_snprintf( path, sizeof( path ), "maps/%s.%s", modelname, ext );
|
||||||
@@ -1715,31 +1792,15 @@ static qboolean Mod_LoadLitfile( model_t *mod, const char *ext, size_t expected_
|
|||||||
if( iCompare < 0 ) // this may happens if level-designer used -onlyents key for hlcsg
|
if( iCompare < 0 ) // this may happens if level-designer used -onlyents key for hlcsg
|
||||||
Con_Printf( S_WARN "%s probably is out of date\n", path );
|
Con_Printf( S_WARN "%s probably is out of date\n", path );
|
||||||
|
|
||||||
in = FS_LoadFile( path, &datasize, false );
|
f = FS_Open( path, "rb", false );
|
||||||
|
|
||||||
if( !in )
|
if( !f )
|
||||||
{
|
{
|
||||||
Con_Printf( S_ERROR "couldn't load %s\n", path );
|
Con_Printf( S_ERROR "couldn't load %s\n", path );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( datasize <= 8 ) // header + version
|
datasize = FS_FileLength( f );
|
||||||
{
|
|
||||||
Con_Printf( S_ERROR "%s is too short\n", path );
|
|
||||||
goto cleanup_and_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( LittleLong( ((uint *)in)[0] ) != IDDELUXEMAPHEADER )
|
|
||||||
{
|
|
||||||
Con_Printf( S_ERROR "%s is corrupted\n", path );
|
|
||||||
goto cleanup_and_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( LittleLong( ((uint *)in)[1] ) != DELUXEMAP_VERSION )
|
|
||||||
{
|
|
||||||
Con_Printf( S_ERROR "has %s mismatched version (%u should be %u)\n", path, LittleLong( ((uint *)in)[1] ), DELUXEMAP_VERSION );
|
|
||||||
goto cleanup_and_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip header bytes
|
// skip header bytes
|
||||||
datasize -= 8;
|
datasize -= 8;
|
||||||
@@ -1750,14 +1811,33 @@ static qboolean Mod_LoadLitfile( model_t *mod, const char *ext, size_t expected_
|
|||||||
goto cleanup_and_error;
|
goto cleanup_and_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( FS_Read( f, hdr, sizeof( hdr )) != sizeof( hdr ))
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "failed reading header from %s\n", path );
|
||||||
|
goto cleanup_and_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( LittleLong( hdr[0] ) != IDDELUXEMAPHEADER )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "%s is corrupted\n", path );
|
||||||
|
goto cleanup_and_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( LittleLong( hdr[1] ) != DELUXEMAP_VERSION )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "has %s mismatched version (%u should be %u)\n", path, LittleLong( hdr[1] ), DELUXEMAP_VERSION );
|
||||||
|
goto cleanup_and_error;
|
||||||
|
}
|
||||||
|
|
||||||
*out = Mem_Malloc( mod->mempool, datasize );
|
*out = Mem_Malloc( mod->mempool, datasize );
|
||||||
memcpy( *out, in + 8, datasize );
|
|
||||||
*outsize = datasize;
|
*outsize = datasize;
|
||||||
Mem_Free( in );
|
|
||||||
|
FS_Read( f, *out, datasize );
|
||||||
|
FS_Close( f );
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
cleanup_and_error:
|
cleanup_and_error:
|
||||||
Mem_Free( in );
|
FS_Close( f );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1772,6 +1852,7 @@ for embedded submodels
|
|||||||
static void Mod_SetupSubmodels( model_t *mod, dbspmodel_t *bmod )
|
static void Mod_SetupSubmodels( model_t *mod, dbspmodel_t *bmod )
|
||||||
{
|
{
|
||||||
qboolean colored = false;
|
qboolean colored = false;
|
||||||
|
qboolean qbsp2 = false;
|
||||||
poolhandle_t mempool;
|
poolhandle_t mempool;
|
||||||
char *ents;
|
char *ents;
|
||||||
dmodel_t *bm;
|
dmodel_t *bm;
|
||||||
@@ -1783,6 +1864,9 @@ static void Mod_SetupSubmodels( model_t *mod, dbspmodel_t *bmod )
|
|||||||
if( FBitSet( mod->flags, MODEL_COLORED_LIGHTING ))
|
if( FBitSet( mod->flags, MODEL_COLORED_LIGHTING ))
|
||||||
colored = true;
|
colored = true;
|
||||||
|
|
||||||
|
if( FBitSet( mod->flags, MODEL_QBSP2 ))
|
||||||
|
qbsp2 = true;
|
||||||
|
|
||||||
mod->numframes = 2; // regular and alternate animation
|
mod->numframes = 2; // regular and alternate animation
|
||||||
|
|
||||||
// set up the submodels
|
// set up the submodels
|
||||||
@@ -1795,7 +1879,10 @@ static void Mod_SetupSubmodels( model_t *mod, dbspmodel_t *bmod )
|
|||||||
mod->hulls[0].lastclipnode = bm->headnode[0]; // need to be real count
|
mod->hulls[0].lastclipnode = bm->headnode[0]; // need to be real count
|
||||||
|
|
||||||
// counting a real number of clipnodes per each submodel
|
// counting a real number of clipnodes per each submodel
|
||||||
CountClipNodes_r( mod->hulls[0].clipnodes, &mod->hulls[0], bm->headnode[0] );
|
if( bmod->version == QBSP2_VERSION )
|
||||||
|
CountClipNodes32_r( mod->hulls[0].clipnodes32, &mod->hulls[0], bm->headnode[0] );
|
||||||
|
else
|
||||||
|
CountClipNodes16_r( mod->hulls[0].clipnodes16, &mod->hulls[0], bm->headnode[0] );
|
||||||
|
|
||||||
// but hulls1-3 is build individually for a each given submodel
|
// but hulls1-3 is build individually for a each given submodel
|
||||||
for( j = 1; j < MAX_MAP_HULLS; j++ )
|
for( j = 1; j < MAX_MAP_HULLS; j++ )
|
||||||
@@ -1813,6 +1900,7 @@ static void Mod_SetupSubmodels( model_t *mod, dbspmodel_t *bmod )
|
|||||||
|
|
||||||
// this bit will be shared between all the submodels include worldmodel
|
// this bit will be shared between all the submodels include worldmodel
|
||||||
if( colored ) SetBits( mod->flags, MODEL_COLORED_LIGHTING );
|
if( colored ) SetBits( mod->flags, MODEL_COLORED_LIGHTING );
|
||||||
|
if( qbsp2 ) SetBits( mod->flags, MODEL_QBSP2 );
|
||||||
|
|
||||||
if( i != 0 )
|
if( i != 0 )
|
||||||
{
|
{
|
||||||
@@ -2135,15 +2223,15 @@ Mod_LoadEdges
|
|||||||
*/
|
*/
|
||||||
static void Mod_LoadEdges( model_t *mod, dbspmodel_t *bmod )
|
static void Mod_LoadEdges( model_t *mod, dbspmodel_t *bmod )
|
||||||
{
|
{
|
||||||
medge_t *out;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
mod->edges = out = Mem_Malloc( mod->mempool, bmod->numedges * sizeof( medge_t ));
|
|
||||||
mod->numedges = bmod->numedges;
|
mod->numedges = bmod->numedges;
|
||||||
|
|
||||||
if( bmod->version == QBSP2_VERSION )
|
if( bmod->version == QBSP2_VERSION )
|
||||||
{
|
{
|
||||||
dedge32_t *in = (dedge32_t *)bmod->edges32;
|
dedge32_t *in = bmod->edges32;
|
||||||
|
medge32_t *out;
|
||||||
|
mod->edges32 = out = Mem_Malloc( mod->mempool, bmod->numedges * sizeof( *out ));
|
||||||
|
|
||||||
for( i = 0; i < bmod->numedges; i++, in++, out++ )
|
for( i = 0; i < bmod->numedges; i++, in++, out++ )
|
||||||
{
|
{
|
||||||
@@ -2153,7 +2241,9 @@ static void Mod_LoadEdges( model_t *mod, dbspmodel_t *bmod )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dedge_t *in = (dedge_t *)bmod->edges;
|
dedge_t *in = bmod->edges;
|
||||||
|
medge16_t *out;
|
||||||
|
mod->edges16 = out = Mem_Malloc( mod->mempool, bmod->numedges * sizeof( *out ));
|
||||||
|
|
||||||
for( i = 0; i < bmod->numedges; i++, in++, out++ )
|
for( i = 0; i < bmod->numedges; i++, in++, out++ )
|
||||||
{
|
{
|
||||||
@@ -2913,9 +3003,9 @@ static void Mod_LoadSurfaces( model_t *mod, dbspmodel_t *bmod )
|
|||||||
if( FBitSet( out->texinfo->flags, TEX_SPECIAL ))
|
if( FBitSet( out->texinfo->flags, TEX_SPECIAL ))
|
||||||
SetBits( out->flags, SURF_DRAWTILED );
|
SetBits( out->flags, SURF_DRAWTILED );
|
||||||
|
|
||||||
Mod_CalcSurfaceBounds( mod, out );
|
Mod_CalcSurfaceBounds( mod, out, bmod );
|
||||||
Mod_CalcSurfaceExtents( mod, out );
|
Mod_CalcSurfaceExtents( mod, out, bmod );
|
||||||
Mod_CreateFaceBevels( mod, out );
|
Mod_CreateFaceBevels( mod, out, bmod );
|
||||||
|
|
||||||
// grab the second sample to detect colored lighting
|
// grab the second sample to detect colored lighting
|
||||||
if( test_lightsize > 0 && lightofs != -1 )
|
if( test_lightsize > 0 && lightofs != -1 )
|
||||||
@@ -2962,7 +3052,6 @@ static void Mod_LoadSurfaces( model_t *mod, dbspmodel_t *bmod )
|
|||||||
if( samples == 1 || samples == 3 )
|
if( samples == 1 || samples == 3 )
|
||||||
{
|
{
|
||||||
bmod->lightmap_samples = (int)samples;
|
bmod->lightmap_samples = (int)samples;
|
||||||
Con_Reportf( "lighting: %s\n", (bmod->lightmap_samples == 1) ? "monochrome" : "colored" );
|
|
||||||
bmod->lightmap_samples = Q_max( bmod->lightmap_samples, 1 ); // avoid division by zero
|
bmod->lightmap_samples = Q_max( bmod->lightmap_samples, 1 ); // avoid division by zero
|
||||||
}
|
}
|
||||||
else Con_DPrintf( S_WARN "lighting invalid samplecount: %g, defaulting to %i\n", samples, bmod->lightmap_samples );
|
else Con_DPrintf( S_WARN "lighting invalid samplecount: %g, defaulting to %i\n", samples, bmod->lightmap_samples );
|
||||||
@@ -2994,16 +3083,62 @@ static void Mod_LoadNodes( model_t *mod, dbspmodel_t *bmod )
|
|||||||
out->minmaxs[j+3] = in->maxs[j];
|
out->minmaxs[j+3] = in->maxs[j];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !XASH_64BIT
|
||||||
|
if( in->firstface >= BIT( 24 ))
|
||||||
|
{
|
||||||
|
Host_Error( "%s: face index limit exceeded on node %i\n", __func__, i );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( in->numfaces >= BIT( 24 ))
|
||||||
|
{
|
||||||
|
Host_Error( "%s: face count limit exceeded on node %i\n", __func__, i );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
p = in->planenum;
|
p = in->planenum;
|
||||||
out->plane = mod->planes + p;
|
out->plane = mod->planes + p;
|
||||||
out->firstsurface = in->firstface;
|
out->firstsurface_0 = in->firstface & 0xFFFF;
|
||||||
out->numsurfaces = in->numfaces;
|
out->numsurfaces_0 = in->numfaces & 0xFFFF;
|
||||||
|
|
||||||
|
out->firstsurface_1 = in->firstface >> 16;
|
||||||
|
out->numsurfaces_1 = in->numfaces >> 16;
|
||||||
|
|
||||||
for( j = 0; j < 2; j++ )
|
for( j = 0; j < 2; j++ )
|
||||||
{
|
{
|
||||||
p = in->children[j];
|
p = in->children[j];
|
||||||
if( p >= 0 ) out->children[j] = mod->nodes + p;
|
#if XASH_64BIT
|
||||||
else out->children[j] = (mnode_t *)(mod->leafs + ( -1 - p ));
|
if( p >= 0 ) out->children_[j] = mod->nodes + p;
|
||||||
|
else out->children_[j] = (mnode_t *)(mod->leafs + ( -1 - p ));
|
||||||
|
#else
|
||||||
|
if( j == 0 )
|
||||||
|
{
|
||||||
|
if( p >= 0 )
|
||||||
|
{
|
||||||
|
out->child_0_leaf = 0;
|
||||||
|
out->child_0_off = p;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out->child_0_leaf = 1;
|
||||||
|
out->child_0_off = -1 - p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( p >= 0 )
|
||||||
|
{
|
||||||
|
out->child_1_leaf = 0;
|
||||||
|
out->child_1_off = p;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out->child_1_leaf = 1;
|
||||||
|
out->child_1_off = -1 - p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -3018,20 +3153,20 @@ static void Mod_LoadNodes( model_t *mod, dbspmodel_t *bmod )
|
|||||||
|
|
||||||
p = in->planenum;
|
p = in->planenum;
|
||||||
out->plane = mod->planes + p;
|
out->plane = mod->planes + p;
|
||||||
out->firstsurface = in->firstface;
|
out->firstsurface_0 = in->firstface;
|
||||||
out->numsurfaces = in->numfaces;
|
out->numsurfaces_0 = in->numfaces;
|
||||||
|
|
||||||
for( j = 0; j < 2; j++ )
|
for( j = 0; j < 2; j++ )
|
||||||
{
|
{
|
||||||
p = in->children[j];
|
p = in->children[j];
|
||||||
if( p >= 0 ) out->children[j] = mod->nodes + p;
|
if( p >= 0 ) out->children_[j] = mod->nodes + p;
|
||||||
else out->children[j] = (mnode_t *)(mod->leafs + ( -1 - p ));
|
else out->children_[j] = (mnode_t *)(mod->leafs + ( -1 - p ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets nodes and leafs
|
// sets nodes and leafs
|
||||||
Mod_SetParent( mod->nodes, NULL );
|
Mod_SetParent( mod, mod->nodes, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3413,6 +3548,8 @@ static void Mod_LoadLighting( model_t *mod, dbspmodel_t *bmod )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Con_Reportf( "lighting: %s\n", FBitSet( mod->flags, MODEL_COLORED_LIGHTING ) ? "colored" : "monochrome" );
|
||||||
|
|
||||||
// not supposed to be load ?
|
// not supposed to be load ?
|
||||||
if( FBitSet( host.features, ENGINE_LOAD_DELUXEDATA ))
|
if( FBitSet( host.features, ENGINE_LOAD_DELUXEDATA ))
|
||||||
{
|
{
|
||||||
@@ -3491,13 +3628,6 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
|
|||||||
Q_strncpy( loadstat.name, mod->name, sizeof( loadstat.name ));
|
Q_strncpy( loadstat.name, mod->name, sizeof( loadstat.name ));
|
||||||
wadvalue[0] = '\0';
|
wadvalue[0] = '\0';
|
||||||
|
|
||||||
#ifndef SUPPORT_BSP2_FORMAT
|
|
||||||
if( header->version == QBSP2_VERSION )
|
|
||||||
{
|
|
||||||
Con_Printf( S_ERROR DEFAULT_BSP_BUILD_ERROR, mod->name );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
switch( header->version )
|
switch( header->version )
|
||||||
{
|
{
|
||||||
case HLBSP_VERSION:
|
case HLBSP_VERSION:
|
||||||
@@ -3520,6 +3650,9 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
|
|||||||
// everything else
|
// everything else
|
||||||
srclumps[0].lumpnumber = LUMP_ENTITIES;
|
srclumps[0].lumpnumber = LUMP_ENTITIES;
|
||||||
srclumps[1].lumpnumber = LUMP_PLANES;
|
srclumps[1].lumpnumber = LUMP_PLANES;
|
||||||
|
|
||||||
|
if( header->version == QBSP2_VERSION )
|
||||||
|
SetBits( mod->flags, MODEL_QBSP2 );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Con_Printf( S_ERROR "%s has wrong version number (%i should be %i)\n", mod->name, header->version, HLBSP_VERSION );
|
Con_Printf( S_ERROR "%s has wrong version number (%i should be %i)\n", mod->name, header->version, HLBSP_VERSION );
|
||||||
@@ -3570,7 +3703,7 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
|
|||||||
Mod_LoadClipnodes( mod, bmod );
|
Mod_LoadClipnodes( mod, bmod );
|
||||||
|
|
||||||
// preform some post-initalization
|
// preform some post-initalization
|
||||||
Mod_MakeHull0( mod );
|
Mod_MakeHull0( mod, bmod );
|
||||||
Mod_SetupSubmodels( mod, bmod );
|
Mod_SetupSubmodels( mod, bmod );
|
||||||
|
|
||||||
if( isworld )
|
if( isworld )
|
||||||
@@ -3660,15 +3793,6 @@ qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base,
|
|||||||
if( silent )
|
if( silent )
|
||||||
SetBits( flags, LUMP_SILENT );
|
SetBits( flags, LUMP_SILENT );
|
||||||
|
|
||||||
#ifndef SUPPORT_BSP2_FORMAT
|
|
||||||
if( header->version == QBSP2_VERSION )
|
|
||||||
{
|
|
||||||
if( !FBitSet( flags, LUMP_SILENT ))
|
|
||||||
Con_Printf( S_ERROR DEFAULT_BSP_BUILD_ERROR, name );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch( header->version )
|
switch( header->version )
|
||||||
{
|
{
|
||||||
case HLBSP_VERSION:
|
case HLBSP_VERSION:
|
||||||
|
|||||||
@@ -135,6 +135,8 @@ extern poolhandle_t com_studiocache;
|
|||||||
extern convar_t mod_studiocache;
|
extern convar_t mod_studiocache;
|
||||||
extern convar_t r_wadtextures;
|
extern convar_t r_wadtextures;
|
||||||
extern convar_t r_showhull;
|
extern convar_t r_showhull;
|
||||||
|
extern const mclipnode16_t box_clipnodes16[6];
|
||||||
|
extern const mclipnode32_t box_clipnodes32[6];
|
||||||
|
|
||||||
//
|
//
|
||||||
// model.c
|
// model.c
|
||||||
@@ -167,13 +169,12 @@ void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded );
|
|||||||
//
|
//
|
||||||
void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded );
|
void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded );
|
||||||
qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base, qboolean silent, dlump_t *entities );
|
qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base, qboolean silent, dlump_t *entities );
|
||||||
qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf );
|
|
||||||
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis, qboolean false );
|
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis, qboolean false );
|
||||||
qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits );
|
qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits );
|
||||||
int Mod_CheckLump( const char *filename, const int lump, int *lumpsize );
|
int Mod_CheckLump( const char *filename, const int lump, int *lumpsize );
|
||||||
int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize );
|
int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize );
|
||||||
int Mod_SaveLump( const char *filename, const int lump, void *lumpdata, int lumpsize );
|
int Mod_SaveLump( const char *filename, const int lump, void *lumpdata, int lumpsize );
|
||||||
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node );
|
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node, model_t *mod );
|
||||||
int Mod_SampleSizeForFace( const msurface_t *surf );
|
int Mod_SampleSizeForFace( const msurface_t *surf );
|
||||||
byte *Mod_GetPVSForPoint( const vec3_t p );
|
byte *Mod_GetPVSForPoint( const vec3_t p );
|
||||||
void Mod_UnloadBrushModel( model_t *mod );
|
void Mod_UnloadBrushModel( model_t *mod );
|
||||||
|
|||||||
@@ -50,9 +50,8 @@ static matrix3x4 studio_bones[MAXSTUDIOBONES];
|
|||||||
static uint studio_hull_hitgroup[MAXSTUDIOBONES];
|
static uint studio_hull_hitgroup[MAXSTUDIOBONES];
|
||||||
static uint cache_hull_hitgroup[MAXSTUDIOBONES];
|
static uint cache_hull_hitgroup[MAXSTUDIOBONES];
|
||||||
static mstudiocache_t cache_studio[STUDIO_CACHESIZE];
|
static mstudiocache_t cache_studio[STUDIO_CACHESIZE];
|
||||||
static mclipnode_t studio_clipnodes[6];
|
static mplane_t studio_planes[MAXSTUDIOBONES * 6];
|
||||||
static mplane_t studio_planes[768];
|
static mplane_t cache_planes[MAXSTUDIOBONES * 6];
|
||||||
static mplane_t cache_planes[768];
|
|
||||||
|
|
||||||
// current cache state
|
// current cache state
|
||||||
static int cache_current;
|
static int cache_current;
|
||||||
@@ -66,25 +65,14 @@ Mod_InitStudioHull
|
|||||||
*/
|
*/
|
||||||
void Mod_InitStudioHull( void )
|
void Mod_InitStudioHull( void )
|
||||||
{
|
{
|
||||||
int i, side;
|
int i;
|
||||||
|
|
||||||
if( studio_hull[0].planes != NULL )
|
if( studio_hull[0].planes != NULL )
|
||||||
return; // already initailized
|
return; // already initailized
|
||||||
|
|
||||||
for( i = 0; i < 6; i++ )
|
|
||||||
{
|
|
||||||
studio_clipnodes[i].planenum = i;
|
|
||||||
|
|
||||||
side = i & 1;
|
|
||||||
|
|
||||||
studio_clipnodes[i].children[side] = CONTENTS_EMPTY;
|
|
||||||
if( i != 5 ) studio_clipnodes[i].children[side^1] = i + 1;
|
|
||||||
else studio_clipnodes[i].children[side^1] = CONTENTS_SOLID;
|
|
||||||
}
|
|
||||||
|
|
||||||
for( i = 0; i < MAXSTUDIOBONES; i++ )
|
for( i = 0; i < MAXSTUDIOBONES; i++ )
|
||||||
{
|
{
|
||||||
studio_hull[i].clipnodes = studio_clipnodes;
|
studio_hull[i].clipnodes16 = (mclipnode16_t *)box_clipnodes16;
|
||||||
studio_hull[i].planes = &studio_planes[i*6];
|
studio_hull[i].planes = &studio_planes[i*6];
|
||||||
studio_hull[i].firstclipnode = 0;
|
studio_hull[i].firstclipnode = 0;
|
||||||
studio_hull[i].lastclipnode = 5;
|
studio_hull[i].lastclipnode = 5;
|
||||||
@@ -270,6 +258,11 @@ hull_t *Mod_HullForStudio( model_t *model, float frame, int sequence, vec3_t ang
|
|||||||
|
|
||||||
for( i = j = 0; i < mod_studiohdr->numhitboxes; i++, j += 6 )
|
for( i = j = 0; i < mod_studiohdr->numhitboxes; i++, j += 6 )
|
||||||
{
|
{
|
||||||
|
if( world.version == QBSP2_VERSION )
|
||||||
|
studio_hull[i].clipnodes32 = (mclipnode32_t *)box_clipnodes32;
|
||||||
|
else
|
||||||
|
studio_hull[i].clipnodes16 = (mclipnode16_t *)box_clipnodes16;
|
||||||
|
|
||||||
if( bSkipShield && i == 21 )
|
if( bSkipShield && i == 21 )
|
||||||
continue; // CS stuff
|
continue; // CS stuff
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,9 @@ msurface_t *PM_RecursiveSurfCheck( model_t *mod, mnode_t *node, vec3_t p1, vec3_
|
|||||||
int i, side;
|
int i, side;
|
||||||
msurface_t *surf;
|
msurface_t *surf;
|
||||||
vec3_t mid;
|
vec3_t mid;
|
||||||
|
mnode_t *children[2];
|
||||||
|
int numsurfaces, firstsurface;
|
||||||
|
|
||||||
loc0:
|
loc0:
|
||||||
if( node->contents < 0 )
|
if( node->contents < 0 )
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -119,15 +122,17 @@ loc0:
|
|||||||
t1 = PlaneDiff( p1, node->plane );
|
t1 = PlaneDiff( p1, node->plane );
|
||||||
t2 = PlaneDiff( p2, node->plane );
|
t2 = PlaneDiff( p2, node->plane );
|
||||||
|
|
||||||
|
node_children( children, node, mod );
|
||||||
|
|
||||||
if( t1 >= -FRAC_EPSILON && t2 >= -FRAC_EPSILON )
|
if( t1 >= -FRAC_EPSILON && t2 >= -FRAC_EPSILON )
|
||||||
{
|
{
|
||||||
node = node->children[0];
|
node = children[0];
|
||||||
goto loc0;
|
goto loc0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( t1 < FRAC_EPSILON && t2 < FRAC_EPSILON )
|
if( t1 < FRAC_EPSILON && t2 < FRAC_EPSILON )
|
||||||
{
|
{
|
||||||
node = node->children[1];
|
node = children[1];
|
||||||
goto loc0;
|
goto loc0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,13 +142,15 @@ loc0:
|
|||||||
|
|
||||||
VectorLerp( p1, frac, p2, mid );
|
VectorLerp( p1, frac, p2, mid );
|
||||||
|
|
||||||
if(( surf = PM_RecursiveSurfCheck( mod, node->children[side], p1, mid )) != NULL )
|
if(( surf = PM_RecursiveSurfCheck( mod, children[side], p1, mid )) != NULL )
|
||||||
return surf;
|
return surf;
|
||||||
|
|
||||||
// walk through real faces
|
// walk through real faces
|
||||||
for( i = 0; i < node->numsurfaces; i++ )
|
numsurfaces = node_numsurfaces( node, mod );
|
||||||
|
firstsurface = node_firstsurface( node, mod );
|
||||||
|
for( i = 0; i < numsurfaces; i++ )
|
||||||
{
|
{
|
||||||
msurface_t *surf = &mod->surfaces[node->firstsurface + i];
|
msurface_t *surf = &mod->surfaces[firstsurface + i];
|
||||||
mextrasurf_t *info = surf->info;
|
mextrasurf_t *info = surf->info;
|
||||||
mfacebevel_t *fb = info->bevel;
|
mfacebevel_t *fb = info->bevel;
|
||||||
int j, contents;
|
int j, contents;
|
||||||
@@ -172,7 +179,7 @@ loc0:
|
|||||||
return NULL; // through the fence
|
return NULL; // through the fence
|
||||||
}
|
}
|
||||||
|
|
||||||
return PM_RecursiveSurfCheck( mod, node->children[side^1], mid, p2 );
|
return PM_RecursiveSurfCheck( mod, children[side^1], mid, p2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -227,6 +234,9 @@ static int PM_TestLine_r( model_t *mod, mnode_t *node, vec_t p1f, vec_t p2f, con
|
|||||||
float frac, midf;
|
float frac, midf;
|
||||||
int i, r, side;
|
int i, r, side;
|
||||||
vec3_t mid;
|
vec3_t mid;
|
||||||
|
mnode_t *children[2];
|
||||||
|
int numsurfaces, firstsurface;
|
||||||
|
|
||||||
loc0:
|
loc0:
|
||||||
if( node->contents < 0 )
|
if( node->contents < 0 )
|
||||||
{
|
{
|
||||||
@@ -242,15 +252,17 @@ loc0:
|
|||||||
front = PlaneDiff( start, node->plane );
|
front = PlaneDiff( start, node->plane );
|
||||||
back = PlaneDiff( stop, node->plane );
|
back = PlaneDiff( stop, node->plane );
|
||||||
|
|
||||||
|
node_children( children, node, mod );
|
||||||
|
|
||||||
if( front >= -FRAC_EPSILON && back >= -FRAC_EPSILON )
|
if( front >= -FRAC_EPSILON && back >= -FRAC_EPSILON )
|
||||||
{
|
{
|
||||||
node = node->children[0];
|
node = children[0];
|
||||||
goto loc0;
|
goto loc0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( front < FRAC_EPSILON && back < FRAC_EPSILON )
|
if( front < FRAC_EPSILON && back < FRAC_EPSILON )
|
||||||
{
|
{
|
||||||
node = node->children[1];
|
node = children[1];
|
||||||
goto loc0;
|
goto loc0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +273,7 @@ loc0:
|
|||||||
VectorLerp( start, frac, stop, mid );
|
VectorLerp( start, frac, stop, mid );
|
||||||
midf = p1f + ( p2f - p1f ) * frac;
|
midf = p1f + ( p2f - p1f ) * frac;
|
||||||
|
|
||||||
r = PM_TestLine_r( mod, node->children[side], p1f, midf, start, mid, trace );
|
r = PM_TestLine_r( mod, children[side], p1f, midf, start, mid, trace );
|
||||||
|
|
||||||
if( r != CONTENTS_EMPTY )
|
if( r != CONTENTS_EMPTY )
|
||||||
{
|
{
|
||||||
@@ -272,9 +284,11 @@ loc0:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// walk through real faces
|
// walk through real faces
|
||||||
for( i = 0; i < node->numsurfaces; i++ )
|
numsurfaces = node_numsurfaces( node, mod );
|
||||||
|
firstsurface = node_firstsurface( node, mod );
|
||||||
|
for( i = 0; i < numsurfaces; i++ )
|
||||||
{
|
{
|
||||||
msurface_t *surf = &mod->surfaces[node->firstsurface + i];
|
msurface_t *surf = &mod->surfaces[firstsurface + i];
|
||||||
mextrasurf_t *info = surf->info;
|
mextrasurf_t *info = surf->info;
|
||||||
mfacebevel_t *fb = info->bevel;
|
mfacebevel_t *fb = info->bevel;
|
||||||
int j, contents;
|
int j, contents;
|
||||||
@@ -308,7 +322,7 @@ loc0:
|
|||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PM_TestLine_r( mod, node->children[!side], midf, p2f, mid, stop, trace );
|
return PM_TestLine_r( mod, children[!side], midf, p2f, mid, stop, trace );
|
||||||
}
|
}
|
||||||
|
|
||||||
int PM_TestLineExt( playermove_t *pmove, physent_t *ents, int numents, const vec3_t start, const vec3_t end, int flags )
|
int PM_TestLineExt( playermove_t *pmove, physent_t *ents, int numents, const vec3_t start, const vec3_t end, int flags )
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ GNU General Public License for more details.
|
|||||||
#define PM_AllowHitBoxTrace( model, hull ) ( model && model->type == mod_studio && ( FBitSet( model->flags, STUDIO_TRACE_HITBOX ) || hull == 2 ))
|
#define PM_AllowHitBoxTrace( model, hull ) ( model && model->type == mod_studio && ( FBitSet( model->flags, STUDIO_TRACE_HITBOX ) || hull == 2 ))
|
||||||
|
|
||||||
static mplane_t pm_boxplanes[6];
|
static mplane_t pm_boxplanes[6];
|
||||||
static mclipnode_t pm_boxclipnodes[6];
|
static hull_t pm_boxhull;
|
||||||
static hull_t pm_boxhull;
|
|
||||||
|
|
||||||
// default hullmins
|
// default hullmins
|
||||||
static const vec3_t pm_hullmins[MAX_MAP_HULLS] =
|
static const vec3_t pm_hullmins[MAX_MAP_HULLS] =
|
||||||
@@ -65,23 +64,15 @@ can just be stored out and get a proper hull_t structure.
|
|||||||
*/
|
*/
|
||||||
void PM_InitBoxHull( void )
|
void PM_InitBoxHull( void )
|
||||||
{
|
{
|
||||||
int i, side;
|
int i;
|
||||||
|
|
||||||
pm_boxhull.clipnodes = pm_boxclipnodes;
|
pm_boxhull.clipnodes16 = (mclipnode16_t *)box_clipnodes16;
|
||||||
pm_boxhull.planes = pm_boxplanes;
|
pm_boxhull.planes = pm_boxplanes;
|
||||||
pm_boxhull.firstclipnode = 0;
|
pm_boxhull.firstclipnode = 0;
|
||||||
pm_boxhull.lastclipnode = 5;
|
pm_boxhull.lastclipnode = 5;
|
||||||
|
|
||||||
for( i = 0; i < 6; i++ )
|
for( i = 0; i < 6; i++ )
|
||||||
{
|
{
|
||||||
pm_boxclipnodes[i].planenum = i;
|
|
||||||
|
|
||||||
side = i & 1;
|
|
||||||
|
|
||||||
pm_boxclipnodes[i].children[side] = CONTENTS_EMPTY;
|
|
||||||
if( i != 5 ) pm_boxclipnodes[i].children[side^1] = i + 1;
|
|
||||||
else pm_boxclipnodes[i].children[side^1] = CONTENTS_SOLID;
|
|
||||||
|
|
||||||
pm_boxplanes[i].type = i>>1;
|
pm_boxplanes[i].type = i>>1;
|
||||||
pm_boxplanes[i].normal[i>>1] = 1.0f;
|
pm_boxplanes[i].normal[i>>1] = 1.0f;
|
||||||
pm_boxplanes[i].signbits = 0;
|
pm_boxplanes[i].signbits = 0;
|
||||||
@@ -106,6 +97,11 @@ static hull_t *PM_HullForBox( const vec3_t mins, const vec3_t maxs )
|
|||||||
pm_boxplanes[4].dist = maxs[2];
|
pm_boxplanes[4].dist = maxs[2];
|
||||||
pm_boxplanes[5].dist = mins[2];
|
pm_boxplanes[5].dist = mins[2];
|
||||||
|
|
||||||
|
if( world.version == QBSP2_VERSION )
|
||||||
|
pm_boxhull.clipnodes32 = (mclipnode32_t *)box_clipnodes32;
|
||||||
|
else
|
||||||
|
pm_boxhull.clipnodes16 = (mclipnode16_t *)box_clipnodes16;
|
||||||
|
|
||||||
return &pm_boxhull;
|
return &pm_boxhull;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,10 +118,21 @@ int GAME_EXPORT PM_HullPointContents( hull_t *hull, int num, const vec3_t p )
|
|||||||
if( !hull || !hull->planes ) // fantom bmodels?
|
if( !hull || !hull->planes ) // fantom bmodels?
|
||||||
return CONTENTS_NONE;
|
return CONTENTS_NONE;
|
||||||
|
|
||||||
while( num >= 0 )
|
if( world.version == QBSP2_VERSION )
|
||||||
{
|
{
|
||||||
plane = &hull->planes[hull->clipnodes[num].planenum];
|
while( num >= 0 )
|
||||||
num = hull->clipnodes[num].children[PlaneDiff( p, plane ) < 0];
|
{
|
||||||
|
plane = &hull->planes[hull->clipnodes32[num].planenum];
|
||||||
|
num = hull->clipnodes32[num].children[PlaneDiff( p, plane ) < 0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while( num >= 0 )
|
||||||
|
{
|
||||||
|
plane = &hull->planes[hull->clipnodes16[num].planenum];
|
||||||
|
num = hull->clipnodes16[num].children[PlaneDiff( p, plane ) < 0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
@@ -193,7 +200,7 @@ PM_RecursiveHullCheck
|
|||||||
*/
|
*/
|
||||||
qboolean PM_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, pmtrace_t *trace )
|
qboolean PM_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, pmtrace_t *trace )
|
||||||
{
|
{
|
||||||
mclipnode_t *node;
|
int children[2];
|
||||||
mplane_t *plane;
|
mplane_t *plane;
|
||||||
float t1, t2;
|
float t1, t2;
|
||||||
float frac, midf;
|
float frac, midf;
|
||||||
@@ -226,21 +233,31 @@ loc0:
|
|||||||
Host_Error( "%s: bad node number %i\n", __func__, num );
|
Host_Error( "%s: bad node number %i\n", __func__, num );
|
||||||
|
|
||||||
// find the point distances
|
// find the point distances
|
||||||
node = hull->clipnodes + num;
|
if( world.version == QBSP2_VERSION )
|
||||||
plane = hull->planes + node->planenum;
|
{
|
||||||
|
children[0] = hull->clipnodes32[num].children[0];
|
||||||
|
children[1] = hull->clipnodes32[num].children[1];
|
||||||
|
plane = hull->planes + hull->clipnodes32[num].planenum;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
children[0] = hull->clipnodes16[num].children[0];
|
||||||
|
children[1] = hull->clipnodes16[num].children[1];
|
||||||
|
plane = hull->planes + hull->clipnodes16[num].planenum;
|
||||||
|
}
|
||||||
|
|
||||||
t1 = PlaneDiff( p1, plane );
|
t1 = PlaneDiff( p1, plane );
|
||||||
t2 = PlaneDiff( p2, plane );
|
t2 = PlaneDiff( p2, plane );
|
||||||
|
|
||||||
if( t1 >= 0.0f && t2 >= 0.0f )
|
if( t1 >= 0.0f && t2 >= 0.0f )
|
||||||
{
|
{
|
||||||
num = node->children[0];
|
num = children[0];
|
||||||
goto loc0;
|
goto loc0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( t1 < 0.0f && t2 < 0.0f )
|
if( t1 < 0.0f && t2 < 0.0f )
|
||||||
{
|
{
|
||||||
num = node->children[1];
|
num = children[1];
|
||||||
goto loc0;
|
goto loc0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,14 +274,14 @@ loc0:
|
|||||||
VectorLerp( p1, frac, p2, mid );
|
VectorLerp( p1, frac, p2, mid );
|
||||||
|
|
||||||
// move up to the node
|
// move up to the node
|
||||||
if( !PM_RecursiveHullCheck( hull, node->children[side], p1f, midf, p1, mid, trace ))
|
if( !PM_RecursiveHullCheck( hull, children[side], p1f, midf, p1, mid, trace ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// this recursion can not be optimized because mid would need to be duplicated on a stack
|
// this recursion can not be optimized because mid would need to be duplicated on a stack
|
||||||
if( PM_HullPointContents( hull, node->children[side^1], mid ) != CONTENTS_SOLID )
|
if( PM_HullPointContents( hull, children[side^1], mid ) != CONTENTS_SOLID )
|
||||||
{
|
{
|
||||||
// go past the node
|
// go past the node
|
||||||
return PM_RecursiveHullCheck( hull, node->children[side^1], midf, p2f, mid, p2, trace );
|
return PM_RecursiveHullCheck( hull, children[side^1], midf, p2f, mid, p2, trace );
|
||||||
}
|
}
|
||||||
|
|
||||||
// never got out of the solid area
|
// never got out of the solid area
|
||||||
|
|||||||
@@ -16,11 +16,8 @@
|
|||||||
#ifndef EDICT_H
|
#ifndef EDICT_H
|
||||||
#define EDICT_H
|
#define EDICT_H
|
||||||
|
|
||||||
#ifdef SUPPORT_BSP2_FORMAT
|
#define MAX_ENT_LEAFS_32 24 // Orignally was 16
|
||||||
#define MAX_ENT_LEAFS 24 // Orignally was 16
|
#define MAX_ENT_LEAFS_16 48
|
||||||
#else
|
|
||||||
#define MAX_ENT_LEAFS 48
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "progdefs.h"
|
#include "progdefs.h"
|
||||||
|
|
||||||
@@ -33,11 +30,12 @@ struct edict_s
|
|||||||
int headnode; // -1 to use normal leaf check
|
int headnode; // -1 to use normal leaf check
|
||||||
|
|
||||||
int num_leafs;
|
int num_leafs;
|
||||||
#ifdef SUPPORT_BSP2_FORMAT
|
union
|
||||||
int leafnums[MAX_ENT_LEAFS];
|
{
|
||||||
#else
|
int leafnums32[MAX_ENT_LEAFS_32];
|
||||||
short leafnums[MAX_ENT_LEAFS];
|
short leafnums16[MAX_ENT_LEAFS_16];
|
||||||
#endif
|
};
|
||||||
|
|
||||||
float freetime; // sv.time when the object was freed
|
float freetime; // sv.time when the object was freed
|
||||||
|
|
||||||
void* pvPrivateData; // Alloced and freed by engine, used by DLLs
|
void* pvPrivateData; // Alloced and freed by engine, used by DLLs
|
||||||
|
|||||||
@@ -41,8 +41,54 @@ void Platform_MessageBox( const char *title, const char *message, qboolean paren
|
|||||||
}
|
}
|
||||||
#endif // XASH_MESSAGEBOX == MSGBOX_SDL
|
#endif // XASH_MESSAGEBOX == MSGBOX_SDL
|
||||||
|
|
||||||
|
static const char *SDLash_CategoryToString( int category )
|
||||||
|
{
|
||||||
|
switch( category )
|
||||||
|
{
|
||||||
|
case SDL_LOG_CATEGORY_APPLICATION: return "App";
|
||||||
|
case SDL_LOG_CATEGORY_ERROR: return "Error";
|
||||||
|
case SDL_LOG_CATEGORY_ASSERT: return "Assert";
|
||||||
|
case SDL_LOG_CATEGORY_SYSTEM: return "System";
|
||||||
|
case SDL_LOG_CATEGORY_AUDIO: return "Audio";
|
||||||
|
case SDL_LOG_CATEGORY_VIDEO: return "Video";
|
||||||
|
case SDL_LOG_CATEGORY_RENDER: return "Render";
|
||||||
|
case SDL_LOG_CATEGORY_INPUT: return "Input";
|
||||||
|
case SDL_LOG_CATEGORY_TEST: return "Test";
|
||||||
|
default: return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SDLCALL SDLash_LogOutputFunction( void *userdata, int category, SDL_LogPriority priority, const char *message )
|
||||||
|
{
|
||||||
|
switch( priority )
|
||||||
|
{
|
||||||
|
case SDL_LOG_PRIORITY_CRITICAL:
|
||||||
|
case SDL_LOG_PRIORITY_ERROR:
|
||||||
|
Con_Printf( S_ERROR S_BLUE "SDL" S_DEFAULT ": [%s] %s\n", SDLash_CategoryToString( category ), message );
|
||||||
|
break;
|
||||||
|
case SDL_LOG_PRIORITY_WARN:
|
||||||
|
Con_DPrintf( S_WARN S_BLUE "SDL" S_DEFAULT ": [%s] %s\n", SDLash_CategoryToString( category ), message );
|
||||||
|
break;
|
||||||
|
case SDL_LOG_PRIORITY_INFO:
|
||||||
|
Con_Reportf( S_NOTE S_BLUE "SDL" S_DEFAULT ": [%s] %s\n", SDLash_CategoryToString( category ), message );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Con_Reportf( S_BLUE "SDL" S_DEFAULT ": [%s] %s\n", SDLash_CategoryToString( category ), message );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SDLash_Init( void )
|
void SDLash_Init( void )
|
||||||
{
|
{
|
||||||
|
SDL_LogSetOutputFunction( SDLash_LogOutputFunction, NULL );
|
||||||
|
|
||||||
|
if( host_developer.value >= 2 )
|
||||||
|
SDL_LogSetAllPriority( SDL_LOG_PRIORITY_VERBOSE );
|
||||||
|
else if( host_developer.value >= 1 )
|
||||||
|
SDL_LogSetAllPriority( SDL_LOG_PRIORITY_WARN );
|
||||||
|
else
|
||||||
|
SDL_LogSetAllPriority( SDL_LOG_PRIORITY_ERROR );
|
||||||
|
|
||||||
#ifndef SDL_INIT_EVENTS
|
#ifndef SDL_INIT_EVENTS
|
||||||
#define SDL_INIT_EVENTS 0
|
#define SDL_INIT_EVENTS 0
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ GNU General Public License for more details.
|
|||||||
#define MODEL_LIQUID BIT( 2 ) // model has only point hull
|
#define MODEL_LIQUID BIT( 2 ) // model has only point hull
|
||||||
#define MODEL_TRANSPARENT BIT( 3 ) // have transparent surfaces
|
#define MODEL_TRANSPARENT BIT( 3 ) // have transparent surfaces
|
||||||
#define MODEL_COLORED_LIGHTING BIT( 4 ) // lightmaps stored as RGB
|
#define MODEL_COLORED_LIGHTING BIT( 4 ) // lightmaps stored as RGB
|
||||||
|
|
||||||
#define MODEL_WORLD BIT( 29 ) // it's a worldmodel
|
#define MODEL_WORLD BIT( 29 ) // it's a worldmodel
|
||||||
#define MODEL_CLIENT BIT( 30 ) // client sprite
|
#define MODEL_CLIENT BIT( 30 ) // client sprite
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ extern int SV_UPDATE_BACKUP;
|
|||||||
#define MAX_PUSHED_ENTS 256
|
#define MAX_PUSHED_ENTS 256
|
||||||
#define MAX_VIEWENTS 128
|
#define MAX_VIEWENTS 128
|
||||||
|
|
||||||
|
#define MAX_ENT_LEAFS( ext ) (( ext ) ? MAX_ENT_LEAFS_32 : MAX_ENT_LEAFS_16 )
|
||||||
|
|
||||||
#define FCL_RESEND_USERINFO BIT( 0 )
|
#define FCL_RESEND_USERINFO BIT( 0 )
|
||||||
#define FCL_RESEND_MOVEVARS BIT( 1 )
|
#define FCL_RESEND_MOVEVARS BIT( 1 )
|
||||||
#define FCL_SKIP_NET_MESSAGE BIT( 2 )
|
#define FCL_SKIP_NET_MESSAGE BIT( 2 )
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ static qboolean SV_CheckClientVisiblity( sv_client_t *cl, const byte *mask )
|
|||||||
else
|
else
|
||||||
VectorCopy( cl->edict->v.origin, vieworg );
|
VectorCopy( cl->edict->v.origin, vieworg );
|
||||||
|
|
||||||
leaf = Mod_PointInLeaf( vieworg, sv.worldmodel->nodes );
|
leaf = Mod_PointInLeaf( vieworg, sv.worldmodel->nodes, sv.worldmodel );
|
||||||
|
|
||||||
if( CHECKVISBIT( mask, leaf->cluster ))
|
if( CHECKVISBIT( mask, leaf->cluster ))
|
||||||
return true; // visible from player view or camera view
|
return true; // visible from player view or camera view
|
||||||
@@ -342,7 +342,7 @@ static qboolean SV_CheckClientVisiblity( sv_client_t *cl, const byte *mask )
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
VectorAdd( view->v.origin, view->v.view_ofs, vieworg );
|
VectorAdd( view->v.origin, view->v.view_ofs, vieworg );
|
||||||
leaf = Mod_PointInLeaf( vieworg, sv.worldmodel->nodes );
|
leaf = Mod_PointInLeaf( vieworg, sv.worldmodel->nodes, sv.worldmodel );
|
||||||
|
|
||||||
if( CHECKVISBIT( mask, leaf->cluster ))
|
if( CHECKVISBIT( mask, leaf->cluster ))
|
||||||
return true; // visible from portal camera view
|
return true; // visible from portal camera view
|
||||||
@@ -1732,7 +1732,7 @@ static edict_t* GAME_EXPORT pfnFindClientInPVS( edict_t *pEdict )
|
|||||||
VectorAdd( pEdict->v.origin, pEdict->v.view_ofs, view );
|
VectorAdd( pEdict->v.origin, pEdict->v.view_ofs, view );
|
||||||
}
|
}
|
||||||
|
|
||||||
leaf = Mod_PointInLeaf( view, sv.worldmodel->nodes );
|
leaf = Mod_PointInLeaf( view, sv.worldmodel->nodes, sv.worldmodel );
|
||||||
|
|
||||||
if( CHECKVISBIT( clientpvs, leaf->cluster ))
|
if( CHECKVISBIT( clientpvs, leaf->cluster ))
|
||||||
return pClient; // client which currently in PVS
|
return pClient; // client which currently in PVS
|
||||||
@@ -4291,6 +4291,35 @@ static byte *GAME_EXPORT pfnSetFatPAS( const float *org )
|
|||||||
return fatphs;
|
return fatphs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
Mod_HeadnodeVisible
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
static qboolean Mod_HeadnodeVisible( model_t *mod, mnode_t *node, const byte *visbits, int *lastleaf )
|
||||||
|
{
|
||||||
|
if( !node || node->contents == CONTENTS_SOLID )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( node->contents < 0 )
|
||||||
|
{
|
||||||
|
if( !CHECKVISBIT( visbits, ((mleaf_t *)node)->cluster ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( lastleaf )
|
||||||
|
*lastleaf = ((mleaf_t *)node)->cluster;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( Mod_HeadnodeVisible( mod, node_child( node, 0, mod ), visbits, lastleaf ))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if( Mod_HeadnodeVisible( mod, node_child( node, 1, mod ), visbits, lastleaf ))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
pfnCheckVisibility
|
pfnCheckVisibility
|
||||||
@@ -4300,6 +4329,7 @@ pfnCheckVisibility
|
|||||||
static int GAME_EXPORT pfnCheckVisibility( const edict_t *ent, byte *pset )
|
static int GAME_EXPORT pfnCheckVisibility( const edict_t *ent, byte *pset )
|
||||||
{
|
{
|
||||||
int i, leafnum;
|
int i, leafnum;
|
||||||
|
qboolean large_leafs = FBitSet( sv.worldmodel->flags, MODEL_QBSP2 );
|
||||||
|
|
||||||
if( !SV_IsValidEdict( ent ))
|
if( !SV_IsValidEdict( ent ))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -4315,17 +4345,28 @@ static int GAME_EXPORT pfnCheckVisibility( const edict_t *ent, byte *pset )
|
|||||||
// check individual leafs
|
// check individual leafs
|
||||||
for( i = 0; i < ent->num_leafs; i++ )
|
for( i = 0; i < ent->num_leafs; i++ )
|
||||||
{
|
{
|
||||||
if( CHECKVISBIT( pset, ent->leafnums[i] ))
|
if( large_leafs )
|
||||||
return 1; // visible passed by leaf
|
{
|
||||||
|
if( CHECKVISBIT( pset, ent->leafnums32[i] ))
|
||||||
|
return 1; // visible passed by leaf
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( CHECKVISBIT( pset, ent->leafnums16[i] ))
|
||||||
|
return 1; // visible passed by leaf
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for( i = 0; i < MAX_ENT_LEAFS; i++ )
|
for( i = 0; i < MAX_ENT_LEAFS( large_leafs ); i++ )
|
||||||
{
|
{
|
||||||
leafnum = ent->leafnums[i];
|
if( large_leafs )
|
||||||
|
leafnum = ent->leafnums32[i];
|
||||||
|
else
|
||||||
|
leafnum = ent->leafnums16[i];
|
||||||
if( leafnum == -1 ) break;
|
if( leafnum == -1 ) break;
|
||||||
|
|
||||||
if( CHECKVISBIT( pset, leafnum ))
|
if( CHECKVISBIT( pset, leafnum ))
|
||||||
@@ -4333,11 +4374,15 @@ static int GAME_EXPORT pfnCheckVisibility( const edict_t *ent, byte *pset )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// too many leafs for individual check, go by headnode
|
// too many leafs for individual check, go by headnode
|
||||||
if( !Mod_HeadnodeVisible( &sv.worldmodel->nodes[ent->headnode], pset, &leafnum ))
|
if( !Mod_HeadnodeVisible( sv.worldmodel, &sv.worldmodel->nodes[ent->headnode], pset, &leafnum ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
((edict_t *)ent)->leafnums[ent->num_leafs] = leafnum;
|
if( large_leafs )
|
||||||
((edict_t *)ent)->num_leafs = (ent->num_leafs + 1) % MAX_ENT_LEAFS;
|
((edict_t *)ent)->leafnums32[ent->num_leafs] = leafnum;
|
||||||
|
else
|
||||||
|
((edict_t *)ent)->leafnums16[ent->num_leafs] = leafnum;
|
||||||
|
|
||||||
|
((edict_t *)ent)->num_leafs = (ent->num_leafs + 1) % MAX_ENT_LEAFS( large_leafs );
|
||||||
|
|
||||||
return 2; // visible passed by headnode
|
return 2; // visible passed by headnode
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,9 +40,8 @@ HULL BOXES
|
|||||||
===============================================================================
|
===============================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static hull_t box_hull;
|
static hull_t box_hull;
|
||||||
static mclipnode_t box_clipnodes[6];
|
static mplane_t box_planes[6];
|
||||||
static mplane_t box_planes[6];
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===================
|
===================
|
||||||
@@ -54,23 +53,15 @@ can just be stored out and get a proper hull_t structure.
|
|||||||
*/
|
*/
|
||||||
static void SV_InitBoxHull( void )
|
static void SV_InitBoxHull( void )
|
||||||
{
|
{
|
||||||
int i, side;
|
int i;
|
||||||
|
|
||||||
box_hull.clipnodes = box_clipnodes;
|
box_hull.clipnodes16 = (mclipnode16_t *)box_clipnodes16;
|
||||||
box_hull.planes = box_planes;
|
box_hull.planes = box_planes;
|
||||||
box_hull.firstclipnode = 0;
|
box_hull.firstclipnode = 0;
|
||||||
box_hull.lastclipnode = 5;
|
box_hull.lastclipnode = 5;
|
||||||
|
|
||||||
for( i = 0; i < 6; i++ )
|
for( i = 0; i < 6; i++ )
|
||||||
{
|
{
|
||||||
box_clipnodes[i].planenum = i;
|
|
||||||
|
|
||||||
side = i & 1;
|
|
||||||
|
|
||||||
box_clipnodes[i].children[side] = CONTENTS_EMPTY;
|
|
||||||
if( i != 5 ) box_clipnodes[i].children[side^1] = i + 1;
|
|
||||||
else box_clipnodes[i].children[side^1] = CONTENTS_SOLID;
|
|
||||||
|
|
||||||
box_planes[i].type = i>>1;
|
box_planes[i].type = i>>1;
|
||||||
box_planes[i].normal[i>>1] = 1;
|
box_planes[i].normal[i>>1] = 1;
|
||||||
box_planes[i].signbits = 0;
|
box_planes[i].signbits = 0;
|
||||||
@@ -167,6 +158,11 @@ static hull_t *SV_HullForBox( const vec3_t mins, const vec3_t maxs )
|
|||||||
box_planes[4].dist = maxs[2];
|
box_planes[4].dist = maxs[2];
|
||||||
box_planes[5].dist = mins[2];
|
box_planes[5].dist = mins[2];
|
||||||
|
|
||||||
|
if( world.version == QBSP2_VERSION )
|
||||||
|
box_hull.clipnodes32 = (mclipnode32_t *)box_clipnodes32;
|
||||||
|
else
|
||||||
|
box_hull.clipnodes16 = (mclipnode16_t *)box_clipnodes16;
|
||||||
|
|
||||||
return &box_hull;
|
return &box_hull;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,7 +590,7 @@ SV_FindTouchedLeafs
|
|||||||
|
|
||||||
===============
|
===============
|
||||||
*/
|
*/
|
||||||
static void SV_FindTouchedLeafs( edict_t *ent, mnode_t *node, int *headnode )
|
static void SV_FindTouchedLeafs( edict_t *ent, model_t *mod, mnode_t *node, int *headnode )
|
||||||
{
|
{
|
||||||
int sides;
|
int sides;
|
||||||
mleaf_t *leaf;
|
mleaf_t *leaf;
|
||||||
@@ -605,16 +601,19 @@ static void SV_FindTouchedLeafs( edict_t *ent, mnode_t *node, int *headnode )
|
|||||||
// add an efrag if the node is a leaf
|
// add an efrag if the node is a leaf
|
||||||
if( node->contents < 0 )
|
if( node->contents < 0 )
|
||||||
{
|
{
|
||||||
if( ent->num_leafs > ( MAX_ENT_LEAFS - 1 ))
|
if( ent->num_leafs > MAX_ENT_LEAFS( FBitSet( mod->flags, MODEL_QBSP2 )))
|
||||||
{
|
{
|
||||||
// continue counting leafs,
|
// continue counting leafs,
|
||||||
// so we know how many it's overrun
|
// so we know how many it's overrun
|
||||||
ent->num_leafs = (MAX_ENT_LEAFS + 1);
|
ent->num_leafs = (MAX_ENT_LEAFS( FBitSet( mod->flags, MODEL_QBSP2 )) + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
leaf = (mleaf_t *)node;
|
leaf = (mleaf_t *)node;
|
||||||
ent->leafnums[ent->num_leafs] = leaf->cluster;
|
if( FBitSet( mod->flags, MODEL_QBSP2 ))
|
||||||
|
ent->leafnums32[ent->num_leafs] = leaf->cluster;
|
||||||
|
else
|
||||||
|
ent->leafnums16[ent->num_leafs] = leaf->cluster;
|
||||||
ent->num_leafs++;
|
ent->num_leafs++;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -624,11 +623,13 @@ static void SV_FindTouchedLeafs( edict_t *ent, mnode_t *node, int *headnode )
|
|||||||
sides = BOX_ON_PLANE_SIDE( ent->v.absmin, ent->v.absmax, node->plane );
|
sides = BOX_ON_PLANE_SIDE( ent->v.absmin, ent->v.absmax, node->plane );
|
||||||
|
|
||||||
if(( sides == 3 ) && ( *headnode == -1 ))
|
if(( sides == 3 ) && ( *headnode == -1 ))
|
||||||
*headnode = node - sv.worldmodel->nodes;
|
*headnode = node - mod->nodes;
|
||||||
|
|
||||||
// recurse down the contacted sides
|
// recurse down the contacted sides
|
||||||
if( sides & 1 ) SV_FindTouchedLeafs( ent, node->children[0], headnode );
|
if( sides & 1 )
|
||||||
if( sides & 2 ) SV_FindTouchedLeafs( ent, node->children[1], headnode );
|
SV_FindTouchedLeafs( ent, mod, node_child( node, 0, mod ), headnode );
|
||||||
|
if( sides & 2 )
|
||||||
|
SV_FindTouchedLeafs( ent, mod, node_child( node, 1, mod ), headnode );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -650,7 +651,7 @@ void GAME_EXPORT SV_LinkEdict( edict_t *ent, qboolean touch_triggers )
|
|||||||
|
|
||||||
if( ent->v.movetype == MOVETYPE_FOLLOW && SV_IsValidEdict( ent->v.aiment ))
|
if( ent->v.movetype == MOVETYPE_FOLLOW && SV_IsValidEdict( ent->v.aiment ))
|
||||||
{
|
{
|
||||||
memcpy( ent->leafnums, ent->v.aiment->leafnums, sizeof( ent->leafnums ));
|
memcpy( ent->leafnums32, ent->v.aiment->leafnums32, sizeof( ent->leafnums32 ));
|
||||||
ent->num_leafs = ent->v.aiment->num_leafs;
|
ent->num_leafs = ent->v.aiment->num_leafs;
|
||||||
ent->headnode = ent->v.aiment->headnode;
|
ent->headnode = ent->v.aiment->headnode;
|
||||||
}
|
}
|
||||||
@@ -662,11 +663,11 @@ void GAME_EXPORT SV_LinkEdict( edict_t *ent, qboolean touch_triggers )
|
|||||||
headnode = -1;
|
headnode = -1;
|
||||||
|
|
||||||
if( ent->v.modelindex )
|
if( ent->v.modelindex )
|
||||||
SV_FindTouchedLeafs( ent, sv.worldmodel->nodes, &headnode );
|
SV_FindTouchedLeafs( ent, sv.worldmodel, sv.worldmodel->nodes, &headnode );
|
||||||
|
|
||||||
if( ent->num_leafs > MAX_ENT_LEAFS )
|
if( ent->num_leafs > MAX_ENT_LEAFS( FBitSet( sv.worldmodel->flags, MODEL_QBSP2 )))
|
||||||
{
|
{
|
||||||
memset( ent->leafnums, -1, sizeof( ent->leafnums ));
|
memset( ent->leafnums32, -1, sizeof( ent->leafnums32 ));
|
||||||
ent->num_leafs = 0; // so we use headnode instead
|
ent->num_leafs = 0; // so we use headnode instead
|
||||||
ent->headnode = headnode;
|
ent->headnode = headnode;
|
||||||
}
|
}
|
||||||
@@ -1518,6 +1519,8 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
|
|||||||
float front, back, frac;
|
float front, back, frac;
|
||||||
int i, side;
|
int i, side;
|
||||||
vec3_t mid;
|
vec3_t mid;
|
||||||
|
mnode_t *children[2];
|
||||||
|
int numsurfaces, firstsurface;
|
||||||
|
|
||||||
// didn't hit anything
|
// didn't hit anything
|
||||||
if( !node || node->contents < 0 )
|
if( !node || node->contents < 0 )
|
||||||
@@ -1527,25 +1530,29 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
|
|||||||
front = PlaneDiff( start, node->plane );
|
front = PlaneDiff( start, node->plane );
|
||||||
back = PlaneDiff( end, node->plane );
|
back = PlaneDiff( end, node->plane );
|
||||||
|
|
||||||
|
node_children( children, node, model );
|
||||||
|
|
||||||
side = front < 0.0f;
|
side = front < 0.0f;
|
||||||
if(( back < 0.0f ) == side )
|
if(( back < 0.0f ) == side )
|
||||||
return SV_RecursiveLightPoint( model, node->children[side], start, end, point_color );
|
return SV_RecursiveLightPoint( model, children[side], start, end, point_color );
|
||||||
|
|
||||||
frac = front / ( front - back );
|
frac = front / ( front - back );
|
||||||
|
|
||||||
VectorLerp( start, frac, end, mid );
|
VectorLerp( start, frac, end, mid );
|
||||||
|
|
||||||
// co down front side
|
// co down front side
|
||||||
if( SV_RecursiveLightPoint( model, node->children[side], start, mid, point_color ))
|
if( SV_RecursiveLightPoint( model, children[side], start, mid, point_color ))
|
||||||
return true; // hit something
|
return true; // hit something
|
||||||
|
|
||||||
if(( back < 0.0f ) == side )
|
if(( back < 0.0f ) == side )
|
||||||
return false; // didn't hit anything
|
return false; // didn't hit anything
|
||||||
|
|
||||||
// check for impact on this node
|
// check for impact on this node
|
||||||
for( i = 0; i < node->numsurfaces; i++ )
|
numsurfaces = node_numsurfaces( node, model );
|
||||||
|
firstsurface = node_firstsurface( node, model );
|
||||||
|
for( i = 0; i < numsurfaces; i++ )
|
||||||
{
|
{
|
||||||
const msurface_t *surf = &model->surfaces[node->firstsurface + i];
|
const msurface_t *surf = &model->surfaces[firstsurface + i];
|
||||||
const mextrasurf_t *info = surf->info;
|
const mextrasurf_t *info = surf->info;
|
||||||
int smax, tmax, map, size;
|
int smax, tmax, map, size;
|
||||||
int sample_size;
|
int sample_size;
|
||||||
@@ -1596,7 +1603,7 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
|
|||||||
}
|
}
|
||||||
|
|
||||||
// go down back side
|
// go down back side
|
||||||
return SV_RecursiveLightPoint( model, node->children[!side], mid, end, point_color );
|
return SV_RecursiveLightPoint( model, children[!side], mid, end, point_color );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ static void FS_PopulateDirEntries( dir_t *dir, const char *path )
|
|||||||
}
|
}
|
||||||
|
|
||||||
stringlistinit( &list );
|
stringlistinit( &list );
|
||||||
listdirectory( &list, path );
|
listdirectory( &list, path, false );
|
||||||
if( !list.numstrings )
|
if( !list.numstrings )
|
||||||
{
|
{
|
||||||
dir->numentries = DIRENTRY_EMPTY_DIRECTORY;
|
dir->numentries = DIRENTRY_EMPTY_DIRECTORY;
|
||||||
@@ -225,7 +225,7 @@ static int FS_MaybeUpdateDirEntries( dir_t *dir, const char *path, const char *e
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
stringlistinit( &list );
|
stringlistinit( &list );
|
||||||
listdirectory( &list, path );
|
listdirectory( &list, path, false );
|
||||||
|
|
||||||
if( list.numstrings == 0 ) // empty directory
|
if( list.numstrings == 0 ) // empty directory
|
||||||
{
|
{
|
||||||
@@ -421,7 +421,7 @@ static void FS_Search_DIR( searchpath_t *search, stringlist_t *list, const char
|
|||||||
}
|
}
|
||||||
|
|
||||||
stringlistinit( &dirlist );
|
stringlistinit( &dirlist );
|
||||||
listdirectory( &dirlist, netpath );
|
listdirectory( &dirlist, netpath, false );
|
||||||
|
|
||||||
Q_strncpy( temp, basepath, sizeof( temp ));
|
Q_strncpy( temp, basepath, sizeof( temp ));
|
||||||
|
|
||||||
|
|||||||
@@ -225,18 +225,13 @@ static void listlowercase( stringlist_t *list )
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void listdirectory( stringlist_t *list, const char *path )
|
void listdirectory( stringlist_t *list, const char *path, qboolean dirs_only )
|
||||||
{
|
{
|
||||||
#if XASH_WIN32
|
#if XASH_WIN32
|
||||||
char pattern[4096];
|
char pattern[4096];
|
||||||
struct _finddata_t n_file;
|
struct _finddata_t n_file;
|
||||||
intptr_t hFile;
|
intptr_t hFile;
|
||||||
#else
|
|
||||||
DIR *dir;
|
|
||||||
struct dirent *entry;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if XASH_WIN32
|
|
||||||
Q_snprintf( pattern, sizeof( pattern ), "%s/*", path );
|
Q_snprintf( pattern, sizeof( pattern ), "%s/*", path );
|
||||||
|
|
||||||
// ask for the directory listing handle
|
// ask for the directory listing handle
|
||||||
@@ -247,15 +242,33 @@ void listdirectory( stringlist_t *list, const char *path )
|
|||||||
stringlistappend( list, n_file.name );
|
stringlistappend( list, n_file.name );
|
||||||
// iterate through the directory
|
// iterate through the directory
|
||||||
while( _findnext( hFile, &n_file ) == 0 )
|
while( _findnext( hFile, &n_file ) == 0 )
|
||||||
|
{
|
||||||
|
if( dirs_only && !FBitSet( n_file.attrib, _A_SUBDIR ))
|
||||||
|
continue;
|
||||||
|
|
||||||
stringlistappend( list, n_file.name );
|
stringlistappend( list, n_file.name );
|
||||||
|
}
|
||||||
_findclose( hFile );
|
_findclose( hFile );
|
||||||
#else
|
#else
|
||||||
if( !( dir = opendir( path ) ) )
|
DIR *dir;
|
||||||
|
struct dirent *entry;
|
||||||
|
|
||||||
|
dir = opendir( path );
|
||||||
|
|
||||||
|
if( !dir )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// iterate through the directory
|
// iterate through the directory
|
||||||
while( ( entry = readdir( dir ) ))
|
while(( entry = readdir( dir )))
|
||||||
|
{
|
||||||
|
#if HAVE_DIRENT_D_TYPE
|
||||||
|
if( dirs_only && entry->d_type != DT_DIR && entry->d_type != DT_UNKNOWN )
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
stringlistappend( list, entry->d_name );
|
stringlistappend( list, entry->d_name );
|
||||||
|
}
|
||||||
|
|
||||||
closedir( dir );
|
closedir( dir );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -396,7 +409,7 @@ void FS_AddGameDirectory( const char *dir, uint flags )
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
stringlistinit( &list );
|
stringlistinit( &list );
|
||||||
listdirectory( &list, dir );
|
listdirectory( &list, dir, false );
|
||||||
stringlistsort( &list );
|
stringlistsort( &list );
|
||||||
|
|
||||||
for( archive = g_archives; archive->ext; archive++ )
|
for( archive = g_archives; archive->ext; archive++ )
|
||||||
@@ -508,12 +521,13 @@ FS_WriteGameInfo
|
|||||||
assume GameInfo is valid
|
assume GameInfo is valid
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
static void FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo )
|
static qboolean FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo )
|
||||||
{
|
{
|
||||||
file_t *f = FS_Open( filepath, "w", false ); // we in binary-mode
|
file_t *f = FS_Open( filepath, "w", false ); // we in binary-mode
|
||||||
int i, write_ambients = false;
|
int i, write_ambients = false;
|
||||||
|
|
||||||
if( !f ) Sys_Error( "%s: can't write %s\n", __func__, filepath ); // may be disk-space is out?
|
if( !f )
|
||||||
|
return false;
|
||||||
|
|
||||||
FS_Printf( f, "// generated by " XASH_ENGINE_NAME " " XASH_VERSION "-%s (%s-%s)\n\n\n", Q_buildcommit(), Q_buildos(), Q_buildarch() );
|
FS_Printf( f, "// generated by " XASH_ENGINE_NAME " " XASH_VERSION "-%s (%s-%s)\n\n\n", Q_buildcommit(), Q_buildos(), Q_buildarch() );
|
||||||
|
|
||||||
@@ -637,25 +651,50 @@ static void FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo )
|
|||||||
FS_Printf( f, "demomap\t\t\"%s\"\n", GameInfo->demomap );
|
FS_Printf( f, "demomap\t\t\"%s\"\n", GameInfo->demomap );
|
||||||
|
|
||||||
FS_Close( f ); // all done
|
FS_Close( f ); // all done
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir )
|
static void FS_MakeGameInfo( void )
|
||||||
|
{
|
||||||
|
if( FS_WriteGameInfo( "gameinfo.txt", FI.GameInfo ))
|
||||||
|
Con_Printf( "Successfully generated %s/gameinfo.txt\n", FI.GameInfo->gamefolder );
|
||||||
|
else
|
||||||
|
Con_Printf( S_ERROR "Can't open %s/gameinfo.txt for write\n", FI.GameInfo->gamefolder );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir, qboolean quake, time_t mtime )
|
||||||
{
|
{
|
||||||
memset( GameInfo, 0, sizeof( *GameInfo ));
|
memset( GameInfo, 0, sizeof( *GameInfo ));
|
||||||
|
|
||||||
// filesystem info
|
// filesystem info
|
||||||
Q_strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title ));
|
GameInfo->mtime = mtime;
|
||||||
Q_strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder ));
|
Q_strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder ));
|
||||||
Q_strncpy( GameInfo->basedir, fs_basedir, sizeof( GameInfo->basedir ));
|
|
||||||
Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity ));
|
Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity ));
|
||||||
Q_strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity ));
|
Q_strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity ));
|
||||||
Q_strncpy( GameInfo->startmap, "newmap", sizeof( GameInfo->startmap ));
|
|
||||||
Q_strncpy( GameInfo->dll_path, "cl_dlls", sizeof( GameInfo->dll_path ));
|
|
||||||
Q_strncpy( GameInfo->game_dll, "dlls/hl.dll", sizeof( GameInfo->game_dll ));
|
|
||||||
Q_strncpy( GameInfo->game_dll_linux, "dlls/hl.so", sizeof( GameInfo->game_dll_linux ));
|
|
||||||
Q_strncpy( GameInfo->game_dll_osx, "dlls/hl.dylib", sizeof( GameInfo->game_dll_osx ));
|
|
||||||
Q_strncpy( GameInfo->iconpath, "game.ico", sizeof( GameInfo->iconpath ));
|
Q_strncpy( GameInfo->iconpath, "game.ico", sizeof( GameInfo->iconpath ));
|
||||||
|
|
||||||
|
if( quake )
|
||||||
|
{
|
||||||
|
Q_strncpy( GameInfo->basedir, "id1", sizeof( GameInfo->basedir ));
|
||||||
|
Q_strncpy( GameInfo->title, gamedir, sizeof( GameInfo->title ));
|
||||||
|
Q_strncpy( GameInfo->startmap, "start", sizeof( GameInfo->startmap ));
|
||||||
|
Q_strncpy( GameInfo->dll_path, "bin", sizeof( GameInfo->dll_path ));
|
||||||
|
Q_strncpy( GameInfo->game_dll, "bin/progs.dll", sizeof( GameInfo->game_dll ));
|
||||||
|
Q_strncpy( GameInfo->game_dll_linux, "bin/progs.so", sizeof( GameInfo->game_dll_linux ));
|
||||||
|
Q_strncpy( GameInfo->game_dll_osx, "bin/progs.dylib", sizeof( GameInfo->game_dll_osx ));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Q_strncpy( GameInfo->basedir, fs_basedir, sizeof( GameInfo->basedir ));
|
||||||
|
Q_strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title ));
|
||||||
|
Q_strncpy( GameInfo->startmap, "newmap", sizeof( GameInfo->startmap ));
|
||||||
|
Q_strncpy( GameInfo->dll_path, "cl_dlls", sizeof( GameInfo->dll_path ));
|
||||||
|
Q_strncpy( GameInfo->game_dll, "dlls/hl.dll", sizeof( GameInfo->game_dll ));
|
||||||
|
Q_strncpy( GameInfo->game_dll_linux, "dlls/hl.so", sizeof( GameInfo->game_dll_linux ));
|
||||||
|
Q_strncpy( GameInfo->game_dll_osx, "dlls/hl.dylib", sizeof( GameInfo->game_dll_osx ));
|
||||||
|
}
|
||||||
|
|
||||||
GameInfo->max_edicts = DEFAULT_MAX_EDICTS; // default value if not specified
|
GameInfo->max_edicts = DEFAULT_MAX_EDICTS; // default value if not specified
|
||||||
GameInfo->max_tents = 500;
|
GameInfo->max_tents = 500;
|
||||||
GameInfo->max_beams = 128;
|
GameInfo->max_beams = 128;
|
||||||
@@ -940,36 +979,19 @@ static void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
================
|
|
||||||
FS_CreateDefaultGameInfo
|
|
||||||
================
|
|
||||||
*/
|
|
||||||
static void FS_CreateDefaultGameInfo( const char *filename )
|
|
||||||
{
|
|
||||||
gameinfo_t defGI;
|
|
||||||
|
|
||||||
FS_InitGameInfo( &defGI, fs_basedir );
|
|
||||||
|
|
||||||
// make simple gameinfo.txt
|
|
||||||
FS_WriteGameInfo( filename, &defGI );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
FS_ParseLiblistGam
|
FS_ParseLiblistGam
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
static qboolean FS_ParseLiblistGam( const char *filename, const char *gamedir, gameinfo_t *GameInfo )
|
static qboolean FS_ParseLiblistGam( const char *filename, const char *gamedir, gameinfo_t *GameInfo, time_t mtime )
|
||||||
{
|
{
|
||||||
char *afile;
|
char *afile = FS_LoadDirectFile( filename, NULL );
|
||||||
|
|
||||||
if( !GameInfo ) return false;
|
if( !afile )
|
||||||
afile = (char *)FS_LoadDirectFile( filename, NULL );
|
return false;
|
||||||
if( !afile ) return false;
|
|
||||||
|
|
||||||
FS_InitGameInfo( GameInfo, gamedir );
|
|
||||||
|
|
||||||
|
FS_InitGameInfo( GameInfo, gamedir, false, mtime );
|
||||||
FS_ParseGenericGameInfo( GameInfo, afile, false );
|
FS_ParseGenericGameInfo( GameInfo, afile, false );
|
||||||
|
|
||||||
Mem_Free( afile );
|
Mem_Free( afile );
|
||||||
@@ -982,18 +1004,15 @@ static qboolean FS_ParseLiblistGam( const char *filename, const char *gamedir, g
|
|||||||
FS_ConvertGameInfo
|
FS_ConvertGameInfo
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
static qboolean FS_ConvertGameInfo( const char *gamedir, const char *gameinfo_path, const char *liblist_path )
|
static qboolean FS_ConvertGameInfo( const char *gamedir, const char *gameinfo_path, const char *liblist_path, gameinfo_t *gi, time_t liblist_mtime )
|
||||||
{
|
{
|
||||||
gameinfo_t GameInfo;
|
memset( gi, 0, sizeof( *gi ));
|
||||||
|
|
||||||
memset( &GameInfo, 0, sizeof( GameInfo ));
|
// liblist.gam to gameinfo.txt conversion is deprecated, only support for RwDir!
|
||||||
|
if( FS_ParseLiblistGam( liblist_path, gamedir, gi, liblist_mtime ))
|
||||||
if( FS_ParseLiblistGam( liblist_path, gamedir, &GameInfo ))
|
|
||||||
{
|
{
|
||||||
Con_DPrintf( "Convert %s to %s\n", liblist_path, gameinfo_path );
|
Con_DPrintf( "Convert %s to %s\n", liblist_path, gameinfo_path );
|
||||||
FS_WriteGameInfo( gameinfo_path, &GameInfo );
|
return FS_WriteGameInfo( gameinfo_path, gi );
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -1004,16 +1023,14 @@ static qboolean FS_ConvertGameInfo( const char *gamedir, const char *gameinfo_pa
|
|||||||
FS_ReadGameInfo
|
FS_ReadGameInfo
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
static qboolean FS_ReadGameInfo( const char *filepath, const char *gamedir, gameinfo_t *GameInfo )
|
static qboolean FS_ReadGameInfo( const char *filename, const char *gamedir, gameinfo_t *GameInfo, time_t mtime )
|
||||||
{
|
{
|
||||||
char *afile;
|
char *afile = FS_LoadDirectFile( filename, NULL );
|
||||||
|
|
||||||
afile = (char *)FS_LoadFile( filepath, NULL, false );
|
|
||||||
if( !afile )
|
if( !afile )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
FS_InitGameInfo( GameInfo, gamedir );
|
FS_InitGameInfo( GameInfo, gamedir, false, mtime );
|
||||||
|
|
||||||
FS_ParseGenericGameInfo( GameInfo, afile, true );
|
FS_ParseGenericGameInfo( GameInfo, afile, true );
|
||||||
|
|
||||||
Mem_Free( afile );
|
Mem_Free( afile );
|
||||||
@@ -1029,20 +1046,32 @@ Checks if game directory resembles Quake Engine game directory
|
|||||||
(some of checks may as well work with Xash gamedirs, it's not a bug)
|
(some of checks may as well work with Xash gamedirs, it's not a bug)
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
static qboolean FS_CheckForQuakeGameDir( const char *gamedir, qboolean direct )
|
static qboolean FS_CheckForQuakeGameDir( const char *gamedir )
|
||||||
{
|
{
|
||||||
// if directory contain config.cfg or progs.dat it's 100% gamedir
|
// if directory contain quake.rc or progs.dat it's 100% quake gamedir
|
||||||
// quake mods probably always archived but can missed config.cfg before first running
|
// quake mods probably always archived, so check pak0.pak too
|
||||||
const char *files[] = { "config.cfg", "progs.dat", "pak0.pak" };
|
const char *files[] = { "progs.dat", "quake.rc" };
|
||||||
|
char buf[MAX_SYSPATH];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
// try to read pak0.pak first, most quake mods are archived
|
||||||
|
if( Q_snprintf( buf, sizeof( buf ), "%s/pak0.pak", gamedir ) > 0 )
|
||||||
|
{
|
||||||
|
if( FS_SysFileExists( buf ))
|
||||||
|
{
|
||||||
|
if( FS_CheckForQuakePak( buf, files, sizeof( files ) / sizeof( files[0] )))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// search it in the filesystem
|
||||||
for( i = 0; i < sizeof( files ) / sizeof( files[0] ); i++ )
|
for( i = 0; i < sizeof( files ) / sizeof( files[0] ); i++ )
|
||||||
{
|
{
|
||||||
char buf[MAX_VA_STRING];
|
if( Q_snprintf( buf, sizeof( buf ), "%s/%s", gamedir, files[i] ) > 0 )
|
||||||
|
{
|
||||||
Q_snprintf( buf, sizeof( buf ), "%s/%s", gamedir, files[i] );
|
if( FS_SysFileExists( buf ))
|
||||||
if( direct ? FS_SysFileExists( buf ) : FS_FileExists( buf, false ))
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -1055,7 +1084,7 @@ FS_CheckForXashGameDir
|
|||||||
Checks if game directory resembles Xash3D game directory
|
Checks if game directory resembles Xash3D game directory
|
||||||
===============
|
===============
|
||||||
*/
|
*/
|
||||||
static qboolean FS_CheckForXashGameDir( const char *gamedir, qboolean direct )
|
static qboolean FS_CheckForXashGameDir( const char *gamedir )
|
||||||
{
|
{
|
||||||
// if directory contain gameinfo.txt or liblist.gam it's 100% gamedir
|
// if directory contain gameinfo.txt or liblist.gam it's 100% gamedir
|
||||||
const char *files[] = { "gameinfo.txt", "liblist.gam" };
|
const char *files[] = { "gameinfo.txt", "liblist.gam" };
|
||||||
@@ -1063,15 +1092,16 @@ static qboolean FS_CheckForXashGameDir( const char *gamedir, qboolean direct )
|
|||||||
|
|
||||||
for( i = 0; i < sizeof( files ) / sizeof( files[0] ); i++ )
|
for( i = 0; i < sizeof( files ) / sizeof( files[0] ); i++ )
|
||||||
{
|
{
|
||||||
char buf[MAX_SYSPATH];
|
char buf[MAX_SYSPATH];
|
||||||
|
|
||||||
Q_snprintf( buf, sizeof( buf ), "%s/%s", gamedir, files[i] );
|
if( Q_snprintf( buf, sizeof( buf ), "%s/%s", gamedir, files[i] ) > 0 )
|
||||||
if( direct ? FS_SysFileExists( buf ) : FS_FileExists( buf, false ))
|
{
|
||||||
return true;
|
if( FS_SysFileExists( buf ))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1079,86 +1109,74 @@ static qboolean FS_CheckForXashGameDir( const char *gamedir, qboolean direct )
|
|||||||
FS_ParseGameInfo
|
FS_ParseGameInfo
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo )
|
static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo, qboolean rodir )
|
||||||
{
|
{
|
||||||
string liblist_path, gameinfo_path;
|
char liblist_path[MAX_SYSPATH];
|
||||||
string default_gameinfo_path;
|
char gameinfo_path[MAX_SYSPATH];
|
||||||
qboolean haveUpdate = false;
|
char gamedir_path[MAX_SYSPATH];
|
||||||
|
time_t liblist_mtime = -1;
|
||||||
|
time_t gameinfo_mtime = -1;
|
||||||
|
|
||||||
Q_snprintf( default_gameinfo_path, sizeof( default_gameinfo_path ), "%s/gameinfo.txt", fs_basedir );
|
if( rodir )
|
||||||
Q_snprintf( gameinfo_path, sizeof( gameinfo_path ), "%s/gameinfo.txt", gamedir );
|
Q_snprintf( gamedir_path, sizeof( gamedir_path ), "%s/%s", fs_rodir, gamedir );
|
||||||
Q_snprintf( liblist_path, sizeof( liblist_path ), "%s/liblist.gam", gamedir );
|
else
|
||||||
|
Q_snprintf( gamedir_path, sizeof( gamedir_path ), "%s/%s", fs_rootdir, gamedir );
|
||||||
|
|
||||||
// here goes some RoDir magic...
|
if( !FS_CheckForXashGameDir( gamedir_path ))
|
||||||
if( COM_CheckStringEmpty( fs_rodir ))
|
|
||||||
{
|
{
|
||||||
string gameinfo_ro, liblist_ro;
|
// check if we need to generate gameinfo for Quake
|
||||||
fs_offset_t roLibListTime, roGameInfoTime, rwGameInfoTime;
|
if( FS_CheckForQuakeGameDir( gamedir_path ))
|
||||||
|
|
||||||
FS_AllowDirectPaths( true );
|
|
||||||
|
|
||||||
Q_snprintf( gameinfo_ro, sizeof( gameinfo_ro ), "%s/%s/gameinfo.txt", fs_rodir, gamedir );
|
|
||||||
Q_snprintf( liblist_ro, sizeof( liblist_ro ), "%s/%s/liblist.gam", fs_rodir, gamedir );
|
|
||||||
|
|
||||||
roLibListTime = FS_SysFileTime( liblist_ro );
|
|
||||||
roGameInfoTime = FS_SysFileTime( gameinfo_ro );
|
|
||||||
rwGameInfoTime = FS_SysFileTime( gameinfo_path );
|
|
||||||
|
|
||||||
// if rodir's liblist.gam newer than rwdir's gameinfo.txt, then convert it
|
|
||||||
if( roLibListTime > rwGameInfoTime )
|
|
||||||
{
|
{
|
||||||
haveUpdate = FS_ConvertGameInfo( gamedir, gameinfo_path, liblist_ro );
|
// just generate stub gameinfo in memory
|
||||||
}
|
FS_InitGameInfo( GameInfo, gamedir, true, -1 );
|
||||||
// if rodir's gameinfo.txt newer than rwdir's gameinfo.txt, just copy the file
|
GameInfo->rodir = rodir;
|
||||||
else if( roGameInfoTime > rwGameInfoTime )
|
return true;
|
||||||
{
|
|
||||||
file_t *ro, *rw;
|
|
||||||
fs_offset_t ro_size;
|
|
||||||
|
|
||||||
// read & write as binary to copy the exact file
|
|
||||||
ro = FS_SysOpen( gameinfo_ro, "rb" );
|
|
||||||
rw = FS_SysOpen( gameinfo_path, "wb" );
|
|
||||||
|
|
||||||
FS_Seek( ro, 0, SEEK_END );
|
|
||||||
ro_size = FS_Tell( ro );
|
|
||||||
FS_Seek( ro, 0, SEEK_SET );
|
|
||||||
|
|
||||||
FS_FileCopy( rw, ro, ro_size );
|
|
||||||
|
|
||||||
FS_Close( rw );
|
|
||||||
FS_Close( ro );
|
|
||||||
|
|
||||||
haveUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FS_AllowDirectPaths( false );
|
// don't add empty or addon directories
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// do not update gameinfo.txt, if it was just copied from rodir's
|
Q_snprintf( gameinfo_path, sizeof( gameinfo_path ), "%s/gameinfo.txt", gamedir_path );
|
||||||
// if user change liblist.gam update the gameinfo.txt
|
Q_snprintf( liblist_path, sizeof( liblist_path ), "%s/liblist.gam", gamedir_path );
|
||||||
if( !haveUpdate && FS_FileTime( liblist_path, false ) > FS_FileTime( gameinfo_path, false ))
|
|
||||||
FS_ConvertGameInfo( gamedir, gameinfo_path, liblist_path );
|
|
||||||
|
|
||||||
// force to create gameinfo for specified game if missing
|
liblist_mtime = FS_SysFileTime( liblist_path );
|
||||||
if(( FS_CheckForQuakeGameDir( gamedir, false ) || !Q_stricmp( fs_gamedir, gamedir )) && !FS_FileExists( gameinfo_path, false ))
|
gameinfo_mtime = FS_SysFileTime( gameinfo_path );
|
||||||
|
|
||||||
|
// in this function we never write new files for RoDir compatibility
|
||||||
|
// since RoDir is only FWGS feature, do gameinfo.txt conversion only
|
||||||
|
// for RwDir for those who worked with original Xash3D
|
||||||
|
if( !rodir )
|
||||||
{
|
{
|
||||||
gameinfo_t tmpGameInfo;
|
// !!!only if we have both liblist.gam and gameinfo.txt try to convert liblist.gam to gameinfo.txt if it's newer!!!
|
||||||
memset( &tmpGameInfo, 0, sizeof( tmpGameInfo ));
|
if( liblist_mtime >= 0 && gameinfo_mtime >= 0 && liblist_mtime > gameinfo_mtime )
|
||||||
|
|
||||||
if( FS_ReadGameInfo( default_gameinfo_path, gamedir, &tmpGameInfo ))
|
|
||||||
{
|
{
|
||||||
// now we have copy of game info from basedir but needs to change gamedir
|
if( FS_ConvertGameInfo( gamedir, gameinfo_path, liblist_path, GameInfo, liblist_mtime ))
|
||||||
Con_DPrintf( "Convert %s to %s\n", default_gameinfo_path, gameinfo_path );
|
return true;
|
||||||
Q_strncpy( tmpGameInfo.gamefolder, gamedir, sizeof( tmpGameInfo.gamefolder ));
|
|
||||||
FS_WriteGameInfo( gameinfo_path, &tmpGameInfo );
|
|
||||||
}
|
}
|
||||||
else FS_CreateDefaultGameInfo( gameinfo_path );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !GameInfo || !FS_FileExists( gameinfo_path, false ))
|
// can we parse gameinfo.txt?
|
||||||
return false; // no dest
|
if( gameinfo_mtime >= 0 )
|
||||||
|
{
|
||||||
|
if( FS_ReadGameInfo( gameinfo_path, gamedir, GameInfo, gameinfo_mtime ))
|
||||||
|
{
|
||||||
|
GameInfo->rodir = rodir;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return FS_ReadGameInfo( gameinfo_path, gamedir, GameInfo );
|
// can we parse liblist.gam?
|
||||||
|
if( liblist_mtime >= 0 )
|
||||||
|
{
|
||||||
|
if( FS_ParseLiblistGam( liblist_path, gamedir, GameInfo, liblist_mtime ))
|
||||||
|
{
|
||||||
|
GameInfo->rodir = rodir;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1197,7 +1215,7 @@ void FS_AddGameHierarchy( const char *dir, uint flags )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( COM_CheckStringEmpty( fs_rodir ) )
|
if( COM_CheckStringEmpty( fs_rodir ))
|
||||||
{
|
{
|
||||||
// append new flags to rodir, except FS_GAMEDIR_PATH and FS_CUSTOM_PATH
|
// append new flags to rodir, except FS_GAMEDIR_PATH and FS_CUSTOM_PATH
|
||||||
uint new_flags = FS_NOWRITE_PATH | (flags & (~FS_GAMEDIR_PATH|FS_CUSTOM_PATH));
|
uint new_flags = FS_NOWRITE_PATH | (flags & (~FS_GAMEDIR_PATH|FS_CUSTOM_PATH));
|
||||||
@@ -1266,10 +1284,12 @@ void FS_LoadGameInfo( const char *rootfolder )
|
|||||||
// lock uplevel of gamedir for read\write
|
// lock uplevel of gamedir for read\write
|
||||||
FS_AllowDirectPaths( false );
|
FS_AllowDirectPaths( false );
|
||||||
|
|
||||||
if( rootfolder ) Q_strncpy( fs_gamedir, rootfolder, sizeof( fs_gamedir ));
|
if( rootfolder )
|
||||||
|
Q_strncpy( fs_gamedir, rootfolder, sizeof( fs_gamedir ));
|
||||||
|
|
||||||
Con_Reportf( "%s( %s )\n", __func__, fs_gamedir );
|
Con_Reportf( "%s( %s )\n", __func__, fs_gamedir );
|
||||||
|
|
||||||
// clear any old pathes
|
// clear any old paths
|
||||||
FS_ClearSearchPath();
|
FS_ClearSearchPath();
|
||||||
|
|
||||||
// validate gamedir
|
// validate gamedir
|
||||||
@@ -1284,6 +1304,14 @@ void FS_LoadGameInfo( const char *rootfolder )
|
|||||||
|
|
||||||
FI.GameInfo = FI.games[i];
|
FI.GameInfo = FI.games[i];
|
||||||
|
|
||||||
|
if( FI.GameInfo->rodir )
|
||||||
|
{
|
||||||
|
// ensure we have directory in rwdir
|
||||||
|
char buf[MAX_SYSPATH + MAX_QPATH + 2]; // and have plenty of space
|
||||||
|
Q_snprintf( buf, sizeof( buf ), "%s/%s/", fs_rootdir, FI.GameInfo->gamefolder );
|
||||||
|
FS_CreatePath( buf );
|
||||||
|
}
|
||||||
|
|
||||||
FS_Rescan(); // create new filesystem
|
FS_Rescan(); // create new filesystem
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1344,7 +1372,7 @@ static qboolean FS_FindLibrary( const char *dllname, qboolean directpath, fs_dll
|
|||||||
{
|
{
|
||||||
string fixedname;
|
string fixedname;
|
||||||
searchpath_t *search;
|
searchpath_t *search;
|
||||||
int index, start = 0, i, len;
|
int index, start = 0, len;
|
||||||
|
|
||||||
// check for bad exports
|
// check for bad exports
|
||||||
if( !COM_CheckString( dllname ))
|
if( !COM_CheckString( dllname ))
|
||||||
@@ -1479,6 +1507,33 @@ static void *Sys_GetNativeObjectStub( const char *object )
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FS_ValidateDirectories( const char *path, qboolean *has_base_dir, qboolean *has_game_dir )
|
||||||
|
{
|
||||||
|
stringlist_t dirs;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
stringlistinit( &dirs );
|
||||||
|
listdirectory( &dirs, path, true );
|
||||||
|
stringlistsort( &dirs );
|
||||||
|
|
||||||
|
for( i = 0; i < dirs.numstrings; i++ )
|
||||||
|
{
|
||||||
|
if( !FS_SysFolderExists( dirs.strings[i] ))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( !Q_stricmp( fs_basedir, dirs.strings[i] ))
|
||||||
|
*has_base_dir = true;
|
||||||
|
|
||||||
|
if( !Q_stricmp( fs_gamedir, dirs.strings[i] ))
|
||||||
|
*has_game_dir = true;
|
||||||
|
|
||||||
|
if( *has_base_dir && *has_game_dir )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stringlistfreecontents( &dirs );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
FS_Init
|
FS_Init
|
||||||
@@ -1486,11 +1541,9 @@ FS_Init
|
|||||||
*/
|
*/
|
||||||
qboolean FS_InitStdio( qboolean unused_set_to_true, const char *rootdir, const char *basedir, const char *gamedir, const char *rodir )
|
qboolean FS_InitStdio( qboolean unused_set_to_true, const char *rootdir, const char *basedir, const char *gamedir, const char *rodir )
|
||||||
{
|
{
|
||||||
stringlist_t dirs;
|
stringlist_t dirs;
|
||||||
qboolean hasBaseDir = false;
|
int i, rodir_num_games;
|
||||||
qboolean hasGameDir = false;
|
char buf[MAX_SYSPATH];
|
||||||
int i;
|
|
||||||
char buf[MAX_VA_STRING];
|
|
||||||
|
|
||||||
FS_InitMemory();
|
FS_InitMemory();
|
||||||
|
|
||||||
@@ -1503,63 +1556,40 @@ qboolean FS_InitStdio( qboolean unused_set_to_true, const char *rootdir, const c
|
|||||||
Q_strncpy( fs_basedir, basedir, sizeof( fs_basedir ));
|
Q_strncpy( fs_basedir, basedir, sizeof( fs_basedir ));
|
||||||
Q_strncpy( fs_rodir, rodir, sizeof( fs_rodir ));
|
Q_strncpy( fs_rodir, rodir, sizeof( fs_rodir ));
|
||||||
|
|
||||||
// add readonly directories first
|
// validate user input
|
||||||
if( COM_CheckStringEmpty( fs_rodir ))
|
if( COM_CheckStringEmpty( fs_rodir ) && !Q_stricmp( fs_rodir, fs_rootdir ))
|
||||||
{
|
{
|
||||||
if( !Q_stricmp( fs_rodir, fs_rootdir ))
|
Sys_Error( "RoDir and default rootdir can't point to same directory!" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for game directories in RwDir first
|
||||||
|
// this whole check only required to fallback to base directory
|
||||||
|
// (i.e. default game directory hardcoded in the executable file)
|
||||||
|
{
|
||||||
|
qboolean has_base_dir = false;
|
||||||
|
qboolean has_game_dir = false;
|
||||||
|
|
||||||
|
FS_ValidateDirectories( "./", &has_base_dir, &has_game_dir );
|
||||||
|
|
||||||
|
if( !has_game_dir )
|
||||||
{
|
{
|
||||||
Sys_Error( "RoDir and default rootdir can't point to same directory!" );
|
// look for game directories in RoDir now
|
||||||
return false;
|
if( COM_CheckStringEmpty( fs_rodir ))
|
||||||
}
|
FS_ValidateDirectories( fs_rodir, &has_base_dir, &has_game_dir );
|
||||||
|
|
||||||
stringlistinit( &dirs );
|
if( !has_game_dir )
|
||||||
listdirectory( &dirs, fs_rodir );
|
|
||||||
stringlistsort( &dirs );
|
|
||||||
|
|
||||||
for( i = 0; i < dirs.numstrings; i++ )
|
|
||||||
{
|
|
||||||
char roPath[MAX_SYSPATH];
|
|
||||||
|
|
||||||
Q_snprintf( roPath, sizeof( roPath ), "%s/%s/", fs_rodir, dirs.strings[i] );
|
|
||||||
|
|
||||||
// check if it's a directory
|
|
||||||
if( !FS_SysFolderExists( roPath ))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// check if it's gamedir
|
|
||||||
if( FS_CheckForXashGameDir( roPath, true ) || FS_CheckForQuakeGameDir( roPath, true ))
|
|
||||||
{
|
{
|
||||||
char rwPath[MAX_SYSPATH];
|
Con_Printf( S_ERROR "game directory \"%s\" not exist\n", fs_gamedir );
|
||||||
|
|
||||||
Q_snprintf( rwPath, sizeof( rwPath ), "%s/%s/", fs_rootdir, dirs.strings[i] );
|
// revert to base game directory
|
||||||
FS_CreatePath( rwPath );
|
if( has_base_dir )
|
||||||
|
Q_strncpy( fs_gamedir, fs_basedir, sizeof( fs_gamedir ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stringlistfreecontents( &dirs );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate directories
|
// now start building first level of directory hierarchy
|
||||||
stringlistinit( &dirs );
|
|
||||||
listdirectory( &dirs, "./" );
|
|
||||||
stringlistsort( &dirs );
|
|
||||||
|
|
||||||
for( i = 0; i < dirs.numstrings; i++ )
|
|
||||||
{
|
|
||||||
if( !Q_stricmp( fs_basedir, dirs.strings[i] ))
|
|
||||||
hasBaseDir = true;
|
|
||||||
|
|
||||||
if( !Q_stricmp( fs_gamedir, dirs.strings[i] ))
|
|
||||||
hasGameDir = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !hasGameDir )
|
|
||||||
{
|
|
||||||
Con_Printf( S_ERROR "game directory \"%s\" not exist\n", fs_gamedir );
|
|
||||||
if( hasBaseDir ) Q_strncpy( fs_gamedir, fs_basedir, sizeof( fs_gamedir ));
|
|
||||||
}
|
|
||||||
|
|
||||||
// build list of game directories here
|
|
||||||
if( COM_CheckStringEmpty( fs_rodir ))
|
if( COM_CheckStringEmpty( fs_rodir ))
|
||||||
{
|
{
|
||||||
Q_snprintf( buf, sizeof( buf ), "%s/", fs_rodir );
|
Q_snprintf( buf, sizeof( buf ), "%s/", fs_rodir );
|
||||||
@@ -1567,15 +1597,62 @@ qboolean FS_InitStdio( qboolean unused_set_to_true, const char *rootdir, const c
|
|||||||
}
|
}
|
||||||
FS_AddGameDirectory( "./", FS_STATIC_PATH );
|
FS_AddGameDirectory( "./", FS_STATIC_PATH );
|
||||||
|
|
||||||
|
// but scan rodir for games first
|
||||||
|
if( COM_CheckStringEmpty( fs_rodir ))
|
||||||
|
{
|
||||||
|
stringlistinit( &dirs );
|
||||||
|
listdirectory( &dirs, fs_rodir, true );
|
||||||
|
stringlistsort( &dirs );
|
||||||
|
|
||||||
|
for( i = 0; i < dirs.numstrings; i++ )
|
||||||
|
{
|
||||||
|
if( !FS_SysFolderExists( dirs.strings[i] ))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( FI.games[FI.numgames] == NULL )
|
||||||
|
FI.games[FI.numgames] = Mem_Malloc( fs_mempool, sizeof( *FI.games[FI.numgames] ));
|
||||||
|
|
||||||
|
if( FS_ParseGameInfo( dirs.strings[i], FI.games[FI.numgames], true ))
|
||||||
|
FI.numgames++;
|
||||||
|
}
|
||||||
|
|
||||||
|
stringlistfreecontents( &dirs );
|
||||||
|
}
|
||||||
|
|
||||||
|
rodir_num_games = FI.numgames;
|
||||||
|
|
||||||
|
stringlistinit( &dirs );
|
||||||
|
listdirectory( &dirs, "./", true );
|
||||||
|
stringlistsort( &dirs );
|
||||||
|
|
||||||
for( i = 0; i < dirs.numstrings; i++ )
|
for( i = 0; i < dirs.numstrings; i++ )
|
||||||
{
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
if( !FS_SysFolderExists( dirs.strings[i] ))
|
if( !FS_SysFolderExists( dirs.strings[i] ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( FI.games[FI.numgames] == NULL )
|
// update gameinfo from rwdir, if it's newer
|
||||||
FI.games[FI.numgames] = (gameinfo_t *)Mem_Calloc( fs_mempool, sizeof( gameinfo_t ));
|
// with rodir we should never create new gameinfos anymore,
|
||||||
|
// so this only catches possible user changes
|
||||||
|
for( j = 0; j < rodir_num_games; j++ )
|
||||||
|
{
|
||||||
|
if( !Q_stricmp( dirs.strings[i], FI.games[j]->gamefolder ))
|
||||||
|
{
|
||||||
|
gameinfo_t gi;
|
||||||
|
if( FS_ParseGameInfo( dirs.strings[i], &gi, false ))
|
||||||
|
{
|
||||||
|
if( gi.mtime > FI.games[j]->mtime )
|
||||||
|
*FI.games[j] = gi;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( FS_ParseGameInfo( dirs.strings[i], FI.games[FI.numgames] ))
|
if( FI.games[FI.numgames] == NULL )
|
||||||
|
FI.games[FI.numgames] = Mem_Calloc( fs_mempool, sizeof( *FI.games[FI.numgames] ));
|
||||||
|
|
||||||
|
if( FS_ParseGameInfo( dirs.strings[i], FI.games[FI.numgames], false ))
|
||||||
FI.numgames++; // added
|
FI.numgames++; // added
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3187,6 +3264,8 @@ const fs_api_t g_api =
|
|||||||
FS_LoadFileFromArchive,
|
FS_LoadFileFromArchive,
|
||||||
|
|
||||||
FS_GetRootDirectory,
|
FS_GetRootDirectory,
|
||||||
|
|
||||||
|
FS_MakeGameInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
int EXPORT GetFSAPI( int version, fs_api_t *api, fs_globals_t **globals, fs_interface_t *engfuncs );
|
int EXPORT GetFSAPI( int version, fs_api_t *api, fs_globals_t **globals, fs_interface_t *engfuncs );
|
||||||
|
|||||||
@@ -123,6 +123,9 @@ typedef struct gameinfo_s
|
|||||||
qboolean animated_title;
|
qboolean animated_title;
|
||||||
|
|
||||||
char demomap[MAX_QPATH];
|
char demomap[MAX_QPATH];
|
||||||
|
|
||||||
|
qboolean rodir; // if true, parsed from rodir
|
||||||
|
int64_t mtime;
|
||||||
} gameinfo_t;
|
} gameinfo_t;
|
||||||
|
|
||||||
typedef struct fs_dllinfo_t
|
typedef struct fs_dllinfo_t
|
||||||
@@ -226,6 +229,8 @@ typedef struct fs_api_t
|
|||||||
|
|
||||||
// gets current root directory, set by InitStdio
|
// gets current root directory, set by InitStdio
|
||||||
qboolean (*GetRootDirectory)( char *path, size_t size );
|
qboolean (*GetRootDirectory)( char *path, size_t size );
|
||||||
|
|
||||||
|
void (*MakeGameInfo)( void );
|
||||||
} fs_api_t;
|
} fs_api_t;
|
||||||
|
|
||||||
typedef struct fs_interface_t
|
typedef struct fs_interface_t
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ void stringlistinit( stringlist_t *list );
|
|||||||
void stringlistfreecontents( stringlist_t *list );
|
void stringlistfreecontents( stringlist_t *list );
|
||||||
void stringlistappend( stringlist_t *list, const char *text );
|
void stringlistappend( stringlist_t *list, const char *text );
|
||||||
void stringlistsort( stringlist_t *list );
|
void stringlistsort( stringlist_t *list );
|
||||||
void listdirectory( stringlist_t *list, const char *path );
|
void listdirectory( stringlist_t *list, const char *path, qboolean dirs_only );
|
||||||
|
|
||||||
// filesystem ops
|
// filesystem ops
|
||||||
int FS_FileExists( const char *filename, int gamedironly );
|
int FS_FileExists( const char *filename, int gamedironly );
|
||||||
@@ -230,6 +230,7 @@ qboolean FS_FullPathToRelativePath( char *dst, const char *src, size_t size );
|
|||||||
//
|
//
|
||||||
// pak.c
|
// pak.c
|
||||||
//
|
//
|
||||||
|
qboolean FS_CheckForQuakePak( const char *pakfile, const char *files[], size_t num_files );
|
||||||
searchpath_t *FS_AddPak_Fullpath( const char *pakfile, int flags );
|
searchpath_t *FS_AddPak_Fullpath( const char *pakfile, int flags );
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -105,6 +105,8 @@ static pack_t *FS_LoadPackPAK( const char *packfile, int *error )
|
|||||||
|
|
||||||
// TODO: use FS_Open to allow PK3 to be included into other archives
|
// TODO: use FS_Open to allow PK3 to be included into other archives
|
||||||
// Currently, it doesn't work with rodir due to FS_FindFile logic
|
// Currently, it doesn't work with rodir due to FS_FindFile logic
|
||||||
|
// when it will use FS_Open, check that FS_CheckForQuakePak correctly
|
||||||
|
// detects Quake gamedirs in RoDir
|
||||||
packhandle = FS_SysOpen( packfile, "rb" );
|
packhandle = FS_SysOpen( packfile, "rb" );
|
||||||
|
|
||||||
if( packhandle == NULL )
|
if( packhandle == NULL )
|
||||||
@@ -364,3 +366,45 @@ searchpath_t *FS_AddPak_Fullpath( const char *pakfile, int flags )
|
|||||||
|
|
||||||
return search;
|
return search;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
FS_CheckForQuakePak
|
||||||
|
|
||||||
|
To generate fake gameinfo for Quake directory, we need to parse pak0.pak
|
||||||
|
and find progs.dat in it
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
qboolean FS_CheckForQuakePak( const char *pakfile, const char *files[], size_t num_files )
|
||||||
|
{
|
||||||
|
qboolean is_quake = false;
|
||||||
|
pack_t *pak;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
pak = FS_LoadPackPAK( pakfile, NULL );
|
||||||
|
if( !pak )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for( i = 0; i < num_files; i++ )
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for( j = 0; j < pak->numfiles; j++ )
|
||||||
|
{
|
||||||
|
if( Q_strchr( pak->files[j].name, '/' ))
|
||||||
|
continue; // exclude subdirectories
|
||||||
|
|
||||||
|
if( !Q_stricmp( pak->files[j].name, files[i] ))
|
||||||
|
{
|
||||||
|
is_quake = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( is_quake )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mem_Free( pak );
|
||||||
|
return is_quake;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ MEMFD_CREATE_TEST = '''#define _GNU_SOURCE
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
int main(int argc, char **argv) { return memfd_create(argv[0], 0); }'''
|
int main(int argc, char **argv) { return memfd_create(argv[0], 0); }'''
|
||||||
|
|
||||||
|
DIRENT_D_TYPE_TEST = '''#define _GNU_SOURCE
|
||||||
|
#include <dirent.h>
|
||||||
|
int main(int argc, char **argv) { struct dirent entry; entry.d_type = DT_DIR; return 0; }
|
||||||
|
'''
|
||||||
|
|
||||||
def options(opt):
|
def options(opt):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -18,6 +23,9 @@ def configure(conf):
|
|||||||
if conf.check_cc(fragment=MEMFD_CREATE_TEST, msg='Checking for memfd_create', mandatory=False):
|
if conf.check_cc(fragment=MEMFD_CREATE_TEST, msg='Checking for memfd_create', mandatory=False):
|
||||||
conf.define('HAVE_MEMFD_CREATE', 1)
|
conf.define('HAVE_MEMFD_CREATE', 1)
|
||||||
|
|
||||||
|
if conf.check_cc(fragment=DIRENT_D_TYPE_TEST, msg='Checking for d_type field in struct dirent', mandatory=False):
|
||||||
|
conf.define('HAVE_DIRENT_D_TYPE', 1)
|
||||||
|
|
||||||
def build(bld):
|
def build(bld):
|
||||||
bld(name = 'filesystem_includes', export_includes = '.')
|
bld(name = 'filesystem_includes', export_includes = '.')
|
||||||
|
|
||||||
|
|||||||
@@ -670,10 +670,14 @@ static void R_DecalNodeSurfaces( model_t *model, mnode_t *node, decalinfo_t *dec
|
|||||||
// iterate over all surfaces in the node
|
// iterate over all surfaces in the node
|
||||||
msurface_t *surf;
|
msurface_t *surf;
|
||||||
int i;
|
int i;
|
||||||
|
int firstsurface, numsurfaces;
|
||||||
|
|
||||||
surf = model->surfaces + node->firstsurface;
|
firstsurface = node_firstsurface( node, model );
|
||||||
|
numsurfaces = node_numsurfaces( node, model );
|
||||||
|
|
||||||
for( i = 0; i < node->numsurfaces; i++, surf++ )
|
surf = model->surfaces + firstsurface;
|
||||||
|
|
||||||
|
for( i = 0; i < numsurfaces; i++, surf++ )
|
||||||
{
|
{
|
||||||
// never apply decals on the water or sky surfaces
|
// never apply decals on the water or sky surfaces
|
||||||
if( surf->flags & (SURF_DRAWTURB|SURF_DRAWSKY|SURF_CONVEYOR))
|
if( surf->flags & (SURF_DRAWTURB|SURF_DRAWSKY|SURF_CONVEYOR))
|
||||||
@@ -695,6 +699,7 @@ static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo )
|
|||||||
{
|
{
|
||||||
mplane_t *splitplane;
|
mplane_t *splitplane;
|
||||||
float dist;
|
float dist;
|
||||||
|
mnode_t *children[2];
|
||||||
|
|
||||||
Assert( node != NULL );
|
Assert( node != NULL );
|
||||||
|
|
||||||
@@ -706,6 +711,7 @@ static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo )
|
|||||||
|
|
||||||
splitplane = node->plane;
|
splitplane = node->plane;
|
||||||
dist = DotProduct( decalinfo->m_Position, splitplane->normal ) - splitplane->dist;
|
dist = DotProduct( decalinfo->m_Position, splitplane->normal ) - splitplane->dist;
|
||||||
|
node_children( children, node, model );
|
||||||
|
|
||||||
// This is arbitrarily set to 10 right now. In an ideal world we'd have the
|
// This is arbitrarily set to 10 right now. In an ideal world we'd have the
|
||||||
// exact surface but we don't so, this tells me which planes are "sort of
|
// exact surface but we don't so, this tells me which planes are "sort of
|
||||||
@@ -717,19 +723,19 @@ static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo )
|
|||||||
// have a surface normal
|
// have a surface normal
|
||||||
if( dist > decalinfo->m_Size )
|
if( dist > decalinfo->m_Size )
|
||||||
{
|
{
|
||||||
R_DecalNode( model, node->children[0], decalinfo );
|
R_DecalNode( model, children[0], decalinfo );
|
||||||
}
|
}
|
||||||
else if( dist < -decalinfo->m_Size )
|
else if( dist < -decalinfo->m_Size )
|
||||||
{
|
{
|
||||||
R_DecalNode( model, node->children[1], decalinfo );
|
R_DecalNode( model, children[1], decalinfo );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( dist < DECAL_DISTANCE && dist > -DECAL_DISTANCE )
|
if( dist < DECAL_DISTANCE && dist > -DECAL_DISTANCE )
|
||||||
R_DecalNodeSurfaces( model, node, decalinfo );
|
R_DecalNodeSurfaces( model, node, decalinfo );
|
||||||
|
|
||||||
R_DecalNode( model, node->children[0], decalinfo );
|
R_DecalNode( model, children[0], decalinfo );
|
||||||
R_DecalNode( model, node->children[1], decalinfo );
|
R_DecalNode( model, children[1], decalinfo );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,27 +104,33 @@ void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
|
|||||||
float dist;
|
float dist;
|
||||||
msurface_t *surf;
|
msurface_t *surf;
|
||||||
int i;
|
int i;
|
||||||
|
mnode_t *children[2];
|
||||||
|
int firstsurface, numsurfaces;
|
||||||
|
|
||||||
if( !node || node->contents < 0 )
|
if( !node || node->contents < 0 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dist = PlaneDiff( light->origin, node->plane );
|
dist = PlaneDiff( light->origin, node->plane );
|
||||||
|
|
||||||
|
node_children( children, node, RI.currentmodel );
|
||||||
|
firstsurface = node_firstsurface( node, RI.currentmodel );
|
||||||
|
numsurfaces = node_numsurfaces( node, RI.currentmodel );
|
||||||
|
|
||||||
if( dist > light->radius )
|
if( dist > light->radius )
|
||||||
{
|
{
|
||||||
R_MarkLights( light, bit, node->children[0] );
|
R_MarkLights( light, bit, children[0] );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if( dist < -light->radius )
|
if( dist < -light->radius )
|
||||||
{
|
{
|
||||||
R_MarkLights( light, bit, node->children[1] );
|
R_MarkLights( light, bit, children[1] );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark the polygons
|
// mark the polygons
|
||||||
surf = RI.currentmodel->surfaces + node->firstsurface;
|
surf = RI.currentmodel->surfaces + firstsurface;
|
||||||
|
|
||||||
for( i = 0; i < node->numsurfaces; i++, surf++ )
|
for( i = 0; i < numsurfaces; i++, surf++ )
|
||||||
{
|
{
|
||||||
if( !BoundsAndSphereIntersect( surf->info->mins, surf->info->maxs, light->origin, light->radius ))
|
if( !BoundsAndSphereIntersect( surf->info->mins, surf->info->maxs, light->origin, light->radius ))
|
||||||
continue; // no intersection
|
continue; // no intersection
|
||||||
@@ -137,8 +143,8 @@ void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
|
|||||||
surf->dlightbits |= bit;
|
surf->dlightbits |= bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
R_MarkLights( light, bit, node->children[0] );
|
R_MarkLights( light, bit, children[0] );
|
||||||
R_MarkLights( light, bit, node->children[1] );
|
R_MarkLights( light, bit, children[1] );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -202,6 +208,8 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
|
|||||||
mtexinfo_t *tex;
|
mtexinfo_t *tex;
|
||||||
matrix3x4 tbn;
|
matrix3x4 tbn;
|
||||||
vec3_t mid;
|
vec3_t mid;
|
||||||
|
mnode_t *children[2];
|
||||||
|
int firstsurface, numsurfaces;
|
||||||
|
|
||||||
// didn't hit anything
|
// didn't hit anything
|
||||||
if( !node || node->contents < 0 )
|
if( !node || node->contents < 0 )
|
||||||
@@ -210,13 +218,17 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node_children( children, node, model );
|
||||||
|
firstsurface = node_firstsurface( node, model );
|
||||||
|
numsurfaces = node_numsurfaces( node, model );
|
||||||
|
|
||||||
// calculate mid point
|
// calculate mid point
|
||||||
front = PlaneDiff( start, node->plane );
|
front = PlaneDiff( start, node->plane );
|
||||||
back = PlaneDiff( end, node->plane );
|
back = PlaneDiff( end, node->plane );
|
||||||
|
|
||||||
side = front < 0;
|
side = front < 0;
|
||||||
if(( back < 0 ) == side )
|
if(( back < 0 ) == side )
|
||||||
return R_RecursiveLightPoint( model, node->children[side], p1f, p2f, cv, start, end );
|
return R_RecursiveLightPoint( model, children[side], p1f, p2f, cv, start, end );
|
||||||
|
|
||||||
frac = front / ( front - back );
|
frac = front / ( front - back );
|
||||||
|
|
||||||
@@ -224,7 +236,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
|
|||||||
midf = p1f + ( p2f - p1f ) * frac;
|
midf = p1f + ( p2f - p1f ) * frac;
|
||||||
|
|
||||||
// co down front side
|
// co down front side
|
||||||
if( R_RecursiveLightPoint( model, node->children[side], p1f, midf, cv, start, mid ))
|
if( R_RecursiveLightPoint( model, children[side], p1f, midf, cv, start, mid ))
|
||||||
return true; // hit something
|
return true; // hit something
|
||||||
|
|
||||||
if(( back < 0 ) == side )
|
if(( back < 0 ) == side )
|
||||||
@@ -234,10 +246,10 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for impact on this node
|
// check for impact on this node
|
||||||
surf = model->surfaces + node->firstsurface;
|
surf = model->surfaces + firstsurface;
|
||||||
VectorCopy( mid, g_trace_lightspot );
|
VectorCopy( mid, g_trace_lightspot );
|
||||||
|
|
||||||
for( i = 0; i < node->numsurfaces; i++, surf++ )
|
for( i = 0; i < numsurfaces; i++, surf++ )
|
||||||
{
|
{
|
||||||
int smax, tmax;
|
int smax, tmax;
|
||||||
|
|
||||||
@@ -326,7 +338,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// go down back side
|
// go down back side
|
||||||
return R_RecursiveLightPoint( model, node->children[!side], midf, p2f, cv, mid, end );
|
return R_RecursiveLightPoint( model, children[!side], midf, p2f, cv, mid, end );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -600,6 +600,7 @@ watertexture to grab fog values from it
|
|||||||
static gl_texture_t *R_RecursiveFindWaterTexture( const mnode_t *node, const mnode_t *ignore, qboolean down )
|
static gl_texture_t *R_RecursiveFindWaterTexture( const mnode_t *node, const mnode_t *ignore, qboolean down )
|
||||||
{
|
{
|
||||||
gl_texture_t *tex = NULL;
|
gl_texture_t *tex = NULL;
|
||||||
|
mnode_t *children[2];
|
||||||
|
|
||||||
// assure the initial node is not null
|
// assure the initial node is not null
|
||||||
// we could check it here, but we would rather check it
|
// we could check it here, but we would rather check it
|
||||||
@@ -637,15 +638,17 @@ static gl_texture_t *R_RecursiveFindWaterTexture( const mnode_t *node, const mno
|
|||||||
|
|
||||||
// this is a regular node
|
// this is a regular node
|
||||||
// traverse children
|
// traverse children
|
||||||
if( node->children[0] && ( node->children[0] != ignore ))
|
node_children( children, node, WORLDMODEL );
|
||||||
|
|
||||||
|
if( children[0] && ( children[0] != ignore ))
|
||||||
{
|
{
|
||||||
tex = R_RecursiveFindWaterTexture( node->children[0], node, true );
|
tex = R_RecursiveFindWaterTexture( children[0], node, true );
|
||||||
if( tex ) return tex;
|
if( tex ) return tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( node->children[1] && ( node->children[1] != ignore ))
|
if( children[1] && ( children[1] != ignore ))
|
||||||
{
|
{
|
||||||
tex = R_RecursiveFindWaterTexture( node->children[1], node, true );
|
tex = R_RecursiveFindWaterTexture( children[1], node, true );
|
||||||
if( tex ) return tex;
|
if( tex ) return tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,12 +125,25 @@ static void R_TextureCoord( const vec3_t v, const msurface_t *surf, vec2_t coord
|
|||||||
static void R_GetEdgePosition( const model_t *mod, const msurface_t *fa, int i, vec3_t vec )
|
static void R_GetEdgePosition( const model_t *mod, const msurface_t *fa, int i, vec3_t vec )
|
||||||
{
|
{
|
||||||
const int lindex = mod->surfedges[fa->firstedge + i];
|
const int lindex = mod->surfedges[fa->firstedge + i];
|
||||||
const medge_t *pedges = mod->edges;
|
|
||||||
|
|
||||||
if( lindex > 0 )
|
if( FBitSet( mod->flags, MODEL_QBSP2 ))
|
||||||
VectorCopy( mod->vertexes[pedges[lindex].v[0]].position, vec );
|
{
|
||||||
|
const medge32_t *pedges = mod->edges32;
|
||||||
|
|
||||||
|
if( lindex > 0 )
|
||||||
|
VectorCopy( mod->vertexes[pedges[lindex].v[0]].position, vec );
|
||||||
|
else
|
||||||
|
VectorCopy( mod->vertexes[pedges[-lindex].v[1]].position, vec );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
VectorCopy( mod->vertexes[pedges[-lindex].v[1]].position, vec );
|
{
|
||||||
|
const medge16_t *pedges = mod->edges16;
|
||||||
|
|
||||||
|
if( lindex > 0 )
|
||||||
|
VectorCopy( mod->vertexes[pedges[lindex].v[0]].position, vec );
|
||||||
|
else
|
||||||
|
VectorCopy( mod->vertexes[pedges[-lindex].v[1]].position, vec );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void BoundPoly( int numverts, float *verts, vec3_t mins, vec3_t maxs )
|
static void BoundPoly( int numverts, float *verts, vec3_t mins, vec3_t maxs )
|
||||||
@@ -3306,6 +3319,9 @@ static void R_RecursiveWorldNode( mnode_t *node, uint clipflags )
|
|||||||
mleaf_t *pleaf;
|
mleaf_t *pleaf;
|
||||||
int c, side;
|
int c, side;
|
||||||
float dot;
|
float dot;
|
||||||
|
mnode_t *children[2];
|
||||||
|
int numsurfaces, firstsurface;
|
||||||
|
|
||||||
loc0:
|
loc0:
|
||||||
if( node->contents == CONTENTS_SOLID )
|
if( node->contents == CONTENTS_SOLID )
|
||||||
return; // hit a solid leaf
|
return; // hit a solid leaf
|
||||||
@@ -3360,10 +3376,14 @@ loc0:
|
|||||||
side = (dot >= 0.0f) ? 0 : 1;
|
side = (dot >= 0.0f) ? 0 : 1;
|
||||||
|
|
||||||
// recurse down the children, front side first
|
// recurse down the children, front side first
|
||||||
R_RecursiveWorldNode( node->children[side], clipflags );
|
node_children( children, node, WORLDMODEL );
|
||||||
|
R_RecursiveWorldNode( children[side], clipflags );
|
||||||
|
|
||||||
|
firstsurface = node_firstsurface( node, WORLDMODEL );
|
||||||
|
numsurfaces = node_numsurfaces( node, WORLDMODEL );
|
||||||
|
|
||||||
// draw stuff
|
// draw stuff
|
||||||
for( c = node->numsurfaces, surf = WORLDMODEL->surfaces + node->firstsurface; c; c--, surf++ )
|
for( c = numsurfaces, surf = WORLDMODEL->surfaces + firstsurface; c; c--, surf++ )
|
||||||
{
|
{
|
||||||
if( R_CullSurface( surf, &RI.frustum, clipflags ))
|
if( R_CullSurface( surf, &RI.frustum, clipflags ))
|
||||||
continue;
|
continue;
|
||||||
@@ -3382,7 +3402,7 @@ loc0:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// recurse down the back side
|
// recurse down the back side
|
||||||
node = node->children[!side];
|
node = children[!side];
|
||||||
goto loc0;
|
goto loc0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3458,6 +3478,9 @@ static void R_DrawWorldTopView( mnode_t *node, uint clipflags )
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
mnode_t *children[2];
|
||||||
|
int numsurfaces, firstsurface;
|
||||||
|
|
||||||
if( node->contents == CONTENTS_SOLID )
|
if( node->contents == CONTENTS_SOLID )
|
||||||
return; // hit a solid leaf
|
return; // hit a solid leaf
|
||||||
|
|
||||||
@@ -3491,7 +3514,10 @@ static void R_DrawWorldTopView( mnode_t *node, uint clipflags )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// draw stuff
|
// draw stuff
|
||||||
for( c = node->numsurfaces, surf = WORLDMODEL->surfaces + node->firstsurface; c; c--, surf++ )
|
numsurfaces = node_numsurfaces( node, WORLDMODEL );
|
||||||
|
firstsurface = node_firstsurface( node, WORLDMODEL );
|
||||||
|
|
||||||
|
for( c = numsurfaces, surf = WORLDMODEL->surfaces + firstsurface; c; c--, surf++ )
|
||||||
{
|
{
|
||||||
// don't process the same surface twice
|
// don't process the same surface twice
|
||||||
if( surf->visframe == tr.framecount )
|
if( surf->visframe == tr.framecount )
|
||||||
@@ -3510,9 +3536,9 @@ static void R_DrawWorldTopView( mnode_t *node, uint clipflags )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// recurse down both children, we don't care the order...
|
// recurse down both children, we don't care the order...
|
||||||
R_DrawWorldTopView( node->children[0], clipflags );
|
node_children( children, node, WORLDMODEL );
|
||||||
node = node->children[1];
|
R_DrawWorldTopView( children[0], clipflags );
|
||||||
|
node = children[1];
|
||||||
} while( node );
|
} while( node );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ void R_RotateBmodel( void )
|
|||||||
R_RecursiveClipBPoly
|
R_RecursiveClipBPoly
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
static void R_RecursiveClipBPoly( bedge_t *pedges, mnode_t *pnode, msurface_t *psurf )
|
static void R_RecursiveClipBPoly( model_t *mod, bedge_t *pedges, mnode_t *pnode, msurface_t *psurf )
|
||||||
{
|
{
|
||||||
bedge_t *psideedges[2], *pnextedge, *ptedge;
|
bedge_t *psideedges[2], *pnextedge, *ptedge;
|
||||||
int i, side, lastside;
|
int i, side, lastside;
|
||||||
@@ -316,7 +316,7 @@ static void R_RecursiveClipBPoly( bedge_t *pedges, mnode_t *pnode, msurface_t *p
|
|||||||
{
|
{
|
||||||
// draw if we've reached a non-solid leaf, done if all that's left is a
|
// draw if we've reached a non-solid leaf, done if all that's left is a
|
||||||
// solid leaf, and continue down the tree if it's not a leaf
|
// solid leaf, and continue down the tree if it's not a leaf
|
||||||
pn = pnode->children[i];
|
pn = node_child( pnode, i, mod );
|
||||||
|
|
||||||
// we're done with this branch if the node or leaf isn't in the PVS
|
// we're done with this branch if the node or leaf isn't in the PVS
|
||||||
if( pn->visframe == tr.visframecount )
|
if( pn->visframe == tr.visframecount )
|
||||||
@@ -332,8 +332,7 @@ static void R_RecursiveClipBPoly( bedge_t *pedges, mnode_t *pnode, msurface_t *p
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
R_RecursiveClipBPoly( psideedges[i], pnode->children[i],
|
R_RecursiveClipBPoly( mod, psideedges[i], pn, psurf );
|
||||||
psurf );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,13 +355,13 @@ void R_DrawSolidClippedSubmodelPolygons( model_t *pmodel, mnode_t *topnode )
|
|||||||
mplane_t *pplane;
|
mplane_t *pplane;
|
||||||
mvertex_t bverts[MAX_BMODEL_VERTS];
|
mvertex_t bverts[MAX_BMODEL_VERTS];
|
||||||
bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
|
bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
|
||||||
medge_t *pedge, *pedges;
|
medge16_t *pedge, *pedges;
|
||||||
|
|
||||||
// FIXME: use bounding-box-based frustum clipping info?
|
// FIXME: use bounding-box-based frustum clipping info?
|
||||||
|
|
||||||
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
|
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
|
||||||
numsurfaces = pmodel->nummodelsurfaces;
|
numsurfaces = pmodel->nummodelsurfaces;
|
||||||
pedges = pmodel->edges;
|
pedges = pmodel->edges16;
|
||||||
|
|
||||||
for( i = 0; i < numsurfaces; i++, psurf++ )
|
for( i = 0; i < numsurfaces; i++, psurf++ )
|
||||||
{
|
{
|
||||||
@@ -419,7 +418,7 @@ void R_DrawSolidClippedSubmodelPolygons( model_t *pmodel, mnode_t *topnode )
|
|||||||
pbedge[j - 1].pnext = NULL; // mark end of edges
|
pbedge[j - 1].pnext = NULL; // mark end of edges
|
||||||
|
|
||||||
// if ( !( psurf->texinfo->flags & ( SURF_TRANS66 | SURF_TRANS33 ) ) )
|
// if ( !( psurf->texinfo->flags & ( SURF_TRANS66 | SURF_TRANS33 ) ) )
|
||||||
R_RecursiveClipBPoly( pbedge, topnode, psurf );
|
R_RecursiveClipBPoly( pmodel, pbedge, topnode, psurf );
|
||||||
// else
|
// else
|
||||||
// R_RenderBmodelFace( pbedge, psurf );
|
// R_RenderBmodelFace( pbedge, psurf );
|
||||||
}
|
}
|
||||||
@@ -566,6 +565,9 @@ static void R_RecursiveWorldNode( mnode_t *node, int clipflags )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
mnode_t *children[2];
|
||||||
|
int firstsurface;
|
||||||
|
|
||||||
// node is just a decision point, so go down the apropriate sides
|
// node is just a decision point, so go down the apropriate sides
|
||||||
|
|
||||||
// find which side of the node we are on
|
// find which side of the node we are on
|
||||||
@@ -593,14 +595,16 @@ static void R_RecursiveWorldNode( mnode_t *node, int clipflags )
|
|||||||
side = 1;
|
side = 1;
|
||||||
|
|
||||||
// recurse down the children, front side first
|
// recurse down the children, front side first
|
||||||
R_RecursiveWorldNode( node->children[side], clipflags );
|
node_children( children, node, WORLDMODEL );
|
||||||
|
R_RecursiveWorldNode( children[side], clipflags );
|
||||||
|
|
||||||
// draw stuff
|
// draw stuff
|
||||||
c = node->numsurfaces;
|
c = node_numsurfaces( node, WORLDMODEL );
|
||||||
|
firstsurface = node_firstsurface( node, WORLDMODEL );
|
||||||
|
|
||||||
if( c )
|
if( c )
|
||||||
{
|
{
|
||||||
surf = WORLDMODEL->surfaces + node->firstsurface;
|
surf = WORLDMODEL->surfaces + firstsurface;
|
||||||
|
|
||||||
if( dot < -BACKFACE_EPSILON )
|
if( dot < -BACKFACE_EPSILON )
|
||||||
{
|
{
|
||||||
@@ -636,7 +640,7 @@ static void R_RecursiveWorldNode( mnode_t *node, int clipflags )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// recurse down the back side
|
// recurse down the back side
|
||||||
R_RecursiveWorldNode( node->children[!side], clipflags );
|
R_RecursiveWorldNode( children[!side], clipflags );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -679,23 +679,24 @@ static void R_DecalSurface( msurface_t *surf, decalinfo_t *decalinfo )
|
|||||||
static void R_DecalNodeSurfaces( model_t *model, mnode_t *node, decalinfo_t *decalinfo )
|
static void R_DecalNodeSurfaces( model_t *model, mnode_t *node, decalinfo_t *decalinfo )
|
||||||
{
|
{
|
||||||
// iterate over all surfaces in the node
|
// iterate over all surfaces in the node
|
||||||
msurface_t *surf;
|
msurface_t *surf;
|
||||||
int i;
|
int i;
|
||||||
|
int firstsurface, numsurfaces;
|
||||||
|
|
||||||
surf = model->surfaces + node->firstsurface;
|
firstsurface = node_firstsurface( node, model );
|
||||||
|
numsurfaces = node_numsurfaces( node, model );
|
||||||
|
|
||||||
for( i = 0; i < node->numsurfaces; i++, surf++ )
|
surf = model->surfaces + firstsurface;
|
||||||
|
|
||||||
|
for( i = 0; i < numsurfaces; i++, surf++ )
|
||||||
{
|
{
|
||||||
// never apply decals on the water or sky surfaces
|
// never apply decals on the water or sky surfaces
|
||||||
if( surf->flags & ( SURF_DRAWTURB | SURF_DRAWSKY | SURF_CONVEYOR ))
|
if( surf->flags & (SURF_DRAWTURB|SURF_DRAWSKY|SURF_CONVEYOR))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// we can implement alpha testing without stencil
|
|
||||||
// if( surf->flags & SURF_TRANSPARENT && !glState.stencilEnabled )
|
|
||||||
// continue;
|
|
||||||
|
|
||||||
R_DecalSurface( surf, decalinfo );
|
R_DecalSurface( surf, decalinfo );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -707,6 +708,7 @@ static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo )
|
|||||||
{
|
{
|
||||||
mplane_t *splitplane;
|
mplane_t *splitplane;
|
||||||
float dist;
|
float dist;
|
||||||
|
mnode_t *children[2];
|
||||||
|
|
||||||
Assert( node != NULL );
|
Assert( node != NULL );
|
||||||
|
|
||||||
@@ -718,6 +720,7 @@ static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo )
|
|||||||
|
|
||||||
splitplane = node->plane;
|
splitplane = node->plane;
|
||||||
dist = DotProduct( decalinfo->m_Position, splitplane->normal ) - splitplane->dist;
|
dist = DotProduct( decalinfo->m_Position, splitplane->normal ) - splitplane->dist;
|
||||||
|
node_children( children, node, model );
|
||||||
|
|
||||||
// This is arbitrarily set to 10 right now. In an ideal world we'd have the
|
// This is arbitrarily set to 10 right now. In an ideal world we'd have the
|
||||||
// exact surface but we don't so, this tells me which planes are "sort of
|
// exact surface but we don't so, this tells me which planes are "sort of
|
||||||
@@ -729,19 +732,19 @@ static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo )
|
|||||||
// have a surface normal
|
// have a surface normal
|
||||||
if( dist > decalinfo->m_Size )
|
if( dist > decalinfo->m_Size )
|
||||||
{
|
{
|
||||||
R_DecalNode( model, node->children[0], decalinfo );
|
R_DecalNode( model, children[0], decalinfo );
|
||||||
}
|
}
|
||||||
else if( dist < -decalinfo->m_Size )
|
else if( dist < -decalinfo->m_Size )
|
||||||
{
|
{
|
||||||
R_DecalNode( model, node->children[1], decalinfo );
|
R_DecalNode( model, children[1], decalinfo );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( dist < DECAL_DISTANCE && dist > -DECAL_DISTANCE )
|
if( dist < DECAL_DISTANCE && dist > -DECAL_DISTANCE )
|
||||||
R_DecalNodeSurfaces( model, node, decalinfo );
|
R_DecalNodeSurfaces( model, node, decalinfo );
|
||||||
|
|
||||||
R_DecalNode( model, node->children[0], decalinfo );
|
R_DecalNode( model, children[0], decalinfo );
|
||||||
R_DecalNode( model, node->children[1], decalinfo );
|
R_DecalNode( model, children[1], decalinfo );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,44 +104,50 @@ R_MarkLights
|
|||||||
*/
|
*/
|
||||||
void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
|
void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
|
||||||
{
|
{
|
||||||
float dist;
|
float dist;
|
||||||
msurface_t *surf;
|
msurface_t *surf;
|
||||||
int i;
|
int i;
|
||||||
|
mnode_t *children[2];
|
||||||
|
int firstsurface, numsurfaces;
|
||||||
|
|
||||||
if( !node || node->contents < 0 )
|
if( !node || node->contents < 0 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dist = PlaneDiff( light->origin, node->plane );
|
dist = PlaneDiff( light->origin, node->plane );
|
||||||
|
|
||||||
|
node_children( children, node, RI.currentmodel );
|
||||||
|
firstsurface = node_firstsurface( node, RI.currentmodel );
|
||||||
|
numsurfaces = node_numsurfaces( node, RI.currentmodel );
|
||||||
|
|
||||||
if( dist > light->radius )
|
if( dist > light->radius )
|
||||||
{
|
{
|
||||||
R_MarkLights( light, bit, node->children[0] );
|
R_MarkLights( light, bit, children[0] );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if( dist < -light->radius )
|
if( dist < -light->radius )
|
||||||
{
|
{
|
||||||
R_MarkLights( light, bit, node->children[1] );
|
R_MarkLights( light, bit, children[1] );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark the polygons
|
// mark the polygons
|
||||||
surf = RI.currentmodel->surfaces + node->firstsurface;
|
surf = RI.currentmodel->surfaces + firstsurface;
|
||||||
|
|
||||||
for( i = 0; i < node->numsurfaces; i++, surf++ )
|
for( i = 0; i < numsurfaces; i++, surf++ )
|
||||||
{
|
{
|
||||||
if( !BoundsAndSphereIntersect( surf->info->mins, surf->info->maxs, light->origin, light->radius ))
|
if( !BoundsAndSphereIntersect( surf->info->mins, surf->info->maxs, light->origin, light->radius ))
|
||||||
continue; // no intersection
|
continue; // no intersection
|
||||||
|
|
||||||
if( surf->dlightframe != tr.framecount ) // tr.dlightframecount )
|
if( surf->dlightframe != tr.dlightframecount )
|
||||||
{
|
{
|
||||||
surf->dlightbits = 0;
|
surf->dlightbits = 0;
|
||||||
surf->dlightframe = tr.framecount; // tr.dlightframecount;
|
surf->dlightframe = tr.dlightframecount;
|
||||||
}
|
}
|
||||||
surf->dlightbits |= bit;
|
surf->dlightbits |= bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
R_MarkLights( light, bit, node->children[0] );
|
R_MarkLights( light, bit, children[0] );
|
||||||
R_MarkLights( light, bit, node->children[1] );
|
R_MarkLights( light, bit, children[1] );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -205,6 +211,8 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
|
|||||||
mtexinfo_t *tex;
|
mtexinfo_t *tex;
|
||||||
matrix3x4 tbn;
|
matrix3x4 tbn;
|
||||||
vec3_t mid;
|
vec3_t mid;
|
||||||
|
mnode_t *children[2];
|
||||||
|
int firstsurface, numsurfaces;
|
||||||
|
|
||||||
// didn't hit anything
|
// didn't hit anything
|
||||||
if( !node || node->contents < 0 )
|
if( !node || node->contents < 0 )
|
||||||
@@ -213,13 +221,17 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node_children( children, node, model );
|
||||||
|
firstsurface = node_firstsurface( node, model );
|
||||||
|
numsurfaces = node_numsurfaces( node, model );
|
||||||
|
|
||||||
// calculate mid point
|
// calculate mid point
|
||||||
front = PlaneDiff( start, node->plane );
|
front = PlaneDiff( start, node->plane );
|
||||||
back = PlaneDiff( end, node->plane );
|
back = PlaneDiff( end, node->plane );
|
||||||
|
|
||||||
side = front < 0;
|
side = front < 0;
|
||||||
if(( back < 0 ) == side )
|
if(( back < 0 ) == side )
|
||||||
return R_RecursiveLightPoint( model, node->children[side], p1f, p2f, cv, start, end );
|
return R_RecursiveLightPoint( model, children[side], p1f, p2f, cv, start, end );
|
||||||
|
|
||||||
frac = front / ( front - back );
|
frac = front / ( front - back );
|
||||||
|
|
||||||
@@ -227,7 +239,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
|
|||||||
midf = p1f + ( p2f - p1f ) * frac;
|
midf = p1f + ( p2f - p1f ) * frac;
|
||||||
|
|
||||||
// co down front side
|
// co down front side
|
||||||
if( R_RecursiveLightPoint( model, node->children[side], p1f, midf, cv, start, mid ))
|
if( R_RecursiveLightPoint( model, children[side], p1f, midf, cv, start, mid ))
|
||||||
return true; // hit something
|
return true; // hit something
|
||||||
|
|
||||||
if(( back < 0 ) == side )
|
if(( back < 0 ) == side )
|
||||||
@@ -237,10 +249,10 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for impact on this node
|
// check for impact on this node
|
||||||
surf = model->surfaces + node->firstsurface;
|
surf = model->surfaces + firstsurface;
|
||||||
VectorCopy( mid, g_trace_lightspot );
|
VectorCopy( mid, g_trace_lightspot );
|
||||||
|
|
||||||
for( i = 0; i < node->numsurfaces; i++, surf++ )
|
for( i = 0; i < numsurfaces; i++, surf++ )
|
||||||
{
|
{
|
||||||
int smax, tmax;
|
int smax, tmax;
|
||||||
|
|
||||||
@@ -330,7 +342,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// go down back side
|
// go down back side
|
||||||
return R_RecursiveLightPoint( model, node->children[!side], midf, p2f, cv, mid, end );
|
return R_RecursiveLightPoint( model, children[!side], midf, p2f, cv, mid, end );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -933,7 +933,7 @@ typedef struct edge_s
|
|||||||
unsigned short surfs[2];
|
unsigned short surfs[2];
|
||||||
struct edge_s *nextremove;
|
struct edge_s *nextremove;
|
||||||
float nearzi;
|
float nearzi;
|
||||||
medge_t *owner;
|
medge16_t *owner;
|
||||||
} edge_t;
|
} edge_t;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -524,6 +524,7 @@ watertexture to grab fog values from it
|
|||||||
static image_t *R_RecursiveFindWaterTexture( const mnode_t *node, const mnode_t *ignore, qboolean down )
|
static image_t *R_RecursiveFindWaterTexture( const mnode_t *node, const mnode_t *ignore, qboolean down )
|
||||||
{
|
{
|
||||||
image_t *tex = NULL;
|
image_t *tex = NULL;
|
||||||
|
mnode_t *children[2];
|
||||||
|
|
||||||
// assure the initial node is not null
|
// assure the initial node is not null
|
||||||
// we could check it here, but we would rather check it
|
// we could check it here, but we would rather check it
|
||||||
@@ -561,18 +562,18 @@ static image_t *R_RecursiveFindWaterTexture( const mnode_t *node, const mnode_t
|
|||||||
|
|
||||||
// this is a regular node
|
// this is a regular node
|
||||||
// traverse children
|
// traverse children
|
||||||
if( node->children[0] && ( node->children[0] != ignore ))
|
node_children( children, node, WORLDMODEL );
|
||||||
|
|
||||||
|
if( children[0] && ( children[0] != ignore ))
|
||||||
{
|
{
|
||||||
tex = R_RecursiveFindWaterTexture( node->children[0], node, true );
|
tex = R_RecursiveFindWaterTexture( children[0], node, true );
|
||||||
if( tex )
|
if( tex ) return tex;
|
||||||
return tex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( node->children[1] && ( node->children[1] != ignore ))
|
if( children[1] && ( children[1] != ignore ))
|
||||||
{
|
{
|
||||||
tex = R_RecursiveFindWaterTexture( node->children[1], node, true );
|
tex = R_RecursiveFindWaterTexture( children[1], node, true );
|
||||||
if( tex )
|
if( tex ) return tex;
|
||||||
return tex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// for down recursion, return immediately
|
// for down recursion, return immediately
|
||||||
@@ -796,9 +797,9 @@ static mnode_t *R_FindTopnode( vec3_t mins, vec3_t maxs )
|
|||||||
|
|
||||||
// not split yet; recurse down the contacted side
|
// not split yet; recurse down the contacted side
|
||||||
if( sides & 1 )
|
if( sides & 1 )
|
||||||
node = node->children[0];
|
node = node_child( node, 0, WORLDMODEL );
|
||||||
else
|
else
|
||||||
node = node->children[1];
|
node = node_child( node, 1, WORLDMODEL );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1392,6 +1393,12 @@ void GAME_EXPORT R_NewMap( void )
|
|||||||
R_ClearDecals(); // clear all level decals
|
R_ClearDecals(); // clear all level decals
|
||||||
R_StudioResetPlayerModels();
|
R_StudioResetPlayerModels();
|
||||||
|
|
||||||
|
if( FBitSet( world->flags, MODEL_QBSP2 ))
|
||||||
|
{
|
||||||
|
gEngfuncs.Host_Error( "Sorry, ref_soft can't load maps in BSP2 format.\n" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
r_cnumsurfs = sw_maxsurfs.value;
|
r_cnumsurfs = sw_maxsurfs.value;
|
||||||
|
|
||||||
if( r_cnumsurfs <= MINSURFACES )
|
if( r_cnumsurfs <= MINSURFACES )
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ int c_faceclip; // numbe
|
|||||||
clipplane_t *entity_clipplanes;
|
clipplane_t *entity_clipplanes;
|
||||||
clipplane_t world_clipplanes[16];
|
clipplane_t world_clipplanes[16];
|
||||||
|
|
||||||
medge_t *r_pedge;
|
medge16_t *r_pedge;
|
||||||
|
|
||||||
qboolean r_leftclipped, r_rightclipped;
|
qboolean r_leftclipped, r_rightclipped;
|
||||||
static qboolean makeleftedge, makerightedge;
|
static qboolean makeleftedge, makerightedge;
|
||||||
@@ -68,7 +68,7 @@ msurface_t *r_skyfaces;
|
|||||||
mplane_t r_skyplanes[6];
|
mplane_t r_skyplanes[6];
|
||||||
mtexinfo_t r_skytexinfo[6];
|
mtexinfo_t r_skytexinfo[6];
|
||||||
mvertex_t *r_skyverts;
|
mvertex_t *r_skyverts;
|
||||||
medge_t *r_skyedges;
|
medge16_t *r_skyedges;
|
||||||
int *r_skysurfedges;
|
int *r_skysurfedges;
|
||||||
|
|
||||||
// I just copied this data from a box map...
|
// I just copied this data from a box map...
|
||||||
@@ -438,7 +438,7 @@ void R_RenderFace( msurface_t *fa, int clipflags )
|
|||||||
mplane_t *pplane;
|
mplane_t *pplane;
|
||||||
float distinv;
|
float distinv;
|
||||||
vec3_t p_normal;
|
vec3_t p_normal;
|
||||||
medge_t *pedges, tedge;
|
medge16_t *pedges, tedge;
|
||||||
clipplane_t *pclip;
|
clipplane_t *pclip;
|
||||||
|
|
||||||
// translucent surfaces are not drawn by the edge renderer
|
// translucent surfaces are not drawn by the edge renderer
|
||||||
@@ -490,7 +490,7 @@ void R_RenderFace( msurface_t *fa, int clipflags )
|
|||||||
r_nearzi = 0;
|
r_nearzi = 0;
|
||||||
r_nearzionly = false;
|
r_nearzionly = false;
|
||||||
makeleftedge = makerightedge = false;
|
makeleftedge = makerightedge = false;
|
||||||
pedges = RI.currentmodel->edges;
|
pedges = RI.currentmodel->edges16;
|
||||||
r_lastvertvalid = false;
|
r_lastvertvalid = false;
|
||||||
|
|
||||||
for( i = 0; i < fa->numedges; i++ )
|
for( i = 0; i < fa->numedges; i++ )
|
||||||
@@ -560,7 +560,7 @@ void R_RenderFace( msurface_t *fa, int clipflags )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// it's cached if the cached edge is valid and is owned
|
// it's cached if the cached edge is valid and is owned
|
||||||
// by this medge_t
|
// by this medge16_t
|
||||||
if((((uintptr_t)edge_p - (uintptr_t)r_edges )
|
if((((uintptr_t)edge_p - (uintptr_t)r_edges )
|
||||||
> r_pedge->cachededgeoffset )
|
> r_pedge->cachededgeoffset )
|
||||||
&& (((edge_t *)((uintptr_t)r_edges
|
&& (((edge_t *)((uintptr_t)r_edges
|
||||||
@@ -651,7 +651,7 @@ void R_RenderBmodelFace( bedge_t *pedges, msurface_t *psurf )
|
|||||||
mplane_t *pplane;
|
mplane_t *pplane;
|
||||||
float distinv;
|
float distinv;
|
||||||
vec3_t p_normal;
|
vec3_t p_normal;
|
||||||
medge_t tedge;
|
medge16_t tedge;
|
||||||
clipplane_t *pclip;
|
clipplane_t *pclip;
|
||||||
|
|
||||||
/*if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
|
/*if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
cd $GITHUB_WORKSPACE
|
cd $GITHUB_WORKSPACE
|
||||||
|
|
||||||
wget http://libsdl.org/release/SDL2-$SDL_VERSION.dmg -O SDL2.dmg
|
wget https://github.com/libsdl-org/SDL/releases/download/release-$SDL_VERSION/SDL2-$SDL_VERSION.dmg -O SDL2.dmg
|
||||||
hdiutil mount SDL2.dmg
|
hdiutil mount SDL2.dmg
|
||||||
sudo cp -vr /Volumes/SDL2/SDL2.framework /Library/Frameworks
|
sudo cp -vr /Volumes/SDL2/SDL2.framework /Library/Frameworks
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
curl http://libsdl.org/release/SDL2-devel-$SDL_VERSION-VC.zip -o SDL2.zip
|
curl -L https://github.com/libsdl-org/SDL/releases/download/release-$SDL_VERSION/SDL2-devel-$SDL_VERSION-VC.zip -o SDL2.zip
|
||||||
unzip -q SDL2.zip
|
unzip -q SDL2.zip
|
||||||
mv SDL2-$SDL_VERSION SDL2_VC
|
mv SDL2-$SDL_VERSION SDL2_VC
|
||||||
|
|||||||
6
wscript
6
wscript
@@ -91,7 +91,7 @@ SUBDIRS = [
|
|||||||
Subproject('3rdparty/gl-wes-v2', lambda x: not x.env.DEDICATED and x.env.GLWES),
|
Subproject('3rdparty/gl-wes-v2', lambda x: not x.env.DEDICATED and x.env.GLWES),
|
||||||
Subproject('3rdparty/gl4es', lambda x: not x.env.DEDICATED and x.env.GL4ES),
|
Subproject('3rdparty/gl4es', lambda x: not x.env.DEDICATED and x.env.GL4ES),
|
||||||
Subproject('ref/gl', lambda x: not x.env.DEDICATED and (x.env.GL or x.env.NANOGL or x.env.GLWES or x.env.GL4ES)),
|
Subproject('ref/gl', lambda x: not x.env.DEDICATED and (x.env.GL or x.env.NANOGL or x.env.GLWES or x.env.GL4ES)),
|
||||||
Subproject('ref/soft', lambda x: not x.env.DEDICATED and not x.env.SUPPORT_BSP2_FORMAT and x.env.SOFT),
|
Subproject('ref/soft', lambda x: not x.env.DEDICATED and x.env.SOFT),
|
||||||
Subproject('ref/null', lambda x: not x.env.DEDICATED and x.env.NULL),
|
Subproject('ref/null', lambda x: not x.env.DEDICATED and x.env.NULL),
|
||||||
Subproject('3rdparty/bzip2', lambda x: not x.env.DEDICATED and not x.env.HAVE_SYSTEM_BZ2),
|
Subproject('3rdparty/bzip2', lambda x: not x.env.DEDICATED and not x.env.HAVE_SYSTEM_BZ2),
|
||||||
Subproject('3rdparty/opus', lambda x: not x.env.DEDICATED and not x.env.HAVE_SYSTEM_OPUS),
|
Subproject('3rdparty/opus', lambda x: not x.env.DEDICATED and not x.env.HAVE_SYSTEM_OPUS),
|
||||||
@@ -148,9 +148,6 @@ def options(opt):
|
|||||||
grp.add_option('--enable-bundled-deps', action = 'store_true', dest = 'BUILD_BUNDLED_DEPS', default = False,
|
grp.add_option('--enable-bundled-deps', action = 'store_true', dest = 'BUILD_BUNDLED_DEPS', default = False,
|
||||||
help = 'prefer to build bundled dependencies (like opus) instead of relying on system provided')
|
help = 'prefer to build bundled dependencies (like opus) instead of relying on system provided')
|
||||||
|
|
||||||
grp.add_option('--enable-bsp2', action = 'store_true', dest = 'SUPPORT_BSP2_FORMAT', default = False,
|
|
||||||
help = 'build engine and renderers with BSP2 map support(recommended for Quake, breaks compatibility!) [default: %(default)s]')
|
|
||||||
|
|
||||||
grp.add_option('--enable-hl25-extended-structs', action = 'store_true', dest = 'SUPPORT_HL25_EXTENDED_STRUCTS', default = False,
|
grp.add_option('--enable-hl25-extended-structs', action = 'store_true', dest = 'SUPPORT_HL25_EXTENDED_STRUCTS', default = False,
|
||||||
help = 'build engine and renderers with HL25 extended structs compatibility (might be required for some mods) [default: %(default)s]')
|
help = 'build engine and renderers with HL25 extended structs compatibility (might be required for some mods) [default: %(default)s]')
|
||||||
|
|
||||||
@@ -396,7 +393,6 @@ def configure(conf):
|
|||||||
conf.env.ENABLE_FUZZER = conf.options.ENABLE_FUZZER
|
conf.env.ENABLE_FUZZER = conf.options.ENABLE_FUZZER
|
||||||
conf.env.DEDICATED = conf.options.DEDICATED
|
conf.env.DEDICATED = conf.options.DEDICATED
|
||||||
|
|
||||||
conf.define_cond('SUPPORT_BSP2_FORMAT', conf.options.SUPPORT_BSP2_FORMAT)
|
|
||||||
conf.define_cond('SUPPORT_HL25_EXTENDED_STRUCTS', conf.options.SUPPORT_HL25_EXTENDED_STRUCTS)
|
conf.define_cond('SUPPORT_HL25_EXTENDED_STRUCTS', conf.options.SUPPORT_HL25_EXTENDED_STRUCTS)
|
||||||
|
|
||||||
# disable game_launch compiling on platform where it's not needed
|
# disable game_launch compiling on platform where it's not needed
|
||||||
|
|||||||
Reference in New Issue
Block a user