diff --git a/common/bspfile.h b/common/bspfile.h index d5ecb458..d8b47134 100644 --- a/common/bspfile.h +++ b/common/bspfile.h @@ -134,6 +134,8 @@ BRUSH MODELS #define TEX_EXTRA_LIGHTMAP BIT( 3 ) // bsp31 legacy - using 8 texels per luxel instead of 16 texels per luxel #define TEX_SCROLL BIT( 6 ) // Doom special FX +#define IsLiquidContents( cnt ) ( cnt == CONTENTS_WATER || cnt == CONTENTS_SLIME || cnt == CONTENTS_LAVA ) + // ambient sound types enum { diff --git a/common/com_image.h b/common/com_image.h index f9a8eeb3..33a0f812 100644 --- a/common/com_image.h +++ b/common/com_image.h @@ -8,7 +8,7 @@ typically expanded to rgba buffer NOTE: number at end of pixelformat name it's a total bitscount e.g. PF_RGB_24 == PF_RGB_888 ======================================================================== */ -#define ImageRAW( type ) (type == PF_RGBA_32 || type == PF_BGRA_32 || type == PF_RGB_24 || type == PF_BGR_24) +#define ImageRAW( type ) (type == PF_RGBA_32 || type == PF_BGRA_32 || type == PF_RGB_24 || type == PF_BGR_24 || type == PF_LUMINANCE) #define ImageDXT( type ) (type == PF_DXT1 || type == PF_DXT3 || type == PF_DXT5 || type == PF_ATI2) typedef enum @@ -20,6 +20,7 @@ typedef enum PF_BGRA_32, // big endian RGBA (MacOS) PF_RGB_24, // uncompressed dds or another 24-bit image PF_BGR_24, // big-endian RGB (MacOS) + PF_LUMINANCE, PF_DXT1, // s3tc DXT1 format PF_DXT3, // s3tc DXT3 format PF_DXT5, // s3tc DXT5 format diff --git a/common/com_model.h b/common/com_model.h index 0520c563..f31a754a 100644 --- a/common/com_model.h +++ b/common/com_model.h @@ -109,6 +109,15 @@ typedef struct int reserved[32]; // just for future expansions or mod-makers } mfaceinfo_t; +typedef struct +{ + mplane_t *edges; + int numedges; + vec3_t origin; + vec_t radius; // for culling tests + int contents; // sky or solid +} mfacebevel_t; + typedef struct { float vecs[2][4]; // [s/t] unit vectors in world space. @@ -208,7 +217,7 @@ typedef struct mextrasurf_s // begin userdata struct msurface_s *lightmapchain; // lightmapped polys struct mextrasurf_s *detailchain; // for detail textures drawing - struct mextrasurf_s *mirrorchain; // for gl_texsort drawing + mfacebevel_t *bevel; // for exact face traceline struct mextrasurf_s *lumachain; // draw fullbrights struct cl_entity_s *parent; // upcast to owner entity diff --git a/common/enginefeatures.h b/common/enginefeatures.h index bee561fd..d1e90ba2 100644 --- a/common/enginefeatures.h +++ b/common/enginefeatures.h @@ -23,7 +23,7 @@ GNU General Public License for more details. #define ENGINE_PHYSICS_PUSHER_EXT (1<<3) // enable sets of improvements for MOVETYPE_PUSH physics #define ENGINE_LARGE_LIGHTMAPS (1<<4) // change lightmap sizes from 128x128 to 1024x1024 #define ENGINE_COMPENSATE_QUAKE_BUG (1<<5) // compensate stupid quake bug (inverse pitch) for mods where this bug is fixed -// reserved +#define ENGINE_IMPROVED_LINETRACE (1<<6) // new traceline that tracing through alphatextures #define ENGINE_COMPUTE_STUDIO_LERP (1<<7) // enable MOVETYPE_STEP lerping back in engine #endif//FEATURES_H \ No newline at end of file diff --git a/common/render_api.h b/common/render_api.h index a7276e21..be141c02 100644 --- a/common/render_api.h +++ b/common/render_api.h @@ -60,6 +60,7 @@ GNU General Public License for more details. #define PARM_GLES_WRAPPER 35 // #define PARM_STENCIL_ACTIVE 36 #define PARM_WATER_ALPHA 37 +#define PARM_TEX_MEMORY 38 // returns total memory of uploaded texture in bytes // skybox ordering enum diff --git a/engine/client/avi/avi_win.c b/engine/client/avi/avi_win.c index abedebab..a8314fd6 100644 --- a/engine/client/avi/avi_win.c +++ b/engine/client/avi/avi_win.c @@ -405,7 +405,7 @@ int AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, int offset, int leng for( i = 0; i < length; i++ ) audiodata[i] = 0; - return length; +// return length; } } diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index f9f118ff..145e8e50 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -257,7 +257,7 @@ Return contents for point */ int CL_PointContents( const vec3_t p ) { - int cont = CL_TruePointContents( p ); + int cont = PM_PointContents( clgame.pmove, p ); if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN ) cont = CONTENTS_WATER; @@ -2201,7 +2201,7 @@ static int pfnPointContents( const float *p, int *truecontents ) { int cont, truecont; - truecont = cont = CL_TruePointContents( p ); + truecont = cont = PM_PointContents( clgame.pmove, p ); if( truecontents ) *truecontents = truecont; if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN ) diff --git a/engine/client/cl_gameui.c b/engine/client/cl_gameui.c index 67d5c541..eca1a6a9 100644 --- a/engine/client/cl_gameui.c +++ b/engine/client/cl_gameui.c @@ -380,7 +380,7 @@ static HIMAGE pfnPIC_Load( const char *szPicName, const byte *image_buf, int ima { HIMAGE tx; - if( !szPicName || !*szPicName ) + if( !COM_CheckString( szPicName )) { Con_Reportf( S_ERROR "CL_LoadImage: refusing to load image with empty name\n" ); return 0; @@ -932,7 +932,7 @@ pfnHostEndGame static void pfnHostEndGame( const char *szFinalMessage ) { if( !szFinalMessage ) szFinalMessage = ""; - Host_EndGame( true, "%s", szFinalMessage ); + Host_EndGame( false, "%s", szFinalMessage ); } /* diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index b9d822dd..5740b799 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -2224,6 +2224,7 @@ void CL_ReadPackets( void ) // check resource for downloading and precache CL_EstimateNeededResources(); CL_BatchResourceRequest( false ); + cls.dl.doneregistering = false; cls.dl.custom = true; } diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 84d57bc8..a51bb552 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1532,7 +1532,7 @@ void CL_RegisterResources( sizebuf_t *msg ) ASSERT( clgame.entities != NULL ); clgame.entities->model = cl.worldmodel; - if( cls.state != ca_disconnected ) + if( !cl.video_prepped && !cl.audio_prepped ) { Con_Printf( "Setting up renderer...\n" ); diff --git a/engine/client/cl_pmove.c b/engine/client/cl_pmove.c index d82af9dc..db6ecf8b 100644 --- a/engine/client/cl_pmove.c +++ b/engine/client/cl_pmove.c @@ -472,7 +472,7 @@ void CL_AddLinksToPmove( frame_t *frame ) if( VectorIsNull( state->mins ) && VectorIsNull( state->maxs )) continue; - if( state->solid == SOLID_NOT && state->skin < CONTENTS_EMPTY ) + if( state->solid == SOLID_NOT && state->skin == CONTENTS_LADDER ) { if( clgame.pmove->nummoveent >= MAX_MOVEENTS ) continue; @@ -588,67 +588,6 @@ void CL_SetSolidPlayers( int playernum ) } } -/* -============= -CL_TruePointContents - -============= -*/ -int CL_TruePointContents( const vec3_t p ) -{ - int i, contents; - int oldhull; - hull_t *hull; - vec3_t test, offset; - physent_t *pe; - - // sanity check - if( !p ) return CONTENTS_NONE; - - oldhull = clgame.pmove->usehull; - - // get base contents from world - contents = PM_HullPointContents( &cl.worldmodel->hulls[0], 0, p ); - - for( i = 0; i < clgame.pmove->nummoveent; i++ ) - { - pe = &clgame.pmove->moveents[i]; - - if( pe->solid != SOLID_NOT ) // disabled ? - continue; - - // only brushes can have special contents - if( !pe->model || pe->model->type != mod_brush ) - continue; - - // check water brushes accuracy - clgame.pmove->usehull = 2; - hull = PM_HullForBsp( pe, clgame.pmove, offset ); - clgame.pmove->usehull = oldhull; - - // offset the test point appropriately for this hull. - VectorSubtract( p, offset, test ); - - if( FBitSet( pe->model->flags, MODEL_HAS_ORIGIN ) && !VectorIsNull( pe->angles )) - { - matrix4x4 matrix; - - Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f ); - Matrix4x4_VectorITransform( matrix, p, test ); - } - - // test hull for intersection with this model - if( PM_HullPointContents( hull, hull->firstclipnode, test ) == CONTENTS_EMPTY ) - continue; - - // compare contents ranking - if( RankForContents( pe->skin ) > RankForContents( contents )) - contents = pe->skin; // new content has more priority - } - - return contents; -} - /* ============= CL_WaterEntity @@ -666,9 +605,9 @@ int CL_WaterEntity( const float *rgflPos ) oldhull = clgame.pmove->usehull; - for( i = 0; i < clgame.pmove->nummoveent; i++ ) + for( i = 0; i < clgame.pmove->numphysent; i++ ) { - pe = &clgame.pmove->moveents[i]; + pe = &clgame.pmove->physents[i]; if( pe->solid != SOLID_NOT ) // disabled ? continue; @@ -793,7 +732,7 @@ static int pfnPointContents( float *p, int *truecontents ) { int cont, truecont; - truecont = cont = CL_TruePointContents( p ); + truecont = cont = PM_PointContents( clgame.pmove, p ); if( truecontents ) *truecontents = truecont; if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN ) @@ -803,7 +742,7 @@ static int pfnPointContents( float *p, int *truecontents ) static int pfnTruePointContents( float *p ) { - return CL_TruePointContents( p ); + return PM_TruePointContents( clgame.pmove, p ); } static int pfnHullPointContents( struct hull_s *hull, int num, float *p ) diff --git a/engine/client/console.c b/engine/client/console.c index d5e6b9ec..956b87f5 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -144,7 +144,7 @@ void Con_SetColor_f( void ) { vec3_t color; - switch( Cmd_Argc() ) + switch( Cmd_Argc( )) { case 1: Con_Printf( "\"con_color\" is %i %i %i\n", g_color_table[7][0], g_color_table[7][1], g_color_table[7][2] ); diff --git a/engine/client/keys.c b/engine/client/keys.c index 66f0e6c0..08927c1c 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -335,6 +335,9 @@ void Key_Unbindall_f( void ) if( keys[i].binding ) Key_SetBinding( i, "" ); } + + // set some defaults + Key_SetBinding( K_ESCAPE, "cancelselect" ); } /* diff --git a/engine/common/cmd.c b/engine/common/cmd.c index e97d60ec..4d61064e 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -1006,9 +1006,8 @@ void Cmd_ExecuteString( char *text ) } else #endif // XASH_DEDICATED - if( text[0] != '@' && Cvar_VariableInteger( "host_gameloaded" )) + if( Cvar_VariableInteger( "host_gameloaded" )) { - // commands with leading '@' are hidden system commands Con_Printf( S_WARN "Unknown command \"%s\"\n", text ); } } diff --git a/engine/common/common.h b/engine/common/common.h index d079de5d..b2ea5645 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -885,7 +885,6 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float void SV_StartMusic( const char *curtrack, const char *looptrack, int position ); void SV_CreateDecal( sizebuf_t *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale ); void Log_Printf( const char *fmt, ... ) _format( 1 ); -struct sizebuf_s *SV_GetReliableDatagram( void ); void SV_BroadcastCommand( const char *fmt, ... ) _format( 1 ); qboolean SV_RestoreCustomDecal( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent ); void SV_BroadcastPrintf( sv_client_t *ignore, char *fmt, ... ) _format( 2 ); diff --git a/engine/common/crclib.c b/engine/common/crclib.c index 0d1f9d65..c811ec7c 100644 --- a/engine/common/crclib.c +++ b/engine/common/crclib.c @@ -229,7 +229,7 @@ qboolean CRC32_File( dword *crcvalue, const char *filename ) qboolean CRC32_MapFile( dword *crcvalue, const char *filename, qboolean multiplayer ) { - char headbuf[256], buffer[1024]; + char headbuf[1024], buffer[1024]; int i, num_bytes, lumplen; int version, hdr_size; dheader_t *header; diff --git a/engine/common/host.c b/engine/common/host.c index ade560b4..cd725fb6 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -49,6 +49,8 @@ sysinfo_t SI; CVAR_DEFINE( host_developer, "developer", "0", 0, "engine is in development-mode" ); CVAR_DEFINE_AUTO( sys_ticrate, "100", 0, "framerate in dedicated mode" ); + +convar_t *host_serverstate; convar_t *host_gameloaded; convar_t *host_clientloaded; convar_t *host_limitlocal; @@ -460,6 +462,7 @@ double Host_CalcFPS( void ) else { fps = host_maxfps->value; + if( fps == 0.0 ) fps = MAX_FPS; fps = bound( MIN_FPS, fps, MAX_FPS ); } @@ -943,6 +946,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa Cmd_AddCommand ( "crash", Host_Crash_f, "a way to force a bus error for development reasons"); } + host_serverstate = Cvar_Get( "host_serverstate", "0", FCVAR_READ_ONLY, "displays current server state" ); host_maxfps = Cvar_Get( "fps_max", "72", FCVAR_ARCHIVE, "host fps upper limit" ); host_framerate = Cvar_Get( "host_framerate", "0", 0, "locks frame timing to this value in seconds" ); host_sleeptime = Cvar_Get( "sleeptime", "1", FCVAR_ARCHIVE, "milliseconds to sleep for each frame. higher values reduce fps accuracy" ); diff --git a/engine/common/imagelib/img_dds.c b/engine/common/imagelib/img_dds.c index 03b31ee0..ac752d7e 100644 --- a/engine/common/imagelib/img_dds.c +++ b/engine/common/imagelib/img_dds.c @@ -18,7 +18,6 @@ GNU General Public License for more details. qboolean Image_CheckDXT3Alpha( dds_t *hdr, byte *fin ) { - uint bitmask; word sAlpha; byte *alpha; int x, y, i, j; @@ -27,10 +26,8 @@ qboolean Image_CheckDXT3Alpha( dds_t *hdr, byte *fin ) { for( x = 0; x < hdr->dwWidth; x += 4 ) { - alpha = fin; - fin += 8; - bitmask = ((uint *)fin)[1]; - fin += 8; + alpha = fin + 8; + fin += 16; for( j = 0; j < 4; j++ ) { @@ -138,11 +135,21 @@ void Image_DXTGetPixelFormat( dds_t *hdr ) } else { - if( bits == 32 ) + switch( bits ) + { + case 32: image.type = PF_BGRA_32; - else if( bits == 24 ) + break; + case 24: image.type = PF_BGR_24; - else image.type = PF_UNKNOWN; // assume error; + break; + case 8: + image.type = PF_LUMINANCE; + break; + default: + image.type = PF_UNKNOWN; + break; + } } } @@ -162,6 +169,7 @@ size_t Image_DXTGetLinearSize( int type, int width, int height, int depth ) case PF_DXT3: case PF_DXT5: case PF_ATI2: return ((( width + 3 ) / 4 ) * (( height + 3 ) / 4 ) * depth * 16 ); + case PF_LUMINANCE: return (width * height * depth); case PF_BGR_24: case PF_RGB_24: return (width * height * depth * 3); case PF_BGRA_32: @@ -314,6 +322,9 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, fs_offset_t filesi break; } + if( image.type == PF_LUMINANCE ) + ClearBits( image.flags, IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA ); + if( header.dwReserved1[1] != 0 ) { // store texture reflectivity diff --git a/engine/common/imagelib/img_main.c b/engine/common/imagelib/img_main.c index 5e44b466..4d169f5f 100644 --- a/engine/common/imagelib/img_main.c +++ b/engine/common/imagelib/img_main.c @@ -72,17 +72,18 @@ static const cubepack_t load_cubemap[] = // soul of ImageLib - table of image format constants const bpc_desc_t PFDesc[] = { -{PF_UNKNOWN, "raw", 0x1908, 0 }, -{PF_INDEXED_24, "pal 24", 0x1908, 1 }, -{PF_INDEXED_32, "pal 32", 0x1908, 1 }, -{PF_RGBA_32, "RGBA 32",0x1908, 4 }, -{PF_BGRA_32, "BGRA 32",0x80E1, 4 }, -{PF_RGB_24, "RGB 24", 0x1908, 3 }, -{PF_BGR_24, "BGR 24", 0x80E0, 3 }, -{PF_DXT1, "DXT 1", 0x83F1, 4 }, -{PF_DXT3, "DXT 3", 0x83F2, 4 }, -{PF_DXT5, "DXT 5", 0x83F3, 4 }, -{PF_ATI2, "ATI 2", 0x8837, 4 }, +{ PF_UNKNOWN, "raw", 0x1908, 0 }, +{ PF_INDEXED_24, "pal 24", 0x1908, 1 }, +{ PF_INDEXED_32, "pal 32", 0x1908, 1 }, +{ PF_RGBA_32, "RGBA 32",0x1908, 4 }, +{ PF_BGRA_32, "BGRA 32",0x80E1, 4 }, +{ PF_RGB_24, "RGB 24", 0x1908, 3 }, +{ PF_BGR_24, "BGR 24", 0x80E0, 3 }, +{ PF_LUMINANCE, "LUM 8", 0x1909, 1 }, +{ PF_DXT1, "DXT 1", 0x83F1, 4 }, +{ PF_DXT3, "DXT 3", 0x83F2, 4 }, +{ PF_DXT5, "DXT 5", 0x83F3, 4 }, +{ PF_ATI2, "ATI 2", 0x8837, 4 }, }; void Image_Reset( void ) diff --git a/engine/common/imagelib/img_utils.c b/engine/common/imagelib/img_utils.c index 13e6bb7e..6ac7b7be 100644 --- a/engine/common/imagelib/img_utils.c +++ b/engine/common/imagelib/img_utils.c @@ -150,11 +150,16 @@ void Image_Init( void ) image.loadformats = load_game; image.saveformats = save_game; break; - default: // all other instances not using imagelib - image.cmd_flags = 0; + case HOST_DEDICATED: + image.cmd_flags = 0; image.loadformats = load_game; image.saveformats = save_null; break; + default: // all other instances not using imagelib + image.cmd_flags = 0; + image.loadformats = load_null; + image.saveformats = save_null; + break; } image.tempbuffer = NULL; diff --git a/engine/common/mod_bmodel.c b/engine/common/mod_bmodel.c index 37e22028..824e241f 100644 --- a/engine/common/mod_bmodel.c +++ b/engine/common/mod_bmodel.c @@ -36,7 +36,7 @@ typedef struct leaflist_s int count; int maxcount; qboolean overflowed; - short *list; + int *list; vec3_t mins, maxs; int topnode; // for overflows where each leaf can't be stored individually } leaflist_t; @@ -668,7 +668,7 @@ static void Mod_BoxLeafnums_r( leaflist_t *ll, mnode_t *node ) Mod_BoxLeafnums ================== */ -static int Mod_BoxLeafnums( const vec3_t mins, const vec3_t maxs, short *list, int listsize, int *topnode ) +static int Mod_BoxLeafnums( const vec3_t mins, const vec3_t maxs, int *list, int listsize, int *topnode ) { leaflist_t ll; @@ -699,7 +699,7 @@ is potentially visible */ qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits ) { - short leafList[MAX_BOX_LEAFS]; + int leafList[MAX_BOX_LEAFS]; int i, count; if( !visbits || !mins || !maxs ) @@ -884,6 +884,59 @@ int Mod_SampleSizeForFace( msurface_t *surf ) return LM_SAMPLE_SIZE; } +/* +================== +Mod_GetFaceContents + +determine face contents by name +================== +*/ +static int Mod_GetFaceContents( const char *name ) +{ + if( !Q_strnicmp( name, "SKY", 3 )) + return CONTENTS_SKY; + + if( name[0] == '!' || name[0] == '*' ) + { + if( !Q_strnicmp( name + 1, "lava", 4 )) + return CONTENTS_LAVA; + else if( !Q_strnicmp( name + 1, "slime", 5 )) + return CONTENTS_SLIME; + return CONTENTS_WATER; // otherwise it's water + } + + if( !Q_strnicmp( name, "water", 5 )) + return CONTENTS_WATER; + + return CONTENTS_SOLID; +} + +/* +================== +Mod_GetFaceContents + +determine face contents by name +================== +*/ +static mvertex_t *Mod_GetVertexByNumber( model_t *mod, int surfedge ) +{ + int lindex; + medge_t *edge; + + lindex = mod->surfedges[surfedge]; + + if( lindex > 0 ) + { + edge = &mod->edges[lindex]; + return &mod->vertexes[edge->v[0]]; + } + else + { + edge = &mod->edges[-lindex]; + return &mod->vertexes[edge->v[1]]; + } +} + /* ================== Mod_MakeNormalAxial @@ -1068,6 +1121,66 @@ static void Mod_CalcSurfaceBounds( msurface_t *surf ) VectorAverage( surf->info->mins, surf->info->maxs, surf->info->origin ); } +/* +================= +Mod_CreateFaceBevels +================= +*/ +static void Mod_CreateFaceBevels( msurface_t *surf ) +{ + vec3_t delta, edgevec; + byte *facebevel; + vec3_t faceNormal; + mvertex_t *v0, *v1; + int contents; + int i, size; + vec_t radius; + mfacebevel_t *fb; + + if( surf->texinfo && surf->texinfo->texture ) + contents = Mod_GetFaceContents( surf->texinfo->texture->name ); + else contents = CONTENTS_SOLID; + + size = sizeof( mfacebevel_t ) + surf->numedges * sizeof( mplane_t ); + facebevel = (byte *)Mem_Calloc( loadmodel->mempool, size ); + fb = (mfacebevel_t *)facebevel; + facebevel += sizeof( mfacebevel_t ); + fb->edges = (mplane_t *)facebevel; + fb->numedges = surf->numedges; + fb->contents = contents; + surf->info->bevel = fb; + + if( FBitSet( surf->flags, SURF_PLANEBACK )) + VectorNegate( surf->plane->normal, faceNormal ); + else VectorCopy( surf->plane->normal, faceNormal ); + + // compute face origin and plane edges + for( i = 0; i < surf->numedges; i++ ) + { + mplane_t *dest = &fb->edges[i]; + + v0 = Mod_GetVertexByNumber( loadmodel, surf->firstedge + i ); + v1 = Mod_GetVertexByNumber( loadmodel, surf->firstedge + (i + 1) % surf->numedges ); + VectorSubtract( v1->position, v0->position, edgevec ); + CrossProduct( faceNormal, edgevec, dest->normal ); + VectorNormalize( dest->normal ); + dest->dist = DotProduct( dest->normal, v0->position ); + dest->type = PlaneTypeForNormal( dest->normal ); + VectorAdd( fb->origin, v0->position, fb->origin ); + } + + VectorScale( fb->origin, 1.0f / surf->numedges, fb->origin ); + + // compute face radius + for( i = 0; i < surf->numedges; i++ ) + { + v0 = Mod_GetVertexByNumber( loadmodel, surf->firstedge + i ); + VectorSubtract( v0->position, fb->origin, delta ); + radius = DotProduct( delta, delta ); + fb->radius = Q_max( radius, fb->radius ); + } +} + /* ================= Mod_SetParent @@ -1520,7 +1633,7 @@ static void Mod_LoadEntities( dbspmodel_t *bmod ) { byte *entpatch = NULL; char token[MAX_TOKEN]; - char wadstring[2048]; + char wadstring[MAX_TOKEN]; string keyname; char *pfile; @@ -1822,6 +1935,8 @@ static void Mod_LoadTextures( dbspmodel_t *bmod ) for( i = 0; i < loadmodel->numtextures; i++ ) { + int txFlags = 0; + if( in->dataofs[i] == -1 ) { // create default texture (some mods requires this) @@ -1853,6 +1968,10 @@ static void Mod_LoadTextures( dbspmodel_t *bmod ) tx->width = mt->width; tx->height = mt->height; + + if( FBitSet( host.features, ENGINE_IMPROVED_LINETRACE ) && mt->name[0] == '{' ) + SetBits( txFlags, TF_KEEP_SOURCE ); // Paranoia2 texture alpha-tracing + if( mt->offsets[0] > 0 ) { int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6); @@ -1904,7 +2023,7 @@ static void Mod_LoadTextures( dbspmodel_t *bmod ) if( FS_FileExists( texpath, false )) { - tx->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texpath, NULL, 0, TF_ALLOW_EMBOSS ); + tx->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texpath, NULL, 0, TF_ALLOW_EMBOSS|txFlags ); bmod->wadlist.wadusage[j]++; // this wad are really used break; } @@ -1920,14 +2039,13 @@ static void Mod_LoadTextures( dbspmodel_t *bmod ) if( custom_palette ) size += sizeof( short ) + 768; Q_snprintf( texname, sizeof( texname ), "#%s:%s.mip", loadstat.name, mt->name ); - tx->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texname, (byte *)mt, size, TF_ALLOW_EMBOSS ); + tx->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texname, (byte *)mt, size, TF_ALLOW_EMBOSS|txFlags ); } // if texture is completely missed if( !tx->gl_texturenum ) { - if( host.type != HOST_DEDICATED ) - Con_DPrintf( S_ERROR "unable to find %s.mip\n", mt->name ); + Con_DPrintf( S_ERROR "unable to find %s.mip\n", mt->name ); tx->gl_texturenum = R_GetBuiltinTexture( REF_DEFAULT_TEXTURE ); } @@ -2225,6 +2343,7 @@ static void Mod_LoadSurfaces( dbspmodel_t *bmod ) Mod_CalcSurfaceBounds( out ); Mod_CalcSurfaceExtents( out ); + Mod_CreateFaceBevels( out ); // grab the second sample to detect colored lighting if( test_lightsize > 0 && lightofs != -1 ) @@ -2816,7 +2935,7 @@ check lump for existing */ int Mod_CheckLump( const char *filename, const int lump, int *lumpsize ) { - file_t *f = FS_Open( filename, "rb", true ); + file_t *f = FS_Open( filename, "rb", false ); byte buffer[sizeof( dheader_t ) + sizeof( dextrahdr_t )]; size_t prefetch_size = sizeof( buffer ); dextrahdr_t *extrahdr; @@ -2875,7 +2994,7 @@ reading random lump by user request */ int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize ) { - file_t *f = FS_Open( filename, "rb", true ); + file_t *f = FS_Open( filename, "rb", false ); byte buffer[sizeof( dheader_t ) + sizeof( dextrahdr_t )]; size_t prefetch_size = sizeof( buffer ); dextrahdr_t *extrahdr; diff --git a/engine/common/mod_studio.c b/engine/common/mod_studio.c index 383752ef..a90687ff 100644 --- a/engine/common/mod_studio.c +++ b/engine/common/mod_studio.c @@ -749,6 +749,8 @@ void Mod_StudioGetAttachment( const edict_t *e, int iAtt, float *origin, float * { mstudioattachment_t *pAtt; vec3_t angles2; + matrix3x4 localPose; + matrix3x4 worldPose; model_t *mod; mod = SV_ModelHandle( e->v.modelindex ); @@ -776,19 +778,15 @@ void Mod_StudioGetAttachment( const edict_t *e, int iAtt, float *origin, float * pBlendAPI->SV_StudioSetupBones( mod, e->v.frame, e->v.sequence, angles2, e->v.origin, e->v.controller, e->v.blending, pAtt->bone, e ); - // compute pos and angles - if( origin != NULL ) - Matrix3x4_VectorTransform( studio_bones[pAtt->bone], pAtt->org, origin ); + Matrix3x4_LoadIdentity( localPose ); + Matrix3x4_SetOrigin( localPose, pAtt->org[0], pAtt->org[1], pAtt->org[2] ); + Matrix3x4_ConcatTransforms( worldPose, studio_bones[pAtt->bone], localPose ); - if( FBitSet( host.features, ENGINE_COMPUTE_STUDIO_LERP ) && origin != NULL && angles != NULL ) - { - vec3_t forward, bonepos; + if( origin != NULL ) // origin is used always + Matrix3x4_OriginFromMatrix( worldPose, origin ); - Matrix3x4_OriginFromMatrix( studio_bones[pAtt->bone], bonepos ); - VectorSubtract( origin, bonepos, forward ); // make forward - VectorNormalizeFast( forward ); - VectorAngles( forward, angles ); - } + if( FBitSet( host.features, ENGINE_COMPUTE_STUDIO_LERP ) && angles != NULL ) + Matrix3x4_AnglesFromMatrix( worldPose, angles ); } /* @@ -807,7 +805,7 @@ void Mod_GetBonePosition( const edict_t *e, int iBone, float *origin, float *ang pBlendAPI->SV_StudioSetupBones( mod, e->v.frame, e->v.sequence, e->v.angles, e->v.origin, e->v.controller, e->v.blending, iBone, e ); if( origin ) Matrix3x4_OriginFromMatrix( studio_bones[iBone], origin ); - if( angles ) VectorAngles( studio_bones[iBone][0], angles ); // bone forward to angles + if( angles ) Matrix3x4_AnglesFromMatrix( studio_bones[iBone], angles ); } /* diff --git a/engine/common/model.c b/engine/common/model.c index bb65ed53..10915f62 100644 --- a/engine/common/model.c +++ b/engine/common/model.c @@ -120,6 +120,11 @@ void Mod_FreeModel( model_t *mod ) =============================================================================== */ +/* +================ +Mod_Init +================ +*/ void Mod_Init( void ) { com_studiocache = Mem_AllocPool( "Studio Cache" ); diff --git a/engine/common/net_buffer.c b/engine/common/net_buffer.c index abba581c..bb948e7c 100644 --- a/engine/common/net_buffer.c +++ b/engine/common/net_buffer.c @@ -214,11 +214,11 @@ void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits ) } } -void MSG_WriteBitLong( sizebuf_t *sb, uint data, int numbits, qboolean bSigned ) +void MSG_WriteBitLong( sizebuf_t *sb, int data, int numbits, qboolean bSigned ) { if( bSigned ) - MSG_WriteSBitLong( sb, (int)data, numbits ); - else MSG_WriteUBitLong( sb, data, numbits ); + MSG_WriteSBitLong( sb, data, numbits ); + else MSG_WriteUBitLong( sb, (uint)data, numbits ); } qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits ) @@ -616,7 +616,6 @@ void MSG_ReadVec3Angles( sizebuf_t *sb, vec3_t fa ) fa[2] = MSG_ReadBitAngle( sb, 16 ); } - int MSG_ReadLong( sizebuf_t *sb ) { return MSG_ReadSBitLong( sb, sizeof( int ) << 3 ); diff --git a/engine/common/net_buffer.h b/engine/common/net_buffer.h index 4a631898..53eb33ff 100644 --- a/engine/common/net_buffer.h +++ b/engine/common/net_buffer.h @@ -73,7 +73,7 @@ void MSG_Clear( sizebuf_t *sb ); void MSG_WriteOneBit( sizebuf_t *sb, int nValue ); void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits ); void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits ); -void MSG_WriteBitLong( sizebuf_t *sb, uint data, int numbits, qboolean bSigned ); +void MSG_WriteBitLong( sizebuf_t *sb, int data, int numbits, qboolean bSigned ); qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits ); void MSG_WriteBitAngle( sizebuf_t *sb, float fAngle, int numbits ); void MSG_WriteBitFloat( sizebuf_t *sb, float val ); diff --git a/engine/common/net_encode.c b/engine/common/net_encode.c index 5cdac1e6..8472d399 100644 --- a/engine/common/net_encode.c +++ b/engine/common/net_encode.c @@ -312,7 +312,7 @@ delta_info_t *Delta_FindStruct( const char *name ) { int i; - if( !name || !name[0] ) + if( !COM_CheckString( name )) return NULL; for( i = 0; i < NUM_FIELDS( dt_info ); i++ ) @@ -431,8 +431,12 @@ qboolean Delta_AddField( const char *pStructName, const char *pName, int flags, { if( !Q_strcmp( pField->name, pName )) { - Con_Reportf( "Delta_Add: %s->%s already existing\n", pStructName, pName ); - return false; // field already exist + // update existed field + pField->flags = flags; + pField->bits = bits; + pField->multiplier = mul; + pField->post_multiplier = post_mul; + return true; } } @@ -474,7 +478,7 @@ void Delta_WriteTableField( sizebuf_t *msg, int tableIndex, const delta_t *pFiel Assert( pField != NULL ); - if( !pField->name || !*pField->name ) + if( !COM_CheckString( pField->name )) return; // not initialized ? dt = Delta_FindStructByIndex( tableIndex ); @@ -484,7 +488,7 @@ void Delta_WriteTableField( sizebuf_t *msg, int tableIndex, const delta_t *pFiel Assert( nameIndex >= 0 && nameIndex < dt->maxFields ); MSG_BeginServerCmd( msg, svc_deltatable ); - MSG_WriteUBitLong( msg, tableIndex, 4 ); // assume we support 16 network tables + MSG_WriteUBitLong( msg, tableIndex, 4 ); // assume we support 16 network tables MSG_WriteUBitLong( msg, nameIndex, 8 ); // 255 fields by struct should be enough MSG_WriteUBitLong( msg, pField->flags, 10 ); // flags are indicated various input types MSG_WriteUBitLong( msg, pField->bits - 1, 5 ); // max received value is 32 (32 bit) @@ -626,7 +630,6 @@ qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delt } // read delta-bits - if(( *delta_script = COM_ParseFile( *delta_script, token )) == NULL ) { Con_DPrintf( S_ERROR "Delta_ReadField: %s field bits argument is missing\n", pField->name ); @@ -781,13 +784,8 @@ void Delta_InitFields( void ) Delta_ParseTable( &pfile, dt, encodeDll, encodeFunc ); } + Mem_Free( afile ); -#if 0 - // adding some required fields that user may forget or don't know how to specified - Delta_AddField( "event_t", "velocity[0]", DT_SIGNED | DT_FLOAT, 16, 8.0f, 1.0f ); - Delta_AddField( "event_t", "velocity[1]", DT_SIGNED | DT_FLOAT, 16, 8.0f, 1.0f ); - Delta_AddField( "event_t", "velocity[2]", DT_SIGNED | DT_FLOAT, 16, 8.0f, 1.0f ); -#endif } void Delta_Init( void ) @@ -894,73 +892,18 @@ Delta_ClampIntegerField prevent data to out of range ===================== */ -int Delta_ClampIntegerField( int iValue, qboolean bSigned, int bits ) +int Delta_ClampIntegerField( delta_t *pField, int iValue, qboolean bSigned, int numbits ) { - switch( bits ) +#ifdef _DEBUG + if( numbits < 32 && abs( iValue ) >= (uint)BIT( numbits )) + Msg( "%s %d overflow %d\n", pField->name, abs( iValue ), (uint)BIT( numbits )); +#endif + if( numbits < 32 ) { - case 1: - iValue = bound( 0, (byte)iValue, 1 ); - break; - case 2: - if( bSigned ) iValue = bound( -2, (short)iValue, 1 ); - else iValue = bound( 0, (word)iValue, 3 ); - break; - case 3: - if( bSigned ) iValue = bound( -4, (short)iValue, 3 ); - else iValue = bound( 0, (word)iValue, 7 ); - break; - case 4: - if( bSigned ) iValue = bound( -8, (short)iValue, 7 ); - else iValue = bound( 0, (word)iValue, 15 ); - break; - case 5: - if( bSigned ) iValue = bound( -16, (short)iValue, 15 ); - else iValue = bound( 0, (word)iValue, 31 ); - break; - case 6: - if( bSigned ) iValue = bound( -32, (short)iValue, 31 ); - else iValue = bound( 0, (word)iValue, 63 ); - break; - case 7: - if( bSigned ) iValue = bound( -64, (short)iValue, 63 ); - else iValue = bound( 0, (word)iValue, 127 ); - break; - case 8: - if( bSigned ) iValue = bound( -128, (short)iValue, 127 ); - else iValue = bound( 0, (word)iValue, 255 ); - break; - case 9: - if( bSigned ) iValue = bound( -256, (short)iValue, 255 ); - else iValue = bound( 0, (word)iValue, 511 ); - break; - case 10: - if( bSigned ) iValue = bound( -512, (short)iValue, 511 ); - else iValue = bound( 0, (word)iValue, 1023 ); - break; - case 11: - if( bSigned ) iValue = bound( -1024, (short)iValue, 1023 ); - else iValue = bound( 0, (word)iValue, 2047 ); - break; - case 12: - if( bSigned ) iValue = bound( -2048, (short)iValue, 2047 ); - else iValue = bound( 0, (word)iValue, 4095 ); - break; - case 13: - if( bSigned ) iValue = bound( -4096, (short)iValue, 4095 ); - else iValue = bound( 0, (word)iValue, 8191 ); - break; - case 14: - if( bSigned ) iValue = bound( -8192, (short)iValue, 8191 ); - else iValue = bound( 0, (word)iValue, 16383 ); - break; - case 15: - if( bSigned ) iValue = bound( -16384, (short)iValue, 16383 ); - else iValue = bound( 0, (word)iValue, 32767 ); - break; - case 16: - if( bSigned ) iValue = bound( -32768, (short)iValue, 32767 ); - else iValue = bound( 0, (word)iValue, 65535 ); - break; + int signbits = bSigned ? (numbits - 1) : numbits; + int maxnum = BIT( signbits ) - 1; + int minnum = bSigned ? -maxnum : 0; + iValue = bound( minnum, iValue, maxnum ); } return iValue; // clamped; @@ -1002,8 +945,8 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, float timeba toF = *(byte *)((byte *)to + pField->offset ); } - fromF = Delta_ClampIntegerField( fromF, bSigned, pField->bits ); - toF = Delta_ClampIntegerField( toF, bSigned, pField->bits ); + fromF = Delta_ClampIntegerField( pField, fromF, bSigned, pField->bits ); + toF = Delta_ClampIntegerField( pField, toF, bSigned, pField->bits ); if( pField->multiplier != 1.0f ) fromF *= pField->multiplier; if( pField->multiplier != 1.0f ) toF *= pField->multiplier; } @@ -1020,8 +963,8 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, float timeba toF = *(word *)((byte *)to + pField->offset ); } - fromF = Delta_ClampIntegerField( fromF, bSigned, pField->bits ); - toF = Delta_ClampIntegerField( toF, bSigned, pField->bits ); + fromF = Delta_ClampIntegerField( pField, fromF, bSigned, pField->bits ); + toF = Delta_ClampIntegerField( pField, toF, bSigned, pField->bits ); if( pField->multiplier != 1.0f ) fromF *= pField->multiplier; if( pField->multiplier != 1.0f ) toF *= pField->multiplier; } @@ -1038,8 +981,8 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, float timeba toF = *(uint *)((byte *)to + pField->offset ); } - fromF = Delta_ClampIntegerField( fromF, bSigned, pField->bits ); - toF = Delta_ClampIntegerField( toF, bSigned, pField->bits ); + fromF = Delta_ClampIntegerField( pField, fromF, bSigned, pField->bits ); + toF = Delta_ClampIntegerField( pField, toF, bSigned, pField->bits ); if( pField->multiplier != 1.0f ) fromF *= pField->multiplier; if( pField->multiplier != 1.0f ) toF *= pField->multiplier; } @@ -1175,21 +1118,21 @@ qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to if( pField->flags & DT_BYTE ) { iValue = *(byte *)((byte *)to + pField->offset ); - iValue = Delta_ClampIntegerField( iValue, bSigned, pField->bits ); + iValue = Delta_ClampIntegerField( pField, iValue, bSigned, pField->bits ); if( pField->multiplier != 1.0f ) iValue *= pField->multiplier; MSG_WriteBitLong( msg, iValue, pField->bits, bSigned ); } else if( pField->flags & DT_SHORT ) { iValue = *(word *)((byte *)to + pField->offset ); - iValue = Delta_ClampIntegerField( iValue, bSigned, pField->bits ); + iValue = Delta_ClampIntegerField( pField, iValue, bSigned, pField->bits ); if( pField->multiplier != 1.0f ) iValue *= pField->multiplier; MSG_WriteBitLong( msg, iValue, pField->bits, bSigned ); } else if( pField->flags & DT_INTEGER ) { iValue = *(uint *)((byte *)to + pField->offset ); - iValue = Delta_ClampIntegerField( iValue, bSigned, pField->bits ); + iValue = Delta_ClampIntegerField( pField, iValue, bSigned, pField->bits ); if( pField->multiplier != 1.0f ) iValue *= pField->multiplier; MSG_WriteBitLong( msg, iValue, pField->bits, bSigned ); } @@ -1197,6 +1140,7 @@ qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to { flValue = *(float *)((byte *)to + pField->offset ); iValue = (int)(flValue * pField->multiplier); + iValue = Delta_ClampIntegerField( pField, iValue, bSigned, pField->bits ); MSG_WriteBitLong( msg, iValue, pField->bits, bSigned ); } else if( pField->flags & DT_ANGLE ) @@ -1210,9 +1154,9 @@ qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to else if( pField->flags & DT_TIMEWINDOW_8 ) { flValue = *(float *)((byte *)to + pField->offset ); - flTime = Q_rint( timebase * 100.0f ) - Q_rint(flValue * 100.0f); + flTime = Q_rint( timebase * 100.0f ) - Q_rint( flValue * 100.0f ); iValue = (uint)abs( flTime ); - + iValue = Delta_ClampIntegerField( pField, iValue, bSigned, pField->bits ); MSG_WriteBitLong( msg, iValue, pField->bits, bSigned ); } else if( pField->flags & DT_TIMEWINDOW_BIG ) @@ -1220,7 +1164,7 @@ qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to flValue = *(float *)((byte *)to + pField->offset ); flTime = Q_rint( timebase * pField->multiplier ) - Q_rint( flValue * pField->multiplier ); iValue = (uint)abs( flTime ); - + iValue = Delta_ClampIntegerField( pField, iValue, bSigned, pField->bits ); MSG_WriteBitLong( msg, iValue, pField->bits, bSigned ); } else if( pField->flags & DT_STRING ) diff --git a/engine/common/pm_local.h b/engine/common/pm_local.h index a61ad1cd..76f797cf 100644 --- a/engine/common/pm_local.h +++ b/engine/common/pm_local.h @@ -36,6 +36,8 @@ qboolean PM_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec pmtrace_t PM_PlayerTraceExt( playermove_t *pm, vec3_t p1, vec3_t p2, int flags, int numents, physent_t *ents, int ignore_pe, pfnIgnore pmFilter ); int PM_TestPlayerPosition( playermove_t *pmove, vec3_t pos, pmtrace_t *ptrace, pfnIgnore pmFilter ); int PM_HullPointContents( hull_t *hull, int num, const vec3_t p ); +int PM_TruePointContents( playermove_t *pmove, const vec3_t p ); +int PM_PointContents( playermove_t *pmove, const vec3_t p ); void PM_ConvertTrace( trace_t *out, pmtrace_t *in, edict_t *ent ); // diff --git a/engine/common/pm_surface.c b/engine/common/pm_surface.c index 59a9ab1b..c7ccfb26 100644 --- a/engine/common/pm_surface.c +++ b/engine/common/pm_surface.c @@ -16,84 +16,160 @@ GNU General Public License for more details. #include "common.h" #include "mathlib.h" #include "pm_local.h" +#include "ref_common.h" + +#define FRAC_EPSILON (1.0f / 32.0f) typedef struct { - float fraction; - int contents; + float fraction; + int contents; + msurface_t *surface; } linetrace_t; +/* +============== +fix_coord + +converts the reletive tex coords to absolute +============== +*/ +static uint fix_coord( vec_t in, uint width ) +{ + if( in > 0 ) return (uint)in % width; + return width - ((uint)fabs( in ) % width); +} + +/* +============= +SampleMiptex + +fence texture testing +============= +*/ +int PM_SampleMiptex( const msurface_t *surf, const vec3_t point ) +{ + mextrasurf_t *info = surf->info; + mfacebevel_t *fb = info->bevel; + int contents; + vec_t ds, dt; + int x, y; + mtexinfo_t *tx; + texture_t *mt; + + // fill the default contents + if( fb ) contents = fb->contents; + else contents = CONTENTS_SOLID; + + if( !surf->texinfo || !surf->texinfo->texture ) + return contents; + + tx = surf->texinfo; + mt = tx->texture; + + if( mt->name[0] != '{' ) + return contents; + + // TODO: this won't work under dedicated + // should we bring up imagelib and keep original buffers? + if( !Host_IsDedicated() ) + { + const byte *data; + + data = ref.dllFuncs.R_GetTextureOriginalBuffer( mt->gl_texturenum ); + + if( !data ) return contents; // original doesn't kept + + ds = DotProduct( point, tx->vecs[0] ) + tx->vecs[0][3]; + dt = DotProduct( point, tx->vecs[1] ) + tx->vecs[1][3]; + + // convert ST to real pixels position + x = fix_coord( ds, mt->width - 1 ); + y = fix_coord( dt, mt->height - 1 ); + + ASSERT( x >= 0 && y >= 0 ); + + if( data[(mt->width * y) + x] == 255 ) + return CONTENTS_EMPTY; + return CONTENTS_SOLID; + } + + return contents; +} + /* ================== PM_RecursiveSurfCheck ================== */ -msurface_t *PM_RecursiveSurfCheck( model_t *model, mnode_t *node, vec3_t p1, vec3_t p2 ) +msurface_t *PM_RecursiveSurfCheck( model_t *mod, mnode_t *node, vec3_t p1, vec3_t p2 ) { float t1, t2, frac; - int side, ds, dt; - mplane_t *plane; + int i, side; msurface_t *surf; vec3_t mid; - int i; - +loc0: if( node->contents < 0 ) return NULL; - plane = node->plane; + t1 = PlaneDiff( p1, node->plane ); + t2 = PlaneDiff( p2, node->plane ); - if( plane->type < 3 ) + if( t1 >= -FRAC_EPSILON && t2 >= -FRAC_EPSILON ) { - t1 = p1[plane->type] - plane->dist; - t2 = p2[plane->type] - plane->dist; - } - else - { - t1 = DotProduct( plane->normal, p1 ) - plane->dist; - t2 = DotProduct( plane->normal, p2 ) - plane->dist; + node = node->children[0]; + goto loc0; } - if( t1 >= 0.0f && t2 >= 0.0f ) - return PM_RecursiveSurfCheck( model, node->children[0], p1, p2 ); - if( t1 < 0.0f && t2 < 0.0f ) - return PM_RecursiveSurfCheck( model, node->children[1], p1, p2 ); + if( t1 < FRAC_EPSILON && t2 < FRAC_EPSILON ) + { + node = node->children[1]; + goto loc0; + } + side = (t1 < 0.0f); frac = t1 / ( t1 - t2 ); - - if( frac < 0.0f ) frac = 0.0f; - if( frac > 1.0f ) frac = 1.0f; + frac = bound( 0.0f, frac, 1.0f ); VectorLerp( p1, frac, p2, mid ); - side = (t1 < 0.0f); - - // now this is weird. - surf = PM_RecursiveSurfCheck( model, node->children[side], p1, mid ); - - if( surf != NULL || ( t1 >= 0.0f && t2 >= 0.0f ) || ( t1 < 0.0f && t2 < 0.0f )) - { + if(( surf = PM_RecursiveSurfCheck( mod, node->children[side], p1, mid )) != NULL ) return surf; - } - surf = model->surfaces + node->firstsurface; - - for( i = 0; i < node->numsurfaces; i++, surf++ ) + // walk through real faces + for( i = 0; i < node->numsurfaces; i++ ) { - ds = (int)((float)DotProduct( mid, surf->texinfo->vecs[0] ) + surf->texinfo->vecs[0][3] ); - dt = (int)((float)DotProduct( mid, surf->texinfo->vecs[1] ) + surf->texinfo->vecs[1][3] ); + msurface_t *surf = &mod->surfaces[node->firstsurface + i]; + mextrasurf_t *info = surf->info; + mfacebevel_t *fb = info->bevel; + int j, contents; + vec3_t delta; - if( ds >= surf->texturemins[0] && dt >= surf->texturemins[1] ) + if( !fb ) continue; // ??? + + VectorSubtract( mid, fb->origin, delta ); + if( DotProduct( delta, delta ) >= fb->radius ) + continue; // no intersection + + for( j = 0; j < fb->numedges; j++ ) { - int s = ds - surf->texturemins[0]; - int t = dt - surf->texturemins[1]; - - if( s <= surf->extents[0] && t <= surf->extents[1] ) - return surf; + if( PlaneDiff( mid, &fb->edges[j] ) > FRAC_EPSILON ) + break; // outside the bounds } + + if( j != fb->numedges ) + continue; // we are outside the bounds of the facet + + // hit the surface + contents = PM_SampleMiptex( surf, mid ); + + if( contents != CONTENTS_EMPTY ) + return surf; + return NULL; // through the fence } - return PM_RecursiveSurfCheck( model, node->children[side^1], mid, p2 ); + return PM_RecursiveSurfCheck( mod, node->children[side^1], mid, p2 ); } /* @@ -160,32 +236,34 @@ PM_TestLine_r optimized trace for light gathering ================== */ -int PM_TestLine_r( mnode_t *node, vec_t p1f, vec_t p2f, const vec3_t start, const vec3_t stop, linetrace_t *trace ) +int PM_TestLine_r( model_t *mod, mnode_t *node, vec_t p1f, vec_t p2f, const vec3_t start, const vec3_t stop, linetrace_t *trace ) { float front, back; float frac, midf; - int r, side; + int i, r, side; vec3_t mid; loc0: if( node->contents < 0 ) - trace->contents = node->contents; - if( node->contents == CONTENTS_SOLID ) - return CONTENTS_SOLID; - if( node->contents == CONTENTS_SKY ) - return CONTENTS_SKY; - if( node->contents < 0 ) + { + // water, slime or lava interpret as empty + if( node->contents == CONTENTS_SOLID ) + return CONTENTS_SOLID; + if( node->contents == CONTENTS_SKY ) + return CONTENTS_SKY; + trace->fraction = 1.0f; return CONTENTS_EMPTY; + } front = PlaneDiff( start, node->plane ); back = PlaneDiff( stop, node->plane ); - if( front >= -ON_EPSILON && back >= -ON_EPSILON ) + if( front >= -FRAC_EPSILON && back >= -FRAC_EPSILON ) { node = node->children[0]; goto loc0; } - if( front < ON_EPSILON && back < ON_EPSILON ) + if( front < FRAC_EPSILON && back < FRAC_EPSILON ) { node = node->children[1]; goto loc0; @@ -198,15 +276,54 @@ loc0: VectorLerp( start, frac, stop, mid ); midf = p1f + ( p2f - p1f ) * frac; - r = PM_TestLine_r( node->children[side], p1f, midf, start, mid, trace ); + r = PM_TestLine_r( mod, node->children[side], p1f, midf, start, mid, trace ); if( r != CONTENTS_EMPTY ) { - trace->fraction = midf; + if( trace->surface == NULL ) + trace->fraction = midf; + trace->contents = r; return r; } - return PM_TestLine_r( node->children[!side], midf, p2f, mid, stop, trace ); + // walk through real faces + for( i = 0; i < node->numsurfaces; i++ ) + { + msurface_t *surf = &mod->surfaces[node->firstsurface + i]; + mextrasurf_t *info = surf->info; + mfacebevel_t *fb = info->bevel; + int j, contents; + vec3_t delta; + + if( !fb ) continue; + + VectorSubtract( mid, fb->origin, delta ); + if( DotProduct( delta, delta ) >= fb->radius ) + continue; // no intersection + + for( j = 0; j < fb->numedges; j++ ) + { + if( PlaneDiff( mid, &fb->edges[j] ) > FRAC_EPSILON ) + break; // outside the bounds + } + + if( j != fb->numedges ) + continue; // we are outside the bounds of the facet + + // hit the surface + contents = PM_SampleMiptex( surf, mid ); + + // fill the trace and out + trace->contents = contents; + trace->fraction = midf; + + if( contents != CONTENTS_EMPTY ) + trace->surface = surf; + + return contents; + } + + return PM_TestLine_r( mod, node->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 ) @@ -221,18 +338,19 @@ int PM_TestLineExt( playermove_t *pmove, physent_t *ents, int numents, const vec trace.contents = CONTENTS_EMPTY; trace.fraction = 1.0f; + trace.surface = NULL; for( i = 0; i < numents; i++ ) { pe = &ents[i]; - if( i != 0 && ( flags & PM_WORLD_ONLY )) + if( i != 0 && FBitSet( flags, PM_WORLD_ONLY )) break; if( !pe->model || pe->model->type != mod_brush || pe->solid != SOLID_BSP ) continue; - if( pe->rendermode != kRenderNormal ) + if( FBitSet( flags, PM_GLASS_IGNORE ) && pe->rendermode != kRenderNormal ) continue; hull = &pe->model->hulls[0]; @@ -257,8 +375,9 @@ int PM_TestLineExt( playermove_t *pmove, physent_t *ents, int numents, const vec trace_bbox.contents = CONTENTS_EMPTY; trace_bbox.fraction = 1.0f; + trace_bbox.surface = NULL; - PM_TestLine_r( &pe->model->nodes[hull->firstclipnode], 0.0f, 1.0f, start_l, end_l, &trace_bbox ); + PM_TestLine_r( pe->model, &pe->model->nodes[hull->firstclipnode], 0.0f, 1.0f, start_l, end_l, &trace_bbox ); if( trace_bbox.contents != CONTENTS_EMPTY || trace_bbox.fraction < trace.fraction ) { @@ -267,4 +386,4 @@ int PM_TestLineExt( playermove_t *pmove, physent_t *ents, int numents, const vec } return trace.contents; -} \ No newline at end of file +} diff --git a/engine/common/pm_trace.c b/engine/common/pm_trace.c index e159128c..c6bb13ae 100644 --- a/engine/common/pm_trace.c +++ b/engine/common/pm_trace.c @@ -654,4 +654,82 @@ int PM_TestPlayerPosition( playermove_t *pmove, vec3_t pos, pmtrace_t *ptrace, p } return -1; // didn't hit anything +} + +/* +============= +PM_TruePointContents + +============= +*/ +int PM_TruePointContents( playermove_t *pmove, const vec3_t p ) +{ + hull_t *hull = &pmove->physents[0].model->hulls[0]; + + if( hull ) + { + return PM_HullPointContents( hull, hull->firstclipnode, p ); + } + else + { + return CONTENTS_EMPTY; + } +} + +/* +============= +PM_PointContents + +============= +*/ +int PM_PointContents( playermove_t *pmove, const vec3_t p ) +{ + int i, contents; + hull_t *hull; + vec3_t test; + physent_t *pe; + + // sanity check + if( !p || !pmove->physents[0].model ) + return CONTENTS_NONE; + + // get base contents from world + contents = PM_HullPointContents( &pmove->physents[0].model->hulls[0], 0, p ); + + for( i = 1; i < pmove->numphysent; i++ ) + { + pe = &pmove->physents[i]; + + if( pe->solid != SOLID_NOT ) // disabled ? + continue; + + // only brushes can have special contents + if( !pe->model ) continue; + + // check water brushes accuracy + hull = &pe->model->hulls[0]; + + if( FBitSet( pe->model->flags, MODEL_HAS_ORIGIN ) && !VectorIsNull( pe->angles )) + { + matrix4x4 matrix; + + Matrix4x4_CreateFromEntity( matrix, pe->angles, pe->origin, 1.0f ); + Matrix4x4_VectorITransform( matrix, p, test ); + } + else + { + // offset the test point appropriately for this hull. + VectorSubtract( p, pe->origin, test ); + } + + // test hull for intersection with this model + if( PM_HullPointContents( hull, hull->firstclipnode, test ) == CONTENTS_EMPTY ) + continue; + + // compare contents ranking + if( RankForContents( pe->skin ) > RankForContents( contents )) + contents = pe->skin; // new content has more priority + } + + return contents; } \ No newline at end of file diff --git a/engine/common/zone.c b/engine/common/zone.c index 015b3c9a..25500dd3 100644 --- a/engine/common/zone.c +++ b/engine/common/zone.c @@ -256,7 +256,7 @@ qboolean Mem_IsAllocatedExt( byte *poolptr, void *data ) void Mem_CheckHeaderSentinels( void *data, const char *filename, int fileline ) { - memheader_t *mem; + memheader_t *mem; if( data == NULL ) Sys_Error( "Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)\n", filename, fileline ); @@ -269,7 +269,7 @@ void Mem_CheckHeaderSentinels( void *data, const char *filename, int fileline ) Sys_Error( "Mem_CheckSentinels: trashed header sentinel 1 (block allocated at %s:%i, sentinel check at %s:%i)\n", mem->filename, mem->fileline, filename, fileline ); } - if( *((byte *) mem + sizeof(memheader_t) + mem->size) != MEMHEADER_SENTINEL2 ) + if( *((byte *)mem + sizeof(memheader_t) + mem->size) != MEMHEADER_SENTINEL2 ) { mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args Sys_Error( "Mem_CheckSentinels: trashed header sentinel 2 (block allocated at %s:%i, sentinel check at %s:%i)\n", mem->filename, mem->fileline, filename, fileline ); diff --git a/engine/server/server.h b/engine/server/server.h index 3a6d3034..db4dd50a 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -264,7 +264,6 @@ typedef struct sv_client_s a program error, like an overflowed reliable buffer ============================================================================= */ - // MAX_CHALLENGES is made large to prevent a denial // of service attack that could cycle all of them // out before legitimate users connected @@ -458,6 +457,7 @@ void SV_ProcessFile( sv_client_t *cl, const char *filename ); void SV_SendResource( resource_t *pResource, sizebuf_t *msg ); void SV_SendResourceList( sv_client_t *cl ); void SV_AddToMaster( netadr_t from, sizebuf_t *msg ); +void Host_SetServerState( int state ); qboolean SV_IsSimulating( void ); qboolean SV_InitGame( void ); void SV_FreeClients( void ); diff --git a/engine/server/sv_cmds.c b/engine/server/sv_cmds.c index 29de4872..7cc661b5 100644 --- a/engine/server/sv_cmds.c +++ b/engine/server/sv_cmds.c @@ -16,6 +16,8 @@ GNU General Public License for more details. #include "common.h" #include "server.h" +extern convar_t *con_gamemaps; + /* ================= SV_ClientPrintf @@ -282,7 +284,7 @@ void SV_NextMap_f( void ) int i, next; search_t *t; - t = FS_Search( "maps/*.bsp", true, true ); // only in gamedir + t = FS_Search( "maps\\*.bsp", true, CVAR_TO_BOOL( con_gamemaps )); // only in gamedir if( !t ) { Con_Printf( "next map can't be found\n" ); @@ -869,6 +871,7 @@ void SV_EntityInfo_f( void ) Con_Printf( "\n" ); } } + /* ================== SV_InitHostCommands diff --git a/engine/server/sv_frame.c b/engine/server/sv_frame.c index 9544ee76..e0c5ef40 100644 --- a/engine/server/sv_frame.c +++ b/engine/server/sv_frame.c @@ -155,7 +155,7 @@ static void SV_AddEntitiesToPacket( edict_t *pViewEnt, edict_t *pClient, client_ if( fullvis ) continue; // portal ents will be added anyway, ignore recursion - // if its a portal entity, add everything visible from its camera position + // if it's a portal entity, add everything visible from its camera position if( from_client && FBitSet( ent->v.effects, EF_MERGE_VISIBILITY )) { SetBits( sv.hostflags, SVF_MERGE_VISIBILITY ); @@ -658,7 +658,7 @@ void SV_WriteEntitiesToClient( sv_client_t *cl, sizebuf_t *msg ) if( c_notsend > 0 ) Con_Printf( S_ERROR "Too many entities in visible packet list. Ignored %d entities\n", c_notsend ); cl->ignored_ents = c_notsend; - } + } // if there were portals visible, there may be out of order entities // in the list which will need to be resorted for the delta compression @@ -809,33 +809,18 @@ void SV_UpdateToReliableMessages( void ) continue; // reliables go to all connected or spawned if( MSG_GetNumBytesWritten( &sv.reliable_datagram ) < MSG_GetNumBytesLeft( &cl->netchan.message )) - { MSG_WriteBits( &cl->netchan.message, MSG_GetBuf( &sv.reliable_datagram ), MSG_GetNumBitsWritten( &sv.reliable_datagram )); - } - else - { - Netchan_CreateFragments( &cl->netchan, &sv.reliable_datagram ); - } + else Netchan_CreateFragments( &cl->netchan, &sv.reliable_datagram ); if( MSG_GetNumBytesWritten( &sv.datagram ) < MSG_GetNumBytesLeft( &cl->datagram )) - { MSG_WriteBits( &cl->datagram, MSG_GetBuf( &sv.datagram ), MSG_GetNumBitsWritten( &sv.datagram )); - } - else - { - Con_DPrintf( S_WARN "Ignoring unreliable datagram for %s, would overflow\n", cl->name ); - } + else Con_DPrintf( S_WARN "Ignoring unreliable datagram for %s, would overflow\n", cl->name ); if( FBitSet( cl->flags, FCL_HLTV_PROXY )) { if( MSG_GetNumBytesWritten( &sv.spec_datagram ) < MSG_GetNumBytesLeft( &cl->datagram )) - { MSG_WriteBits( &cl->datagram, MSG_GetBuf( &sv.spec_datagram ), MSG_GetNumBitsWritten( &sv.spec_datagram )); - } - else - { - Con_DPrintf( S_WARN "Ignoring spectator datagram for %s, would overflow\n", cl->name ); - } + else Con_DPrintf( S_WARN "Ignoring spectator datagram for %s, would overflow\n", cl->name ); } } diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index 974c50e9..55c07749 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -766,18 +766,18 @@ Create entity patch for selected map */ void SV_WriteEntityPatch( const char *filename ) { - int ver = -1, lumpofs = 0, lumplen = 0; - byte buf[MAX_SYSPATH]; // 1 kb + int lumpofs = 0, lumplen = 0; + byte buf[MAX_TOKEN]; // 1 kb string bspfilename; dheader_t *header; file_t *f; - Q_strncpy( bspfilename, va( "maps/%s.bsp", filename ), sizeof( bspfilename )); + Q_strncpy( bspfilename, va( "maps/%s.bsp", filename ), sizeof( bspfilename )); f = FS_Open( bspfilename, "rb", false ); if( !f ) return; - memset( buf, 0, MAX_SYSPATH ); - FS_Read( f, buf, MAX_SYSPATH ); + memset( buf, 0, MAX_TOKEN ); + FS_Read( f, buf, MAX_TOKEN ); header = (dheader_t *)buf; // check all the lumps and some other errors @@ -815,9 +815,9 @@ pfnMapIsValid use this static char *SV_ReadEntityScript( const char *filename, int *flags ) { string bspfilename, entfilename; - int ver = -1, lumpofs = 0, lumplen = 0; + int lumpofs = 0, lumplen = 0; + byte buf[MAX_TOKEN]; char *ents = NULL; - byte buf[1024]; dheader_t *header; size_t ft1, ft2; file_t *f; @@ -829,8 +829,8 @@ static char *SV_ReadEntityScript( const char *filename, int *flags ) if( !f ) return NULL; SetBits( *flags, MAP_IS_EXIST ); - memset( buf, 0, MAX_SYSPATH ); - FS_Read( f, buf, MAX_SYSPATH ); + memset( buf, 0, MAX_TOKEN ); + FS_Read( f, buf, MAX_TOKEN ); header = (dheader_t *)buf; // check all the lumps and some other errors @@ -848,7 +848,7 @@ static char *SV_ReadEntityScript( const char *filename, int *flags ) // check for entfile too Q_strncpy( entfilename, va( "maps/%s.ent", filename ), sizeof( entfilename )); - // make sure what entity patch is never than bsp + // make sure what entity patch is newer than bsp ft1 = FS_FileTime( bspfilename, false ); ft2 = FS_FileTime( entfilename, true ); @@ -889,7 +889,7 @@ int SV_MapIsValid( const char *filename, const char *spawn_entity, const char *l if( ents ) { qboolean need_landmark = Q_strlen( landmark_name ) > 0 ? true : false; - char token[2048]; + char token[MAX_TOKEN]; string check_name; // g-cont. in-dev mode we can entering on map even without "info_player_start" @@ -1294,6 +1294,7 @@ pfnSetModel void pfnSetModel( edict_t *e, const char *m ) { char name[MAX_QPATH]; + qboolean found = false; model_t *mod; int i; @@ -1306,19 +1307,17 @@ void pfnSetModel( edict_t *e, const char *m ) if( COM_CheckString( name )) { - qboolean notfound = true; - // check to see if model was properly precached for( i = 1; i < MAX_MODELS && sv.model_precache[i][0]; i++ ) { if( !Q_stricmp( sv.model_precache[i], name )) { - notfound = false; + found = true; break; } } - if( notfound ) + if( !found ) { Con_Printf( S_ERROR "Failed to set model %s: was not precached\n", name ); return; @@ -2800,7 +2799,7 @@ void pfnWriteString( const char *src ) { static char string[MAX_USERMSG_LENGTH]; int len = Q_strlen( src ) + 1; - int rem = rem = sizeof( string ) - 1; + int rem = sizeof( string ) - 1; char *dst; if( len == 1 ) @@ -4756,7 +4755,7 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent ) // keynames with a leading underscore are used for // utility comments and are immediately discarded by engine - if( keyname[0] == '_' && Q_strcmp( keyname, "_light" )) + if( FBitSet( world.flags, FWORLD_SKYSPHERE ) && keyname[0] == '_' ) continue; // ignore attempts to set value "" @@ -4859,7 +4858,7 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent ) Mem_Free( pkvd[i].szValue ); } - if( classname ) + if( classname && Mem_IsAllocatedExt( host.mempool, classname )) Mem_Free( classname ); return true; diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 727c7e06..3a4b9911 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -136,7 +136,6 @@ int SV_SoundIndex( const char *filename ) char name[MAX_QPATH]; int i; - // don't precache sentence names! if( !COM_CheckString( filename )) return 0; @@ -264,7 +263,7 @@ int SV_GenericIndex( const char *filename ) ================ SV_ModelHandle -register unique model for a server and client +get model by handle ================ */ model_t *SV_ModelHandle( int modelindex ) @@ -300,6 +299,13 @@ void SV_ReadResourceList( const char *filename ) Mem_Free( afile ); } +/* +================ +SV_CreateGenericResources + +loads external resource list +================ +*/ void SV_CreateGenericResources( void ) { string filename; @@ -312,6 +318,13 @@ void SV_CreateGenericResources( void ) SV_ReadResourceList( "reslist.txt" ); } +/* +================ +SV_CreateResourceList + +add resources to common list +================ +*/ void SV_CreateResourceList( void ) { qboolean ffirstsent = false; @@ -582,7 +595,7 @@ void SV_ActivateServer( int runPhysics ) Mod_FreeUnused (); host.movevars_changed = true; - sv.state = ss_active; + Host_SetServerState( ss_active ); Con_DPrintf( "level loaded at %.2f sec\n", Sys_DoubleTime() - svs.timestart ); @@ -620,7 +633,7 @@ void SV_DeactivateServer( void ) svgame.globals->time = sv.time; svgame.dllFuncs.pfnServerDeactivate(); - sv.state = ss_dead; + Host_SetServerState( ss_dead ); SV_FreeEdicts (); @@ -833,7 +846,7 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba COM_FileBase( mapname, sv.name ); // precache and static commands can be issued during map initialization - sv.state = ss_loading; + Host_SetServerState( ss_loading ); if( startspot ) Q_strncpy( sv.startspot, startspot, sizeof( sv.startspot )); diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index f3aa5aef..90baeeeb 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -152,6 +152,9 @@ send updates to client if changed */ void SV_UpdateMovevars( qboolean initialize ) { + if( sv.state == ss_dead ) + return; + if( !initialize && !host.movevars_changed ) return; @@ -260,6 +263,13 @@ void SV_CheckCmdTimes( void ) } } +/* +================= +SV_ProcessFile + +process incoming file (customization) +================= +*/ void SV_ProcessFile( sv_client_t *cl, const char *filename ) { customization_t *pList; @@ -549,11 +559,6 @@ qboolean SV_IsSimulating( void ) return false; } -/* -================= -SV_RunGameFrame -================= -*/ /* ================= SV_RunGameFrame @@ -639,6 +644,17 @@ void Host_ServerFrame( void ) Master_Heartbeat (); } +/* +================== +Host_SetServerState +================== +*/ +void Host_SetServerState( int state ) +{ + Cvar_FullSet( "host_serverstate", va( "%i", state ), FCVAR_READ_ONLY ); + sv.state = state; +} + //============================================================================ /* @@ -877,7 +893,7 @@ to totally exit after returning from this function. */ void SV_FinalMessage( const char *message, qboolean reconnect ) { - byte msg_buf[64]; + byte msg_buf[1024]; sv_client_t *cl; sizebuf_t msg; int i; @@ -984,6 +1000,9 @@ void SV_Shutdown( const char *finalmsg ) SV_FreeClients(); svs.maxclients = 0; + // release all models + Mod_FreeAll(); + HPAK_FlushHostQueue(); Log_Printf( "Server shutdown\n" ); Log_Close(); diff --git a/engine/server/sv_pmove.c b/engine/server/sv_pmove.c index 0d059133..733e7f9e 100644 --- a/engine/server/sv_pmove.c +++ b/engine/server/sv_pmove.c @@ -73,7 +73,7 @@ qboolean SV_CopyEdictToPhysEnt( physent_t *pe, edict_t *ed ) if( FBitSet( ed->v.flags, FL_CLIENT )) { // client - SV_GetTrueOrigin( &svs.clients[pe->info - 1], pe->info, pe->origin ); + SV_GetTrueOrigin( sv.current_client, pe->info, pe->origin ); if( FBitSet( ed->v.flags, FL_FAKECLIENT )) // fakeclients have client flag too { // bot @@ -306,7 +306,7 @@ void SV_AddLaddersToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3 model_t *mod; physent_t *pe; - // get water edicts + // get ladder edicts for( l = node->solid_edicts.next; l != &node->solid_edicts; l = next ) { next = l->next; @@ -362,6 +362,11 @@ static void pfnParticle( const float *origin, int color, float life, int zpos, i MSG_WriteByte( &sv.reliable_datagram, bound( 0, life * 8, 255 )); } +int SV_TestLine( const vec3_t start, const vec3_t end, int flags ) +{ + return PM_TestLineExt( svgame.pmove, svgame.pmove->physents, svgame.pmove->numphysent, start, end, flags ); +} + static int pfnTestPlayerPosition( float *pos, pmtrace_t *ptrace ) { return PM_TestPlayerPosition( svgame.pmove, pos, ptrace, NULL ); @@ -390,7 +395,7 @@ static int pfnPointContents( float *p, int *truecontents ) { int cont, truecont; - truecont = cont = SV_TruePointContents( p ); + truecont = cont = PM_PointContents( svgame.pmove, p ); if( truecontents ) *truecontents = truecont; if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN ) @@ -400,7 +405,7 @@ static int pfnPointContents( float *p, int *truecontents ) static int pfnTruePointContents( float *p ) { - return SV_TruePointContents( p ); + return PM_TruePointContents( svgame.pmove, p ); } static int pfnHullPointContents( struct hull_s *hull, int num, float *p ) @@ -778,11 +783,11 @@ static void SV_FinishPMove( playermove_t *pmove, sv_client_t *cl ) if( pmove->onground == -1 ) { - clent->v.flags &= ~FL_ONGROUND; + ClearBits( clent->v.flags, FL_ONGROUND ); } else if( pmove->onground >= 0 && pmove->onground < pmove->numphysent ) { - clent->v.flags |= FL_ONGROUND; + SetBits( clent->v.flags, FL_ONGROUND ); clent->v.groundentity = EDICT_NUM( pmove->physents[pmove->onground].info ); } @@ -903,10 +908,7 @@ void SV_SetupMoveInterpolant( sv_client_t *cl ) if( SV_UnlagCheckTeleport( state->origin, lerp->finalpos )) lerp->nointerp = true; } - else - { - lerp->firstframe = true; - } + else lerp->firstframe = true; VectorCopy( state->origin, lerp->finalpos ); } @@ -1004,10 +1006,10 @@ void SV_RestoreMoveInterpolant( sv_client_t *cl ) oldlerp = &svgame.interp[i]; - if( VectorCompare( oldlerp->oldpos, oldlerp->newpos ) || !oldlerp->moving ) + if( VectorCompareEpsilon( oldlerp->oldpos, oldlerp->newpos, ON_EPSILON )) continue; // they didn't actually move. - if( !oldlerp->active ) + if( !oldlerp->moving || !oldlerp->active ) continue; if( VectorCompare( oldlerp->curpos, check->edict->v.origin )) @@ -1057,9 +1059,7 @@ void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed ) } if( !FBitSet( cl->flags, FCL_FAKECLIENT )) - { SV_SetupMoveInterpolant( cl ); - } svgame.dllFuncs.pfnCmdStart( cl->edict, ucmd, random_seed ); diff --git a/engine/server/sv_world.c b/engine/server/sv_world.c index 70d65186..2d67ec31 100644 --- a/engine/server/sv_world.c +++ b/engine/server/sv_world.c @@ -1113,6 +1113,7 @@ or custom physics implementation */ void SV_CustomClipMoveToEntity( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, trace_t *trace ) { + // initialize custom trace memset( trace, 0, sizeof( trace_t )); VectorCopy( end, trace->endpos ); trace->allsolid = true; @@ -1256,7 +1257,7 @@ static void SV_ClipToLinks( areanode_t *node, moveclip_t *clip ) if( !SV_ClipToEntity( touch, clip )) return; // trace.allsoild } - + // recurse down both sides if( node->axis == -1 ) return; @@ -1288,7 +1289,7 @@ static void SV_ClipToPortals( areanode_t *node, moveclip_t *clip ) if( !SV_ClipToEntity( touch, clip )) return; // trace.allsoild } - + // recurse down both sides if( node->axis == -1 ) return; diff --git a/ref_gl/gl_beams.c b/ref_gl/gl_beams.c index a73f425f..6dc29b06 100644 --- a/ref_gl/gl_beams.c +++ b/ref_gl/gl_beams.c @@ -485,7 +485,7 @@ void R_DrawDisk( vec3_t source, vec3_t delta, float width, float scale, float fr scale = scale * length; // clamp the beam width - w = fmod( freq, width ) * delta[2]; + w = fmod( freq, width * 0.1f ) * delta[2]; // NOTE: we must force the degenerate triangles to be on the edge for( i = 0; i < segments; i++ ) diff --git a/ref_gl/gl_decals.c b/ref_gl/gl_decals.c index c2c1cc53..1ea17337 100644 --- a/ref_gl/gl_decals.c +++ b/ref_gl/gl_decals.c @@ -75,7 +75,7 @@ static void R_DecalUnlink( decal_t *pdecal ) else { tmp = pdecal->psurface->pdecals; - if( !tmp ) gEngfuncs.Host_Error( "D_DecalUnlink: bad decal list\n" ); + if( !tmp ) gEngfuncs.Host_Error( "R_DecalUnlink: bad decal list\n" ); while( tmp->pnext ) { diff --git a/ref_gl/gl_image.c b/ref_gl/gl_image.c index 3fcba776..71bf502c 100644 --- a/ref_gl/gl_image.c +++ b/ref_gl/gl_image.c @@ -111,6 +111,9 @@ void GL_ApplyTextureParams( gl_texture_t *tex ) { vec4_t border = { 0.0f, 0.0f, 0.0f, 1.0f }; + if( !glw_state.initialized ) + return; + Assert( tex != NULL ); // set texture filter @@ -347,6 +350,9 @@ static size_t GL_CalcImageSize( pixformat_t format, int width, int height, int d switch( format ) { + case PF_LUMINANCE: + size = width * height * depth; + break; case PF_RGB_24: case PF_BGR_24: size = width * height * depth * 3; @@ -1086,6 +1092,10 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) qboolean normalMap; const byte *bufend; + // dedicated server + if( !glw_state.initialized ) + return true; + Assert( pic != NULL ); Assert( tex != NULL ); @@ -1211,6 +1221,7 @@ do specified actions on pixels */ static void GL_ProcessImage( gl_texture_t *tex, rgbdata_t *pic ) { + float emboss_scale = 0.0f; uint img_flags = 0; // force upload texture as RGB or RGBA (detail textures requires this) @@ -1256,8 +1267,12 @@ static void GL_ProcessImage( gl_texture_t *tex, rgbdata_t *pic ) if( pic->type == PF_INDEXED_24 || pic->type == PF_INDEXED_32 ) img_flags |= IMAGE_FORCE_RGBA; + // dedicated server doesn't register this variable + if( gl_emboss_scale != NULL ) + emboss_scale = gl_emboss_scale->value; + // processing image before uploading (force to rgba, make luma etc) - if( pic->buffer ) gEngfuncs.Image_Process( &pic, 0, 0, img_flags, gl_emboss_scale->value ); + if( pic->buffer ) gEngfuncs.Image_Process( &pic, 0, 0, img_flags, emboss_scale ); if( FBitSet( tex->flags, TF_LUMINANCE )) ClearBits( pic->flags, IMAGE_HAS_COLOR ); @@ -1271,7 +1286,7 @@ GL_CheckTexName */ qboolean GL_CheckTexName( const char *name ) { - if( !COM_CheckString( name ) || !glw_state.initialized ) + if( !COM_CheckString( name )) return false; // because multi-layered textures can exceed name string @@ -1386,7 +1401,8 @@ static void GL_DeleteTexture( gl_texture_t *tex ) if( tex->original ) gEngfuncs.FS_FreeImage( tex->original ); - pglDeleteTextures( 1, &tex->texnum ); + if( glw_state.initialized ) + pglDeleteTextures( 1, &tex->texnum ); memset( tex, 0, sizeof( *tex )); } @@ -1644,6 +1660,7 @@ int GL_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags } GL_ProcessImage( tex, pic ); + if( !GL_UploadTexture( tex, pic )) { memset( tex, 0, sizeof( gl_texture_t )); @@ -1770,8 +1787,7 @@ GL_FreeTexture void GL_FreeTexture( GLenum texnum ) { // number 0 it's already freed - if( texnum <= 0 || !glw_state.initialized ) - return; + if( texnum <= 0 ) return; GL_DeleteTexture( &gl_textures[texnum] ); } @@ -1828,6 +1844,23 @@ void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor ) gEngfuncs.FS_FreeImage( pic ); } +/* +================ +GL_TexMemory + +return size of all uploaded textures +================ +*/ +int GL_TexMemory( void ) +{ + int i, total = 0; + + for( i = 0; i < gl_numTextures; i++ ) + total += gl_textures[i].size; + + return total; +} + /* ============================================================================== diff --git a/ref_gl/gl_local.h b/ref_gl/gl_local.h index d9b48916..66b34ec1 100644 --- a/ref_gl/gl_local.h +++ b/ref_gl/gl_local.h @@ -235,7 +235,6 @@ typedef struct int recursion_level; int max_recursion; - byte visbytes[(MAX_MAP_LEAFS+7)/8]; // member custom PVS int lightstylevalue[MAX_LIGHTSTYLES]; // value 0 - 65536 int block_size; // lightmap blocksize @@ -360,6 +359,7 @@ void R_InitDlightTexture( void ); void R_TextureList_f( void ); void R_InitImages( void ); void R_ShutdownImages( void ); +int GL_TexMemory( void ); // // gl_rlight.c @@ -682,6 +682,7 @@ typedef struct GLboolean texIdentityMatrix[MAX_TEXTURE_UNITS]; GLint genSTEnabled[MAX_TEXTURE_UNITS]; // 0 - disabled, OR 1 - S, OR 2 - T, OR 4 - R GLint texCoordArrayMode[MAX_TEXTURE_UNITS]; // 0 - disabled, 1 - enabled, 2 - cubemap + GLint isFogEnabled; int faceCull; diff --git a/ref_gl/gl_opengl.c b/ref_gl/gl_opengl.c index c53bf53a..67a9c865 100644 --- a/ref_gl/gl_opengl.c +++ b/ref_gl/gl_opengl.c @@ -644,13 +644,13 @@ void GL_InitExtensionsBigGL() } GL_CheckExtension( "GL_ARB_texture_non_power_of_two", NULL, "gl_texture_npot", GL_ARB_TEXTURE_NPOT_EXT ); - GL_CheckExtension( "GL_ARB_texture_compression", texturecompressionfuncs, "gl_dds_hardware_support", GL_TEXTURE_COMPRESSION_EXT ); + GL_CheckExtension( "GL_ARB_texture_compression", texturecompressionfuncs, "gl_texture_dxt_compression", GL_TEXTURE_COMPRESSION_EXT ); GL_CheckExtension( "GL_EXT_texture_edge_clamp", NULL, "gl_clamp_to_edge", GL_CLAMPTOEDGE_EXT ); if( !GL_Support( GL_CLAMPTOEDGE_EXT )) GL_CheckExtension( "GL_SGIS_texture_edge_clamp", NULL, "gl_clamp_to_edge", GL_CLAMPTOEDGE_EXT ); glConfig.max_texture_anisotropy = 0.0f; - GL_CheckExtension( "GL_EXT_texture_filter_anisotropic", NULL, "gl_ext_anisotropic_filter", GL_ANISOTROPY_EXT ); + GL_CheckExtension( "GL_EXT_texture_filter_anisotropic", NULL, "gl_texture_anisotropic_filter", GL_ANISOTROPY_EXT ); if( GL_Support( GL_ANISOTROPY_EXT )) pglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.max_texture_anisotropy ); @@ -663,12 +663,13 @@ void GL_InitExtensionsBigGL() if( GL_Support( GL_TEXTURE_LOD_BIAS )) pglGetFloatv( GL_MAX_TEXTURE_LOD_BIAS_EXT, &glConfig.max_texture_lod_bias ); - GL_CheckExtension( "GL_ARB_texture_border_clamp", NULL, "gl_ext_texborder_clamp", GL_CLAMP_TEXBORDER_EXT ); - GL_CheckExtension( "GL_ARB_depth_texture", NULL, "gl_depthtexture", GL_DEPTH_TEXTURE ); - GL_CheckExtension( "GL_ARB_texture_float", NULL, "gl_arb_texture_float", GL_ARB_TEXTURE_FLOAT_EXT ); - GL_CheckExtension( "GL_ARB_depth_buffer_float", NULL, "gl_arb_depth_float", GL_ARB_DEPTH_FLOAT_EXT ); + GL_CheckExtension( "GL_ARB_texture_border_clamp", NULL, NULL, GL_CLAMP_TEXBORDER_EXT ); + + GL_CheckExtension( "GL_ARB_depth_texture", NULL, NULL, GL_DEPTH_TEXTURE ); + GL_CheckExtension( "GL_ARB_texture_float", NULL, "gl_texture_float", GL_ARB_TEXTURE_FLOAT_EXT ); + GL_CheckExtension( "GL_ARB_depth_buffer_float", NULL, "gl_texture_depth_float", GL_ARB_DEPTH_FLOAT_EXT ); GL_CheckExtension( "GL_EXT_gpu_shader4", NULL, NULL, GL_EXT_GPU_SHADER4 ); // don't confuse users - GL_CheckExtension( "GL_ARB_shading_language_100", NULL, "gl_glslprogram", GL_SHADER_GLSL100_EXT ); + GL_CheckExtension( "GL_ARB_shading_language_100", NULL, NULL, GL_SHADER_GLSL100_EXT ); GL_CheckExtension( "GL_ARB_vertex_buffer_object", vbofuncs, "gl_vertex_buffer_object", GL_ARB_VERTEX_BUFFER_OBJECT_EXT ); // rectangle textures support diff --git a/ref_gl/gl_rmain.c b/ref_gl/gl_rmain.c index db237dc9..60a0191b 100644 --- a/ref_gl/gl_rmain.c +++ b/ref_gl/gl_rmain.c @@ -41,18 +41,14 @@ static int R_RankForRenderMode( int rendermode ) void R_AllowFog( qboolean allowed ) { - static int isFogEnabled; - if( allowed ) { - if( isFogEnabled ) + if( glState.isFogEnabled ) pglEnable( GL_FOG ); } else { - isFogEnabled = pglIsEnabled( GL_FOG ); - - if( isFogEnabled ) + if( glState.isFogEnabled ) pglDisable( GL_FOG ); } } @@ -498,6 +494,9 @@ static void R_SetupFrame( void ) // setup viewplane dist RI.viewplanedist = DotProduct( RI.vieworg, RI.vforward ); + // NOTE: this request is the fps-killer on some NVidia drivers + glState.isFogEnabled = pglIsEnabled( GL_FOG ); + if( !gl_nosort->value ) { // sort translucents entities by rendermode and distance @@ -701,7 +700,11 @@ static void R_CheckFog( void ) // in some cases waterlevel jumps from 3 to 1. Catch it RI.cached_waterlevel = ENGINE_GET_PARM( PARM_WATER_LEVEL ); RI.cached_contents = CONTENTS_EMPTY; - if( !RI.fogCustom ) pglDisable( GL_FOG ); + if( !RI.fogCustom ) + { + glState.isFogEnabled = false; + pglDisable( GL_FOG ); + } } return; } diff --git a/ref_gl/gl_rmisc.c b/ref_gl/gl_rmisc.c index eff199a9..20f4f087 100644 --- a/ref_gl/gl_rmisc.c +++ b/ref_gl/gl_rmisc.c @@ -156,6 +156,7 @@ void R_NewMap( void ) for( i = 0; i < WORLDMODEL->numleafs; i++ ) WORLDMODEL->leafs[i+1].efrags = NULL; + glState.isFogEnabled = false; tr.skytexturenum = -1; tr.max_recursion = 0; pglDisable( GL_FOG ); diff --git a/ref_gl/gl_rpart.c b/ref_gl/gl_rpart.c index 3d65eedc..1f6a6972 100644 --- a/ref_gl/gl_rpart.c +++ b/ref_gl/gl_rpart.c @@ -287,9 +287,6 @@ void CL_DrawParticlesExternal( const ref_viewpass_t *rvp, qboolean trans_pass, f R_SetupRefParams( rvp ); R_SetupFrustum(); R_SetupGL( false ); // don't touch GL-states - - // setup PVS for frame - memcpy( RI.visbytes, tr.visbytes, gpGlobals->visbytes ); tr.frametime = frametime; gEngfuncs.CL_DrawEFX( frametime, trans_pass ); diff --git a/ref_gl/gl_rsurf.c b/ref_gl/gl_rsurf.c index 6397a690..91acd821 100644 --- a/ref_gl/gl_rsurf.c +++ b/ref_gl/gl_rsurf.c @@ -205,7 +205,7 @@ void GL_SetupFogColorForSurfaces( void ) vec3_t fogColor; float factor, div; - if( !pglIsEnabled( GL_FOG )) + if( !glState.isFogEnabled) return; if( RI.currententity && RI.currententity->curstate.rendermode == kRenderTransTexture ) @@ -225,7 +225,7 @@ void GL_SetupFogColorForSurfaces( void ) void GL_ResetFogColor( void ) { // restore fog here - if( pglIsEnabled( GL_FOG )) + if( glState.isFogEnabled ) pglFogfv( GL_FOG_COLOR, RI.fogColor ); } @@ -1155,7 +1155,7 @@ void R_RenderBrushPoly( msurface_t *fa, int cull_type ) if( CVAR_TO_BOOL( r_detailtextures )) { - if( pglIsEnabled( GL_FOG )) + if( glState.isFogEnabled ) { // don't apply detail textures for windows in the fog if( RI.currententity->curstate.rendermode != kRenderTransTexture ) diff --git a/ref_gl/gl_studio.c b/ref_gl/gl_studio.c index ca9be5b2..3418f547 100644 --- a/ref_gl/gl_studio.c +++ b/ref_gl/gl_studio.c @@ -1302,8 +1302,6 @@ StudioCalcAttachments static void R_StudioCalcAttachments( void ) { mstudioattachment_t *pAtt; - vec3_t forward, bonepos; - vec3_t localOrg, localAng; int i; // calculate attachment points @@ -1312,11 +1310,6 @@ static void R_StudioCalcAttachments( void ) for( i = 0; i < Q_min( MAXSTUDIOATTACHMENTS, m_pStudioHeader->numattachments ); i++ ) { Matrix3x4_VectorTransform( g_studio.lighttransform[pAtt[i].bone], pAtt[i].org, RI.currententity->attachment[i] ); - VectorSubtract( RI.currententity->attachment[i], RI.currententity->origin, localOrg ); - Matrix3x4_OriginFromMatrix( g_studio.lighttransform[pAtt[i].bone], bonepos ); - VectorSubtract( localOrg, bonepos, forward ); // make forward - VectorNormalizeFast( forward ); - VectorAngles( forward, localAng ); } } @@ -3826,7 +3819,7 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture gEngfuncs.Image_SetMDLPointer((byte *)phdr + ptexture->index); size = sizeof( mstudiotexture_t ) + ptexture->width * ptexture->height + 768; - if( FBitSet( ENGINE_GET_PARM( PARM_FEATURES ), ENGINE_LOAD_DELUXEDATA ) && FBitSet( ptexture->flags, STUDIO_NF_MASKED )) + if( FBitSet( ENGINE_GET_PARM( PARM_FEATURES ), ENGINE_IMPROVED_LINETRACE ) && FBitSet( ptexture->flags, STUDIO_NF_MASKED )) flags |= TF_KEEP_SOURCE; // Paranoia2 texture alpha-tracing // build the texname diff --git a/ref_gl/gl_triapi.c b/ref_gl/gl_triapi.c index eb6b298d..4d4bffce 100644 --- a/ref_gl/gl_triapi.c +++ b/ref_gl/gl_triapi.c @@ -268,7 +268,7 @@ void TriFog( float flFogColor[3], float flStart, float flEnd, int bOn ) // check for invalid parms if( flEnd <= flStart ) { - RI.fogCustom = false; + glState.isFogEnabled = RI.fogCustom = false; pglDisable( GL_FOG ); return; }