From: MirceaKitsune Date: Sun, 18 Mar 2012 21:26:27 +0000 (+0200) Subject: Update the darkplaces engine source X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=1d6d760b32b75b7915660035fd9e949f83340e96;p=voretournament%2Fvoretournament.git Update the darkplaces engine source --- diff --git a/misc/source/darkplaces-src/bspfile.h b/misc/source/darkplaces-src/bspfile.h index 648b294d..e29a9f39 100644 --- a/misc/source/darkplaces-src/bspfile.h +++ b/misc/source/darkplaces-src/bspfile.h @@ -54,6 +54,16 @@ typedef struct hullinfo_s float hullsizes[MAX_MAP_HULLS][2][3]; } hullinfo_t; +typedef struct mmodel_s +{ + float mins[3], maxs[3]; + float origin[3]; + int headnode[MAX_MAP_HULLS]; + int visleafs; // not including the solid leaf 0 + int firstface, numfaces; +} mmodel_t; + +/* // WARNING: this struct does NOT match q1bsp's disk format because MAX_MAP_HULLS has been changed by Sajt's MCBSP code, this struct is only being used in memory as a result typedef struct dmodel_s { @@ -75,8 +85,10 @@ typedef struct dmiptexlump_s int nummiptex; int dataofs[4]; // [nummiptex] } dmiptexlump_t; +*/ #define MIPLEVELS 4 +/* typedef struct miptex_s { char name[16]; @@ -89,6 +101,7 @@ typedef struct dvertex_s { float point[3]; } dvertex_t; +*/ // 0-2 are axial planes @@ -101,12 +114,14 @@ typedef struct dvertex_s #define PLANE_ANYY 4 #define PLANE_ANYZ 5 +/* typedef struct dplane_s { float normal[3]; float dist; int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate } dplane_t; +*/ // contents values in Q1 maps @@ -223,7 +238,7 @@ typedef struct dplane_s #define SUPERCONTENTS_WINDOW 0x00000000 */ - +/* typedef struct dnode_s { int planenum; @@ -247,16 +262,20 @@ typedef struct texinfo_s int miptex; int flags; } texinfo_t; +*/ #define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision // note that edge 0 is never used, because negative edge nums are used for // counterclockwise use of the edge in a face +/* typedef struct dedge_s { unsigned short v[2]; // vertex numbers } dedge_t; +*/ #define MAXLIGHTMAPS 4 +/* typedef struct dface_s { // LordHavoc: changed from short to unsigned short for q2 support @@ -271,6 +290,7 @@ typedef struct dface_s unsigned char styles[MAXLIGHTMAPS]; int lightofs; // start of [numstyles*surfsize] samples } dface_t; +*/ @@ -283,6 +303,7 @@ typedef struct dface_s // leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas // all other leafs need visibility info +/* typedef struct dleaf_s { int contents; @@ -296,4 +317,5 @@ typedef struct dleaf_s unsigned char ambient_level[NUM_AMBIENTS]; } dleaf_t; +*/ diff --git a/misc/source/darkplaces-src/cl_demo.c b/misc/source/darkplaces-src/cl_demo.c index e60ac367..1584cb7b 100644 --- a/misc/source/darkplaces-src/cl_demo.c +++ b/misc/source/darkplaces-src/cl_demo.c @@ -609,6 +609,5 @@ void CL_TimeDemo_f (void) cls.timedemo = true; cls.td_frames = -2; // skip the first frame cls.demonum = -1; // stop demo loop - cls.demonum = -1; // stop demo loop } diff --git a/misc/source/darkplaces-src/cl_gecko.c b/misc/source/darkplaces-src/cl_gecko.c deleted file mode 100644 index e66482d6..00000000 --- a/misc/source/darkplaces-src/cl_gecko.c +++ /dev/null @@ -1,1010 +0,0 @@ -/* --- 8< --- 8< --- OffscreenGecko headers --- >8 --- >8 --- */ -/* NOTE: Documentation comments have been omitted. Documentation is - available in the OffscreenGecko SDK download. */ - -/* OffscreenGecko/defs.h */ - -#define OSGK_CLASSTYPE_DEF struct -#define OSGK_CLASSTYPE_REF struct - -#include -#include -#define OSGK_ASSERT(x) assert(x) - -typedef unsigned int OSGK_GeckoResult; - -#if defined(__cplusplus) || defined(__GNUC__) -# define OSGK_INLINE inline -#elif defined(_MSC_VER) -# define OSGK_INLINE __inline -#else -# define OSGK_INLINE -#endif - -/* OffscreenGecko/baseobj.h */ - -struct OSGK_BaseObject_s -{ - int reserved; -}; -typedef struct OSGK_BaseObject_s OSGK_BaseObject; - -#define OSGK_DERIVEDTYPE(T) \ - typedef struct T ## _s { \ - OSGK_BaseObject baseobj; \ - } T - -static int (*osgk_addref) (OSGK_BaseObject* obj); -static int (*osgk_release) (OSGK_BaseObject* obj); - -/*static OSGK_INLINE int osgk_addref_real (OSGK_BaseObject* obj) -{ - return osgk_addref (obj); -}*/ - -static OSGK_INLINE int osgk_release_real (OSGK_BaseObject* obj) -{ - return osgk_release (obj); -} - -#define osgk_addref(obj) osgk_addref_real (&((obj)->baseobj)) -#define osgk_release(obj) osgk_release_real (&((obj)->baseobj)) - -/* OffscreenGecko/embedding.h */ - -OSGK_DERIVEDTYPE(OSGK_EmbeddingOptions); - -static OSGK_EmbeddingOptions* (*osgk_embedding_options_create) (void); -static void (*osgk_embedding_options_add_search_path) ( - OSGK_EmbeddingOptions* options, const char* path); -/*static void (*osgk_embedding_options_add_components_path) ( - OSGK_EmbeddingOptions* options, const char* path);*/ -static void (*osgk_embedding_options_set_profile_dir) ( - OSGK_EmbeddingOptions* options, const char* profileDir, - const char* localProfileDir); - -OSGK_DERIVEDTYPE(OSGK_Embedding); - -#define OSGK_API_VERSION 1 - -static OSGK_Embedding* (*osgk_embedding_create2) ( - unsigned int apiVer, OSGK_EmbeddingOptions* options, - OSGK_GeckoResult* geckoResult); - -/*static OSGK_INLINE OSGK_Embedding* osgk_embedding_create ( - OSGK_GeckoResult* geckoResult) -{ - return osgk_embedding_create2 (OSGK_API_VERSION, 0, geckoResult); -}*/ - -static OSGK_INLINE OSGK_Embedding* osgk_embedding_create_with_options ( - OSGK_EmbeddingOptions* options, OSGK_GeckoResult* geckoResult) -{ - return osgk_embedding_create2 (OSGK_API_VERSION, options, geckoResult); -} - -/*static OSGK_GeckoMem* (*osgk_embedding_get_gecko_mem) ( - OSGK_Embedding* embedding);*/ - -/*static OSGK_ComponentMgr* (*osgk_embedding_get_component_mgr) ( - OSGK_Embedding* embedding);*/ - -/*OSGK_CLASSTYPE_DEF nsIComponentManager; -OSGK_CLASSTYPE_DEF nsIComponentRegistrar; -OSGK_CLASSTYPE_DEF nsIServiceManager;*/ - -/*static OSGK_CLASSTYPE_REF nsIComponentManager* -(*osgk_embedding_get_gecko_component_manager) (OSGK_Embedding* embedding);*/ -/*static OSGK_CLASSTYPE_REF nsIComponentRegistrar* -(*osgk_embedding_get_gecko_component_registrar) (OSGK_Embedding* embedding);*/ -/*static OSGK_CLASSTYPE_REF nsIServiceManager* -(*osgk_embedding_get_gecko_service_manager) (OSGK_Embedding* embedding);*/ - -enum -{ - jsgPrivileged = 1 -}; -/*static int (*osgk_embedding_register_js_global) ( - OSGK_Embedding* embedding, const char* name, const char* contractID, - unsigned int flags, OSGK_String** previousContract, - OSGK_GeckoResult* geckoResult);*/ - -/*static void (*osgk_embedding_clear_focus*) (OSGK_Embedding* embedding);*/ -/*void (*osgk_embedding_set_auto_focus) (OSGK_Embedding* embedding, int autoFocus);*/ -/*static int (*osgk_embedding_get_auto_focus) (OSGK_Embedding* embedding);*/ - -/* OffscreenGecko/browser.h */ -OSGK_DERIVEDTYPE(OSGK_Browser); - -static OSGK_Browser* (*osgk_browser_create) ( - OSGK_Embedding* embedding, int width, int height); -static void (*osgk_browser_navigate) (OSGK_Browser* browser, - const char* uri); - -static int (*osgk_browser_query_dirty) (OSGK_Browser* browser); -static const unsigned char* (*osgk_browser_lock_data) ( - OSGK_Browser* browser, int* isDirty); -static void (*osgk_browser_unlock_data) (OSGK_Browser* browser, - const unsigned char* data); - -typedef enum OSGK_MouseButton -{ - mbLeft, - mbRight, - mbMiddle -} OSGK_MouseButton; - -typedef enum OSGK_MouseButtonEventType -{ - meDown, - meUp, - meDoubleClick -} OSGK_MouseButtonEventType; - -static void (*osgk_browser_event_mouse_move) ( - OSGK_Browser* browser, int x, int y); -static void (*osgk_browser_event_mouse_button) ( - OSGK_Browser* browser, OSGK_MouseButton button, - OSGK_MouseButtonEventType eventType); - -typedef enum OSGK_WheelAxis -{ - waVertical, - waHorizontal -} OSGK_WheelAxis; - -typedef enum OSGK_WheelDirection -{ - wdPositive, - wdNegative, - wdPositivePage, - wdNegativePage -} OSGK_WheelDirection; - -static void (*osgk_browser_event_mouse_wheel) ( - OSGK_Browser* browser, OSGK_WheelAxis axis, - OSGK_WheelDirection direction); - -typedef enum OSGK_KeyboardEventType -{ - keDown, - keUp, - kePress -} OSGK_KeyboardEventType; - -enum -{ - OSGKKey_First = 0x110000, - - OSGKKey_Backspace = OSGKKey_First, - OSGKKey_Tab, - OSGKKey_Return, - OSGKKey_Shift, - OSGKKey_Control, - OSGKKey_Alt, - OSGKKey_CapsLock, - OSGKKey_Escape, - OSGKKey_Space, - OSGKKey_PageUp, - OSGKKey_PageDown, - OSGKKey_End, - OSGKKey_Home, - OSGKKey_Left, - OSGKKey_Up, - OSGKKey_Right, - OSGKKey_Down, - OSGKKey_Insert, - OSGKKey_Delete, - OSGKKey_F1, - OSGKKey_F2, - OSGKKey_F3, - OSGKKey_F4, - OSGKKey_F5, - OSGKKey_F6, - OSGKKey_F7, - OSGKKey_F8, - OSGKKey_F9, - OSGKKey_F10, - OSGKKey_F11, - OSGKKey_F12, - OSGKKey_NumLock, - OSGKKey_ScrollLock, - OSGKKey_Meta -}; - -static int (*osgk_browser_event_key) ( - OSGK_Browser* browser, unsigned int key, - OSGK_KeyboardEventType eventType); - -typedef enum OSGK_AntiAliasType -{ - aaNone, - aaGray, - aaSubpixel -} OSGK_AntiAliasType; - -/*static void (*osgk_browser_set_antialias) ( - OSGK_Browser* browser, OSGK_AntiAliasType aaType);*/ -/*static OSGK_AntiAliasType (*osgk_browser_get_antialias) (OSGK_Browser* browser);*/ - -/*static void (*osgk_browser_focus) (OSGK_Browser* browser);*/ - -static void (*osgk_browser_resize) (OSGK_Browser* browser, - int width, int height); - -static int (*osgk_browser_set_user_data) (OSGK_Browser* browser, - unsigned int key, void* data, int overrideData); -static int (*osgk_browser_get_user_data) (OSGK_Browser* browser, - unsigned int key, void** data); - -/* OffscreenGecko/string.h */ -OSGK_DERIVEDTYPE(OSGK_String); - -static const char* (*osgk_string_get) (OSGK_String* str); - -static OSGK_String* (*osgk_string_create) (const char* str); - -/* OffscreenGecko/scriptvariant.h */ - -OSGK_CLASSTYPE_DEF nsISupports; - -OSGK_DERIVEDTYPE(OSGK_ScriptVariant); - -typedef enum OSGK_ScriptVariantType -{ - svtEmpty, - svtInt, - svtUint, - svtFloat, - svtDouble, - svtBool, - svtChar, - svtString, - svtISupports, - svtScriptObject, - svtArray -} OSGK_ScriptVariantType; - -/*static OSGK_ScriptVariantType (*osgk_variant_get_type) ( - OSGK_ScriptVariant* variant);*/ -static OSGK_ScriptVariant* (*osgk_variant_convert) ( - OSGK_ScriptVariant* variant, OSGK_ScriptVariantType newType); - -/*static int (*osgk_variant_get_int) (OSGK_ScriptVariant* variant, - int* val);*/ -/*static int (*osgk_variant_get_uint) (OSGK_ScriptVariant* variant, - unsigned int* val);*/ -/*static int (*osgk_variant_get_float) (OSGK_ScriptVariant* variant, - float* val);*/ -/*static int (*osgk_variant_get_double) (OSGK_ScriptVariant* variant, - double* val);*/ -/*static int (*osgk_variant_get_bool) (OSGK_ScriptVariant* variant, - int* val);*/ -/*static int (*osgk_variant_get_char) (OSGK_ScriptVariant* variant, - unsigned int* val);*/ -// Does not increase ref count -static int (*osgk_variant_get_string) (OSGK_ScriptVariant* variant, - OSGK_String** val); -/*// Does not increase ref count -static int (*osgk_variant_get_isupports) (OSGK_ScriptVariant* variant, - OSGK_CLASSTYPE_REF nsISupports** val);*/ -/*static int (*osgk_variant_get_script_object) (OSGK_ScriptVariant* variant, - void** tag);*/ -/*static int (*osgk_variant_get_array_size) (OSGK_ScriptVariant* variant, - size_t* size);*/ -/*static int (*osgk_variant_get_array_item) (OSGK_ScriptVariant* variant, - OSGK_ScriptVariant** val);*/ - -/*static OSGK_ScriptVariant* (*osgk_variant_create_empty) ( - OSGK_Embedding* embedding);*/ -/*static OSGK_ScriptVariant* (*osgk_variant_create_int) ( - OSGK_Embedding* embedding, int val);*/ -/*static OSGK_ScriptVariant* (*osgk_variant_create_uint) ( - OSGK_Embedding* embedding, unsigned int val);*/ -/*static OSGK_ScriptVariant* (*osgk_variant_create_float) ( - OSGK_Embedding* embedding, float val);*/ -/*static OSGK_ScriptVariant* (*osgk_variant_create_double) ( - OSGK_Embedding* embedding, double val);*/ -/*OSGK_ScriptVariant* (*osgk_variant_create_bool) ( - OSGK_Embedding* embedding, int val);*/ -/*static OSGK_ScriptVariant* (*osgk_variant_create_char) ( - OSGK_Embedding* embedding, unsigned int val);*/ -static OSGK_ScriptVariant* (*osgk_variant_create_string) ( - OSGK_Embedding* embedding, OSGK_String* val); -/*static OSGK_ScriptVariant* (*osgk_variant_create_isupports) ( - OSGK_Embedding* embedding, OSGK_CLASSTYPE_REF nsISupports* val);*/ -/*static OSGK_ScriptVariant* (*osgk_variant_create_script_object) ( - OSGK_Embedding* embedding, void* tag);*/ -/*static OSGK_ScriptVariant* (*osgk_variant_create_array) ( - OSGK_Embedding* embedding, size_t numItems, OSGK_ScriptVariant** items);*/ - -/* OffscreenGecko/scriptobjecttemplate.h */ - -OSGK_DERIVEDTYPE(OSGK_ScriptObjectTemplate); - -typedef enum OSGK_ScriptResult -{ - srSuccess = 0, - srFailed = (int)0x80004005L /* actually NS_ERROR_FAILURE */ -} OSGK_ScriptResult; - -typedef struct OSGK_ScriptObjectCreateParams_s -{ - void* createParam; - OSGK_Browser* browser; -} OSGK_ScriptObjectCreateParams; - -typedef OSGK_ScriptResult (*OSGK_CreateObjFunc) ( - OSGK_ScriptObjectCreateParams* params, void** objTag); -typedef void (*OSGK_DestroyObjFunc) (void* objTag); - -static OSGK_ScriptObjectTemplate* (*osgk_sot_create) ( - OSGK_Embedding* embedding, - OSGK_CreateObjFunc createFunc, OSGK_DestroyObjFunc destroyFunc, - void* createParam); - -typedef OSGK_ScriptVariant* (*OSGK_GetPropertyFunc) (void* objTag, - void* propTag); -typedef OSGK_ScriptResult (*OSGK_SetPropertyFunc) (void* objTag, - void* propTag, OSGK_ScriptVariant* val); - -/*static int (*osgk_sot_add_property) ( - OSGK_ScriptObjectTemplate* templ, const char* propName, void* propTag, - OSGK_GetPropertyFunc getter, OSGK_SetPropertyFunc setter);*/ - -typedef OSGK_ScriptResult (*OSGK_FunctionCallFunc) (void* objTag, - void* methTag, size_t numParams, OSGK_ScriptVariant** params, - OSGK_ScriptVariant** returnVal); - -static int (*osgk_sot_add_function) ( - OSGK_ScriptObjectTemplate* templ, const char* funcName, void* funcTag, - OSGK_FunctionCallFunc callFunc); - -/*static OSGK_ScriptVariant* (*osgk_sot_instantiate) ( - OSGK_ScriptObjectTemplate* templ, void** objTag); */ - -static int (*osgk_sot_register) ( - OSGK_ScriptObjectTemplate* templ, OSGK_Embedding* embedding, - const char* name, unsigned int flags); - -/* --- >8 --- >8 --- End OffscreenGecko headers --- 8< --- 8< --- */ - -#include "quakedef.h" -#include "cl_dyntexture.h" -#include "cl_gecko.h" -#include "timing.h" - -#define DEFAULT_GECKO_SIZE 512 - -static rtexturepool_t *cl_geckotexturepool; -static OSGK_Embedding *cl_geckoembedding; - -struct clgecko_s { - qboolean active; - char name[ MAX_QPATH + 32 ]; - int ownerProg; - - OSGK_Browser *browser; - int width, height; - int texWidth, texHeight; - - rtexture_t *texture; -}; - -#define USERDATAKEY_CL_GECKO_T 0 - -static dllhandle_t osgk_dll = NULL; - -static clgecko_t cl_geckoinstances[ MAX_GECKO_INSTANCES ]; - -static clgecko_t * cl_gecko_findunusedinstance( void ) { - int i; - for( i = 0 ; i < MAX_GECKO_INSTANCES ; i++ ) { - clgecko_t *instance = &cl_geckoinstances[ i ]; - if( !instance->active ) { - return instance; - } - } - Con_DPrintf( "cl_gecko_findunusedinstance: out of geckos\n" ); - return NULL; -} - -clgecko_t * CL_Gecko_FindBrowser( const char *name ) { - int i; - - if( !name || !*name || strncmp( name, CLGECKOPREFIX, sizeof( CLGECKOPREFIX ) - 1 ) != 0 ) { - Con_DPrintf( "CL_Gecko_FindBrowser: Bad gecko texture name '%s'!\n", name ); - return NULL; - } - - for( i = 0 ; i < MAX_GECKO_INSTANCES ; i++ ) { - clgecko_t *instance = &cl_geckoinstances[ i ]; - if( instance->active && strcmp( instance->name, name ) == 0 ) { - return instance; - } - } - - Con_DPrintf( "CL_Gecko_FindBrowser: No browser named '%s'!\n", name ); - - return NULL; -} - -static void cl_gecko_updatecallback( rtexture_t *texture, void* callbackData ) { - clgecko_t *instance = (clgecko_t *) callbackData; - const unsigned char *data; - if( instance->browser ) { - // TODO: OSGK only supports BGRA right now - TIMING_TIMESTATEMENT(data = osgk_browser_lock_data( instance->browser, NULL )); - R_UpdateTexture( texture, data, 0, 0, 0, instance->width, instance->height, 1 ); - osgk_browser_unlock_data( instance->browser, data ); - } -} - -static void cl_gecko_linktexture( clgecko_t *instance ) { - // TODO: assert that instance->texture == NULL - instance->texture = R_LoadTexture2D( cl_geckotexturepool, instance->name, - instance->texWidth, instance->texHeight, NULL, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_PERSISTENT, -1, NULL ); - R_MakeTextureDynamic( instance->texture, cl_gecko_updatecallback, instance ); - CL_LinkDynTexture( instance->name, instance->texture ); -} - -static void cl_gecko_unlinktexture( clgecko_t *instance ) { - if( instance->texture ) { - CL_UnlinkDynTexture( instance->name ); - R_FreeTexture( instance->texture ); - instance->texture = NULL; - } -} - -void CL_Gecko_Resize( clgecko_t *instance, int width, int height ) { - int newWidth, newHeight; - - // early out if bad parameters are passed (no resize to a texture size bigger than the original texture size) - if( !instance || !instance->browser) { - return; - } - - newWidth = CeilPowerOf2( width ); - newHeight = CeilPowerOf2( height ); - if ((newWidth != instance->texWidth) || (newHeight != instance->texHeight)) - { - cl_gecko_unlinktexture( instance ); - instance->texWidth = newWidth; - instance->texHeight = newHeight; - cl_gecko_linktexture( instance ); - } - else - { - /* The gecko area will only cover a part of the texture; to avoid - 'old' pixels bleeding in at the border clear the texture. */ - R_ClearTexture( instance->texture ); - } - - osgk_browser_resize( instance->browser, width, height); - instance->width = width; - instance->height = height; -} - -void CL_Gecko_GetTextureExtent( clgecko_t *instance, float* pwidth, float* pheight ) -{ - if( !instance || !instance->browser ) { - return; - } - - *pwidth = (float)instance->width / instance->texWidth; - *pheight = (float)instance->height / instance->texHeight; -} - -static OSGK_ScriptResult dpGlobal_create (OSGK_ScriptObjectCreateParams* params, - void** objTag) -{ - if (!osgk_browser_get_user_data (params->browser, USERDATAKEY_CL_GECKO_T, objTag)) - return srFailed; - return srSuccess; -} - -static OSGK_ScriptResult dpGlobal_query (void* objTag, void* methTag, - size_t numParams, - OSGK_ScriptVariant** params, - OSGK_ScriptVariant** returnVal) -{ - clgecko_t *instance = (clgecko_t *) objTag; - OSGK_ScriptVariant* strVal; - OSGK_ScriptResult result = srFailed; - prvm_prog_t * saveProg; - - /* Can happen when created from console */ - if (instance->ownerProg < 0) return srFailed; - - /* Require exactly one param, for now */ - if (numParams != 1) return srFailed; - - strVal = osgk_variant_convert (params[0], svtString); - if (strVal == 0) return srFailed; - - saveProg = prog; - PRVM_SetProg(instance->ownerProg); - - if (PRVM_clientfunction(Gecko_Query)) - { - OSGK_String* paramStr, *resultStr; - - if (!osgk_variant_get_string (strVal, ¶mStr)) return srFailed; - PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString (instance->name); - PRVM_G_INT(OFS_PARM1) = PRVM_SetTempString (osgk_string_get (paramStr)); - PRVM_ExecuteProgram(PRVM_clientfunction(Gecko_Query),"Gecko_Query() required"); - resultStr = osgk_string_create (PRVM_G_STRING (OFS_RETURN)); - *returnVal = osgk_variant_create_string (cl_geckoembedding, resultStr); - osgk_release (resultStr); - - result = srSuccess; - } - - prog = saveProg; - - return result; -} - -#if defined(_WIN64) -# define XULRUNNER_DIR_SUFFIX "win64" -#elif defined(WIN32) -# define XULRUNNER_DIR_SUFFIX "win32" -#elif defined(DP_OS_STR) && defined(DP_ARCH_STR) -# define XULRUNNER_DIR_SUFFIX DP_OS_STR "-" DP_ARCH_STR -#endif - -static qboolean CL_Gecko_Embedding_Init (void) -{ - char profile_path [MAX_OSPATH]; - OSGK_GeckoResult grc; - OSGK_EmbeddingOptions *options; - OSGK_ScriptObjectTemplate* dpGlobalTemplate; - - if (!osgk_dll) return false; - - if( cl_geckoembedding != NULL ) return true; - - Con_DPrintf( "CL_Gecko_Embedding_Init: setting up gecko embedding\n" ); - - options = osgk_embedding_options_create(); -#ifdef XULRUNNER_DIR_SUFFIX - osgk_embedding_options_add_search_path( options, "./xulrunner-" XULRUNNER_DIR_SUFFIX "/" ); -#endif - osgk_embedding_options_add_search_path( options, "./xulrunner/" ); - dpsnprintf (profile_path, sizeof (profile_path), "%s/xulrunner_profile/", fs_gamedir); - osgk_embedding_options_set_profile_dir( options, profile_path, 0 ); - cl_geckoembedding = osgk_embedding_create_with_options( options, &grc ); - osgk_release( options ); - - if( cl_geckoembedding == NULL ) { - Con_Printf( "CL_Gecko_Embedding_Init: Couldn't retrieve gecko embedding object (%.8x)!\n", grc ); - return false; - } - - Con_DPrintf( "CL_Gecko_Embedding_Init: Embedding set up correctly\n" ); - - dpGlobalTemplate = osgk_sot_create( cl_geckoembedding, dpGlobal_create, NULL, NULL ); - - osgk_sot_add_function (dpGlobalTemplate, "query", 0, dpGlobal_query); - - osgk_sot_register (dpGlobalTemplate, cl_geckoembedding, "Darkplaces", 0); - osgk_release( dpGlobalTemplate ); - - return true; -} - -clgecko_t * CL_Gecko_CreateBrowser( const char *name, int ownerProg ) { - clgecko_t *instance; - - if (!CL_Gecko_Embedding_Init ()) return NULL; - - // TODO: verify that we dont use a name twice - instance = cl_gecko_findunusedinstance(); - // TODO: assert != NULL - - instance->active = true; - strlcpy( instance->name, name, sizeof( instance->name ) ); - instance->browser = osgk_browser_create( cl_geckoembedding, DEFAULT_GECKO_SIZE, DEFAULT_GECKO_SIZE ); - if( instance->browser == NULL ) { - Con_Printf( "CL_Gecko_CreateBrowser: Browser object creation failed!\n" ); - } - // TODO: assert != NULL - osgk_browser_set_user_data (instance->browser, USERDATAKEY_CL_GECKO_T, - instance, 0); - instance->ownerProg = ownerProg; - - instance->width = instance->texWidth = DEFAULT_GECKO_SIZE; - instance->height = instance->texHeight = DEFAULT_GECKO_SIZE; - cl_gecko_linktexture( instance ); - - return instance; -} - -void CL_Gecko_DestroyBrowser( clgecko_t *instance ) { - if( !instance || !instance->active ) { - return; - } - - instance->active = false; - cl_gecko_unlinktexture( instance ); - - osgk_release( instance->browser ); - instance->browser = NULL; -} - -void CL_Gecko_Frame( void ) { - int i; - // FIXME: track cl_numgeckoinstances to avoid scanning the entire array? - for( i = 0 ; i < MAX_GECKO_INSTANCES ; i++ ) { - clgecko_t *instance = &cl_geckoinstances[ i ]; - if( instance->active ) { - if( instance->browser && osgk_browser_query_dirty( instance->browser ) == 1 ) { - R_MarkDirtyTexture( instance->texture ); - } - } - } -} - -static void cl_gecko_start( void ) -{ - int i; - cl_geckotexturepool = R_AllocTexturePool(); - - // recreate textures on module start - for( i = 0 ; i < MAX_GECKO_INSTANCES ; i++ ) { - clgecko_t *instance = &cl_geckoinstances[ i ]; - if( instance->active ) { - cl_gecko_linktexture( instance ); - } - } -} - -static void cl_gecko_shutdown( void ) -{ - int i; - for( i = 0 ; i < MAX_GECKO_INSTANCES ; i++ ) { - clgecko_t *instance = &cl_geckoinstances[ i ]; - if( instance->active ) { - cl_gecko_unlinktexture( instance ); - } - } - R_FreeTexturePool( &cl_geckotexturepool ); -} - -static void cl_gecko_newmap( void ) -{ - // DO NOTHING -} - -void CL_Gecko_Shutdown( void ) { - int i; - for( i = 0 ; i < MAX_GECKO_INSTANCES ; i++ ) { - clgecko_t *instance = &cl_geckoinstances[ i ]; - if( instance->active ) { - cl_gecko_unlinktexture( instance ); - } - } - - if (cl_geckoembedding != NULL) - { - osgk_release( cl_geckoembedding ); - cl_geckoembedding = NULL; - } - - if (osgk_dll != NULL) - { - Sys_UnloadLibrary (&osgk_dll); - } -} - -static void cl_gecko_create_f( void ) { - char name[MAX_QPATH]; - - if (Cmd_Argc() != 2) - { - Con_Print("usage: gecko_create \npcreates a browser (full texture path " CLGECKOPREFIX ")\n"); - return; - } - - dpsnprintf(name, sizeof(name), CLGECKOPREFIX "%s", Cmd_Argv(1)); - CL_Gecko_CreateBrowser( name, -1 ); -} - -static void cl_gecko_destroy_f( void ) { - char name[MAX_QPATH]; - - if (Cmd_Argc() != 2) - { - Con_Print("usage: gecko_destroy \ndestroys a browser\n"); - return; - } - - dpsnprintf(name, sizeof(name), CLGECKOPREFIX "%s", Cmd_Argv(1)); - CL_Gecko_DestroyBrowser( CL_Gecko_FindBrowser( name ) ); -} - -static void cl_gecko_navigate_f( void ) { - char name[MAX_QPATH]; - const char *URI; - - if (Cmd_Argc() != 3) - { - Con_Print("usage: gecko_navigate \nnavigates to a certain URI\n"); - return; - } - - dpsnprintf(name, sizeof(name), CLGECKOPREFIX "%s", Cmd_Argv(1)); - URI = Cmd_Argv( 2 ); - CL_Gecko_NavigateToURI( CL_Gecko_FindBrowser( name ), URI ); -} - -static void cl_gecko_injecttext_f( void ) { - char name[MAX_QPATH]; - const char *text; - clgecko_t *instance; - const char *p; - - if (Cmd_Argc() < 3) - { - Con_Print("usage: gecko_injecttext \ninjects a certain text into the browser\n"); - return; - } - - dpsnprintf(name, sizeof(name), CLGECKOPREFIX "%s", Cmd_Argv(1)); - instance = CL_Gecko_FindBrowser( name ); - if( !instance ) { - Con_Printf( "cl_gecko_injecttext_f: gecko instance '%s' couldn't be found!\n", name ); - return; - } - - text = Cmd_Argv( 2 ); - - for( p = text ; *p ; p++ ) { - unsigned key = *p; - switch( key ) { - case ' ': - key = K_SPACE; - break; - case '\\': - key = *++p; - switch( key ) { - case 'n': - key = K_ENTER; - break; - case '\0': - --p; - key = '\\'; - break; - } - break; - } - - CL_Gecko_Event_Key( instance, (keynum_t) key, CLG_BET_PRESS ); - } -} - -static void gl_gecko_movecursor_f( void ) { - char name[MAX_QPATH]; - float x, y; - - if (Cmd_Argc() != 4) - { - Con_Print("usage: gecko_movecursor \nmove the cursor to a certain position\n"); - return; - } - - dpsnprintf(name, sizeof(name), CLGECKOPREFIX "%s", Cmd_Argv(1)); - x = atof( Cmd_Argv( 2 ) ); - y = atof( Cmd_Argv( 3 ) ); - - CL_Gecko_Event_CursorMove( CL_Gecko_FindBrowser( name ), x, y ); -} - -#undef osgk_addref -#undef osgk_release - -static const dllfunction_t osgkFuncs[] = -{ - {"osgk_addref", (void **) &osgk_addref}, - {"osgk_release", (void **) &osgk_release}, - {"osgk_embedding_create2", (void **) &osgk_embedding_create2}, - {"osgk_embedding_options_create", (void **) &osgk_embedding_options_create}, - {"osgk_embedding_options_add_search_path", (void **) &osgk_embedding_options_add_search_path}, - {"osgk_embedding_options_set_profile_dir", (void **) &osgk_embedding_options_set_profile_dir}, - {"osgk_browser_create", (void **) &osgk_browser_create}, - {"osgk_browser_query_dirty", (void **) &osgk_browser_query_dirty}, - {"osgk_browser_navigate", (void **) &osgk_browser_navigate}, - {"osgk_browser_lock_data", (void **) &osgk_browser_lock_data}, - {"osgk_browser_unlock_data", (void **) &osgk_browser_unlock_data}, - {"osgk_browser_resize", (void **) &osgk_browser_resize}, - {"osgk_browser_event_mouse_move", (void **) &osgk_browser_event_mouse_move}, - {"osgk_browser_event_mouse_button", (void **) &osgk_browser_event_mouse_button}, - {"osgk_browser_event_mouse_wheel", (void **) &osgk_browser_event_mouse_wheel}, - {"osgk_browser_event_key", (void **) &osgk_browser_event_key}, - {"osgk_browser_set_user_data", (void **) &osgk_browser_set_user_data}, - {"osgk_browser_get_user_data", (void **) &osgk_browser_get_user_data}, - {"osgk_sot_create", (void **) &osgk_sot_create}, - {"osgk_sot_register", (void **) &osgk_sot_register}, - {"osgk_sot_add_function", (void **) &osgk_sot_add_function}, - {"osgk_string_get", (void **) &osgk_string_get}, - {"osgk_string_create", (void **) &osgk_string_create}, - {"osgk_variant_convert", (void **) &osgk_variant_convert}, - {"osgk_variant_get_string", (void **) &osgk_variant_get_string}, - {"osgk_variant_create_string", (void **) &osgk_variant_create_string}, - {NULL, NULL} -}; - -qboolean CL_Gecko_OpenLibrary (void) -{ - const char* dllnames_gecko [] = - { -#if defined(WIN32) - "OffscreenGecko.dll", -#elif defined(MACOSX) - "OffscreenGecko.dylib", -#else - "libOffscreenGecko.so", -#endif - NULL - }; - - // Already loaded? - if (osgk_dll) - return true; - -// COMMANDLINEOPTION: Sound: -nogecko disables gecko support (web browser support for menu and computer terminals) - if (COM_CheckParm("-nogecko")) - return false; - - return Sys_LoadLibrary (dllnames_gecko, &osgk_dll, osgkFuncs); -} - -void CL_Gecko_Init( void ) -{ - CL_Gecko_OpenLibrary(); - - Cmd_AddCommand( "gecko_create", cl_gecko_create_f, "Create a gecko browser instance" ); - Cmd_AddCommand( "gecko_destroy", cl_gecko_destroy_f, "Destroy a gecko browser instance" ); - Cmd_AddCommand( "gecko_navigate", cl_gecko_navigate_f, "Navigate a gecko browser to a URI" ); - Cmd_AddCommand( "gecko_injecttext", cl_gecko_injecttext_f, "Injects text into a browser" ); - Cmd_AddCommand( "gecko_movecursor", gl_gecko_movecursor_f, "Move the cursor to a certain position" ); - - R_RegisterModule( "CL_Gecko", cl_gecko_start, cl_gecko_shutdown, cl_gecko_newmap, NULL, NULL ); -} - -void CL_Gecko_NavigateToURI( clgecko_t *instance, const char *URI ) { - if( !instance || !instance->browser ) { - return; - } - - if( instance->active ) { - osgk_browser_navigate( instance->browser, URI ); - } -} - -void CL_Gecko_Event_CursorMove( clgecko_t *instance, float x, float y ) { - // TODO: assert x, y \in [0.0, 1.0] - int mappedx, mappedy; - - if( !instance || !instance->browser ) { - return; - } - - mappedx = (int) (x * instance->width); - mappedy = (int) (y * instance->height); - osgk_browser_event_mouse_move( instance->browser, mappedx, mappedy ); -} - -typedef struct geckokeymapping_s { - keynum_t keycode; - unsigned int geckokeycode; -} geckokeymapping_t; - -static geckokeymapping_t geckokeymappingtable[] = { - { K_BACKSPACE, OSGKKey_Backspace }, - { K_TAB, OSGKKey_Tab }, - { K_ENTER, OSGKKey_Return }, - { K_SHIFT, OSGKKey_Shift }, - { K_CTRL, OSGKKey_Control }, - { K_ALT, OSGKKey_Alt }, - { K_CAPSLOCK, OSGKKey_CapsLock }, - { K_ESCAPE, OSGKKey_Escape }, - { K_SPACE, OSGKKey_Space }, - { K_PGUP, OSGKKey_PageUp }, - { K_PGDN, OSGKKey_PageDown }, - { K_END, OSGKKey_End }, - { K_HOME, OSGKKey_Home }, - { K_LEFTARROW, OSGKKey_Left }, - { K_UPARROW, OSGKKey_Up }, - { K_RIGHTARROW, OSGKKey_Right }, - { K_DOWNARROW, OSGKKey_Down }, - { K_INS, OSGKKey_Insert }, - { K_DEL, OSGKKey_Delete }, - { K_F1, OSGKKey_F1 }, - { K_F2, OSGKKey_F2 }, - { K_F3, OSGKKey_F3 }, - { K_F4, OSGKKey_F4 }, - { K_F5, OSGKKey_F5 }, - { K_F6, OSGKKey_F6 }, - { K_F7, OSGKKey_F7 }, - { K_F8, OSGKKey_F8 }, - { K_F9, OSGKKey_F9 }, - { K_F10, OSGKKey_F10 }, - { K_F11, OSGKKey_F11 }, - { K_F12, OSGKKey_F12 }, - { K_NUMLOCK, OSGKKey_NumLock }, - { K_SCROLLOCK, OSGKKey_ScrollLock } -}; - -qboolean CL_Gecko_Event_Key( clgecko_t *instance, keynum_t key, clgecko_buttoneventtype_t eventtype ) { - if( !instance || !instance->browser ) { - return false; - } - - // determine whether its a keyboard event - if( key < K_OTHERDEVICESBEGIN ) { - - OSGK_KeyboardEventType mappedtype = kePress; - unsigned int mappedkey = key; - - unsigned int i; - // yes! then convert it if necessary! - for( i = 0 ; i < sizeof( geckokeymappingtable ) / sizeof( *geckokeymappingtable ) ; i++ ) { - const geckokeymapping_t * const mapping = &geckokeymappingtable[ i ]; - if( key == mapping->keycode ) { - mappedkey = mapping->geckokeycode; - break; - } - } - - // convert the eventtype - // map the type - switch( eventtype ) { - case CLG_BET_DOWN: - mappedtype = keDown; - break; - case CLG_BET_UP: - mappedtype = keUp; - break; - case CLG_BET_DOUBLECLICK: - // TODO: error message - break; - case CLG_BET_PRESS: - mappedtype = kePress; - } - - return osgk_browser_event_key( instance->browser, mappedkey, mappedtype ) != 0; - } else if( K_MOUSE1 <= key && key <= K_MOUSE3 ) { - OSGK_MouseButtonEventType mappedtype = meDoubleClick; - OSGK_MouseButton mappedbutton; - - mappedbutton = (OSGK_MouseButton) (mbLeft + (key - K_MOUSE1)); - - switch( eventtype ) { - case CLG_BET_DOWN: - mappedtype = meDown; - break; - case CLG_BET_UP: - mappedtype = meUp; - break; - case CLG_BET_DOUBLECLICK: - mappedtype = meDoubleClick; - break; - case CLG_BET_PRESS: - // hihi, hacky hacky - osgk_browser_event_mouse_button( instance->browser, mappedbutton, meDown ); - mappedtype = meUp; - break; - } - - osgk_browser_event_mouse_button( instance->browser, mappedbutton, mappedtype ); - return true; - } else if( K_MWHEELUP <= key && key <= K_MWHEELDOWN ) { - if( eventtype == CLG_BET_DOWN ) - osgk_browser_event_mouse_wheel( instance->browser, - waVertical, (key == K_MWHEELUP) ? wdNegative : wdPositive ); - return true; - } - // TODO: error? - return false; -} diff --git a/misc/source/darkplaces-src/cl_gecko.h b/misc/source/darkplaces-src/cl_gecko.h deleted file mode 100644 index c95b410b..00000000 --- a/misc/source/darkplaces-src/cl_gecko.h +++ /dev/null @@ -1,39 +0,0 @@ -// Andreas Kirsch 07 - -#ifndef CL_GECKO_H -#define CL_GECKO_H - -#include "cl_dyntexture.h" - -#define CLGECKOPREFIX CLDYNTEXTUREPREFIX "gecko/" - -typedef enum clgecko_buttoneventtype_e { - CLG_BET_DOWN, - CLG_BET_UP, - CLG_BET_DOUBLECLICK, - // use for up + down (but dont use both) - CLG_BET_PRESS -} clgecko_buttoneventtype_t; - -typedef struct clgecko_s clgecko_t; - -void CL_Gecko_Frame( void ); -void CL_Gecko_Init( void ); -void CL_Gecko_Shutdown( void ); - -clgecko_t * CL_Gecko_CreateBrowser( const char *name, int ownerProg ); -clgecko_t * CL_Gecko_FindBrowser( const char *name ); -void CL_Gecko_DestroyBrowser( clgecko_t *instance ); - -void CL_Gecko_NavigateToURI( clgecko_t *instance, const char *URI ); -// x and y between 0.0 and 1.0 (0.0 is top-left?) -void CL_Gecko_Event_CursorMove( clgecko_t *instance, float x, float y ); - -// returns whether the key/button event was handled or not -qboolean CL_Gecko_Event_Key( clgecko_t *instance, keynum_t key, clgecko_buttoneventtype_t eventtype ); - -void CL_Gecko_Resize( clgecko_t *instance, int width, int height ); -// get the ratio between gecko instance's size in the texture and the actual texture size.. -void CL_Gecko_GetTextureExtent( clgecko_t *instance, float* pwidth, float* pheight ); -#endif - diff --git a/misc/source/darkplaces-src/cl_input.c b/misc/source/darkplaces-src/cl_input.c index af5289f5..2dd21acd 100644 --- a/misc/source/darkplaces-src/cl_input.c +++ b/misc/source/darkplaces-src/cl_input.c @@ -837,7 +837,7 @@ static qboolean CL_ClientMovement_Unstick(cl_clientmovement_state_t *s) for (i = 0;i < NUMOFFSETS;i++) { VectorAdd(offsets[i], s->origin, neworigin); - if (!CL_TraceBox(neworigin, cl.playercrouchmins, cl.playercrouchmaxs, neworigin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true).startsolid) + if (!CL_TraceBox(neworigin, cl.playercrouchmins, cl.playercrouchmaxs, neworigin, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true).startsolid) { VectorCopy(neworigin, s->origin); return true; @@ -869,7 +869,7 @@ static void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s) // low ceiling first if (s->crouched) { - trace = CL_TraceBox(s->origin, cl.playerstandmins, cl.playerstandmaxs, s->origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); + trace = CL_TraceBox(s->origin, cl.playerstandmins, cl.playerstandmaxs, s->origin, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); if (!trace.startsolid) s->crouched = false; } @@ -888,7 +888,7 @@ static void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s) // set onground VectorSet(origin1, s->origin[0], s->origin[1], s->origin[2] + 1); VectorSet(origin2, s->origin[0], s->origin[1], s->origin[2] - 1); // -2 causes clientside doublejump bug at above 150fps, raising that to 300fps :) - trace = CL_TraceBox(origin1, s->mins, s->maxs, origin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); + trace = CL_TraceBox(origin1, s->mins, s->maxs, origin2, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); if(trace.fraction < 1 && trace.plane.normal[2] > 0.7) { s->onground = true; @@ -904,16 +904,16 @@ static void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s) // set watertype/waterlevel VectorSet(origin1, s->origin[0], s->origin[1], s->origin[2] + s->mins[2] + 1); s->waterlevel = WATERLEVEL_NONE; - s->watertype = CL_TracePoint(origin1, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK; + s->watertype = CL_TracePoint(origin1, MOVE_NOMONSTERS, s->self, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK; if (s->watertype) { s->waterlevel = WATERLEVEL_WETFEET; origin1[2] = s->origin[2] + (s->mins[2] + s->maxs[2]) * 0.5f; - if (CL_TracePoint(origin1, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK) + if (CL_TracePoint(origin1, MOVE_NOMONSTERS, s->self, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK) { s->waterlevel = WATERLEVEL_SWIMMING; origin1[2] = s->origin[2] + 22; - if (CL_TracePoint(origin1, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK) + if (CL_TracePoint(origin1, MOVE_NOMONSTERS, s->self, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK) s->waterlevel = WATERLEVEL_SUBMERGED; } } @@ -940,20 +940,20 @@ static void CL_ClientMovement_Move(cl_clientmovement_state_t *s) for (bump = 0, t = s->cmd.frametime;bump < 8 && VectorLength2(s->velocity) > 0;bump++) { VectorMA(s->origin, t, s->velocity, neworigin); - trace = CL_TraceBox(s->origin, s->mins, s->maxs, neworigin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); + trace = CL_TraceBox(s->origin, s->mins, s->maxs, neworigin, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); if (trace.fraction < 1 && trace.plane.normal[2] == 0) { // may be a step or wall, try stepping up // first move forward at a higher level VectorSet(currentorigin2, s->origin[0], s->origin[1], s->origin[2] + cl.movevars_stepheight); VectorSet(neworigin2, neworigin[0], neworigin[1], s->origin[2] + cl.movevars_stepheight); - trace2 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); + trace2 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); if (!trace2.startsolid) { // then move down from there VectorCopy(trace2.endpos, currentorigin2); VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], s->origin[2]); - trace3 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); + trace3 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); //Con_Printf("%f %f %f %f : %f %f %f %f : %f %f %f %f\n", trace.fraction, trace.endpos[0], trace.endpos[1], trace.endpos[2], trace2.fraction, trace2.endpos[0], trace2.endpos[1], trace2.endpos[2], trace3.fraction, trace3.endpos[0], trace3.endpos[1], trace3.endpos[2]); // accept the new trace if it made some progress if (fabs(trace3.endpos[0] - trace.endpos[0]) >= 0.03125 || fabs(trace3.endpos[1] - trace.endpos[1]) >= 0.03125) @@ -972,8 +972,12 @@ static void CL_ClientMovement_Move(cl_clientmovement_state_t *s) if (trace.fraction == 1) break; - //if (trace.plane.normal[2] > 0.7) - // s->onground = true; + // this is only really needed for nogravityonground combined with gravityunaffectedbyticrate + // I'm pretty sure I commented it out solely because it seemed redundant + // this got commented out in a change that supposedly makes the code match QW better + // so if this is broken, maybe put it in an if(cls.protocol != PROTOCOL_QUAKEWORLD) block + if (trace.plane.normal[2] > 0.7) + s->onground = true; t -= t * trace.fraction; @@ -1003,10 +1007,10 @@ static void CL_ClientMovement_Physics_Swim(cl_clientmovement_state_t *s) AngleVectors(yawangles, forward, NULL, NULL); VectorMA(s->origin, 24, forward, spot); spot[2] += 8; - if (CL_TracePoint(spot, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsolid) + if (CL_TracePoint(spot, MOVE_NOMONSTERS, s->self, 0, true, false, NULL, false).startsolid) { spot[2] += 24; - if (!CL_TracePoint(spot, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsolid) + if (!CL_TracePoint(spot, MOVE_NOMONSTERS, s->self, 0, true, false, NULL, false).startsolid) { VectorScale(forward, 50, s->velocity); s->velocity[2] = 310; @@ -1349,9 +1353,9 @@ static void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s) VectorSet(neworigin2, s->origin[0] + s->velocity[0]*(16/f), s->origin[1] + s->velocity[1]*(16/f), s->origin[2] + s->mins[2]); VectorSet(neworigin3, neworigin2[0], neworigin2[1], neworigin2[2] - 34); if (cls.protocol == PROTOCOL_QUAKEWORLD) - trace = CL_TraceBox(neworigin2, s->mins, s->maxs, neworigin3, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); + trace = CL_TraceBox(neworigin2, s->mins, s->maxs, neworigin3, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); else - trace = CL_TraceLine(neworigin2, neworigin3, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true, false); + trace = CL_TraceLine(neworigin2, neworigin3, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true, false); if (trace.fraction == 1 && !trace.startsolid) friction *= cl.movevars_edgefriction; } @@ -1366,20 +1370,23 @@ static void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s) accelspeed = min(cl.movevars_accelerate * s->cmd.frametime * wishspeed, addspeed); VectorMA(s->velocity, accelspeed, wishdir, s->velocity); } - if(cl.moveflags & MOVEFLAG_NOGRAVITYONGROUND) - gravity = 0; - else - gravity = cl.movevars_gravity * cl.movevars_entgravity * s->cmd.frametime; - if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) - s->velocity[2] -= gravity * 0.5f; - else - s->velocity[2] -= gravity; + gravity = cl.movevars_gravity * cl.movevars_entgravity * s->cmd.frametime; + if(!(cl.moveflags & MOVEFLAG_NOGRAVITYONGROUND)) + { + if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) + s->velocity[2] -= gravity * 0.5f; + else + s->velocity[2] -= gravity; + } if (cls.protocol == PROTOCOL_QUAKEWORLD) s->velocity[2] = 0; if (VectorLength2(s->velocity)) CL_ClientMovement_Move(s); - if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) - s->velocity[2] -= gravity * 0.5f; + if(!(cl.moveflags & MOVEFLAG_NOGRAVITYONGROUND) || !s->onground) + { + if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) + s->velocity[2] -= gravity * 0.5f; + } } else { @@ -1435,12 +1442,15 @@ static void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s) else s->velocity[2] -= gravity; CL_ClientMovement_Move(s); - if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) - s->velocity[2] -= gravity * 0.5f; + if(!(cl.moveflags & MOVEFLAG_NOGRAVITYONGROUND) || !s->onground) + { + if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) + s->velocity[2] -= gravity * 0.5f; + } } } -void CL_ClientMovement_PlayerMove(cl_clientmovement_state_t *s) +static void CL_ClientMovement_PlayerMove(cl_clientmovement_state_t *s) { //Con_Printf(" %f", frametime); if (!s->cmd.jump) @@ -1545,6 +1555,27 @@ void CL_UpdateMoveVars(void) cl.movevars_aircontrol_power = 2; // CPMA default } +void CL_ClientMovement_PlayerMove_Frame(cl_clientmovement_state_t *s) +{ + // if a move is more than 50ms, do it as two moves (matching qwsv) + //Con_Printf("%i ", s.cmd.msec); + if(s->cmd.frametime > 0.0005) + { + if (s->cmd.frametime > 0.05) + { + s->cmd.frametime /= 2; + CL_ClientMovement_PlayerMove(s); + } + CL_ClientMovement_PlayerMove(s); + } + else + { + // we REALLY need this handling to happen, even if the move is not executed + if (!s->cmd.jump) + s->cmd.canjump = true; + } +} + void CL_ClientMovement_Replay(void) { int i; @@ -1590,23 +1621,8 @@ void CL_ClientMovement_Replay(void) if (i < CL_MAX_USERCMDS - 1) s.cmd.canjump = cl.movecmd[i+1].canjump; - // if a move is more than 50ms, do it as two moves (matching qwsv) - //Con_Printf("%i ", s.cmd.msec); - if(s.cmd.frametime > 0.0005) - { - if (s.cmd.frametime > 0.05) - { - s.cmd.frametime /= 2; - CL_ClientMovement_PlayerMove(&s); - } - CL_ClientMovement_PlayerMove(&s); - } - else - { - // we REALLY need this handling to happen, even if the move is not executed - if (!s.cmd.jump) - s.cmd.canjump = true; - } + CL_ClientMovement_PlayerMove_Frame(&s); + cl.movecmd[i].canjump = s.cmd.canjump; } //Con_Printf("\n"); diff --git a/misc/source/darkplaces-src/cl_main.c b/misc/source/darkplaces-src/cl_main.c index cb03ffab..94562c27 100644 --- a/misc/source/darkplaces-src/cl_main.c +++ b/misc/source/darkplaces-src/cl_main.c @@ -1174,6 +1174,8 @@ static void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean int e->render.flags |= RENDER_ADDITIVE; if (e->render.effects & EF_DOUBLESIDED) e->render.flags |= RENDER_DOUBLESIDED; + if (e->render.effects & EF_DYNAMICMODELLIGHT) + e->render.flags |= RENDER_DYNAMICMODELLIGHT; // make the other useful stuff e->render.allowdecals = true; @@ -2488,6 +2490,3 @@ void CL_Init (void) CL_Video_Init(); } - - - diff --git a/misc/source/darkplaces-src/cl_parse.c b/misc/source/darkplaces-src/cl_parse.c index 55e1a79a..9e414372 100644 --- a/misc/source/darkplaces-src/cl_parse.c +++ b/misc/source/darkplaces-src/cl_parse.c @@ -167,7 +167,7 @@ cvar_t cl_worldname = {CVAR_READONLY, "cl_worldname", "", "name of current world cvar_t cl_worldnamenoextension = {CVAR_READONLY, "cl_worldnamenoextension", "", "name of current worldmodel without extension"}; cvar_t cl_worldbasename = {CVAR_READONLY, "cl_worldbasename", "", "name of current worldmodel without maps/ prefix or extension"}; -cvar_t developer_networkentities = {0, "developer_networkentities", "0", "prints received entities, value is 0-4 (higher for more info)"}; +cvar_t developer_networkentities = {0, "developer_networkentities", "0", "prints received entities, value is 0-10 (higher for more info, 10 being the most verbose)"}; cvar_t cl_gameplayfix_soundsmovewithentities = {0, "cl_gameplayfix_soundsmovewithentities", "1", "causes sounds made by lifts, players, projectiles, and any other entities, to move with the entity, so for example a rocket noise follows the rocket rather than staying at the starting position"}; cvar_t cl_sound_wizardhit = {0, "cl_sound_wizardhit", "wizard/hit.wav", "sound to play during TE_WIZSPIKE (empty cvar disables sound)"}; cvar_t cl_sound_hknighthit = {0, "cl_sound_hknighthit", "hknight/hit.wav", "sound to play during TE_KNIGHTSPIKE (empty cvar disables sound)"}; @@ -1119,7 +1119,7 @@ static void CL_BeginDownloads(qboolean aborteddownload) + cl.loadsound_total * LOADPROGRESSWEIGHT_SOUND ) ); - SCR_BeginLoadingPlaque(); + SCR_BeginLoadingPlaque(false); } for (;cl.loadmodel_current < cl.loadmodel_total;cl.loadmodel_current++) { @@ -1651,7 +1651,7 @@ static void CL_ParseServerInfo (void) // if server is active, we already began a loading plaque if (!sv.active) { - SCR_BeginLoadingPlaque(); + SCR_BeginLoadingPlaque(false); S_StopAllSounds(); // free q3 shaders so that any newly downloaded shaders will be active Mod_FreeQ3Shaders(); @@ -2187,7 +2187,7 @@ static void CL_ParseClientdata (void) cl.stats[STAT_CELLS] = MSG_ReadShort(&cl_message); cl.stats[STAT_ACTIVEWEAPON] = (unsigned short) MSG_ReadShort(&cl_message); } - else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4) + else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4) { cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte(&cl_message) : 0; cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte(&cl_message) : 0; @@ -2947,6 +2947,7 @@ static void CL_IPLog_Load(void); static void CL_IPLog_Add(const char *address, const char *name, qboolean checkexisting, qboolean addtofile) { int i; + size_t sz_name, sz_address; if (!address || !address[0] || !name || !name[0]) return; if (!cl_iplog_loaded) @@ -2979,12 +2980,14 @@ static void CL_IPLog_Add(const char *address, const char *name, qboolean checkex Mem_Free(olditems); } } - cl_iplog_items[cl_iplog_numitems].address = (char *) Mem_Alloc(cls.permanentmempool, strlen(address) + 1); - cl_iplog_items[cl_iplog_numitems].name = (char *) Mem_Alloc(cls.permanentmempool, strlen(name) + 1); - strlcpy(cl_iplog_items[cl_iplog_numitems].address, address, strlen(address) + 1); + sz_address = strlen(address) + 1; + sz_name = strlen(name) + 1; + cl_iplog_items[cl_iplog_numitems].address = (char *) Mem_Alloc(cls.permanentmempool, sz_address); + cl_iplog_items[cl_iplog_numitems].name = (char *) Mem_Alloc(cls.permanentmempool, sz_name); + strlcpy(cl_iplog_items[cl_iplog_numitems].address, address, sz_address); // TODO: maybe it would be better to strip weird characters from name when // copying it here rather than using a straight strcpy? - strlcpy(cl_iplog_items[cl_iplog_numitems].name, name, strlen(name) + 1); + strlcpy(cl_iplog_items[cl_iplog_numitems].name, name, sz_name); cl_iplog_numitems++; if (addtofile) { diff --git a/misc/source/darkplaces-src/cl_particles.c b/misc/source/darkplaces-src/cl_particles.c index 01e9701c..1e7a909d 100644 --- a/misc/source/darkplaces-src/cl_particles.c +++ b/misc/source/darkplaces-src/cl_particles.c @@ -114,6 +114,7 @@ typedef struct particleeffectinfo_s float lightcolor[3]; qboolean lightshadow; int lightcubemapnum; + float lightcorona[2]; unsigned int staincolor[2]; // note: 0x808080 = neutral (particle's own color), these are modding factors for the particle's original color! int staintex[2]; float stainalpha[2]; @@ -263,6 +264,7 @@ particleeffectinfo_t baselineparticleeffectinfo = {1.0f, 1.0f, 1.0f}, //float lightcolor[3]; true, //qboolean lightshadow; 0, //int lightcubemapnum; + {1.0f, 0.25f}, //float lightcorona[2]; {(unsigned int)-1, (unsigned int)-1}, //unsigned int staincolor[2]; // note: 0x808080 = neutral (particle's own color), these are modding factors for the particle's original color! {-1, -1}, //int staintex[2]; {1.0f, 1.0f}, //float stainalpha[2]; @@ -438,6 +440,7 @@ static void CL_Particles_ParseEffectInfo(const char *textstart, const char *text else if (!strcmp(argv[0], "lightcolor")) {readfloats(info->lightcolor, 3);} else if (!strcmp(argv[0], "lightshadow")) {readbool(info->lightshadow);} else if (!strcmp(argv[0], "lightcubemapnum")) {readint(info->lightcubemapnum);} + else if (!strcmp(argv[0], "lightcorona")) {readints(info->lightcorona, 2);} else if (!strcmp(argv[0], "underwater")) {checkparms(1);info->flags |= PARTICLEEFFECT_UNDERWATER;} else if (!strcmp(argv[0], "notunderwater")) {checkparms(1);info->flags |= PARTICLEEFFECT_NOTUNDERWATER;} else if (!strcmp(argv[0], "trailspacing")) {readfloat(info->trailspacing);if (info->trailspacing > 0) info->countmultiplier = 1.0f / info->trailspacing;} @@ -1487,7 +1490,7 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins { // light flash (explosion, etc) // called when effect starts - CL_AllocLightFlash(NULL, &tempmatrix, info->lightradiusstart, info->lightcolor[0]*avgtint[0]*avgtint[3], info->lightcolor[1]*avgtint[1]*avgtint[3], info->lightcolor[2]*avgtint[2]*avgtint[3], info->lightradiusfade, info->lighttime, info->lightcubemapnum, -1, info->lightshadow, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &tempmatrix, info->lightradiusstart, info->lightcolor[0]*avgtint[0]*avgtint[3], info->lightcolor[1]*avgtint[1]*avgtint[3], info->lightcolor[2]*avgtint[2]*avgtint[3], info->lightradiusfade, info->lighttime, info->lightcubemapnum, -1, info->lightshadow, info->lightcorona[0], info->lightcorona[1], 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (r_refdef.scene.numlights < MAX_DLIGHTS) { @@ -1497,7 +1500,7 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins rvec[0] = info->lightcolor[0]*avgtint[0]*avgtint[3]; rvec[1] = info->lightcolor[1]*avgtint[1]*avgtint[3]; rvec[2] = info->lightcolor[2]*avgtint[2]*avgtint[3]; - R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, rvec, -1, info->lightcubemapnum > 0 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", info->lightcubemapnum) : NULL, info->lightshadow, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, rvec, -1, info->lightcubemapnum > 0 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", info->lightcubemapnum) : NULL, info->lightshadow, info->lightcorona[0], info->lightcorona[1], 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++; } } diff --git a/misc/source/darkplaces-src/cl_screen.c b/misc/source/darkplaces-src/cl_screen.c index 7724b5ce..f1ae5669 100644 --- a/misc/source/darkplaces-src/cl_screen.c +++ b/misc/source/darkplaces-src/cl_screen.c @@ -39,6 +39,7 @@ cvar_t scr_loadingscreen_scale = {0, "scr_loadingscreen_scale","1", "scale facto cvar_t scr_loadingscreen_scale_base = {0, "scr_loadingscreen_scale_base","0", "0 = console pixels, 1 = video pixels"}; cvar_t scr_loadingscreen_scale_limit = {0, "scr_loadingscreen_scale_limit","0", "0 = no limit, 1 = until first edge hits screen edge, 2 = until last edge hits screen edge, 3 = until width hits screen width, 4 = until height hits screen height"}; cvar_t scr_loadingscreen_count = {0, "scr_loadingscreen_count","1", "number of loading screen files to use randomly (named loading.tga, loading2.tga, loading3.tga, ...)"}; +cvar_t scr_loadingscreen_firstforstartup = {0, "scr_loadingscreen_firstforstartup","0", "remove loading.tga from random scr_loadingscreen_count selection and only display it on client startup, 0 = normal, 1 = firstforstartup"}; cvar_t scr_loadingscreen_barcolor = {0, "scr_loadingscreen_barcolor", "0 0 1", "rgb color of loadingscreen progress bar"}; cvar_t scr_loadingscreen_barheight = {0, "scr_loadingscreen_barheight", "8", "the height of the loadingscreen progress bar"}; cvar_t scr_infobar_height = {0, "scr_infobar_height", "8", "the height of the infobar items"}; @@ -709,13 +710,13 @@ SCR_BeginLoadingPlaque ================ */ -void SCR_BeginLoadingPlaque (void) +void SCR_BeginLoadingPlaque (qboolean startup) { // save console log up to this point to log_file if it was set by configs Log_Start(); Host_StartVideo(); - SCR_UpdateLoadingScreen(false); + SCR_UpdateLoadingScreen(false, startup); } //============================================================================= @@ -916,6 +917,7 @@ void CL_Screen_Init(void) Cvar_RegisterVariable (&scr_loadingscreen_scale_base); Cvar_RegisterVariable (&scr_loadingscreen_scale_limit); Cvar_RegisterVariable (&scr_loadingscreen_count); + Cvar_RegisterVariable (&scr_loadingscreen_firstforstartup); Cvar_RegisterVariable (&scr_loadingscreen_barcolor); Cvar_RegisterVariable (&scr_loadingscreen_barheight); Cvar_RegisterVariable (&scr_infobar_height); @@ -1890,7 +1892,7 @@ static void SCR_SetLoadingScreenTexture(void) void SCR_UpdateLoadingScreenIfShown(void) { if(loadingscreendone) - SCR_UpdateLoadingScreen(loadingscreencleared); + SCR_UpdateLoadingScreen(loadingscreencleared, false); } void SCR_PushLoadingScreen (qboolean redraw, const char *msg, float len_in_parent) @@ -2128,7 +2130,7 @@ static void SCR_DrawLoadingScreen_SharedFinish (qboolean clear) VID_Finish(); } -void SCR_UpdateLoadingScreen (qboolean clear) +void SCR_UpdateLoadingScreen (qboolean clear, qboolean startup) { keydest_t old_key_dest; int old_key_consoleactive; @@ -2144,7 +2146,17 @@ void SCR_UpdateLoadingScreen (qboolean clear) clear |= loadingscreencleared; if(!loadingscreendone) - loadingscreenpic_number = rand() % (scr_loadingscreen_count.integer > 1 ? scr_loadingscreen_count.integer : 1); + { + if(startup && scr_loadingscreen_firstforstartup.integer) + loadingscreenpic_number = 0; + else if(scr_loadingscreen_firstforstartup.integer) + if(scr_loadingscreen_count.integer > 1) + loadingscreenpic_number = rand() % (scr_loadingscreen_count.integer - 1) + 1; + else + loadingscreenpic_number = 0; + else + loadingscreenpic_number = rand() % (scr_loadingscreen_count.integer > 1 ? scr_loadingscreen_count.integer : 1); + } if(clear) SCR_ClearLoadingScreenTexture(); @@ -2205,20 +2217,90 @@ extern cvar_t cl_minfps; extern cvar_t cl_minfps_fade; extern cvar_t cl_minfps_qualitymax; extern cvar_t cl_minfps_qualitymin; -extern cvar_t cl_minfps_qualitypower; -extern cvar_t cl_minfps_qualityscale; -extern cvar_t r_viewscale_fpsscaling; -static double cl_updatescreen_rendertime = 0; +extern cvar_t cl_minfps_qualitymultiply; +extern cvar_t cl_minfps_qualityhysteresis; +extern cvar_t cl_minfps_qualitystepmax; +extern cvar_t cl_minfps_force; static double cl_updatescreen_quality = 1; void CL_UpdateScreen(void) { vec3_t vieworigin; - double rendertime1; - double drawscreenstart; + static double drawscreenstart = 0.0; + double drawscreendelta; float conwidth, conheight; - float f; r_viewport_t viewport; + if(drawscreenstart) + { + drawscreendelta = Sys_DirtyTime() - drawscreenstart; + if (cl_minfps.value > 0 && (cl_minfps_force.integer || !(cls.timedemo || (cls.capturevideo.active && !cls.capturevideo.realtime))) && drawscreendelta >= 0 && drawscreendelta < 60) + { + // quality adjustment according to render time + double actualframetime; + double targetframetime; + double adjust; + double f; + double h; + + // fade lastdrawscreentime + r_refdef.lastdrawscreentime += (drawscreendelta - r_refdef.lastdrawscreentime) * cl_minfps_fade.value; + + // find actual and target frame times + actualframetime = r_refdef.lastdrawscreentime; + targetframetime = (1.0 / cl_minfps.value); + + // we scale hysteresis by quality + h = cl_updatescreen_quality * cl_minfps_qualityhysteresis.value; + + // calculate adjustment assuming linearity + f = cl_updatescreen_quality / actualframetime * cl_minfps_qualitymultiply.value; + adjust = (targetframetime - actualframetime) * f; + + // one sided hysteresis + if(adjust > 0) + adjust = max(0, adjust - h); + + // adjust > 0 if: + // (targetframetime - actualframetime) * f > h + // ((1.0 / cl_minfps.value) - actualframetime) * (cl_updatescreen_quality / actualframetime * cl_minfps_qualitymultiply.value) > (cl_updatescreen_quality * cl_minfps_qualityhysteresis.value) + // ((1.0 / cl_minfps.value) - actualframetime) * (cl_minfps_qualitymultiply.value / actualframetime) > cl_minfps_qualityhysteresis.value + // (1.0 / cl_minfps.value) * (cl_minfps_qualitymultiply.value / actualframetime) - cl_minfps_qualitymultiply.value > cl_minfps_qualityhysteresis.value + // (1.0 / cl_minfps.value) * (cl_minfps_qualitymultiply.value / actualframetime) > cl_minfps_qualityhysteresis.value + cl_minfps_qualitymultiply.value + // (1.0 / cl_minfps.value) / actualframetime > (cl_minfps_qualityhysteresis.value + cl_minfps_qualitymultiply.value) / cl_minfps_qualitymultiply.value + // (1.0 / cl_minfps.value) / actualframetime > 1.0 + cl_minfps_qualityhysteresis.value / cl_minfps_qualitymultiply.value + // cl_minfps.value * actualframetime < 1.0 / (1.0 + cl_minfps_qualityhysteresis.value / cl_minfps_qualitymultiply.value) + // actualframetime < 1.0 / cl_minfps.value / (1.0 + cl_minfps_qualityhysteresis.value / cl_minfps_qualitymultiply.value) + // actualfps > cl_minfps.value * (1.0 + cl_minfps_qualityhysteresis.value / cl_minfps_qualitymultiply.value) + + // adjust < 0 if: + // (targetframetime - actualframetime) * f < 0 + // ((1.0 / cl_minfps.value) - actualframetime) * (cl_updatescreen_quality / actualframetime * cl_minfps_qualitymultiply.value) < 0 + // ((1.0 / cl_minfps.value) - actualframetime) < 0 + // -actualframetime) < -(1.0 / cl_minfps.value) + // actualfps < cl_minfps.value + + /* + Con_Printf("adjust UP if fps > %f, adjust DOWN if fps < %f\n", + cl_minfps.value * (1.0 + cl_minfps_qualityhysteresis.value / cl_minfps_qualitymultiply.value), + cl_minfps.value); + */ + + // don't adjust too much at once + adjust = bound(-cl_minfps_qualitystepmax.value, adjust, cl_minfps_qualitystepmax.value); + + // adjust! + cl_updatescreen_quality += adjust; + cl_updatescreen_quality = bound(max(0.01, cl_minfps_qualitymin.value), cl_updatescreen_quality, cl_minfps_qualitymax.value); + } + else + { + cl_updatescreen_quality = 1; + r_refdef.lastdrawscreentime = 0; + } + } + + drawscreenstart = Sys_DirtyTime(); + Sbar_ShowFPS_Update(); if (!scr_initialized || !con_initialized || !scr_refresh.integer) @@ -2245,8 +2327,6 @@ void CL_UpdateScreen(void) return; } - rendertime1 = Sys_DirtyTime(); - conwidth = bound(160, vid_conwidth.value, 32768); conheight = bound(90, vid_conheight.value, 24576); if (vid_conwidth.value != conwidth) @@ -2315,8 +2395,9 @@ void CL_UpdateScreen(void) R_ClearScreen(false); r_refdef.view.clear = false; r_refdef.view.isoverlay = false; - f = pow((float)cl_updatescreen_quality, cl_minfps_qualitypower.value) * cl_minfps_qualityscale.value; - r_refdef.view.quality = bound(cl_minfps_qualitymin.value, f, cl_minfps_qualitymax.value); + + // calculate r_refdef.view.quality + r_refdef.view.quality = cl_updatescreen_quality; #ifndef USE_GLES2 if (qglPolygonStipple) @@ -2347,9 +2428,6 @@ void CL_UpdateScreen(void) } #endif - if (r_viewscale_fpsscaling.integer) - GL_Finish(); - drawscreenstart = Sys_DirtyTime(); #ifndef USE_GLES2 if (R_Stereo_Active()) { @@ -2385,22 +2463,12 @@ void CL_UpdateScreen(void) else #endif SCR_DrawScreen(); - if (r_viewscale_fpsscaling.integer) - GL_Finish(); - r_refdef.lastdrawscreentime = Sys_DirtyTime() - drawscreenstart; SCR_CaptureVideo(); if (qglFlush) qglFlush(); // FIXME: should we really be using qglFlush here? - // quality adjustment according to render time - cl_updatescreen_rendertime += ((Sys_DirtyTime() - rendertime1) - cl_updatescreen_rendertime) * bound(0, cl_minfps_fade.value, 1); - if (cl_minfps.value > 0 && cl_updatescreen_rendertime > 0 && !cls.timedemo && (!cls.capturevideo.active || !cls.capturevideo.realtime)) - cl_updatescreen_quality = 1 / (cl_updatescreen_rendertime * cl_minfps.value); - else - cl_updatescreen_quality = 1; - if (!vid_activewindow) VID_SetMouse(false, false, false); else if (key_consoleactive) diff --git a/misc/source/darkplaces-src/client.h b/misc/source/darkplaces-src/client.h index f28e5adb..9f86fdab 100644 --- a/misc/source/darkplaces-src/client.h +++ b/misc/source/darkplaces-src/client.h @@ -996,6 +996,7 @@ typedef struct client_state_s float bob2_smooth; float bobfall_speed; float bobfall_swing; + double calcrefdef_prevtime; // don't change view angle, full screen, etc int intermission; @@ -1448,7 +1449,7 @@ void V_StartPitchDrift (void); void V_StopPitchDrift (void); void V_Init (void); -float V_CalcRoll (vec3_t angles, vec3_t velocity); +float V_CalcRoll (const vec3_t angles, const vec3_t velocity); void V_UpdateBlends (void); void V_ParseDamage (void); @@ -1849,6 +1850,8 @@ waterlevel_t; typedef struct cl_clientmovement_state_s { + // entity to be ignored for movement + struct prvm_edict_s *self; // position vec3_t origin; vec3_t velocity; @@ -1871,7 +1874,7 @@ typedef struct cl_clientmovement_state_s usercmd_t cmd; } cl_clientmovement_state_t; -void CL_ClientMovement_PlayerMove(cl_clientmovement_state_t *s); +void CL_ClientMovement_PlayerMove_Frame(cl_clientmovement_state_t *s); // warpzone prediction hack (CSQC builtin) void CL_RotateMoves(const matrix4x4_t *m); @@ -1889,7 +1892,7 @@ void SCR_CaptureVideo_SoundFrame(const portable_sampleframe_t *paintbuffer, size void V_DriftPitch(void); void V_FadeViewFlashs(void); void V_CalcViewBlend(void); -void V_CalcRefdefUsing(const matrix4x4_t *entrendermatrix, const vec3_t clviewangles, qboolean teleported, qboolean clonground, qboolean clcmdjump); +void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewangles, qboolean teleported, qboolean clonground, qboolean clcmdjump, float clstatsviewheight, qboolean cldead, qboolean clintermission, const vec3_t clvelocity); void V_CalcRefdef(void); void CL_Locs_Reload_f(void); diff --git a/misc/source/darkplaces-src/clvm_cmds.c b/misc/source/darkplaces-src/clvm_cmds.c index f07cf854..d03b632e 100644 --- a/misc/source/darkplaces-src/clvm_cmds.c +++ b/misc/source/darkplaces-src/clvm_cmds.c @@ -911,6 +911,9 @@ static void VM_CL_R_SetView (prvm_prog_t *prog) case VF_FOG_FADEDEPTH: PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_fadedepth; break; + case VF_MINFPS_QUALITY: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.quality; + break; default: PRVM_G_FLOAT(OFS_RETURN) = 0; VM_Warning(prog, "VM_CL_R_GetView : unknown parm %i\n", c); @@ -1061,6 +1064,9 @@ static void VM_CL_R_SetView (prvm_prog_t *prog) case VF_FOG_FADEDEPTH: r_refdef.fog_fadedepth = k; break; + case VF_MINFPS_QUALITY: + r_refdef.view.quality = k; + break; default: PRVM_G_FLOAT(OFS_RETURN) = 0; VM_Warning(prog, "VM_CL_R_SetView : unknown parm %i\n", c); @@ -1440,40 +1446,74 @@ static void VM_CL_setsensitivityscale (prvm_prog_t *prog) } //#347 void() runstandardplayerphysics (EXT_CSQC) -#define PMF_JUMP_HELD 1 -#define PMF_LADDER 2 // not used by DP -#define PMF_DUCKED 4 // FIXME FTEQW doesn't have this for Q1 like movement +#define PMF_JUMP_HELD 1 // matches FTEQW +#define PMF_LADDER 2 // not used by DP, FTEQW sets this in runplayerphysics but does not read it +#define PMF_DUCKED 4 // FIXME FTEQW doesn't have this for Q1 like movement because Q1 cannot crouch +#define PMF_ONGROUND 8 // FIXME FTEQW doesn't have this for Q1 like movement and expects CSQC code to do its own trace, this is stupid CPU waste static void VM_CL_runplayerphysics (prvm_prog_t *prog) { cl_clientmovement_state_t s; prvm_edict_t *ent; - VM_SAFEPARMCOUNT(1, VM_CL_runplayerphysics); + memset(&s, 0, sizeof(s)); + + VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_runplayerphysics); + + ent = (prog->argc == 1 ? PRVM_G_EDICT(OFS_PARM0) : prog->edicts); + if(ent == prog->edicts) + { + // deprecated use + s.self = NULL; + VectorCopy(PRVM_clientglobalvector(pmove_org), s.origin); + VectorCopy(PRVM_clientglobalvector(pmove_vel), s.velocity); + VectorCopy(PRVM_clientglobalvector(pmove_mins), s.mins); + VectorCopy(PRVM_clientglobalvector(pmove_maxs), s.maxs); + s.crouched = 0; + s.waterjumptime = PRVM_clientglobalfloat(pmove_waterjumptime); + s.cmd.canjump = (int)PRVM_clientglobalfloat(pmove_jump_held) == 0; + } + else + { + // new use + s.self = ent; + VectorCopy(PRVM_clientedictvector(ent, origin), s.origin); + VectorCopy(PRVM_clientedictvector(ent, velocity), s.velocity); + VectorCopy(PRVM_clientedictvector(ent, mins), s.mins); + VectorCopy(PRVM_clientedictvector(ent, maxs), s.maxs); + s.crouched = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_DUCKED) != 0; + s.waterjumptime = 0; // FIXME where do we get this from? FTEQW lacks support for this too + s.cmd.canjump = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_JUMP_HELD) == 0; + } - ent = PRVM_G_EDICT(OFS_PARM0); - VectorCopy(PRVM_clientedictvector(ent, origin), s.origin); - VectorCopy(PRVM_clientedictvector(ent, velocity), s.velocity); - VectorCopy(PRVM_clientedictvector(ent, mins), s.mins); - VectorCopy(PRVM_clientedictvector(ent, maxs), s.maxs); - s.crouched = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_DUCKED) != 0; - s.waterjumptime = 0; // FIXME where do we get this from? FTEQW lacks support for this too VectorCopy(PRVM_clientglobalvector(input_angles), s.cmd.viewangles); s.cmd.forwardmove = PRVM_clientglobalvector(input_movevalues)[0]; s.cmd.sidemove = PRVM_clientglobalvector(input_movevalues)[1]; s.cmd.upmove = PRVM_clientglobalvector(input_movevalues)[2]; s.cmd.buttons = PRVM_clientglobalfloat(input_buttons); s.cmd.frametime = PRVM_clientglobalfloat(input_timelength); - s.cmd.canjump = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_JUMP_HELD) == 0; s.cmd.jump = (s.cmd.buttons & 2) != 0; s.cmd.crouch = (s.cmd.buttons & 16) != 0; - CL_ClientMovement_PlayerMove(&s); + CL_ClientMovement_PlayerMove_Frame(&s); - VectorCopy(s.origin, PRVM_clientedictvector(ent, origin)); - VectorCopy(s.velocity, PRVM_clientedictvector(ent, velocity)); - PRVM_clientedictfloat(ent, pmove_flags) = - (s.crouched ? PMF_DUCKED : 0) | - (s.cmd.canjump ? 0 : PMF_JUMP_HELD); + if(ent == prog->edicts) + { + // deprecated use + VectorCopy(s.origin, PRVM_clientglobalvector(pmove_org)); + VectorCopy(s.velocity, PRVM_clientglobalvector(pmove_vel)); + PRVM_clientglobalfloat(pmove_jump_held) = !s.cmd.canjump; + PRVM_clientglobalfloat(pmove_waterjumptime) = s.waterjumptime; + } + else + { + // new use + VectorCopy(s.origin, PRVM_clientedictvector(ent, origin)); + VectorCopy(s.velocity, PRVM_clientedictvector(ent, velocity)); + PRVM_clientedictfloat(ent, pmove_flags) = + (s.crouched ? PMF_DUCKED : 0) | + (s.cmd.canjump ? 0 : PMF_JUMP_HELD) | + (s.onground ? PMF_ONGROUND : 0); + } } //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC) @@ -2464,7 +2504,8 @@ static void VM_CL_gettagindex (prvm_prog_t *prog) { tag_index = CL_GetTagIndex(prog, ent, tag_name); if (tag_index == 0) - Con_DPrintf("VM_CL_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name); + if(developer_extra.integer) + Con_DPrintf("VM_CL_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name); } PRVM_G_FLOAT(OFS_RETURN) = tag_index; } @@ -3815,7 +3856,7 @@ static void VM_CL_skel_build(prvm_prog_t *prog) Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac); for (blendindex = 0;blendindex < numblends;blendindex++) { - Matrix4x4_FromBonePose6s(&matrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + bonenum)); + Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum)); Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp); } skeleton->relativetransforms[bonenum] = blendedmatrix; @@ -4111,6 +4152,47 @@ static void VM_CL_loadcubemap(prvm_prog_t *prog) R_GetCubemap(name); } +#define REFDEFFLAG_TELEPORTED 1 +#define REFDEFFLAG_JUMPING 2 +#define REFDEFFLAG_DEAD 4 +#define REFDEFFLAG_INTERMISSION 8 +static void VM_CL_V_CalcRefdef(prvm_prog_t *prog) +{ + matrix4x4_t entrendermatrix; + vec3_t clviewangles; + vec3_t clvelocity; + qboolean teleported; + qboolean clonground; + qboolean clcmdjump; + qboolean cldead; + qboolean clintermission; + float clstatsviewheight; + prvm_edict_t *ent; + int flags; + + VM_SAFEPARMCOUNT(2, VM_CL_V_CalcRefdef); + ent = PRVM_G_EDICT(OFS_PARM0); + flags = PRVM_G_FLOAT(OFS_PARM1); + + // use the CL_GetTagMatrix function on self to ensure consistent behavior (duplicate code would be bad) + CL_GetTagMatrix(prog, &entrendermatrix, ent, 0); + + VectorCopy(cl.csqc_viewangles, clviewangles); + teleported = (flags & REFDEFFLAG_TELEPORTED) != 0; + clonground = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_ONGROUND) != 0; + clcmdjump = (flags & REFDEFFLAG_JUMPING) != 0; + clstatsviewheight = PRVM_clientedictvector(ent, view_ofs)[2]; + cldead = (flags & REFDEFFLAG_DEAD) != 0; + clintermission = (flags & REFDEFFLAG_INTERMISSION) != 0; + VectorCopy(PRVM_clientedictvector(ent, velocity), clvelocity); + + V_CalcRefdefUsing(&entrendermatrix, clviewangles, teleported, clonground, clcmdjump, clstatsviewheight, cldead, clintermission, clvelocity); + + VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin); + VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles); + CSQC_R_RecalcView(); +} + //============================================================================ // To create a almost working builtin file from this replace: @@ -4765,7 +4847,8 @@ NULL, // #636 NULL, // #637 VM_CL_RotateMoves, // #638 VM_digest_hex, // #639 -NULL, // #640 +VM_CL_V_CalcRefdef, // #640 void(entity e) V_CalcRefdef (DP_CSQC_V_CALCREFDEF) +NULL, // #641 }; const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t); diff --git a/misc/source/darkplaces-src/cmd.c b/misc/source/darkplaces-src/cmd.c index 0a42ca4a..beee312d 100644 --- a/misc/source/darkplaces-src/cmd.c +++ b/misc/source/darkplaces-src/cmd.c @@ -177,8 +177,8 @@ static sizebuf_t cmd_text; static unsigned char cmd_text_buf[CMDBUFSIZE]; void *cmd_text_mutex = NULL; -#define Cbuf_LockThreadMutex() (cmd_text_mutex ? Thread_LockMutex(cmd_text_mutex),1 : 0) -#define Cbuf_UnlockThreadMutex() (cmd_text_mutex ? Thread_UnlockMutex(cmd_text_mutex),1 : 0) +#define Cbuf_LockThreadMutex() (void)(cmd_text_mutex ? Thread_LockMutex(cmd_text_mutex) : 0) +#define Cbuf_UnlockThreadMutex() (void)(cmd_text_mutex ? Thread_UnlockMutex(cmd_text_mutex) : 0) /* ============ @@ -275,7 +275,7 @@ static void Cbuf_Execute_Deferred (void) Cbuf_Execute ============ */ -static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ); +static qboolean Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ); void Cbuf_Execute (void) { int i; @@ -360,8 +360,8 @@ void Cbuf_Execute (void) (strncmp(firstchar, "in_bind", 7) || !ISWHITESPACE(firstchar[7])) ) { - Cmd_PreprocessString( line, preprocessed, sizeof(preprocessed), NULL ); - Cmd_ExecuteString (preprocessed, src_command, false); + if(Cmd_PreprocessString( line, preprocessed, sizeof(preprocessed), NULL )) + Cmd_ExecuteString (preprocessed, src_command, false); } else { @@ -463,7 +463,8 @@ static void Cmd_StuffCmds_f (void) static void Cmd_Exec(const char *filename) { char *f; - qboolean isdefaultcfg = strlen(filename) >= 11 && !strcmp(filename + strlen(filename) - 11, "default.cfg"); + size_t filenameLen = strlen(filename); + qboolean isdefaultcfg = filenameLen >= 11 && !strcmp(filename + filenameLen - 11, "default.cfg"); if (!strcmp(filename, "config.cfg")) { @@ -920,9 +921,11 @@ static const char *Cmd_GetCvarValue(const char *var, size_t varlen, cmdalias_t * { static char varname[MAX_INPUTLINE]; // cmd_mutex static char varval[MAX_INPUTLINE]; // cmd_mutex - const char *varstr; + const char *varstr = NULL; char *varfunc; -static char asis[] = "asis"; // just to suppress const char warnings + qboolean required = false; + qboolean optional = false; + static char asis[] = "asis"; // just to suppress const char warnings if(varlen >= MAX_INPUTLINE) varlen = MAX_INPUTLINE - 1; @@ -939,10 +942,37 @@ static char asis[] = "asis"; // just to suppress const char warnings if(*var == 0) { // empty cvar name? - return NULL; + if(alias) + Con_Printf("Warning: Could not expand $ in alias %s\n", alias->name); + else + Con_Printf("Warning: Could not expand $\n"); + return "$"; } - varstr = NULL; + if(varfunc) + { + char *p; + // ? means optional + while((p = strchr(varfunc, '?'))) + { + optional = true; + memmove(p, p+1, strlen(p)); // with final NUL + } + // ! means required + while((p = strchr(varfunc, '!'))) + { + required = true; + memmove(p, p+1, strlen(p)); // with final NUL + } + // kill spaces + while((p = strchr(varfunc, ' '))) + { + memmove(p, p+1, strlen(p)); // with final NUL + } + // if no function is left, NULL it + if(!*varfunc) + varfunc = NULL; + } if(varname[0] == '$') varstr = Cmd_GetDirectCvarValue(Cmd_GetDirectCvarValue(varname + 1, alias, NULL), alias, NULL); @@ -958,11 +988,27 @@ static char asis[] = "asis"; // just to suppress const char warnings if(!varstr) { - if(alias) - Con_Printf("Warning: Could not expand $%s in alias %s\n", varname, alias->name); + if(required) + { + if(alias) + Con_Printf("Error: Could not expand $%s in alias %s\n", varname, alias->name); + else + Con_Printf("Error: Could not expand $%s\n", varname); + return NULL; + } + else if(optional) + { + return ""; + } else - Con_Printf("Warning: Could not expand $%s\n", varname); - return NULL; + { + if(alias) + Con_Printf("Warning: Could not expand $%s in alias %s\n", varname, alias->name); + else + Con_Printf("Warning: Could not expand $%s\n", varname); + dpsnprintf(varval, sizeof(varval), "$%s", varname); + return varval; + } } if(!varfunc || !strcmp(varfunc, "q")) // note: quoted form is default, use "asis" to override! @@ -987,7 +1033,7 @@ Cmd_PreprocessString Preprocesses strings and replaces $*, $param#, $cvar accordingly. Also strips comments. */ -static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ) { +static qboolean Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ) { const char *in; size_t eat, varlen; unsigned outlen; @@ -995,7 +1041,7 @@ static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned ma // don't crash if there's no room in the outtext buffer if( maxoutlen == 0 ) { - return; + return false; } maxoutlen--; // because of \0 @@ -1016,6 +1062,10 @@ static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned ma // that way) // - ${var asis} inserts the cvar value as is, without doing this // quoting + // - ${var ?} silently expands to the empty string if + // $var does not exist + // - ${var !} fails expansion and executes nothing if + // $var does not exist // - prefix the cvar name with a dollar sign to do indirection; // for example, if $x has the value timelimit, ${$x} will return // the value of $timelimit @@ -1026,6 +1076,7 @@ static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned ma // parameters, without extra quoting, so one can use $* to just // pass all parameters around. All parameters starting from $n // can be referred to as $n- (so $* is equivalent to $1-). + // - ${* q} and ${n- q} force quoting anyway // // Note: when expanding an alias, cvar expansion is done in the SAME step // as alias expansion so that alias parameters or cvar values containing @@ -1062,6 +1113,8 @@ static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned ma if(in[varlen + 1] == '}') { val = Cmd_GetCvarValue(in + 1, varlen, alias); + if(!val) + return false; eat = varlen + 2; } else @@ -1073,6 +1126,8 @@ static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned ma } else { varlen = strspn(in, "#*0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"); val = Cmd_GetCvarValue(in, varlen, alias); + if(!val) + return false; eat = varlen; } if(val) @@ -1097,6 +1152,7 @@ static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned ma outtext[outlen++] = *in++; } outtext[outlen] = 0; + return true; } /* @@ -1110,7 +1166,9 @@ static void Cmd_ExecuteAlias (cmdalias_t *alias) { static char buffer[ MAX_INPUTLINE ]; // cmd_mutex static char buffer2[ MAX_INPUTLINE ]; // cmd_mutex - Cmd_PreprocessString( alias->value, buffer, sizeof(buffer) - 2, alias ); + qboolean ret = Cmd_PreprocessString( alias->value, buffer, sizeof(buffer) - 2, alias ); + if(!ret) + return; // insert at start of command buffer, so that aliases execute in order // (fixes bug introduced by Black on 20050705) diff --git a/misc/source/darkplaces-src/common.c b/misc/source/darkplaces-src/common.c index ada40e20..3b986194 100644 --- a/misc/source/darkplaces-src/common.c +++ b/misc/source/darkplaces-src/common.c @@ -405,6 +405,14 @@ void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol) // reading functions // +void MSG_InitReadBuffer (sizebuf_t *buf, unsigned char *data, int size) +{ + memset(buf, 0, sizeof(*buf)); + buf->data = data; + buf->maxsize = buf->cursize = size; + MSG_BeginReading(buf); +} + void MSG_BeginReading(sizebuf_t *sb) { sb->readcount = 0; @@ -1461,9 +1469,11 @@ static const gamemode_info_t gamemode_info [GAME_COUNT] = { GAME_DARSANA, GAME_DARSANA, "darsana", "-darsana", "Darsana", "ddata", NULL, "darsana", "darsana" }, // COMMANDLINEOPTION: Game: -darsana runs the game Darsana { GAME_CONTAGIONTHEORY, GAME_CONTAGIONTHEORY, "contagiontheory", "-contagiontheory", "Contagion Theory", "ctdata", NULL, "ct", "contagiontheory" }, // COMMANDLINEOPTION: Game: -contagiontheory runs the game Contagion Theory { GAME_EDU2P, GAME_EDU2P, "edu2p", "-edu2p", "EDU2 Prototype", "id1", "edu2", "edu2_p", "edu2prototype" }, // COMMANDLINEOPTION: Game: -edu2p runs the game Edu2 prototype -{ GAME_PROPHECY, GAME_PROPHECY, "prophecy", "-prophecy", "Prophecy", "data", NULL, "prophecy", "prophecy" }, // COMMANDLINEOPTION: Game: -prophecy runs the game Prophecy +{ GAME_PROPHECY, GAME_PROPHECY, "prophecy", "-prophecy", "Prophecy", "gamedata", NULL, "phcy", "prophecy" }, // COMMANDLINEOPTION: Game: -prophecy runs the game Prophecy { GAME_BLOODOMNICIDE, GAME_BLOODOMNICIDE, "omnicide", "-omnicide", "Blood Omnicide", "kain", NULL, "omnicide", "omnicide" }, // COMMANDLINEOPTION: Game: -omnicide runs the game Blood Omnicide { GAME_STEELSTORM, GAME_STEELSTORM, "steelstorm", "-steelstorm", "Steel-Storm", "gamedata", NULL, "ss", "steelstorm" }, // COMMANDLINEOPTION: Game: -steelstorm runs the game Steel Storm +{ GAME_STEELSTORM2, GAME_STEELSTORM2, "steelstorm2", "-steelstorm2", "Steel Storm 2", "gamedata", NULL, "ss2", "steelstorm2" }, // COMMANDLINEOPTION: Game: -steelstorm2 runs the game Steel Storm 2 +{ GAME_TOMESOFMEPHISTOPHELES, GAME_TOMESOFMEPHISTOPHELES, "tomesofmephistopheles", "-tomesofmephistopheles", "Tomes of Mephistopheles", "gamedata", NULL, "tom", "tomesofmephistopheles" }, // COMMANDLINEOPTION: Game: -steelstorm runs the game Steel Storm { GAME_STRAPBOMB, GAME_STRAPBOMB, "strapbomb", "-strapbomb", "Strap-on-bomb Car", "id1", NULL, "strap", "strapbomb" }, // COMMANDLINEOPTION: Game: -strapbomb runs the game Strap-on-bomb Car { GAME_MOONHELM, GAME_MOONHELM, "moonhelm", "-moonhelm", "MoonHelm", "data", NULL, "mh", "moonhelm" }, // COMMANDLINEOPTION: Game: -moonhelm runs the game MoonHelm }; @@ -1480,18 +1490,12 @@ void COM_InitGameType (void) COM_ToLowerString(name, name, sizeof (name)); for (i = 1;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++) if (gamemode_info[i].prog_name && gamemode_info[i].prog_name[0] && strstr (name, gamemode_info[i].prog_name)) - { index = i; - break; - } // check commandline options for keywords for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++) if (COM_CheckParm (gamemode_info[i].cmdline)) - { index = i; - break; - } com_startupgamemode = gamemode_info[index].mode; com_startupgamegroup = gamemode_info[index].group; diff --git a/misc/source/darkplaces-src/common.h b/misc/source/darkplaces-src/common.h index e91be283..8a6dbd2a 100644 --- a/misc/source/darkplaces-src/common.h +++ b/misc/source/darkplaces-src/common.h @@ -147,6 +147,7 @@ protocolversion_t; * @{ */ +void MSG_InitReadBuffer (sizebuf_t *buf, unsigned char *data, int size); void MSG_WriteChar (sizebuf_t *sb, int c); void MSG_WriteByte (sizebuf_t *sb, int c); void MSG_WriteShort (sizebuf_t *sb, int c); @@ -290,6 +291,8 @@ typedef enum gamemode_e GAME_PROPHECY, GAME_BLOODOMNICIDE, GAME_STEELSTORM, // added by motorsep + GAME_STEELSTORM2, // added by motorsep + GAME_TOMESOFMEPHISTOPHELES, // added by motorsep GAME_STRAPBOMB, // added by motorsep for Urre GAME_MOONHELM, GAME_COUNT diff --git a/misc/source/darkplaces-src/console.c b/misc/source/darkplaces-src/console.c index 14175b07..e21f2cbf 100644 --- a/misc/source/darkplaces-src/console.c +++ b/misc/source/darkplaces-src/console.c @@ -590,7 +590,8 @@ void Con_ClearNotify (void) { int i; for(i = 0; i < CON_LINES_COUNT; ++i) - CON_LINES(i).mask |= CON_MASK_HIDENOTIFY; + if(!(CON_LINES(i).mask & CON_MASK_CHAT)) + CON_LINES(i).mask |= CON_MASK_HIDENOTIFY; } @@ -905,13 +906,16 @@ void Con_Rcon_Redirect_Init(lhnetsocket_t *sock, lhnetaddress_t *dest, qboolean static void Con_Rcon_Redirect_Flush(void) { - rcon_redirect_buffer[rcon_redirect_bufferpos] = 0; - if (rcon_redirect_proquakeprotocol) + if(rcon_redirect_sock) { - // update the length in the packet header - StoreBigLong((unsigned char *)rcon_redirect_buffer, NETFLAG_CTL | (rcon_redirect_bufferpos & NETFLAG_LENGTH_MASK)); + rcon_redirect_buffer[rcon_redirect_bufferpos] = 0; + if (rcon_redirect_proquakeprotocol) + { + // update the length in the packet header + StoreBigLong((unsigned char *)rcon_redirect_buffer, NETFLAG_CTL | (rcon_redirect_bufferpos & NETFLAG_LENGTH_MASK)); + } + NetConn_Write(rcon_redirect_sock, rcon_redirect_buffer, rcon_redirect_bufferpos, rcon_redirect_dest); } - NetConn_Write(rcon_redirect_sock, rcon_redirect_buffer, rcon_redirect_bufferpos, rcon_redirect_dest); memcpy(rcon_redirect_buffer, "\377\377\377\377n", 5); // QW rcon print rcon_redirect_bufferpos = 5; rcon_redirect_proquakeprotocol = false; @@ -2053,11 +2057,10 @@ qboolean GetMapList (const char *s, char *completedname, int completednamebuffer lumplen = LittleLong(header->lumps[Q2LUMP_ENTITIES].filelen); } } - else if((p = BuffLittleLong(buf)) == BSPVERSION || p == 30) + else if((p = BuffLittleLong(buf)) == BSPVERSION || p == 30 || !memcmp(buf, "BSP2", 4)) { - dheader_t *header = (dheader_t *)buf; - lumpofs = LittleLong(header->lumps[LUMP_ENTITIES].fileofs); - lumplen = LittleLong(header->lumps[LUMP_ENTITIES].filelen); + lumpofs = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES); + lumplen = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES + 4); } else p = 0; @@ -2482,7 +2485,7 @@ static void Nicks_CutMatchesAlphaNumeric(int count) if(Nicks_strcleanlen(Nicks_sanlist[0]) < strlen(tempstr)) { // if the clean sanitized one is longer than the current one, use it, it has crap chars which definitely are in there - strlcpy(Nicks_sanlist[0], tempstr, sizeof(tempstr)); + strlcpy(Nicks_sanlist[0], tempstr, sizeof(Nicks_sanlist[0])); } } @@ -2538,7 +2541,7 @@ static void Nicks_CutMatchesNoSpaces(int count) if(Nicks_strcleanlen(Nicks_sanlist[0]) < strlen(tempstr)) { // if the clean sanitized one is longer than the current one, use it, it has crap chars which definitely are in there - strlcpy(Nicks_sanlist[0], tempstr, sizeof(tempstr)); + strlcpy(Nicks_sanlist[0], tempstr, sizeof(Nicks_sanlist[0])); } } diff --git a/misc/source/darkplaces-src/crypto.c b/misc/source/darkplaces-src/crypto.c index 09c164e2..30b9bd86 100644 --- a/misc/source/darkplaces-src/crypto.c +++ b/misc/source/darkplaces-src/crypto.c @@ -147,6 +147,8 @@ static size_t Crypto_UnParsePack(char *buf, size_t len, unsigned long header, co #define qd0_blind_id_sign_with_private_id_sign_detached d0_blind_id_sign_with_private_id_sign_detached #define qd0_blind_id_setmallocfuncs d0_blind_id_setmallocfuncs #define qd0_blind_id_setmutexfuncs d0_blind_id_setmutexfuncs +#define qd0_blind_id_verify_public_id d0_blind_id_verify_public_id +#define qd0_blind_id_verify_private_id d0_blind_id_verify_private_id #else @@ -205,6 +207,8 @@ static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_sign_with_private_ static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_sign_with_private_id_sign_detached) (d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen); static D0_EXPORT void (*qd0_blind_id_setmallocfuncs)(d0_malloc_t *m, d0_free_t *f); static D0_EXPORT void (*qd0_blind_id_setmutexfuncs)(d0_createmutex_t *c, d0_destroymutex_t *d, d0_lockmutex_t *l, d0_unlockmutex_t *u); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_verify_public_id)(const d0_blind_id_t *ctx, D0_BOOL *status); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_verify_private_id)(const d0_blind_id_t *ctx); static dllfunction_t d0_blind_id_funcs[] = { {"d0_blind_id_new", (void **) &qd0_blind_id_new}, @@ -244,6 +248,8 @@ static dllfunction_t d0_blind_id_funcs[] = {"d0_blind_id_sign_with_private_id_sign_detached", (void **) &qd0_blind_id_sign_with_private_id_sign_detached}, {"d0_blind_id_setmallocfuncs", (void **) &qd0_blind_id_setmallocfuncs}, {"d0_blind_id_setmutexfuncs", (void **) &qd0_blind_id_setmutexfuncs}, + {"d0_blind_id_verify_public_id", (void **) &qd0_blind_id_verify_public_id}, + {"d0_blind_id_verify_private_id", (void **) &qd0_blind_id_verify_private_id}, {NULL, NULL} }; // end of d0_blind_id interface @@ -456,6 +462,7 @@ static qboolean Crypto_AddPrivateKey(d0_blind_id_t *pk, char *buf, size_t len) static d0_blind_id_t *pubkeys[MAX_PUBKEYS]; static char pubkeys_fp64[MAX_PUBKEYS][FP64_SIZE+1]; static qboolean pubkeys_havepriv[MAX_PUBKEYS]; +static qboolean pubkeys_havesig[MAX_PUBKEYS]; static char pubkeys_priv_fp64[MAX_PUBKEYS][FP64_SIZE+1]; static char challenge_append[1400]; static size_t challenge_append_length; @@ -538,7 +545,7 @@ qboolean Crypto_ServerFinishInstance(crypto_t *out, crypto_t *crypto) } CLEAR_CDATA; memcpy(out, crypto, sizeof(*out)); - memset(crypto, 0, sizeof(crypto)); + memset(crypto, 0, sizeof(*crypto)); return true; } @@ -714,7 +721,7 @@ qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *k return true; } -int Crypto_RetrieveLocalKey(int keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen) // return value: -1 if more to come, +1 if valid, 0 if end of list +int Crypto_RetrieveLocalKey(int keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, qboolean *issigned) // return value: -1 if more to come, +1 if valid, 0 if end of list { if(keyid < 0 || keyid >= MAX_PUBKEYS) return 0; @@ -729,6 +736,8 @@ int Crypto_RetrieveLocalKey(int keyid, char *keyfp, size_t keyfplen, char *idfp, if(idfp) if(pubkeys_havepriv[keyid]) strlcpy(idfp, pubkeys_priv_fp64[keyid], keyfplen); + if(issigned) + *issigned = pubkeys_havesig[keyid]; return 1; } // end @@ -763,6 +772,34 @@ static void Crypto_BuildChallengeAppend(void) challenge_append_length = p - challenge_append; } +static qboolean Crypto_SavePubKeyTextFile(int i) +{ + qfile_t *f; + char vabuf[1024]; + + if(!pubkeys_havepriv[i]) + return false; + f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d-public-fp%s.txt", *fs_userdir ? fs_userdir : fs_basedir, i, sessionid.string), "w", false); + if(!f) + return false; + + // we ignore errors for this file, as it's not necessary to have + FS_Printf(f, "ID-Fingerprint: %s\n", pubkeys_priv_fp64[i]); + FS_Printf(f, "ID-Is-Signed: %s\n", pubkeys_havesig[i] ? "yes" : "no"); + FS_Printf(f, "ID-Is-For-Key: %s\n", pubkeys_fp64[i]); + FS_Printf(f, "\n"); + FS_Printf(f, "This is a PUBLIC ID file for DarkPlaces.\n"); + FS_Printf(f, "You are free to share this file or its contents.\n"); + FS_Printf(f, "\n"); + FS_Printf(f, "This file will be automatically generated again if deleted.\n"); + FS_Printf(f, "\n"); + FS_Printf(f, "However, NEVER share the accompanying SECRET ID file called\n"); + FS_Printf(f, "key_%d.d0si%s, as doing so would compromise security!\n", i, sessionid.string); + FS_Close(f); + + return true; +} + void Crypto_LoadKeys(void) { char buf[8192]; @@ -791,6 +828,7 @@ void Crypto_LoadKeys(void) memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i])); memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i])); pubkeys_havepriv[i] = false; + pubkeys_havesig[i] = false; len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0pk", i), buf, sizeof(buf), false); if((pubkeys[i] = Crypto_ReadPublicKey(buf, len))) { @@ -806,14 +844,36 @@ void Crypto_LoadKeys(void) len2 = FP64_SIZE; if(qd0_blind_id_fingerprint64_public_id(pubkeys[i], pubkeys_priv_fp64[i], &len2)) // keeps final NUL { + D0_BOOL status = 0; + Con_Printf("Loaded private ID key_%d.d0si%s for key_%d.d0pk (public key fingerprint: %s)\n", i, sessionid.string, i, pubkeys_priv_fp64[i]); - pubkeys_havepriv[i] = true; - strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[i], pubkeys_fp64[i]), sizeof(crypto_idstring_buf)); + + // verify the key we just loaded (just in case) + if(qd0_blind_id_verify_private_id(pubkeys[i]) && qd0_blind_id_verify_public_id(pubkeys[i], &status)) + { + pubkeys_havepriv[i] = true; + strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[i], pubkeys_fp64[i]), sizeof(crypto_idstring_buf)); + + // verify the key we just got (just in case) + if(status) + pubkeys_havesig[i] = true; + else + Con_Printf("NOTE: this ID has not yet been signed!\n"); + + Crypto_SavePubKeyTextFile(i); + } + else + { + Con_Printf("d0_blind_id_verify_private_id failed, this is not a valid key!\n"); + qd0_blind_id_free(pubkeys[i]); + pubkeys[i] = NULL; + } } else { - // can't really happen - // but nothing leaked here + Con_Printf("d0_blind_id_fingerprint64_public_id failed\n"); + qd0_blind_id_free(pubkeys[i]); + pubkeys[i] = NULL; } } } @@ -885,6 +945,7 @@ static void Crypto_UnloadKeys(void) qd0_blind_id_free(pubkeys[i]); pubkeys[i] = NULL; pubkeys_havepriv[i] = false; + pubkeys_havesig[i] = false; memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i])); memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i])); challenge_append_length = 0; @@ -999,11 +1060,9 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch size_t l[1]; static char buf[8192]; static char buf2[8192]; - size_t bufsize, buf2size; + size_t buf2size; qfile_t *f = NULL; - d0_blind_id_t *ctx, *ctx2; D0_BOOL status; - size_t len2; char vabuf[1024]; SV_LockThreadMutex(); @@ -1054,95 +1113,19 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch } // verify the key we just got (just in case) - ctx = qd0_blind_id_new(); - if(!ctx) - { - Con_Printf("d0_blind_id_new failed\n"); - keygen_i = -1; - SV_UnlockThreadMutex(); - return; - } - ctx2 = qd0_blind_id_new(); - if(!ctx2) - { - Con_Printf("d0_blind_id_new failed\n"); - qd0_blind_id_free(ctx); - keygen_i = -1; - SV_UnlockThreadMutex(); - return; - } - if(!qd0_blind_id_copy(ctx, pubkeys[keygen_i])) - { - Con_Printf("d0_blind_id_copy failed\n"); - qd0_blind_id_free(ctx); - qd0_blind_id_free(ctx2); - keygen_i = -1; - SV_UnlockThreadMutex(); - return; - } - if(!qd0_blind_id_copy(ctx2, pubkeys[keygen_i])) - { - Con_Printf("d0_blind_id_copy failed\n"); - qd0_blind_id_free(ctx); - qd0_blind_id_free(ctx2); - keygen_i = -1; - SV_UnlockThreadMutex(); - return; - } - bufsize = sizeof(buf); - if(!qd0_blind_id_authenticate_with_private_id_start(ctx, 1, 1, "hello world", 11, buf, &bufsize)) - { - Con_Printf("d0_blind_id_authenticate_with_private_id_start failed\n"); - qd0_blind_id_free(ctx); - qd0_blind_id_free(ctx2); - keygen_i = -1; - SV_UnlockThreadMutex(); - return; - } - buf2size = sizeof(buf2); - if(!qd0_blind_id_authenticate_with_private_id_challenge(ctx2, 1, 1, buf, bufsize, buf2, &buf2size, &status) || !status) + if(!qd0_blind_id_verify_public_id(pubkeys[keygen_i], &status) || !status) { - Con_Printf("d0_blind_id_authenticate_with_private_id_challenge failed (server does not have the requested private key)\n"); - qd0_blind_id_free(ctx); - qd0_blind_id_free(ctx2); + Con_Printf("d0_blind_id_verify_public_id failed\n"); keygen_i = -1; SV_UnlockThreadMutex(); return; } - bufsize = sizeof(buf); - if(!qd0_blind_id_authenticate_with_private_id_response(ctx, buf2, buf2size, buf, &bufsize)) - { - Con_Printf("d0_blind_id_authenticate_with_private_id_response failed\n"); - qd0_blind_id_free(ctx); - qd0_blind_id_free(ctx2); - keygen_i = -1; - SV_UnlockThreadMutex(); - return; - } - buf2size = sizeof(buf2); - if(!qd0_blind_id_authenticate_with_private_id_verify(ctx2, buf, bufsize, buf2, &buf2size, &status) || !status) - { - Con_Printf("d0_blind_id_authenticate_with_private_id_verify failed (server does not have the requested private key)\n"); - qd0_blind_id_free(ctx); - qd0_blind_id_free(ctx2); - keygen_i = -1; - SV_UnlockThreadMutex(); - return; - } - qd0_blind_id_free(ctx); - qd0_blind_id_free(ctx2); // we have a valid key now! // make the rest of crypto.c know that - len2 = FP64_SIZE; - if(qd0_blind_id_fingerprint64_public_id(pubkeys[keygen_i], pubkeys_priv_fp64[keygen_i], &len2)) // keeps final NUL - { - Con_Printf("Received private ID key_%d.d0pk (public key fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]); - pubkeys_havepriv[keygen_i] = true; - strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[keygen_i], pubkeys_fp64[keygen_i]), sizeof(crypto_idstring_buf)); - crypto_idstring = crypto_idstring_buf; - Crypto_BuildChallengeAppend(); - } + Con_Printf("Received signature for private ID key_%d.d0pk (public key fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]); + pubkeys_havesig[keygen_i] = true; + // write the key to disk p[0] = buf; l[0] = sizeof(buf); @@ -1173,7 +1156,10 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch FS_Write(f, buf2, buf2size); FS_Close(f); + Crypto_SavePubKeyTextFile(keygen_i); + Con_Printf("Saved to key_%d.d0si%s\n", keygen_i, sessionid.string); + keygen_i = -1; SV_UnlockThreadMutex(); } @@ -1185,7 +1171,12 @@ static void Crypto_KeyGen_f(void) size_t l[1]; static char buf[8192]; static char buf2[8192]; + size_t buf2size; size_t buf2l, buf2pos; + char vabuf[1024]; + size_t len2; + qfile_t *f = NULL; + if(!d0_blind_id_dll) { Con_Print("libd0_blind_id DLL not found, this command is inactive.\n"); @@ -1205,12 +1196,6 @@ static void Crypto_KeyGen_f(void) SV_UnlockThreadMutex(); return; } - if(pubkeys_havepriv[i]) - { - Con_Printf("there is already a private key for %d\n", i); - SV_UnlockThreadMutex(); - return; - } if(keygen_i >= 0) { Con_Printf("there is already a keygen run on the way\n"); @@ -1218,12 +1203,82 @@ static void Crypto_KeyGen_f(void) return; } keygen_i = i; - if(!qd0_blind_id_generate_private_id_start(pubkeys[keygen_i])) + + // how to START the keygenning... + if(pubkeys_havepriv[keygen_i]) { - Con_Printf("d0_blind_id_start failed\n"); - keygen_i = -1; - SV_UnlockThreadMutex(); - return; + if(pubkeys_havesig[keygen_i]) + { + Con_Printf("there is already a signed private key for %d\n", i); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + // if we get here, we only need a signature, no new keygen run needed + Con_Printf("Only need a signature for an existing key...\n"); + } + else + { + // we also need a new ID itself + if(!qd0_blind_id_generate_private_id_start(pubkeys[keygen_i])) + { + Con_Printf("d0_blind_id_start failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + // verify the key we just got (just in case) + if(!qd0_blind_id_verify_private_id(pubkeys[keygen_i])) + { + Con_Printf("d0_blind_id_verify_private_id failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + // we have a valid key now! + // make the rest of crypto.c know that + len2 = FP64_SIZE; + if(qd0_blind_id_fingerprint64_public_id(pubkeys[keygen_i], pubkeys_priv_fp64[keygen_i], &len2)) // keeps final NUL + { + Con_Printf("Generated private ID key_%d.d0pk (public key fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]); + pubkeys_havepriv[keygen_i] = true; + strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[keygen_i], pubkeys_fp64[keygen_i]), sizeof(crypto_idstring_buf)); + crypto_idstring = crypto_idstring_buf; + Crypto_BuildChallengeAppend(); + } + // write the key to disk + p[0] = buf; + l[0] = sizeof(buf); + if(!qd0_blind_id_write_private_id(pubkeys[keygen_i], buf, &l[0])) + { + Con_Printf("d0_blind_id_write_private_id failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + if(!(buf2size = Crypto_UnParsePack(buf2, sizeof(buf2), FOURCC_D0SI, p, l, 1))) + { + Con_Printf("Crypto_UnParsePack failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + + FS_CreatePath(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string)); + f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string), "wb", false); + if(!f) + { + Con_Printf("Cannot open key_%d.d0si%s\n", keygen_i, sessionid.string); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + FS_Write(f, buf2, buf2size); + FS_Close(f); + + Crypto_SavePubKeyTextFile(keygen_i); + + Con_Printf("Saved unsigned key to key_%d.d0si%s\n", keygen_i, sessionid.string); } p[0] = buf; l[0] = sizeof(buf); @@ -1259,7 +1314,7 @@ static void Crypto_KeyGen_f(void) SV_UnlockThreadMutex(); return; } - Con_Printf("key generation in progress\n"); + Con_Printf("Signature generation in progress...\n"); SV_UnlockThreadMutex(); } // end @@ -1286,7 +1341,11 @@ static void Crypto_Keys_f(void) { Con_Printf("%2d: public key key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_fp64[i]); if(pubkeys_havepriv[i]) + { Con_Printf(" private ID key_%d.d0si%s (public key fingerprint: %s)\n", i, sessionid.string, pubkeys_priv_fp64[i]); + if(!pubkeys_havesig[i]) + Con_Printf(" NOTE: this ID has not yet been signed!\n"); + } } } } @@ -2017,7 +2076,7 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out, { int wantserverid = -1; Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL); - if(!crypto || !crypto->authenticated) + if(!crypto || !crypto->authenticated) // we ALSO get here if we are using an encrypted connection, so let's rule this out { if(wantserverid >= 0) return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present"); @@ -2026,11 +2085,33 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out, } return CRYPTO_NOMATCH; } - else if (len_in >= 1 && string[0] == 'j' && cls.connect_trying && d0_rijndael_dll && crypto_aeslevel.integer >= 3) + else if (len_in >= 1 && string[0] == 'j' && cls.connect_trying && d0_rijndael_dll) { int wantserverid = -1; Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL); - if(!crypto || !crypto->authenticated) + //if(!crypto || !crypto->authenticated) + { + if(wantserverid >= 0) + return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present"); + if(crypto_aeslevel.integer >= 3) + return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)"); + } + return CRYPTO_NOMATCH; + } + else if (len_in >= 5 && BuffLittleLong((unsigned char *) string) == ((int)NETFLAG_CTL | (int)len_in)) + { + int wantserverid = -1; + + // these three are harmless + if(string[4] == CCREP_SERVER_INFO) + return CRYPTO_NOMATCH; + if(string[4] == CCREP_PLAYER_INFO) + return CRYPTO_NOMATCH; + if(string[4] == CCREP_RULE_INFO) + return CRYPTO_NOMATCH; + + Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL); + //if(!crypto || !crypto->authenticated) { if(wantserverid >= 0) return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present"); diff --git a/misc/source/darkplaces-src/crypto.h b/misc/source/darkplaces-src/crypto.h index 7edfcd98..ddc00a92 100644 --- a/misc/source/darkplaces-src/crypto.h +++ b/misc/source/darkplaces-src/crypto.h @@ -54,7 +54,7 @@ const char *Crypto_GetInfoResponseDataString(void); // retrieves a host key for an address (can be exposed to menuqc, or used by the engine to look up stored keys e.g. for server bookmarking) // pointers may be NULL qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel); -int Crypto_RetrieveLocalKey(int keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen); // return value: -1 if more to come, +1 if valid, 0 if end of list +int Crypto_RetrieveLocalKey(int keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, qboolean *issigned); // return value: -1 if more to come, +1 if valid, 0 if end of list size_t Crypto_SignData(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size); size_t Crypto_SignDataDetached(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size); diff --git a/misc/source/darkplaces-src/csprogs.c b/misc/source/darkplaces-src/csprogs.c index 47573d3c..7faa8877 100644 --- a/misc/source/darkplaces-src/csprogs.c +++ b/misc/source/darkplaces-src/csprogs.c @@ -249,6 +249,8 @@ static void CSQC_SetGlobals (void) VectorCopy(cl.punchvector, PRVM_clientglobalvector(view_punchvector)); PRVM_clientglobalfloat(maxclients) = cl.maxclients; + PRVM_clientglobalfloat(player_localentnum) = cl.viewentity; + CSQC_R_RecalcView(); CSQC_END } @@ -358,9 +360,9 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum) // model light if (renderflags & RF_MODELLIGHT) { - if(PRVM_clientedictvector(ed, modellight_ambient)) VectorCopy(PRVM_clientedictvector(ed, modellight_ambient), entrender->modellight_ambient); - if(PRVM_clientedictvector(ed, modellight_diffuse)) VectorCopy(PRVM_clientedictvector(ed, modellight_diffuse), entrender->modellight_diffuse); - if(PRVM_clientedictvector(ed, modellight_dir)) VectorCopy(PRVM_clientedictvector(ed, modellight_dir), entrender->modellight_lightdir); + if (PRVM_clientedictvector(ed, modellight_ambient)) VectorCopy(PRVM_clientedictvector(ed, modellight_ambient), entrender->modellight_ambient); else VectorClear(entrender->modellight_ambient); + if (PRVM_clientedictvector(ed, modellight_diffuse)) VectorCopy(PRVM_clientedictvector(ed, modellight_diffuse), entrender->modellight_diffuse); else VectorClear(entrender->modellight_diffuse); + if (PRVM_clientedictvector(ed, modellight_dir)) VectorCopy(PRVM_clientedictvector(ed, modellight_dir), entrender->modellight_lightdir); else VectorClear(entrender->modellight_lightdir); entrender->flags |= RENDER_CUSTOMIZEDMODELLIGHT; } @@ -371,6 +373,7 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum) if(renderflags & RF_WORLDOBJECT) entrender->flags |= RENDER_WORLDOBJECT; if(renderflags & RF_DEPTHHACK) entrender->flags |= RENDER_NODEPTHTEST; if(renderflags & RF_ADDITIVE) entrender->flags |= RENDER_ADDITIVE; + if(renderflags & RF_DYNAMICMODELLIGHT) entrender->flags |= RENDER_DYNAMICMODELLIGHT; } c = (int)PRVM_clientedictfloat(ed, colormap); @@ -407,10 +410,13 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum) entrender->flags |= RENDER_ADDITIVE; if (entrender->effects & EF_DOUBLESIDED) entrender->flags |= RENDER_DOUBLESIDED; + if (entrender->effects & EF_DYNAMICMODELLIGHT) + entrender->flags |= RENDER_DYNAMICMODELLIGHT; // make the other useful stuff memcpy(entrender->framegroupblend, ed->priv.server->framegroupblend, sizeof(ed->priv.server->framegroupblend)); CL_UpdateRenderEntity(entrender); + // override animation data with full control memcpy(entrender->frameblend, ed->priv.server->frameblend, sizeof(ed->priv.server->frameblend)); if (ed->priv.server->skeleton.relativetransforms) @@ -1112,7 +1118,8 @@ void CL_VM_Init (void) PRVM_clientglobaledict(self) = 0; PRVM_clientglobalstring(mapname) = PRVM_SetEngineString(prog, cl.worldname); - PRVM_clientglobalfloat(player_localentnum) = cl.playerentity; + PRVM_clientglobalfloat(player_localnum) = cl.realplayerentity - 1; + PRVM_clientglobalfloat(player_localentnum) = cl.viewentity; // set map description (use world entity 0) PRVM_clientedictstring(prog->edicts, message) = PRVM_SetEngineString(prog, cl.worldmessage); @@ -1223,3 +1230,10 @@ qboolean CL_VM_TransformView(int entnum, matrix4x4_t *viewmatrix, mplane_t *clip return ret; } + +int CL_VM_GetViewEntity(void) +{ + if(cl.csqc_server2csqcentitynumber[cl.viewentity]) + return cl.csqc_server2csqcentitynumber[cl.viewentity] + MAX_EDICTS; + return cl.viewentity; +} diff --git a/misc/source/darkplaces-src/csprogs.h b/misc/source/darkplaces-src/csprogs.h index 2aba12b3..02fa972a 100644 --- a/misc/source/darkplaces-src/csprogs.h +++ b/misc/source/darkplaces-src/csprogs.h @@ -36,9 +36,13 @@ #define VF_CL_VIEWANGLES_Y 35 //(float) #define VF_CL_VIEWANGLES_Z 36 //(float) +// FTEQW's extension range #define VF_PERSPECTIVE 200 //(float) + +// what is this doing here? This is a DP extension introduced by Black, should be in 4xx range #define VF_CLEARSCREEN 201 //(float) +// what is this doing here? This is a DP extension introduced by VorteX, should be in 4xx range #define VF_FOG_DENSITY 202 //(float) #define VF_FOG_COLOR 203 //(vector) #define VF_FOG_COLOR_R 204 //(float) @@ -50,7 +54,9 @@ #define VF_FOG_HEIGHT 210 //(float) #define VF_FOG_FADEDEPTH 211 //(float) -#define VF_MAINVIEW 212 //(float) +// DP's extension range +#define VF_MAINVIEW 400 //(float) +#define VF_MINFPS_QUALITY 401 //(float) #define RF_VIEWMODEL 1 // The entity is never drawn in mirrors. In engines with realtime lighting, it casts no shadows. #define RF_EXTERNALMODEL 2 // The entity is appears in mirrors but not in the normal view. It does still cast shadows in engines with realtime lighting. @@ -62,6 +68,7 @@ #define RF_USETRANSPARENTOFFSET 64 // Allows QC to customize origin used for transparent sorting via transparent_origin global, helps to fix transparent sorting bugs on a very large entities #define RF_WORLDOBJECT 128 // for large outdoor entities that should not be culled #define RF_MODELLIGHT 4096 // CSQC-set model light +#define RF_DYNAMICMODELLIGHT 8192 // origin-dependent model light #define RF_FULLBRIGHT 256 #define RF_NOSHADOW 512 @@ -109,4 +116,6 @@ void CSQC_R_RecalcView(void); dp_model_t *CL_GetModelByIndex(int modelindex); +int CL_VM_GetViewEntity(void); + #endif diff --git a/misc/source/darkplaces-src/dpdefs/csprogsdefs.qc b/misc/source/darkplaces-src/dpdefs/csprogsdefs.qc index 8fa52e44..2d376d4f 100644 --- a/misc/source/darkplaces-src/dpdefs/csprogsdefs.qc +++ b/misc/source/darkplaces-src/dpdefs/csprogsdefs.qc @@ -166,7 +166,7 @@ const float MASK_NORMAL = 4; const float RF_VIEWMODEL = 1; const float RF_EXTERNALMODEL = 2; const float RF_DEPTHHACK = 4; -const float RF_ADDATIVE = 8; +const float RF_ADDITIVE = 8; const float RF_USEAXIS = 16; const float VF_MIN = 1; //(vector) @@ -313,6 +313,14 @@ const float PFL_CROUCH = 2; const float PFL_DEAD = 4; const float PFL_GIBBED = 8; +// draw flags +const float DRAWFLAG_NORMAL = 0; +const float DRAWFLAG_ADDITIVE = 1; +const float DRAWFLAG_MODULATE = 2; +const float DRAWFLAG_2XMODULATE = 3; +const float DRAWFLAG_SCREEN = 4; +const float DRAWFLAG_MIPMAP = 0x100; // only for R_BeginPolygon + /* ============================================================================== @@ -454,7 +462,7 @@ void() renderscene = #304; void(vector org, float radius, vector lightcolours) adddynamiclight = #305; void(vector org, float radius, vector lightcolours, float style, string cubemapname, float pflags) adddynamiclight2 = #305; //void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon = #306; -void(string texturename, float flag, float is2d, float lines) R_BeginPolygon = #306; +void(string texturename, float flag, ...) R_BeginPolygon = #306; void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex = #307; void() R_EndPolygon = #308; vector (vector v) cs_unproject = #310; @@ -462,7 +470,7 @@ vector (vector v) cs_project = #311; void(float width, vector pos1, vector pos2, float flag) drawline = #315; float(string name) iscachedpic = #316; -string(string name, float trywad) precache_pic = #317; +string(string name, ...) precache_pic = #317; string(string name) precache_cubemap = #317; vector(string picname) draw_getimagesize = #318; void(string name) freepic = #319; @@ -476,7 +484,7 @@ float(vector position, string text, vector scale, float alpha, float flag) drawc vector(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawcolorcodedstring2 = #326; float(float stnum) getstatf = #330; -float(float stnum) getstati = #331; +float(float stnum, ...) getstati = #331; // can optionally take first bit and count string(float firststnum) getstats = #332; void(entity e, float mdlindex) setmodelindex = #333; string(float mdlindex) modelnameforindex = #334; @@ -493,7 +501,7 @@ void(float usecursor) setcursormode = #343; vector() getmousepos = #344; float(float framenum) getinputstate = #345; void(float sens) setsensitivityscale = #346; -void() runstandardplayerphysics = #347; +void(...) runstandardplayerphysics = #347; // this may or may not take a player ent string(float playernum, string keyname) getplayerkeyvalue = #348; float() isdemo = #349; float() isserver = #350; @@ -591,7 +599,6 @@ float(string s) strlennocol = #476; // This is the correct name for the function string(string s) decolorizedstring = #477; string(string s) strdecolorize = #477; // This is the correct name for the function, but not removing the decolorizedstring mapping. string(float uselocaltime, string format, ...) strftime = #478; -float(string s) tokenizebyseparator = #479; string(string s) strtolower = #480; string(string s) strtoupper = #481; string(string s) cvar_defstring = #482; @@ -887,9 +894,535 @@ float(string url, float id, string content_type, string delim, float buf, float //idea: divVerent //darkplaces implementation: divVerent //constant definitions: -const float VF_MAINVIEW = 212; +const float VF_MAINVIEW = 400; //use setproperty(VF_MAINVIEW, 1); before calling R_RenderView for the render //that shall become the "main" view, which is e.g. used by PRYDON_CLIENTCURSOR //this flag is set for the first scene, and not cleared by R_ClearScene //this flag is automatically cleared by R_RenderView //so when not using this extension, the first view rendered is the main view + +//DP_CSQC_MINFPS_QUALITY +//idea: divVerent +//darkplaces implementation: divVerent +//constant definitions: +const float VF_MINFPS_QUALITY = 401; +//use getproperty(VF_MINFPS_QUALITY); to do CSQC based LOD based on cl_minfps +//1 should lead to an unmodified view + +//DP_CSQC_V_CALCREFDEF_WIP1 +//DP_CSQC_V_CALCREFDEF_WIP2 +//idea: divVerent +//darkplaces implementation: divVerent +//builtin definitions: +void(entity e, float refdefflags) V_CalcRefdef = #640; +//constant definitions: +float PMF_DUCKED = 4; +float PMF_ONGROUND = 8; +float REFDEFFLAG_TELEPORTED = 1; +float REFDEFFLAG_JUMPING = 2; +float REFDEFFLAG_DEAD = 4; +float REFDEFFLAG_INTERMISSION = 8; +//- use this on the player entity after performing prediction +//- pass REFDEFFLAG_TELEPORTED if the player teleported since last frame +//- pass REFDEFFLAG_JUMPING if jump button is pressed +//- pass REFDEFFLAG_DEAD if dead (DP_CSQC_V_CALCREFDEF_WIP2) +//- pass REFDEFFLAG_INTERMISSION if in intermission (DP_CSQC_V_CALCREFDEF_WIP2) +//- the player entity needs to have origin, velocity, pmove_flags set according +// to prediction (the above two PMF_ flags are used in the player's pmove_flags) +//- NOTE: to check for this, ALSO OR a check with DP_CSQC_V_CALCREFDEF to also support +// the finished extension once done + +// assorted builtins +float drawsubpic(vector position, vector size, string pic, vector srcPosition, vector srcSize, vector rgb, float alpha, float flag) = #328; +vector drawgetimagesize(string pic) = #318; +#define SPA_POSITION 0 +#define SPA_S_AXIS 1 +#define SPA_T_AXIS 2 +#define SPA_R_AXIS 3 +#define SPA_TEXCOORDS0 4 +#define SPA_LIGHTMAP0_TEXCOORDS 5 +#define SPA_LIGHTMAP_COLOR 6 +float (entity e, float s) getsurfacenumpoints = #434; +vector (entity e, float s, float n) getsurfacepoint = #435; +vector (entity e, float s) getsurfacenormal = #436; +string (entity e, float s) getsurfacetexture = #437; +float (entity e, vector p) getsurfacenearpoint = #438; +vector (entity e, float s, vector p) getsurfaceclippedpoint = #439; +vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; +float(entity e, float s) getsurfacenumtriangles = #628; +vector(entity e, float s, float n) getsurfacetriangle = #629; + +//DP_QC_ASINACOSATANATAN2TAN +//idea: Urre +//darkplaces implementation: LordHavoc +//constant definitions: +float DEG2RAD = 0.0174532925199432957692369076848861271344287188854172545609719144; +float RAD2DEG = 57.2957795130823208767981548141051703324054724665643215491602438612; +float PI = 3.1415926535897932384626433832795028841971693993751058209749445923; +//builtin definitions: +float(float s) asin = #471; // returns angle in radians for a given sin() value, the result is in the range -PI*0.5 to PI*0.5 +float(float c) acos = #472; // returns angle in radians for a given cos() value, the result is in the range 0 to PI +float(float t) atan = #473; // returns angle in radians for a given tan() value, the result is in the range -PI*0.5 to PI*0.5 +float(float c, float s) atan2 = #474; // returns angle in radians for a given cos() and sin() value pair, the result is in the range -PI to PI (this is identical to vectoyaw except it returns radians rather than degrees) +float(float a) tan = #475; // returns tangent value (which is simply sin(a)/cos(a)) for the given angle in radians, the result is in the range -infinity to +infinity +//description: +//useful math functions for analyzing vectors, note that these all use angles in radians (just like the cos/sin functions) not degrees unlike makevectors/vectoyaw/vectoangles, so be sure to do the appropriate conversions (multiply by DEG2RAD or RAD2DEG as needed). +//note: atan2 can take unnormalized vectors (just like vectoyaw), and the function was included only for completeness (more often you want vectoyaw or vectoangles), atan2(v_x,v_y) * RAD2DEG gives the same result as vectoyaw(v) + +//DP_QC_SPRINTF +//idea: divVerent +//darkplaces implementation: divVerent +//builtin definitions: +string(string format, ...) sprintf = #627; +//description: +//you know sprintf :P +//supported stuff: +// % +// optional: $ for the argument to format +// flags: #0- + +// optional: , *, or *$ for the field width +// optional: ., .*, or .*$ for the precision +// length modifiers: h for forcing a float, l for forcing an int/entity (by default, %d etc. cast a float to int) +// conversions: +// d takes a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to an int +// i takes an int/entity if no length is specified or i is, and a float if h is specified as length, and cast it to an int +// ouxXc take a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to an unsigned int +// eEfFgG take a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to a double +// s takes a string +// vV takes a vector, and processes the three components as if it were a gG for all three components, separated by space +// For conversions s and c, the flag # makes precision and width interpreted +// as byte count, by default it is interpreted as character count in UTF-8 +// enabled engines. No other conversions can create wide characters, and # +// has another meaning in these. + +//DP_QC_GETTIME +//idea: tZork +//darkplaces implementation: tZork, divVerent +//constant definitions: +float GETTIME_FRAMESTART = 0; // time of start of frame +float GETTIME_REALTIME = 1; // current time (may be OS specific) +float GETTIME_HIRES = 2; // like REALTIME, but may reset between QC invocations and thus can be higher precision +float GETTIME_UPTIME = 3; // time since start of the engine +//builtin definitions: +float(float tmr) gettime = #519; +//description: +//some timers to query... + +//DP_QC_GETTIME_CDTRACK +//idea: divVerent +//darkplaces implementation: divVerent +//constant definitions: +float GETTIME_CDTRACK = 4; +//description: +//returns the playing time of the current cdtrack when passed to gettime() +//see DP_END_GETSOUNDTIME for similar functionality but for entity sound channels + +//DP_QC_TOKENIZEBYSEPARATOR +//idea: Electro, SavageX, LordHavoc +//darkplaces implementation: LordHavoc +//builtin definitions: +float(string s, string separator1, ...) tokenizebyseparator = #479; +//description: +//this function returns tokens separated by any of the supplied separator strings, example: +//numnumbers = tokenizebyseparator("10.2.3.4", "."); +//returns 4 and the tokens are "10" "2" "3" "4" +//possibly useful for parsing IPv4 addresses (such as "1.2.3.4") and IPv6 addresses (such as "[1234:5678:9abc:def0:1234:5678:9abc:def0]:26000") + +//DP_QC_TOKENIZE_CONSOLE +//idea: divVerent +//darkplaces implementation: divVerent +//builtin definitions: +float(string s) tokenize_console = #514; +float(float i) argv_start_index = #515; +float(float i) argv_end_index = #516; +//description: +//this function returns tokens separated just like the console does +//also, functions are provided to get the index of the first and last character of each token in the original string +//Passing negative values to them, or to argv, will be treated as indexes from the LAST token (like lists work in Perl). So argv(-1) will return the LAST token. + +//DP_SND_SOUND7_WIP1 +//DP_SND_SOUND7_WIP2 +//idea: divVerent +//darkplaces implementation: divVerent +//builtin definitions: +void(entity e, float chan, string samp, float vol, float atten, float speed, float flags) sound7 = #8; +float SOUNDFLAG_RELIABLE = 1; +//description: +//plays a sound, with some more flags +//extensions to sound(): +//- channel may be in the range from -128 to 127; channels -128 to 0 are "auto", +// i.e. support multiple sounds at once, but cannot be stopped/restarted +//- a value 0 in the speed parameter means no change; otherwise, it is a +// percentage of playback speed ("pitch shifting"). 100 is normal pitch, 50 is +// half speed, 200 is double speed, etc. (DP_SND_SOUND7_WIP2) +//- the flag SOUNDFLAG_RELIABLE can be specified, which makes the sound send +// to MSG_ALL (reliable) instead of MSG_BROADCAST (unreliable, default); +// similarily, SOUNDFLAG_RELIABLE_TO_ONE sends to MSG_ONE +//- channel 0 is controlled by snd_channel0volume; channel 1 and -1 by +// snd_channel1volume, etc. (so, a channel shares the cvar with its respective +// auto-channel); however, the mod MUST define snd_channel8volume and upwards +// in default.cfg if they are to be used, as the engine does not create them +// to not litter the cvar list +//- this extension applies to CSQC as well; CSQC_Event_Sound will get speed and +// flags as extra 7th and 8th argument +//- WIP2 ideas: SOUNDFLAG_RELIABLE_TO_ONE, SOUNDFLAG_NOPHS, SOUNDFLAG_FORCELOOP +//- NOTE: to check for this, ALSO OR a check with DP_SND_SOUND7 to also support +// the finished extension once done + +//DP_MOVETYPEFLYWORLDONLY +//idea: Samual +//darkplaces implementation: Samual +//movetype definitions: +float MOVETYPE_FLY_WORLDONLY = 33; +//description: +//like MOVETYPE_FLY, but does all traces with MOVE_WORLDONLY, and is ignored by MOVETYPE_PUSH. Should only be combined with SOLID_NOT and SOLID_TRIGGER. + +//DP_PRECACHE_PIC_FLAGS +//idea: divVerent +//darkplaces implementation: divVerent +//constant definitions: +float PRECACHE_PIC_FROMWAD = 1; // this one actually is part of EXT_CSQC +float PRECACHE_PIC_NOTPERSISTENT = 2; // picture may get deallocated when unused +float PRECACHE_PIC_MIPMAP = 8; // mipmap the texture for possibly better downscaling at memory expense +//notes: these constants are given as optional second argument to precache_pic() + +//DP_QC_TRACE_MOVETYPE_WORLDONLY +//idea: LordHavoc +//darkplaces implementation: LordHavoc +//constant definitions: +float MOVE_WORLDONLY = 3; +//description: +//allows traces to hit only world (ignoring all entities, unlike MOVE_NOMONSTERS which hits all bmodels), use as the nomonsters parameter to trace functions + +//DP_SND_GETSOUNDTIME +//idea: VorteX +//darkplaces implementation: VorteX +//constant definitions: +float(entity e, float channel) getsoundtime = #533; // get currently sound playing position on entity channel, -1 if not playing or error +float(string sample) soundlength = #534; // returns length of sound sample in seconds, -1 on error (sound not precached, sound system not initialized etc.) +//description: provides opportunity to query length of sound samples and realtime tracking of sound playing on entities (similar to DP_GETTIME_CDTRACK) +//note: beware dedicated server not running sound engine at all, so in dedicated mode this builtins will not work in server progs +//note also: menu progs not supporting getsoundtime() (will give a warning) since it has no sound playing on entities +//examples of use: +// - QC-driven looped sounds +// - QC events when sound playing is finished +// - toggleable ambientsounds +// - subtitles + +//DP_QC_NUM_FOR_EDICT +//idea: Blub\0 +//darkplaces implementation: Blub\0 +//Function to get the number of an entity - a clean way. +float(entity num) num_for_edict = #512; + +//DP_TRACE_HITCONTENTSMASK_SURFACEINFO +//idea: LordHavoc +//darkplaces implementation: LordHavoc +//globals: +.float dphitcontentsmask; // if non-zero on the entity passed to traceline/tracebox/tracetoss this will override the normal collidable contents rules and instead hit these contents values (for example AI can use tracelines that hit DONOTENTER if it wants to, by simply changing this field on the entity passed to traceline), this affects normal movement as well as trace calls +float trace_dpstartcontents; // DPCONTENTS_ value at start position of trace +float trace_dphitcontents; // DPCONTENTS_ value of impacted surface (not contents at impact point, just contents of the surface that was hit) +float trace_dphitq3surfaceflags; // Q3SURFACEFLAG_ value of impacted surface +string trace_dphittexturename; // texture name of impacted surface +//constants: +float DPCONTENTS_SOLID = 1; // hit a bmodel, not a bounding box +float DPCONTENTS_WATER = 2; +float DPCONTENTS_SLIME = 4; +float DPCONTENTS_LAVA = 8; +float DPCONTENTS_SKY = 16; +float DPCONTENTS_BODY = 32; // hit a bounding box, not a bmodel +float DPCONTENTS_CORPSE = 64; // hit a SOLID_CORPSE entity +float DPCONTENTS_NODROP = 128; // an area where backpacks should not spawn +float DPCONTENTS_PLAYERCLIP = 256; // blocks player movement +float DPCONTENTS_MONSTERCLIP = 512; // blocks monster movement +float DPCONTENTS_DONOTENTER = 1024; // AI hint brush +float DPCONTENTS_LIQUIDSMASK = 14; // WATER | SLIME | LAVA +float DPCONTENTS_BOTCLIP = 2048; // AI hint brush +float DPCONTENTS_OPAQUE = 4096; // only fully opaque brushes get this (may be useful for line of sight checks) +float Q3SURFACEFLAG_NODAMAGE = 1; +float Q3SURFACEFLAG_SLICK = 2; // low friction surface +float Q3SURFACEFLAG_SKY = 4; // sky surface (also has NOIMPACT and NOMARKS set) +float Q3SURFACEFLAG_LADDER = 8; // climbable surface +float Q3SURFACEFLAG_NOIMPACT = 16; // projectiles should remove themselves on impact (this is set on sky) +float Q3SURFACEFLAG_NOMARKS = 32; // projectiles should not leave marks, such as decals (this is set on sky) +float Q3SURFACEFLAG_FLESH = 64; // projectiles should do a fleshy effect (blood?) on impact +float Q3SURFACEFLAG_NODRAW = 128; // compiler hint (not important to qc) +//float Q3SURFACEFLAG_HINT = 256; // compiler hint (not important to qc) +//float Q3SURFACEFLAG_SKIP = 512; // compiler hint (not important to qc) +//float Q3SURFACEFLAG_NOLIGHTMAP = 1024; // compiler hint (not important to qc) +//float Q3SURFACEFLAG_POINTLIGHT = 2048; // compiler hint (not important to qc) +float Q3SURFACEFLAG_METALSTEPS = 4096; // walking on this surface should make metal step sounds +float Q3SURFACEFLAG_NOSTEPS = 8192; // walking on this surface should not make footstep sounds +float Q3SURFACEFLAG_NONSOLID = 16384; // compiler hint (not important to qc) +//float Q3SURFACEFLAG_LIGHTFILTER = 32768; // compiler hint (not important to qc) +//float Q3SURFACEFLAG_ALPHASHADOW = 65536; // compiler hint (not important to qc) +//float Q3SURFACEFLAG_NODLIGHT = 131072; // compiler hint (not important to qc) +//float Q3SURFACEFLAG_DUST = 262144; // translucent 'light beam' effect (not important to qc) +//description: +//adds additional information after a traceline/tracebox/tracetoss call. +//also (very important) sets trace_* globals before calling .touch functions, +//this allows them to inspect the nature of the collision (for example +//determining if a projectile hit sky), clears trace_* variables for the other +//object in a touch event (that is to say, a projectile moving will see the +//trace results in its .touch function, but the player it hit will see very +//little information in the trace_ variables as it was not moving at the time) + +//DP_QC_CVAR_TYPE +//idea: divVerent +//DarkPlaces implementation: divVerent +//builtin definitions: +float(string name) cvar_type = #495; +float CVAR_TYPEFLAG_EXISTS = 1; +float CVAR_TYPEFLAG_SAVED = 2; +float CVAR_TYPEFLAG_PRIVATE = 4; +float CVAR_TYPEFLAG_ENGINE = 8; +float CVAR_TYPEFLAG_HASDESCRIPTION = 16; +float CVAR_TYPEFLAG_READONLY = 32; + +//DP_QC_CRC16 +//idea: divVerent +//darkplaces implementation: divVerent +//Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol. +//When caseinsensitive is set, the CRC is calculated of the lower cased string. +float(float caseinsensitive, string s, ...) crc16 = #494; + +//DP_QC_URI_ESCAPE +//idea: divVerent +//darkplaces implementation: divVerent +//URI::Escape's functionality +string(string in) uri_escape = #510; +string(string in) uri_unescape = #511; + +//DP_QC_DIGEST +//idea: motorsep, Spike +//DarkPlaces implementation: divVerent +//builtin definitions: +string(string digest, string data, ...) digest_hex = #639; +//description: +//returns a given hex digest of given data +//the returned digest is always encoded in hexadecimal +//only the "MD4" digest is always supported! +//if the given digest is not supported, string_null is returned +//the digest string is matched case sensitively, use "MD4", not "md4"! + +//DP_QC_DIGEST_SHA256 +//idea: motorsep, Spike +//DarkPlaces implementation: divVerent +//description: +//"SHA256" is also an allowed digest type + +//DP_QC_LOG +//darkplaces implementation: divVerent +//builtin definitions: +float log(float f) = #532; +//description: +//logarithm + +//FTE_CSQC_SKELETONOBJECTS +//idea: Spike, LordHavoc +//darkplaces implementation: LordHavoc +//builtin definitions: +// all skeleton numbers are 1-based (0 being no skeleton) +// all bone numbers are 1-based (0 being invalid) +float(float modlindex) skel_create = #263; // create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex, as the skeleton uses the hierarchy from the model. +float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure +float(float skel) skel_get_numbones = #265; // returns how many bones exist in the created skeleton, 0 if skeleton does not exist +string(float skel, float bonenum) skel_get_bonename = #266; // returns name of bone (as a tempstring), "" if invalid bonenum (< 1 for example) or skeleton does not exist +float(float skel, float bonenum) skel_get_boneparent = #267; // returns parent num for supplied bonenum, 0 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this) +float(float skel, string tagname) skel_find_bone = #268; // get number of bone with specified name, 0 on failure, bonenum (1-based) on success, same as using gettagindex but takes modelindex instead of entity +vector(float skel, float bonenum) skel_get_bonerel = #269; // get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone) +vector(float skel, float bonenum) skel_get_boneabs = #270; // get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity) +void(float skel, float bonenum, vector org) skel_set_bone = #271; // set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone) +void(float skel, float bonenum, vector org) skel_mul_bone = #272; // transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone) +void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones) +void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse +void(float skel) skel_delete = #275; // deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work) +float(float modlindex, string framename) frameforname = #276; // finds number of a specified frame in the animation, returns -1 if no match found +float(float modlindex, float framenum) frameduration = #277; // returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0. +//fields: +.float skeletonindex; // active skeleton overriding standard animation on model +.float frame; // primary framegroup animation (strength = 1 - lerpfrac - lerpfrac3 - lerpfrac4) +.float frame2; // secondary framegroup animation (strength = lerpfrac) +.float frame3; // tertiary framegroup animation (strength = lerpfrac3) +.float frame4; // quaternary framegroup animation (strength = lerpfrac4) +.float lerpfrac; // strength of framegroup blend +.float lerpfrac3; // strength of framegroup blend +.float lerpfrac4; // strength of framegroup blend +.float frame1time; // start time of framegroup animation +.float frame2time; // start time of framegroup animation +.float frame3time; // start time of framegroup animation +.float frame4time; // start time of framegroup animation +//description: +//this extension provides a way to do complex skeletal animation on an entity. +// +//see also DP_SKELETONOBJECTS (this extension implemented on server as well as client) +// +//notes: +//each model contains its own skeleton, reusing a skeleton with incompatible models will yield garbage (or not render). +//each model contains its own animation data, you can use animations from other model files (for example saving out all character animations as separate model files). +//if an engine supports loading an animation-only file format such as .md5anim in FTEQW, it can be used to animate any model with a compatible skeleton. +//proper use of this extension may require understanding matrix transforms (v_forward, v_right, v_up, origin), and you must keep in mind that v_right is negative for this purpose. +// +//features include: +//multiple animations blended together. +//animating a model with animations from another model with a compatible skeleton. +//restricting animation blends to certain bones of a model - for example independent animation of legs, torso, head. +//custom bone controllers - for example making eyes track a target location. +// +// +// +//example code follows... +// +//this helper function lets you identify (by parentage) what group a bone +//belongs to - for example "torso", "leftarm", would return 1 ("torso") for +//all children of the bone named "torso", unless they are children of +//"leftarm" (which is a child of "torso") which would return 2 instead... +float(float skel, float bonenum, string g1, string g2, string g3, string g4, string g5, string g6) example_skel_findbonegroup = +{ + local string bonename; + while (bonenum >= 0) + { + bonename = skel_get_bonename(skel, bonenum); + if (bonename == g1) return 1; + if (bonename == g2) return 2; + if (bonename == g3) return 3; + if (bonename == g4) return 4; + if (bonename == g5) return 5; + if (bonename == g6) return 6; + bonenum = skel_get_boneparent(skel, bonenum); + } + return 0; +}; +// create a skeletonindex for our player using current modelindex +void() example_skel_player_setup = +{ + self.skeletonindex = skel_create(self.modelindex); +}; +// setup bones of skeleton based on an animation +// note: animmodelindex can be a different model than self.modelindex +void(float animmodelindex, float framegroup, float framegroupstarttime) example_skel_player_update_begin = +{ + // start with our standard animation + self.frame = framegroup; + self.frame2 = 0; + self.frame3 = 0; + self.frame4 = 0; + self.frame1time = framegroupstarttime; + self.frame2time = 0; + self.frame3time = 0; + self.frame4time = 0; + self.lerpfrac = 0; + self.lerpfrac3 = 0; + self.lerpfrac4 = 0; + skel_build(self.skeletonindex, self, animmodelindex, 0, 0, 100000); +}; +// apply a different framegroup animation to bones with a specified parent +void(float animmodelindex, float framegroup, float framegroupstarttime, float blendalpha, string groupbonename, string excludegroupname1, string excludegroupname2) example_skel_player_update_applyoverride = +{ + local float bonenum; + local float numbones; + self.frame = framegroup; + self.frame2 = 0; + self.frame3 = 0; + self.frame4 = 0; + self.frame1time = framegroupstarttime; + self.frame2time = 0; + self.frame3time = 0; + self.frame4time = 0; + self.lerpfrac = 0; + self.lerpfrac3 = 0; + self.lerpfrac4 = 0; + bonenum = 0; + numbones = skel_get_numbones(self.skeletonindex); + while (bonenum < numbones) + { + if (example_skel_findbonegroup(self.skeletonindex, bonenum, groupbonename, excludegroupname1, excludegroupname2, "", "", "") == 1) + skel_build(self.skeletonindex, self, animmodelindex, 1 - blendalpha, bonenum, bonenum + 1); + bonenum = bonenum + 1; + } +}; +// make eyes point at a target location, be sure v_forward, v_right, v_up are set correctly before calling +void(vector eyetarget, string bonename) example_skel_player_update_eyetarget = +{ + local float bonenum; + local vector ang; + local vector oldforward, oldright, oldup; + local vector relforward, relright, relup, relorg; + local vector boneforward, boneright, boneup, boneorg; + local vector parentforward, parentright, parentup, parentorg; + local vector u, v; + local vector modeleyetarget; + bonenum = skel_find_bone(self.skeletonindex, bonename) - 1; + if (bonenum < 0) + return; + oldforward = v_forward; + oldright = v_right; + oldup = v_up; + v = eyetarget - self.origin; + modeleyetarget_x = v * v_forward; + modeleyetarget_y = 0-v * v_right; + modeleyetarget_z = v * v_up; + // this is an eyeball, make it point at the target location + // first get all the data we can... + relorg = skel_get_bonerel(self.skeletonindex, bonenum); + relforward = v_forward; + relright = v_right; + relup = v_up; + boneorg = skel_get_boneabs(self.skeletonindex, bonenum); + boneforward = v_forward; + boneright = v_right; + boneup = v_up; + parentorg = skel_get_boneabs(self.skeletonindex, skel_get_boneparent(self.skeletonindex, bonenum)); + parentforward = v_forward; + parentright = v_right; + parentup = v_up; + // get the vector from the eyeball to the target + u = modeleyetarget - boneorg; + // now transform it inversely by the parent matrix to produce new rel vectors + v_x = u * parentforward; + v_y = u * parentright; + v_z = u * parentup; + ang = vectoangles2(v, relup); + ang_x = 0 - ang_x; + makevectors(ang); + // set the relative bone matrix + skel_set_bone(self.skeletonindex, bonenum, relorg); + // restore caller's v_ vectors + v_forward = oldforward; + v_right = oldright; + v_up = oldup; +}; +// delete skeleton when we're done with it +// note: skeleton remains valid until next frame when it is really deleted +void() example_skel_player_delete = +{ + skel_delete(self.skeletonindex); + self.skeletonindex = 0; +}; +// +// END OF EXAMPLES FOR FTE_CSQC_SKELETONOBJECTS +// + +// assorted builtins +const float STAT_MOVEVARS_TICRATE = 240; +const float STAT_MOVEVARS_TIMESCALE = 241; +const float STAT_FRAGLIMIT = 235; +const float STAT_TIMELIMIT = 236; +const float STAT_MOVEVARS_GRAVITY = 242; +string(void) ReadPicture = #501; +float PARTICLES_USEALPHA = 1; +float particles_alphamin, particles_alphamax; +float PARTICLES_USECOLOR = 2; +vector particles_colormin, particles_colormax; +void(float effectindex, entity own, vector org_from, vector org_to, vector dir_from, vector dir_to, float countmultiplier, float flags) boxparticles = #502; +float trace_networkentity; +const float RF_FULLBRIGHT = 256; +const float RF_NOSHADOW = 512; +float RF_DYNAMICMODELLIGHT = 8192; + +float gettaginfo_parent; +string gettaginfo_name; +vector gettaginfo_offset; +vector gettaginfo_forward; +vector gettaginfo_right; +vector gettaginfo_up; diff --git a/misc/source/darkplaces-src/dpdefs/dpextensions.qc b/misc/source/darkplaces-src/dpdefs/dpextensions.qc index 8d214884..0acf262b 100644 --- a/misc/source/darkplaces-src/dpdefs/dpextensions.qc +++ b/misc/source/darkplaces-src/dpdefs/dpextensions.qc @@ -113,6 +113,14 @@ float EF_DOUBLESIDED = 32768; //description: //render entity as double sided (backfaces are visible, I.E. you see the 'interior' of the model, rather than just the front), can be occasionally useful on transparent stuff. +//DP_EF_DYNAMICMODELLIGHT +//idea: C.Brutail, divVerent, maikmerten +//darkplaces implementation: divVerent +//effects bit: +float EF_DYNAMICMODELLIGHT = 131072; +//description: +//force dynamic model light on the entity, even if it's a BSP model (or anything else with lightmaps or light colors) + //DP_EF_FLAME //idea: LordHavoc //darkplaces implementation: LordHavoc @@ -943,14 +951,14 @@ float log(float f) = #532; //idea: LordHavoc //darkplaces implementation: LordHavoc //builtin definitions: -float(float a, float b) min = #94; +float(float a, float b, ...) min = #94; float(float a, float b, float c) min3 = #94; float(float a, float b, float c, float d) min4 = #94; float(float a, float b, float c, float d, float e) min5 = #94; float(float a, float b, float c, float d, float e, float f) min6 = #94; float(float a, float b, float c, float d, float e, float f, float g) min7 = #94; float(float a, float b, float c, float d, float e, float f, float g, float h) min8 = #94; -float(float a, float b) max = #95; +float(float a, float b, ...) max = #95; float(float a, float b, float c) max3 = #95; float(float a, float b, float c, float d) max4 = #95; float(float a, float b, float c, float d, float e) max5 = #95; @@ -1027,7 +1035,9 @@ string(string format, ...) sprintf = #627; // For conversions s and c, the flag # makes precision and width interpreted // as byte count, by default it is interpreted as character count in UTF-8 // enabled engines. No other conversions can create wide characters, and # -// has another meaning in these. +// has another meaning in these. When in character count mode, color codes +// are ignored. To get UTF-8 semantics WITHOUT color code parsing, use +// the + flag. //DP_QC_STRFTIME //idea: LordHavoc @@ -1663,22 +1673,44 @@ void(float effectnum, vector org, vector vel, float howmany) pointparticles = #3 //globals: //new movetypes: const float MOVETYPE_PHYSICS = 32; // need to be set before any physics_* builtins applied -//new solid types: +//new solid types (deprecated): const float SOLID_PHYSICS_BOX = 32; const float SOLID_PHYSICS_SPHERE = 33; const float SOLID_PHYSICS_CAPSULE = 34; const float SOLID_PHYSICS_TRIMESH = 35; const float SOLID_PHYSICS_CYLINDER = 36; -//SOLID_BSP; +//geometry types: +const float GEOMTYPE_NONE = -1; // entity will be entirely skipped by ODE +const float GEOMTYPE_SOLID = 0; // geometry type will be set based on .solid field +const float GEOMTYPE_BOX = 1; // entity bound box +const float GEOMTYPE_SPHERE = 2; // sphere with radius picked from x axis of entity bound box +const float GEOMTYPE_CAPSULE = 3; // with leading axis automatically determined from longest one, radius is picked as minimal of the rest 2 axes +const float GEOMTYPE_TRIMESH = 4; // triangle mesh +const float GEOMTYPE_CYLINDER = 5; // like capsule but not capped + // note that ODE's builtin cylinder support is experimental, somewhat bugged and unfinished (no cylinder-cylinder collision) + // to use properly working cylinder should build ODE with LIBCCD extension +const float GEOMTYPE_CAPSULE_X = 6; // capsule with fixed leading axis +const float GEOMTYPE_CAPSULE_Y = 7; +const float GEOMTYPE_CAPSULE_Z = 8; +const float GEOMTYPE_CYLINDER_X = 9; // cylinder with fixed leading axis +const float GEOMTYPE_CYLINDER_Y = 10; +const float GEOMTYPE_CYLINDER_Z = 11; //joint types: +const float JOINTTYPE_NONE = 0; const float JOINTTYPE_POINT = 1; const float JOINTTYPE_HINGE = 2; const float JOINTTYPE_SLIDER = 3; const float JOINTTYPE_UNIVERSAL = 4; const float JOINTTYPE_HINGE2 = 5; const float JOINTTYPE_FIXED = -1; +//force types: +const float FORCETYPE_NONE = 0; +const float FORCETYPE_FORCE = 1; // applied at center of mass +const float FORCETYPE_FORCEATPOS = 2; +const float FORCETYPE_TORQUE = 3; // common joint properties: -// .entity aiment, enemy; // connected objects +// .entity aiment; // connected objects +// .entity enemy; // connected objects, forces // .vector movedir; // for a spring: // movedir_x = spring constant (force multiplier, must be > 0) @@ -1689,17 +1721,26 @@ const float JOINTTYPE_FIXED = -1; // movedir_y = -1 * max motor force to use // movedir_z = stop position (+/-), set to 0 for no stop // note that ODE does not support both in one anyway +// for a force: +// force vector to apply //field definitions: -.float mass; // ODE mass, standart value is 1 -.vector massofs; // offsets a mass center out of object center, if not set a center of model bounds is used -.float friction; -.float bouncefactor; -.float bouncestop; -.float jointtype; +.float geomtype; // see GEOMTYPE_*, a more correct way to set collision shape, allows to set SOLID_CORPSE and trimesh collisions +.float maxcontacts; // maximum number of contacts to make for this object, lesser = faster (but setting it too low will could make object pass though walls), default is 16, maximum is 32 +.float mass; // ODE mass, standart value is 1 +.vector massofs; // offsets a mass center out of object center, if not set a center of model bounds is used +.float friction; // a friction of object, get multiplied by second objects's friction on contact +.float bouncefactor; +.float bouncestop; +.float jointtype; // type of joint +.float forcetype; // type of force +.float erp; // error restitution parameter, makes ODE solver attempt to fix errors in contacts, + // bringing together 2 joints or fixing object being stuch in other object, + // a value of 0.1 will fix slightly, a value of 1.0 attempts to fix whole error in one frame + // use with care as high values makes system unstable and likely to explode //builtin definitions: void(entity e, float physics_enabled) physics_enable = #540; // enable or disable physics on object -void(entity e, vector force, vector force_pos) physics_addforce = #541; // apply a force from certain origin, length of force vector is power of force -void(entity e, vector torque) physics_addtorque = #542; // add relative torque +void(entity e, vector force, vector force_pos) physics_addforce = #541; // deprecated, apply a force from certain origin, length of force vector is power of force +void(entity e, vector torque) physics_addtorque = #542; // deprecated, add relative torque //description: provides Open Dynamics Engine support, requires extenal dll to be present or engine compiled with statical link option //be sure to checkextension for it to know if library is loaded and ready, also to enable physics set "physics_ode" cvar to 1 //note: this extension is highly experimental and may be unstable diff --git a/misc/source/darkplaces-src/dpdefs/keycodes.qc b/misc/source/darkplaces-src/dpdefs/keycodes.qc new file mode 100644 index 00000000..76945736 --- /dev/null +++ b/misc/source/darkplaces-src/dpdefs/keycodes.qc @@ -0,0 +1,147 @@ +/////////////////////////// +// key constants + +// +// these are the key numbers that should be passed to Key_Event +// +float K_TAB = 9; +float K_ENTER = 13; +float K_ESCAPE = 27; +float K_SPACE = 32; + +// normal keys should be passed as lowercased ascii + +float K_BACKSPACE = 127; +float K_UPARROW = 128; +float K_DOWNARROW = 129; +float K_LEFTARROW = 130; +float K_RIGHTARROW = 131; + +float K_ALT = 132; +float K_CTRL = 133; +float K_SHIFT = 134; + +float K_F1 = 135; +float K_F2 = 136; +float K_F3 = 137; +float K_F4 = 138; +float K_F5 = 139; +float K_F6 = 140; +float K_F7 = 141; +float K_F8 = 142; +float K_F9 = 143; +float K_F10 = 144; +float K_F11 = 145; +float K_F12 = 146; + +float K_INS = 147; +float K_DEL = 148; +float K_PGDN = 149; +float K_PGUP = 150; +float K_HOME = 151; +float K_END = 152; + +float K_NUMLOCK = 154; +float K_CAPSLOCK = 155; +float K_SCROLLLOCK = 156; + +float K_KP_0 = 157; +float K_KP_INS = K_KP_0; +float K_KP_1 = 158; +float K_KP_END = K_KP_1; +float K_KP_2 = 159; +float K_KP_DOWNARROW = K_KP_2; +float K_KP_3 = 160; +float K_KP_PGDN = K_KP_3; +float K_KP_4 = 161; +float K_KP_LEFTARROW = K_KP_4; +float K_KP_5 = 162; +float K_KP_6 = 163; +float K_KP_RIGHTARROW = K_KP_6; +float K_KP_7 = 164; +float K_KP_HOME = K_KP_7; +float K_KP_8 = 165; +float K_KP_UPARROW = K_KP_8; +float K_KP_9 = 166; +float K_KP_PGUP = K_KP_9; +float K_KP_PERIOD = 167; +float K_KP_DEL = K_KP_PERIOD; +float K_KP_DIVIDE = 168; +float K_KP_SLASH = K_KP_DIVIDE; +float K_KP_MULTIPLY = 169; +float K_KP_MINUS = 170; +float K_KP_PLUS = 171; +float K_KP_ENTER = 172; +float K_KP_EQUALS = 173; + +// mouse buttons generate virtual keys +float K_PAUSE = 153; + +// +// joystick buttons +// +float K_JOY1 = 768; +float K_JOY2 = 769; +float K_JOY3 = 770; +float K_JOY4 = 771; + +// +// +// aux keys are for multi-buttoned joysticks to generate so they can use +// the normal binding process +// +float K_AUX1 = 772; +float K_AUX2 = 773; +float K_AUX3 = 774; +float K_AUX4 = 775; +float K_AUX5 = 776; +float K_AUX6 = 777; +float K_AUX7 = 778; +float K_AUX8 = 779; +float K_AUX9 = 780; +float K_AUX10 = 781; +float K_AUX11 = 782; +float K_AUX12 = 783; +float K_AUX13 = 784; +float K_AUX14 = 785; +float K_AUX15 = 786; +float K_AUX16 = 787; +float K_AUX17 = 788; +float K_AUX18 = 789; +float K_AUX19 = 790; +float K_AUX20 = 791; +float K_AUX21 = 792; +float K_AUX22 = 793; +float K_AUX23 = 794; +float K_AUX24 = 795; +float K_AUX25 = 796; +float K_AUX26 = 797; +float K_AUX27 = 798; +float K_AUX28 = 799; +float K_AUX29 = 800; +float K_AUX30 = 801; +float K_AUX31 = 802; +float K_AUX32 = 803; + +// +// mouse buttons generate virtual keys +// +float K_MOUSE1 = 512; +float K_MOUSE2 = 513; +float K_MOUSE3 = 514; +float K_MWHEELUP = 515; +float K_MWHEELDOWN = 516; +float K_MOUSE4 = 517; +float K_MOUSE5 = 518; +float K_MOUSE6 = 519; +float K_MOUSE7 = 520; +float K_MOUSE8 = 521; +float K_MOUSE9 = 522; +float K_MOUSE10 = 523; +float K_MOUSE11 = 524; +float K_MOUSE12 = 525; +float K_MOUSE13 = 526; +float K_MOUSE14 = 527; +float K_MOUSE15 = 528; +float K_MOUSE16 = 529; + diff --git a/misc/source/darkplaces-src/dpdefs/menudefs.qc b/misc/source/darkplaces-src/dpdefs/menudefs.qc index b23e6baf..ad8666ed 100644 --- a/misc/source/darkplaces-src/dpdefs/menudefs.qc +++ b/misc/source/darkplaces-src/dpdefs/menudefs.qc @@ -16,160 +16,18 @@ void end_sys_fields; void() m_init; void(float keynr, float ascii) m_keydown; void() m_draw; -void() m_toggle; +void(float mode) m_toggle; void() m_shutdown; ///////////////////////////////////////////////////////// // sys constants -/////////////////////////// -// key constants - -// -// these are the key numbers that should be passed to Key_Event -// -float K_TAB = 9; -float K_ENTER = 13; -float K_ESCAPE = 27; -float K_SPACE = 32; - -// normal keys should be passed as lowercased ascii - -float K_BACKSPACE = 127; -float K_UPARROW = 128; -float K_DOWNARROW = 129; -float K_LEFTARROW = 130; -float K_RIGHTARROW = 131; - -float K_ALT = 132; -float K_CTRL = 133; -float K_SHIFT = 134; -float K_F1 = 135; -float K_F2 = 136; -float K_F3 = 137; -float K_F4 = 138; -float K_F5 = 139; -float K_F6 = 140; -float K_F7 = 141; -float K_F8 = 142; -float K_F9 = 143; -float K_F10 = 144; -float K_F11 = 145; -float K_F12 = 146; -float K_INS = 147; -float K_DEL = 148; -float K_PGDN = 149; -float K_PGUP = 150; -float K_HOME = 151; -float K_END = 152; - -float K_PAUSE = 153; - -float K_NUMLOCK = 154; -float K_CAPSLOCK = 155; -float K_SCROLLLOCK = 156; - -float K_KP_0 = 157; -float K_KP_INS = K_KP_0; -float K_KP_1 = 158; -float K_KP_END = K_KP_1; -float K_KP_2 = 159; -float K_KP_DOWNARROW = K_KP_2; -float K_KP_3 = 160; -float K_KP_PGDN = K_KP_3; -float K_KP_4 = 161 -float K_KP_LEFTARROW = K_KP_4; -float K_KP_5 = 162; -float K_KP_6 = 163; -float K_KP_RIGHTARROW = K_KP_6; -float K_KP_7 = 164; -float K_KP_HOME = K_KP_7; -float K_KP_8 = 165; -float K_KP_UPARROW = K_KP_8; -float K_KP_9 = 166; -float K_KP_PGUP = K_KP_9; -float K_KP_PERIOD = 167; -float K_KP_DEL = K_KP_PERIOD; -float K_KP_DIVIDE = 168; -float K_KP_SLASH = K_KP_DIVIDE; -float K_KP_MULTIPLY = 169; -float K_KP_MINUS = 170; -float K_KP_PLUS = 171; -float K_KP_ENTER = 172; -float K_KP_EQUALS = 173; - -// mouse buttons generate virtual keys - -float K_MOUSE1 = 512; -float K_MOUSE2 = 513; -float K_MOUSE3 = 514; -float K_MOUSE4 = 515; -float K_MWHEELUP = K_MOUSE4; -float K_MOUSE5 = 516; -float K_MWHEELDOWN = K_MOUSE5; -float K_MOUSE6 = 517; -float K_MOUSE7 = 518; -float K_MOUSE8 = 519; -float K_MOUSE9 = 520; -float K_MOUSE10 = 521; -float K_MOUSE11 = 522; -float K_MOUSE12 = 523; -float K_MOUSE13 = 524; -float K_MOUSE14 = 525; -float K_MOUSE15 = 526; -float K_MOUSE16 = 527; - -// -// joystick buttons -// -float K_JOY1 = 768; -float K_JOY2 = 769; -float K_JOY3 = 770; -float K_JOY4 = 771; - -// -// -// aux keys are for multi-buttoned joysticks to generate so they can use -// the normal binding process -// -float K_AUX1 = 772; -float K_AUX2 = 773; -float K_AUX3 = 774; -float K_AUX4 = 775; -float K_AUX5 = 776; -float K_AUX6 = 777; -float K_AUX7 = 778; -float K_AUX8 = 779; -float K_AUX9 = 780; -float K_AUX10 = 781; -float K_AUX11 = 782; -float K_AUX12 = 783; -float K_AUX13 = 784; -float K_AUX14 = 785; -float K_AUX15 = 786; -float K_AUX16 = 787; -float K_AUX17 = 788; -float K_AUX18 = 789; -float K_AUX19 = 790; -float K_AUX20 = 791; -float K_AUX21 = 792; -float K_AUX22 = 793; -float K_AUX23 = 794; -float K_AUX24 = 795; -float K_AUX25 = 796; -float K_AUX26 = 797; -float K_AUX27 = 798; -float K_AUX28 = 799; -float K_AUX29 = 800; -float K_AUX30 = 801; -float K_AUX31 = 802; -float K_AUX32 = 803; - /////////////////////////// // key dest constants +float KEY_UNKNOWN = -1; float KEY_GAME = 0; float KEY_MENU = 2; -float KEY_UNKNOWN = 3; +float KEY_MENU_GRABBED = 3; /////////////////////////// // file constants @@ -241,6 +99,42 @@ float ERR_BADSCALE = -3; float ERR_BADSIZE = ERR_BADSCALE; float ERR_NOTCACHED = -4; +// server list stuff +float SLIST_HOSTCACHEVIEWCOUNT = 0; +float SLIST_HOSTCACHETOTALCOUNT = 1; +float SLIST_MASTERQUERYCOUNT = 2; +float SLIST_MASTERREPLYCOUNT = 3; +float SLIST_SERVERQUERYCOUNT = 4; +float SLIST_SERVERREPLYCOUNT = 5; +float SLIST_SORTFIELD = 6; +float SLIST_SORTDESCENDING = 7; +float SLIST_LEGACY_LINE1 = 1024; +float SLIST_LEGACY_LINE2 = 1025; +float SLIST_TEST_CONTAINS = 0; +float SLIST_TEST_NOTCONTAIN = 1; +float SLIST_TEST_LESSEQUAL = 2; +float SLIST_TEST_LESS = 3; +float SLIST_TEST_EQUAL = 4; +float SLIST_TEST_GREATER = 5; +float SLIST_TEST_GREATEREQUAL = 6; +float SLIST_TEST_NOTEQUAL = 7; +float SLIST_TEST_STARTSWITH = 8; +float SLIST_TEST_NOTSTARTSWITH = 9; +float SLIST_MASK_AND = 0; +float SLIST_MASK_OR = 512; + +// font stuff +float FONT_DEFAULT = 0; +float FONT_CONSOLE = 1; +float FONT_SBAR = 2; +float FONT_NOTIFY = 3; +float FONT_CHAT = 4; +float FONT_CENTERPRINT = 5; +float FONT_INFOBAR = 6; +float FONT_MENU = 7; +float FONT_USER = 8; // add to this the index, like FONT_USER+3 = user3. At least 8 of them are supported. +float drawfont; + /* not supported at the moment /////////////////////////// // os constants @@ -286,7 +180,7 @@ vector vectoangles(vector v) = #11; float random(void) = #12; -void cmd(string command) = #13; +void cmd(string command, ...) = #13; // cvar cmds @@ -308,7 +202,7 @@ float stof(string val,...) = #21; entity spawn(void) = #22; void remove(entity e) = #23; -entity findstring(entity start, .string field, string match) = #24; +entity find(entity start, .string field, string match) = #24; entity findfloat(entity start, .float field, float match) = #25; entity findentity(entity start, .entity field, entity match) = #25; @@ -399,7 +293,7 @@ void WriteEntity(entity data, float dest, float desto) = #408; ////////////////////////////////////////////////// float iscachedpic(string name) = #451; -string precache_pic(string name) = #452; +string precache_pic(string name, ...) = #452; void freepic(string name) = #453; float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag) = #454; @@ -462,6 +356,11 @@ string(string serveraddress) crypto_getidfp = #634; // retrieves the cached host string(string serveraddress) crypto_getencryptlevel = #635; // 0 if never encrypting, 1 supported, 2 requested, 3 required, appended by list of allowed methods in order of preference ("AES128"), preceded by a space each string(float i) crypto_getmykeyfp = #636; // retrieves the CA key fingerprint of a given CA slot, or "" if slot is unused but more to come, or string_null if end of list string(float i) crypto_getmyidfp = #637; // retrieves the ID fingerprint of a given CA slot, or "" if slot is unused but more to come, or string_null if end of list +float CRYPTO_IDSTATUS_OUTOFRANGE = -1; +float CRYPTO_IDSTATUS_EMPTY = 0; +float CRYPTO_IDSTATUS_UNSIGNED = 1; +float CRYPTO_IDSTATUS_SIGNED = 2; +float(float i) crypto_getmyidstatus = #641; // retrieves the ID's status of a given CA slot, or 0 if slot is unused but more to come, or -1 if end of list float(string url, float id, string content_type, string delim, float buf, float keyid) crypto_uri_postbuf = #513; //description: //use -1 as buffer handle to justs end delim as postdata @@ -489,3 +388,160 @@ vector gecko_get_texture_extent( string name ) = #493; //description: //provides an interface to the offscreengecko library and allows for internet browsing in games +//FTE_STRINGS +//idea: many +//darkplaces implementation: KrimZon +//description: +//various string manipulation functions +float(string str, string sub, float startpos) strstrofs = #221; +float(string str, float ofs) str2chr = #222; +string(float c, ...) chr2str = #223; +string(float ccase, float calpha, float cnum, string s, ...) strconv = #224; +string(float chars, string s, ...) strpad = #225; +string(string info, string key, string value, ...) infoadd = #226; +string(string info, string key) infoget = #227; +float(string s1, string s2, float len) strncmp = #228; +float(string s1, string s2) strcasecmp = #229; +float(string s1, string s2, float len) strncasecmp = #230; + +//DP_PRECACHE_PIC_FLAGS +//idea: divVerent +//darkplaces implementation: divVerent +//constant definitions: +float PRECACHE_PIC_FROMWAD = 1; // this one actually is part of EXT_CSQC +float PRECACHE_PIC_NOTPERSISTENT = 2; // picture may get deallocated when unused +float PRECACHE_PIC_MIPMAP = 8; // mipmap the texture for possibly better downscaling at memory expense +//notes: these constants are given as optional second argument to precache_pic() + +//DP_QC_CRC16 +//idea: div0 +//darkplaces implementation: div0 +//Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol. +//When caseinsensitive is set, the CRC is calculated of the lower cased string. +float(float caseinsensitive, string s, ...) crc16 = #494; + +//DP_QC_CVAR_TYPE +float(string name) cvar_type = #495; +float CVAR_TYPEFLAG_EXISTS = 1; +float CVAR_TYPEFLAG_SAVED = 2; +float CVAR_TYPEFLAG_PRIVATE = 4; +float CVAR_TYPEFLAG_ENGINE = 8; +float CVAR_TYPEFLAG_HASDESCRIPTION = 16; +float CVAR_TYPEFLAG_READONLY = 32; + +//DP_QC_STRINGBUFFERS +//idea: ?? +//darkplaces implementation: LordHavoc +//functions to manage string buffer objects - that is, arbitrary length string arrays that are handled by the engine +float() buf_create = #440; +void(float bufhandle) buf_del = #441; +float(float bufhandle) buf_getsize = #442; +void(float bufhandle_from, float bufhandle_to) buf_copy = #443; +void(float bufhandle, float sortpower, float backward) buf_sort = #444; +string(float bufhandle, string glue) buf_implode = #445; +string(float bufhandle, float string_index) bufstr_get = #446; +void(float bufhandle, float string_index, string str) bufstr_set = #447; +float(float bufhandle, string str, float order) bufstr_add = #448; +void(float bufhandle, float string_index) bufstr_free = #449; +void(float bufhandle, string pattern, string antipattern) buf_cvarlist = #517; + +//DP_QC_STRING_CASE_FUNCTIONS +//idea: Dresk +//darkplaces implementation: LordHavoc / Dresk +//builtin definitions: +string(string s) strtolower = #480; // returns the passed in string in pure lowercase form +string(string s) strtoupper = #481; // returns the passed in string in pure uppercase form +//description: +//provides simple string uppercase and lowercase functions + +//DP_QC_CVAR_DESCRIPTION +//idea: divVerent +//DarkPlaces implementation: divVerent +//builtin definitions: +string(string name) cvar_description = #518; +//description: +//returns the description of a cvar + +//DP_QC_DIGEST +//idea: motorsep, Spike +//DarkPlaces implementation: divVerent +//builtin definitions: +string(string digest, string data, ...) digest_hex = #639; +//description: +//returns a given hex digest of given data +//the returned digest is always encoded in hexadecimal +//only the "MD4" digest is always supported! +//if the given digest is not supported, string_null is returned +//the digest string is matched case sensitively, use "MD4", not "md4"! + +//DP_QC_URI_ESCAPE +//idea: div0 +//darkplaces implementation: div0 +//URI::Escape's functionality +string(string in) uri_escape = #510; +string(string in) uri_unescape = #511; + +//DP_QC_URI_GET +//idea: divVerent +//darkplaces implementation: divVerent +//loads text from an URL into a string +//returns 1 on success of initiation, 0 if there are too many concurrent +//connections already or if the URL is invalid +//the following callback will receive the data and MUST exist! +// void(float id, float status, string data) URI_Get_Callback; +//status is either +// negative for an internal error, +// 0 for success, or +// the HTTP response code on server error (e.g. 404) +//if 1 is returned by uri_get, the callback will be called in the future +float(string url, float id) uri_get = #513; +//DP_QC_URI_POST +//idea: divVerent +//darkplaces implementation: divVerent +//loads text from an URL into a string after POSTing via HTTP +//works like uri_get, but uri_post sends data with Content-Type: content_type to the server +//and uri_post sends the string buffer buf, joined using the delimiter delim +float(string url, float id, string content_type, string data) uri_post = #513; +float(string url, float id, string content_type, string delim, float buf) uri_postbuf = #513; + +// assorted undocumented extensions +string(string, float) netaddress_resolve = #625; +string(string search, string replace, string subject) strreplace = #484; +string(float uselocaltime, string format, ...) strftime = #478; +float(string s) tokenize_console = #514; +float(float i) argv_start_index = #515; +float(float i) argv_end_index = #516; +string(float, float) getgamedirinfo = #626; +#define GETGAMEDIRINFO_NAME 0 +#define GETGAMEDIRINFO_DESCRIPTION 1 +float log(float f) = #532; +string(string format, ...) sprintf = #627; +string(string s) strdecolorize = #477; +entity findflags(entity start, .float field, float match) = #87; +entity findchainflags(.float field, float match) = #88; +float(string s, string separator1, ...) tokenizebyseparator = #479; +float etof(entity ent) = #79; +entity ftoe(float num) = #80; +float validstring(string str) = #81; +float altstr_count(string str) = #82; +string altstr_prepare(string str) = #83; +string altstr_get(string str, float num) = #84; +string altstr_set(string str, float num, string set) = #85; +string altstr_ins(string str, float num, string set) = #86; +float isdemo() = #349; +float drawsubpic(vector position, vector size, string pic, vector srcPosition, vector srcSize, vector rgb, float alpha, float flag) = #469; +//vector getresolution(float number, ...) = #608; // optional argument "isfullscreen" +void parseentitydata(entity ent, string data) = #613; +void resethostcachemasks(void) = #615; +void sethostcachemaskstring(float mask, float fld, string str, float op) = #616; +void sethostcachemasknumber(float mask, float fld, float num, float op) = #617; +void resorthostcache(void) = #618; +void sethostcachesort(float fld, float descending) = #619; +void refreshhostcache(void) = #620; +float gethostcachenumber(float fld, float hostnr) = #621; +float gethostcacheindexforkey(string key) = #622; +void addwantedhostcachekey(string key) = #623; +string getextresponse(void) = #624; +const string cvar_string(string name) = #71; +const string cvar_defstring(string name) = #89; +float stringwidth(string text, float handleColors, vector size) = #468; diff --git a/misc/source/darkplaces-src/dpdefs/progsdefs.qc b/misc/source/darkplaces-src/dpdefs/progsdefs.qc index 2904f7db..912c3eca 100644 --- a/misc/source/darkplaces-src/dpdefs/progsdefs.qc +++ b/misc/source/darkplaces-src/dpdefs/progsdefs.qc @@ -391,173 +391,8 @@ float MSG_ONE = 1; // reliable to one (msg_entity) float MSG_ALL = 2; // reliable to all float MSG_INIT = 3; // write to the init string -//================================================ - -// -// globals -// -float movedist; -float gameover; // set when a rule exits - -string string_null; // null string, nothing should be held here -//float empty_float; - -entity newmis; // launch_spike sets this after spawning it - -entity activator; // the entity that activated a trigger or brush - -entity damage_attacker; // set by T_Damage -float framecount; - -float skill; - -//================================================ - -// -// world fields (FIXME: make globals) -// -//.string wad; -.string map; -.float worldtype; // 0=medieval 1=metal 2=base - -//================================================ - -.string killtarget; - -// -// quakeed fields -// -.float light_lev; // not used by game, but parsed by light util -.float style; - - -// -// monster ai -// -.void() th_stand; -.void() th_walk; -.void() th_run; -.float() th_missile; // LordHavoc: changed from void() to float(), returns true if attacking -.void() th_melee; -.void(entity attacker, float damage, float damgtype, string dethtype) th_pain; -.void() th_die; - -.entity oldenemy; // mad at this player before taking damage - -.float speed; - -.float lefty; - -.float search_time; -.float attack_state; - -float AS_STRAIGHT = 1; -float AS_SLIDING = 2; -float AS_MELEE = 3; -float AS_MISSILE = 4; - -// -// player only fields -// -//.float walkframe; - -.float attack_finished; -.float pain_finished; - -.float invincible_finished; -.float invisible_finished; -.float super_damage_finished; -.float radsuit_finished; -.float spawnshieldtime; - -.float invincible_time, invincible_sound; -.float invisible_time, invisible_sound; -.float super_time, super_sound; -.float rad_time; -.float fly_sound; - -//.float axhitme; - -.float show_hostile; // set to time+0.2 whenever a client fires a - // weapon or takes damage. Used to alert - // monsters that otherwise would let the player go -.float jump_flag; // player jump flag -.float swim_flag; // player swimming sound flag -.float air_finished; // when time > air_finished, start drowning -.float bubble_count; // keeps track of the number of bubbles -.string deathtype; // keeps track of how the player died - -// -// object stuff -// -.string mdl; -.vector mangle; // angle at start - -.vector oldorigin; // only used by secret door - -.float t_length, t_width; - - -// -// doors, etc -// -.vector dest, dest1, dest2; -.float wait; // time from firing to restarting -.float delay; // time from activation to firing -.entity trigger_field; // door's trigger entity -.string noise4; - -// -// monsters -// -.float pausetime; -.entity movetarget; - - -// -// doors -// -.float aflag; -.float dmg; // damage done by door when hit - -// -// misc -// -.float cnt; // misc flag - -// -// subs -// -.void() think1; -//.vector finaldest, finalangle; - -// -// triggers -// -.float count; // for counting triggers - - -// -// plats / doors / buttons -// -.float lip; -.float state; -.vector pos1, pos2; // top and bottom positions -.float height; - -// -// sounds -// -.float waitmin, waitmax; -//.float distance; -//.float volume; - - - - //=========================================================================== - // // builtin functions // @@ -670,524 +505,3 @@ void(entity e) setspawnparms = #78; // set parm1... to the // for coop respawn //============================================================================ - -// -// subs.qc -// -void(vector tdest, float tspeed, void() func) SUB_CalcMove; -void(entity ent, vector tdest, float tspeed, void() func) SUB_CalcMoveEnt; -void(vector destangle, float tspeed, void() func) SUB_CalcAngleMove; -void() SUB_CalcMoveDone; -void() SUB_CalcAngleMoveDone; -void() SUB_Null; -void() SUB_UseTargets; -void() SUB_Remove; - -// -// combat.qc -// - - - -float(entity targ, entity inflictor) CanDamage; - - - - - -//void(vector org, entity en, vector dir, float holetype) newbullethole; - - -//void(float msg, vector a) WriteVec = -//{ -// WriteCoord(msg, a_x); -// WriteCoord(msg, a_y); -// WriteCoord(msg, a_z); -//}; - -float() crandom = -{ - return 2*(random() - 0.5); -}; - -vector(vector m1, vector m2) randompos = -{ - local vector v; - m2 = m2 - m1; - v_x = m2_x * random() + m1_x; - v_y = m2_y * random() + m1_y; - v_z = m2_z * random() + m1_z; - return v; -}; - -// LordHavoc: made this a builtin function -/* -vector() randomvec = -{ - local vector v; - do - { - v_x = random() - 0.5; // scaled up in the return() - v_y = random() - 0.5; - v_z = random() - 0.5; - } - while (vlen(v) > 0.25); - return(v * 2); -}; -*/ - -vector() randomvec2 = -{ - local vector v; - v_x = random() - 0.5; // scale doesn't matter because it's normalized - v_y = random() - 0.5; - v_z = random() - 0.5; - v = normalize(v); - return(v); -}; - -vector() randomdirvec = -{ - local vector v; - do - { - do - { - v_x = random() - 0.5; - v_y = random() - 0.5; - v_z = random() - 0.5; - } - while (vlen(v) > 0.25); - } - while (vlen(v) < 0.1); - return normalize(v); -}; - -/* -float(float a) sqrt = // now this IS silly (using vlen to do square root) -{ - local vector v; - v_x = a; - return (vlen(v)); -}; -*/ - -// returns an empty point near the location if it's in a solid -// (useful for explosions) -vector (vector org) findbetterlocation = -{ - local vector v; - local float c; - if (pointcontents(org) != CONTENT_SOLID) - return org; - c = 0; - while (c < 20) - { - c = c + 1; -// 4.1 to get it to choose +2 occasionally (rather than a 1 in 32768 chance) - v_x = org_x + random() * 4.1 - 2; - v_y = org_y + random() * 4.1 - 2; - v_z = org_z + random() * 4.1 - 2; - if (pointcontents(v) != CONTENT_SOLID) - return v; - } - return org; // failed to find an empty point -}; - -// adjusts the entity's origin to move it out of a solid -// (useful for projectiles with no size, so they explode in open air) -// note this is mostly useless on entities bigger than that -// (unless they happen to have their origin on the surface of a wall) -void (entity e) findbetterlocation2 = -{ - local vector v, org; - local float c; - if (pointcontents(e.origin) != CONTENT_SOLID) - return; - org = e.origin; - c = 0; - while (c < 20) - { - c = c + 1; -// 4.1 to get it to choose 4 occasionally (rather than a 1 in 32768 chance) - v_x = org_x + random() * 4.1 - 2; - v_y = org_y + random() * 4.1 - 2; - v_z = org_z + random() * 4.1 - 2; - if (pointcontents(v) != CONTENT_SOLID) - { - setorigin(e, v); - return; - } - } - return; // failed to find an empty point -}; - -// returns a point at least 12 units away from walls -// (useful for explosion animations, although the blast is performed where it really happened) -vector (vector org) findbetterlocation3 = -{ - local vector v2; - traceline(org, org - '12 0 0' , TRUE, world);if (trace_fraction < 1) {v2 = trace_endpos;traceline(v2, v2 + '12 0 0' , TRUE, world);if (trace_fraction >= 1) org = v2 + '12 0 0' ;} - traceline(org, org - '-12 0 0', TRUE, world);if (trace_fraction < 1) {v2 = trace_endpos;traceline(v2, v2 + '-12 0 0', TRUE, world);if (trace_fraction >= 1) org = v2 + '-12 0 0';} - traceline(org, org - '0 12 0' , TRUE, world);if (trace_fraction < 1) {v2 = trace_endpos;traceline(v2, v2 + '0 12 0' , TRUE, world);if (trace_fraction >= 1) org = v2 + '0 12 0' ;} - traceline(org, org - '0 -12 0', TRUE, world);if (trace_fraction < 1) {v2 = trace_endpos;traceline(v2, v2 + '0 -12 0', TRUE, world);if (trace_fraction >= 1) org = v2 + '0 -12 0';} - traceline(org, org - '0 0 12' , TRUE, world);if (trace_fraction < 1) {v2 = trace_endpos;traceline(v2, v2 + '0 0 12' , TRUE, world);if (trace_fraction >= 1) org = v2 + '0 0 12' ;} - traceline(org, org - '0 0 -12', TRUE, world);if (trace_fraction < 1) {v2 = trace_endpos;traceline(v2, v2 + '0 0 -12', TRUE, world);if (trace_fraction >= 1) org = v2 + '0 0 -12';} - return org; -}; - -vector (vector org) findbetterlocation4 = -{ - local vector v2; - traceline(org, org - '5 0 0' , TRUE, world);if (trace_fraction < 1) {v2 = trace_endpos;traceline(v2, v2 + '5 0 0' , TRUE, world);if (trace_fraction >= 1) org = v2 + '5 0 0' ;} - traceline(org, org - '-5 0 0', TRUE, world);if (trace_fraction < 1) {v2 = trace_endpos;traceline(v2, v2 + '-5 0 0', TRUE, world);if (trace_fraction >= 1) org = v2 + '-5 0 0';} - traceline(org, org - '0 5 0' , TRUE, world);if (trace_fraction < 1) {v2 = trace_endpos;traceline(v2, v2 + '0 5 0' , TRUE, world);if (trace_fraction >= 1) org = v2 + '0 5 0' ;} - traceline(org, org - '0 -5 0', TRUE, world);if (trace_fraction < 1) {v2 = trace_endpos;traceline(v2, v2 + '0 -5 0', TRUE, world);if (trace_fraction >= 1) org = v2 + '0 -5 0';} - traceline(org, org - '0 0 5' , TRUE, world);if (trace_fraction < 1) {v2 = trace_endpos;traceline(v2, v2 + '0 0 5' , TRUE, world);if (trace_fraction >= 1) org = v2 + '0 0 5' ;} - traceline(org, org - '0 0 -5', TRUE, world);if (trace_fraction < 1) {v2 = trace_endpos;traceline(v2, v2 + '0 0 -5', TRUE, world);if (trace_fraction >= 1) org = v2 + '0 0 -5';} - return org; -}; - -/* -void(vector v1, vector v2, vector m1, vector m2) lh_traceagainstbox = -{ - local vector b, dir, delta, dironx, dirony, dironz; - local float completedist, r; - trace_endpos = v2; - trace_fraction = 1; - if (vlen(v2 - v1) < 0.1) // too short, might do a divide by zero - return; - // throw out the complete misses - if (v1_x <= m1_x) if (v2_x <= m1_x) return; - if (v1_x >= m2_x) if (v2_x >= m2_x) return; - if (v1_y <= m1_y) if (v2_y <= m1_y) return; - if (v1_y >= m2_y) if (v2_y >= m2_y) return; - if (v1_z <= m1_z) if (v2_z <= m1_z) return; - if (v1_z >= m2_z) if (v2_z >= m2_z) return; - // starting inside the box? - if (v1_x >= m1_x) if (v1_x < m2_x) if (v1_y >= m1_y) if (v1_y < m2_y) if (v1_z >= m1_z) if (v1_z < m2_z) return; - delta = v2 - v1; - dir = normalize(delta); - completedist = vlen(v2 - v1); - if (delta_x < -0.001 || delta_x > 0.001) - { - dironx_x = 1;if (delta_x < 0) dironx_x = -1; - dironx_y = delta_y / delta_x; - dironx_z = delta_z / delta_x; - } - else - { - dironx_x = 1;if (delta_x < 0) dironx_x = -1; - dironx_y = 0; - dironx_z = 0; - } - if (delta_y < -0.001 || delta_y > 0.001) - { - dirony_x = delta_x / delta_y; - dirony_y = 1;if (delta_y < 0) dirony_y = -1; - dirony_z = delta_z / delta_y; - } - else - { - dirony_x = 0; - dirony_y = 1;if (delta_y < 0) dirony_y = -1; - dirony_z = 0; - } - if (delta_z < -0.001 || delta_z > 0.001) - { - dironz_x = delta_x / delta_z; - dironz_y = delta_y / delta_z; - dironz_z = 1;if (delta_z < 0) dironz_z = -1; - } - else - { - dironz_x = 0; - dironz_y = 0; - dironz_z = 1;if (delta_z < 0) dironz_z = -1; - } - b = v1; - r = floor(random() * 1000); - if (dir_x > 0) - { - if (b_x < m1_x) - { - b = b + dironx * (m1_x - b_x); - trace_fraction = vlen(b - v1) / completedist; - } - } - else - { - if (b_x > m2_x) - { - b = b - dironx * (m2_x - b_x); - trace_fraction = vlen(b - v1) / completedist; - } - } - trace_endpos = b; - if (trace_fraction > 1) trace_fraction = 1; - if (dir_y > 0) - { - if (b_y < m1_y) - { - b = b + dirony * (m1_y - b_y); - trace_fraction = vlen(b - v1) / completedist; - } - } - else - { - if (b_y > m2_y) - { - b = b - dirony * (m2_y - b_y); - trace_fraction = vlen(b - v1) / completedist; - } - } - trace_endpos = b; - if (trace_fraction > 1) trace_fraction = 1; - if (dir_z > 0) - { - if (b_z < m1_z) - { - b = b + dironz * (m1_z - b_z); - trace_fraction = vlen(b - v1) / completedist; - } - } - else - { - if (b_z > m2_z) - { - b = b - dironz * (m2_z - b_z); - trace_fraction = vlen(b - v1) / completedist; - } - } - trace_endpos = b; - if (trace_fraction > 1) trace_fraction = 1; -}; -*/ - -.float cantrigger; - -void(float n) bprintfloat = -{ - local string s; - s = ftos(n); - bprint(s); -}; - -void(vector n) bprintvector = -{ - local string s; - s = vtos(n); - bprint(s); -}; - -void(float n) dprintfloat = -{ - local string s; - s = ftos(n); - dprint(s); -}; - -void(vector n) dprintvector = -{ - local string s; - s = vtos(n); - dprint(s); -}; - -string deathstring1, deathstring2, deathstring3, deathstring4; - -float DTYPE_OTHER = 0; -float DTYPE_PLAYER = 1; -float DTYPE_WORLD = 2; -float DTYPE_TEAMKILL = 3; -float DTYPE_SUICIDE = 4; - -void(entity targ, entity attacker, string dmsg, float dtype) Obituary_Generic = -{ - deathstring1 = targ.netname; - deathstring2 = dmsg; - deathstring3 = ""; - deathstring4 = ""; -}; - -// called by various obit functions to give a generic message for cases they do not handle -void(entity targ, entity attacker, string dmsg, float dtype) Obituary_Fallback = -{ - if (dtype == DTYPE_OTHER) - { - deathstring1 = targ.netname; - deathstring2 = dmsg; - deathstring3 = ""; - deathstring4 = ""; - } - else if (dtype == DTYPE_SUICIDE) - { - deathstring1 = targ.netname; - deathstring2 = " became bored with life"; - deathstring3 = ""; - deathstring4 = ""; - } - else if (dtype == DTYPE_PLAYER) - { - deathstring1 = targ.netname; - deathstring2 = " was killed by "; - deathstring3 = attacker.netname; - deathstring4 = ""; - } - else if (dtype == DTYPE_TEAMKILL) - { - deathstring1 = targ.netname; - deathstring2 = " was mowed down by his teammate "; - deathstring3 = attacker.netname; - deathstring4 = ""; - } - else if (dtype == DTYPE_WORLD) - { - deathstring1 = targ.netname; - deathstring2 = " died of unknown causes"; - deathstring3 = ""; - deathstring4 = ""; - } -}; - -float GAME_QUAKE = 0; -float GAME_NEXUIZ = 1; -float game; - -float darkmode; - -float IT_WEAPON1 = 4096; -float IT_WEAPON2 = 1; -float IT_WEAPON3 = 2; -float IT_WEAPON4 = 4; -float IT_WEAPON5 = 8; -float IT_WEAPON6 = 16; -float IT_WEAPON7 = 32; -float IT_WEAPON8 = 64; -float IT_WEAPON9 = 128; -float IT_WEAPON10 = 8388608; - -// see modecheck.qc for deathmatch and teamplay settings - -// added for Dark Places -float CHAN_SPEECH = 5; -float CHAN_FOOT = 6; -float CHAN_WEAPON2 = 7; - -// .gravity field added in Quake 1.07 (Scourge of Armagon) -.float gravity; - -.float bodyhealth; // used by corpse code -.float iscorpse; // used by corpse code - -.vector dest, dest1, dest2, dest3, dest4;//, dest5; - - -.entity flame; // the flame burning this thing - -.float doobits; // set if this should do obit on death - -//.vector bodymins, bodymaxs, headmins, headmaxs; - -.vector rotate; -.string group; - -// counts of how many keys this player/bot has -.float keys_silver; -.float keys_gold; - -.float havocattack; -.float havocpickup; -.float(entity player, entity item) pickupevalfunc; // returns rating for item considering player's condition (don't pick up health if it's not needed, etc) -.float shoulddodge; -.float dangerrating; - -// called whenever damage is done, if not supplied there is no visible effect. -.void(vector org, float bodydamage, float armordamage, vector vel, float damgtype) bleedfunc; - -// several counters -.float count1, count2, count3, count4, count5, count6, cnt1, cnt2; - -.void(entity t, entity a, string m, float dtyp) obitfunc1; -.entity realowner; - -float maxclients; // set by worldspawn code -float numdecors; -float maxdecors; -.float createdtime; -.void() th_gib; - -//void(vector org, entity en, vector dir, float splattype, float importance) newbloodsplat; -void(vector org, float bodydamage, float armordamage, vector vel, float damgtype) genericbleedfunc; - - - - -// damage stuff - -void(entity targ, entity inflictor, entity attacker, float damage, float bdamage, string dt, float damgtype, vector damgpoint, vector force, void(entity t, entity a, string m, float dtyp) obitfunc) T_Damage; -void(entity inflictor, entity attacker, float damage, float force, float radius, entity ignore, string dethtype, float damgtype, void(entity t, entity a, string m, float dtyp) obitfunc) T_RadiusDamage; - - -// resistances to 4 kinds of damage: -.float resist_bullet, resist_explosive, resist_energy, resist_fire, resist_ice, resist_axe; -// every monster can have resistances -// note: -1 means immune, as 0.0 can't be used - -// kill message -.string deathtype; -// copied from .deathtype for the attacker -// a map entity can gain alot of meaning by -// adding a kill message in the deathtype key -// such as ' was chopped to bits' -// or ' fell into the abyss' -// if you set a deathtype for a monster -// in a map key it will override the normal -// kill message for that monster -// so you could have some hell knights that -// say ' was slain by one of the palace guards' -// and many other ways to add meaning to a map -.string deathmsg; - -.float regenthink; // next time player will regen some health -.float isdecor; -.float radiusdamage_amount; // damage counter -.vector radiusdamage_force; // direction and power of blast kick -.float radiusdamage_hit; // 1 if it was hit, reset to 0 afterward -.vector radiusdamage_lasthit; // location -.float radiusdamage_ownerdamagescale; // if set on inflictor this will scale damage to owner (overriding default of 0.5) -vector raddamage_lasthit; - -.float frozen; -.float thawtime; -.float thawedeffects; -.void() thawedtouch; -.float thawedmovetype; -.void() thawedthink; -.float thawedthinkdelay; - -.void() knockedloosefunc; // called when kinetically disturbed -.float forcescale; // used for damage force calculations (shambler has lower forcescale than player for instance) - -// how much bleeding 'matters' to this entity, a percentage between -// bodydamage (-1 = 0% as 0 doesn't work) and healthdamage (1.0 = 100%) -// for instance a player is 100% and a zombie is 0% (bleeding doesn't matter) -.float bleedratio; -.float(entity e, float healthdamage, float damage, float damgtype, string dethtype) damagemodifier; - -.void() th_gib; - -.float health; // if this goes below 1 the thing is dead -.float bodyhealth; // used for gibbing -.float healthregen; // regenerate this much health per second -.float healthlostthisframe; // reset by iscreature code each frame - -// adjustable monster damage settings -float monsterdamagescale; -float monsterresistancescale; -// adjustable player damage settings -float playerdamagescale; - -void(entity targ, entity attacker, string dmsg, float dtype, void(entity t, entity a, string m, float dtyp) obitfunc) ClientObituary; - -void() monster_death_use; diff --git a/misc/source/darkplaces-src/dpsoftrast.c b/misc/source/darkplaces-src/dpsoftrast.c index a79a9d36..4967ef0e 100644 --- a/misc/source/darkplaces-src/dpsoftrast.c +++ b/misc/source/darkplaces-src/dpsoftrast.c @@ -748,12 +748,12 @@ void DPSOFTRAST_Texture_UpdatePartial(int index, int mip, const unsigned char *p DPSOFTRAST_Flush(); if (pixels) { - dst = texture->bytes + (blocky * texture->mipmap[0][2] + blockx) * 4; + dst = texture->bytes + texture->mipmap[0][1] +(-blocky * texture->mipmap[0][2] + blockx) * 4; while (blockheight > 0) { + dst -= texture->mipmap[0][2] * 4; memcpy(dst, pixels, blockwidth * 4); pixels += blockwidth * 4; - dst += texture->mipmap[0][2] * 4; blockheight--; } } @@ -766,7 +766,16 @@ void DPSOFTRAST_Texture_UpdateFull(int index, const unsigned char *pixels) if (texture->binds) DPSOFTRAST_Flush(); if (pixels) - memcpy(texture->bytes, pixels, texture->mipmap[0][1]); + { + int i, stride = texture->mipmap[0][2]*4; + unsigned char *dst = texture->bytes + texture->mipmap[0][1]; + for (i = texture->mipmap[0][3];i > 0;i--) + { + dst -= stride; + memcpy(dst, pixels, stride); + pixels += stride; + } + } DPSOFTRAST_Texture_CalculateMipmaps(index); } int DPSOFTRAST_Texture_GetWidth(int index, int mip) @@ -1269,9 +1278,10 @@ void DPSOFTRAST_CopyRectangleToTexture(int index, int mip, int tx, int ty, int s if (th > sh) th = sh; if (tw < 1 || th < 1) return; - sy1 = sheight - 1 - sy1; + sy1 = sheight - sy1 - th; + ty1 = theight - ty1 - th; for (y = 0;y < th;y++) - memcpy(tpixels + ((ty1 + y) * twidth + tx1), spixels + ((sy1 - y) * swidth + sx1), tw*4); + memcpy(tpixels + ((ty1 + y) * twidth + tx1), spixels + ((sy1 + y) * swidth + sx1), tw*4); if (texture->mipmaps > 1) DPSOFTRAST_Texture_CalculateMipmaps(index); } @@ -1304,7 +1314,8 @@ void DPSOFTRAST_SetTexture(int unitnum, int index) command->texture = texture; dpsoftrast.texbound[unitnum] = texture; - ATOMIC_ADD(texture->binds, dpsoftrast.numthreads); + if (texture) + ATOMIC_ADD(texture->binds, dpsoftrast.numthreads); } void DPSOFTRAST_SetVertexPointer(const float *vertex3f, size_t stride) @@ -2293,7 +2304,7 @@ static void DPSOFTRAST_Texture2DBGRA8(DPSOFTRAST_Texture *texture, int mip, floa const unsigned char * RESTRICT pixel[4]; int width = texture->mipmap[mip][2], height = texture->mipmap[mip][3]; int wrapmask[2] = { width-1, height-1 }; - pixelbase = (unsigned char *)texture->bytes + texture->mipmap[mip][0]; + pixelbase = (unsigned char *)texture->bytes + texture->mipmap[mip][0] + texture->mipmap[mip][1] - 4*width; if(texture->filter & DPSOFTRAST_TEXTURE_FILTER_LINEAR) { unsigned int tc[2] = { x * (width<<12) - 2048, y * (height<<12) - 2048}; @@ -2316,10 +2327,10 @@ static void DPSOFTRAST_Texture2DBGRA8(DPSOFTRAST_Texture *texture, int mip, floa tci1[0] &= wrapmask[0]; tci1[1] &= wrapmask[1]; } - pixel[0] = pixelbase + 4 * (tci[1]*width+tci[0]); - pixel[1] = pixelbase + 4 * (tci[1]*width+tci1[0]); - pixel[2] = pixelbase + 4 * (tci1[1]*width+tci[0]); - pixel[3] = pixelbase + 4 * (tci1[1]*width+tci1[0]); + pixel[0] = pixelbase + 4 * (tci[0] - tci[1]*width); + pixel[1] = pixelbase + 4 * (tci[0] - tci[1]*width); + pixel[2] = pixelbase + 4 * (tci[0] - tci1[1]*width); + pixel[3] = pixelbase + 4 * (tci[0] - tci1[1]*width); c[0] = (pixel[0][0]*lerp[0]+pixel[1][0]*lerp[1]+pixel[2][0]*lerp[2]+pixel[3][0]*lerp[3])>>24; c[1] = (pixel[0][1]*lerp[0]+pixel[1][1]*lerp[1]+pixel[2][1]*lerp[2]+pixel[3][1]*lerp[3])>>24; c[2] = (pixel[0][2]*lerp[0]+pixel[1][2]*lerp[1]+pixel[2][2]*lerp[2]+pixel[3][2]*lerp[3])>>24; @@ -2338,7 +2349,7 @@ static void DPSOFTRAST_Texture2DBGRA8(DPSOFTRAST_Texture *texture, int mip, floa tci[0] &= wrapmask[0]; tci[1] &= wrapmask[1]; } - pixel[0] = pixelbase + 4 * (tci[1]*width+tci[0]); + pixel[0] = pixelbase + 4 * (tci[0] - tci[1]*width); c[0] = pixel[0][0]; c[1] = pixel[0][1]; c[2] = pixel[0][2]; @@ -2382,7 +2393,7 @@ static void DPSOFTRAST_Draw_Span_Texture2DVarying(DPSOFTRAST_State_Thread *threa return; } mip = triangle->mip[texunitindex]; - pixelbase = (unsigned char *)texture->bytes + texture->mipmap[mip][0]; + pixelbase = (unsigned char *)texture->bytes + texture->mipmap[mip][0] + texture->mipmap[mip][1] - 4*texture->mipmap[mip][2]; // if this mipmap of the texture is 1 pixel, just fill it with that color if (texture->mipmap[mip][1] == 4) { @@ -2404,7 +2415,7 @@ static void DPSOFTRAST_Draw_Span_Texture2DVarying(DPSOFTRAST_State_Thread *threa flags = texture->flags; tcscale[0] = texture->mipmap[mip][2]; tcscale[1] = texture->mipmap[mip][3]; - tciwidth = texture->mipmap[mip][2]; + tciwidth = -texture->mipmap[mip][2]; tcimin[0] = 0; tcimin[1] = 0; tcimax[0] = texture->mipmap[mip][2]-1; @@ -2569,7 +2580,7 @@ static void DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(DPSOFTRAST_State_Thread * return; } mip = triangle->mip[texunitindex]; - pixelbase = (const unsigned char *)texture->bytes + texture->mipmap[mip][0]; + pixelbase = (const unsigned char *)texture->bytes + texture->mipmap[mip][0] + texture->mipmap[mip][1] - 4*texture->mipmap[mip][2]; // if this mipmap of the texture is 1 pixel, just fill it with that color if (texture->mipmap[mip][1] == 4) { @@ -2591,7 +2602,7 @@ static void DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(DPSOFTRAST_State_Thread * if (filter) endtc = _mm_sub_ps(endtc, _mm_set1_ps(0.5f)); endsubtc = _mm_cvtps_epi32(_mm_mul_ps(endtc, _mm_set1_ps(65536.0f))); - tcoffset = _mm_add_epi32(_mm_slli_epi32(_mm_shuffle_epi32(tcsize, _MM_SHUFFLE(0, 0, 0, 0)), 18), _mm_set1_epi32(4)); + tcoffset = _mm_add_epi32(_mm_slli_epi32(_mm_sub_epi32(_mm_setzero_si128(), _mm_shuffle_epi32(tcsize, _MM_SHUFFLE(0, 0, 0, 0))), 18), _mm_set1_epi32(4)); tcmax = _mm_packs_epi32(tcmask, tcmask); for (x = startx;x < endx;) { @@ -3252,6 +3263,12 @@ static void DPSOFTRAST_PixelShader_Generic(DPSOFTRAST_State_Thread *thread, cons } else DPSOFTRAST_Draw_Span_VaryingBGRA8(triangle, span, buffer_FragColorbgra8, 1, buffer_z); + if(thread->shader_permutation & SHADERPERMUTATION_ALPHAKILL) + { + int x; + for (x = span->startx;x < span->endx;x++) + buffer_FragColorbgra8[x*4+3] = buffer_FragColorbgra8[x*4+3] * thread->uniform4f[DPSOFTRAST_UNIFORM_Alpha*4+0]; + } DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8); } diff --git a/misc/source/darkplaces-src/dpsoftrast.h b/misc/source/darkplaces-src/dpsoftrast.h index 9bd1d010..eb3df2ba 100644 --- a/misc/source/darkplaces-src/dpsoftrast.h +++ b/misc/source/darkplaces-src/dpsoftrast.h @@ -185,20 +185,18 @@ typedef enum shaderpermutation_e SHADERPERMUTATION_OFFSETMAPPING = 1<<16, ///< adjust texcoords to roughly simulate a displacement mapped surface SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<17, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!) SHADERPERMUTATION_SHADOWMAP2D = 1<<18, ///< (lightsource) use shadowmap texture as light filter - SHADERPERMUTATION_SHADOWMAPPCF = 1<<19, ///< (lightsource) use percentage closer filtering on shadowmap test results - SHADERPERMUTATION_SHADOWMAPPCF2 = 1<<20, ///< (lightsource) use higher quality percentage closer filtering on shadowmap test results - SHADERPERMUTATION_SHADOWSAMPLER = 1<<21, ///< (lightsource) use hardware shadowmap test - SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<22, ///< (lightsource) use virtual shadow depth cube texture for shadowmap indexing - SHADERPERMUTATION_SHADOWMAPORTHO = 1<<23, ///< (lightsource) use orthographic shadowmap projection - SHADERPERMUTATION_DEFERREDLIGHTMAP = 1<<24, ///< (lightmap) read Texture_ScreenDiffuse/Specular textures and add them on top of lightmapping - SHADERPERMUTATION_ALPHAKILL = 1<<25, ///< (deferredgeometry) discard pixel if diffuse texture alpha below 0.5 - SHADERPERMUTATION_REFLECTCUBE = 1<<26, ///< fake reflections using global cubemap (not HDRI light probe) - SHADERPERMUTATION_NORMALMAPSCROLLBLEND = 1<<27, ///< (water) counter-direction normalmaps scrolling - SHADERPERMUTATION_BOUNCEGRID = 1<<28, ///< (lightmap) use Texture_BounceGrid as an additional source of ambient light - SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL = 1<<29, ///< (lightmap) use 16-component pixels in bouncegrid texture for directional lighting rather than standard 4-component - SHADERPERMUTATION_TRIPPY = 1<<30, ///< use trippy vertex shader effect - SHADERPERMUTATION_DEPTHRGB = 1<<31, ///< read/write depth values in RGB color coded format for older hardware without depth samplers - SHADERPERMUTATION_COUNT = 32 ///< size of shaderpermutationinfo array + SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<19, ///< (lightsource) use virtual shadow depth cube texture for shadowmap indexing + SHADERPERMUTATION_SHADOWMAPORTHO = 1<<20, ///< (lightsource) use orthographic shadowmap projection + SHADERPERMUTATION_DEFERREDLIGHTMAP = 1<<21, ///< (lightmap) read Texture_ScreenDiffuse/Specular textures and add them on top of lightmapping + SHADERPERMUTATION_ALPHAKILL = 1<<22, ///< (deferredgeometry) discard pixel if diffuse texture alpha below 0.5, (generic) apply global alpha + SHADERPERMUTATION_REFLECTCUBE = 1<<23, ///< fake reflections using global cubemap (not HDRI light probe) + SHADERPERMUTATION_NORMALMAPSCROLLBLEND = 1<<24, ///< (water) counter-direction normalmaps scrolling + SHADERPERMUTATION_BOUNCEGRID = 1<<25, ///< (lightmap) use Texture_BounceGrid as an additional source of ambient light + SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL = 1<<26, ///< (lightmap) use 16-component pixels in bouncegrid texture for directional lighting rather than standard 4-component + SHADERPERMUTATION_TRIPPY = 1<<27, ///< use trippy vertex shader effect + SHADERPERMUTATION_DEPTHRGB = 1<<28, ///< read/write depth values in RGB color coded format for older hardware without depth samplers + SHADERPERMUTATION_ALPHAGEN_VERTEX = 1<<29, ///< alphaGen vertex + SHADERPERMUTATION_COUNT = 30 ///< size of shaderpermutationinfo array } shaderpermutation_t; diff --git a/misc/source/darkplaces-src/draw.h b/misc/source/darkplaces-src/draw.h index 5cb62afa..1daa5eb0 100644 --- a/misc/source/darkplaces-src/draw.h +++ b/misc/source/darkplaces-src/draw.h @@ -56,7 +56,9 @@ typedef enum cachepicflags_e CACHEPICFLAG_QUIET = 2, CACHEPICFLAG_NOCOMPRESSION = 4, CACHEPICFLAG_NOCLAMP = 8, - CACHEPICFLAG_NEWPIC = 16 // disables matching texflags check, because a pic created with Draw_NewPic should not be subject to that + CACHEPICFLAG_NEWPIC = 16, // disables matching texflags check, because a pic created with Draw_NewPic should not be subject to that + CACHEPICFLAG_MIPMAP = 32, + CACHEPICFLAG_NEAREST = 64 // force nearest filtering instead of linear } cachepicflags_t; @@ -94,9 +96,10 @@ DRAWFLAG_2XMODULATE, DRAWFLAG_SCREEN, DRAWFLAG_NUMFLAGS, DRAWFLAG_MASK = 0xFF, // ONLY R_BeginPolygon() -DRAWFLAG_MIPMAP = 0x100 // ONLY R_BeginPolygon() +DRAWFLAG_MIPMAP = 0x100, // ONLY R_BeginPolygon() +DRAWFLAG_NOGAMMA = 0x200 // ONLY R_DrawQSuperPic() }; -#define DRAWFLAGS_BLEND (DRAWFLAG_ADDITIVE + DRAWFLAG_MODULATE + DRAWFLAG_2XMODULATE + DRAWFLAG_SCREEN) +#define DRAWFLAGS_BLEND 0xFF /* this matches all blending flags */ typedef struct ft2_settings_s { diff --git a/misc/source/darkplaces-src/fs.c b/misc/source/darkplaces-src/fs.c index 93768046..e21a5839 100644 --- a/misc/source/darkplaces-src/fs.c +++ b/misc/source/darkplaces-src/fs.c @@ -1722,10 +1722,11 @@ void FS_Init_SelfPack (void) p = buf; while(COM_ParseToken_Console(&p)) { + size_t sz = strlen(com_token) + 1; // shut up clang if(i >= args_left) break; - q = (char *)Mem_Alloc(fs_mempool, strlen(com_token) + 1); - strlcpy(q, com_token, strlen(com_token) + 1); + q = (char *)Mem_Alloc(fs_mempool, sz); + strlcpy(q, com_token, sz); new_argv[com_argc + i] = q; ++i; } diff --git a/misc/source/darkplaces-src/gl_backend.c b/misc/source/darkplaces-src/gl_backend.c index 8df14f8e..fefedcb3 100644 --- a/misc/source/darkplaces-src/gl_backend.c +++ b/misc/source/darkplaces-src/gl_backend.c @@ -2630,7 +2630,7 @@ static qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenu qglCompileShader(shaderobject);CHECKGLERROR qglGetShaderiv(shaderobject, GL_COMPILE_STATUS, &shadercompiled);CHECKGLERROR qglGetShaderInfoLog(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR - if (compilelog[0] && (strstr(compilelog, "error") || strstr(compilelog, "ERROR") || strstr(compilelog, "Error") || strstr(compilelog, "WARNING") || strstr(compilelog, "warning") || strstr(compilelog, "Warning") || developer_extra.integer)) + if (compilelog[0] && ((strstr(compilelog, "error") || strstr(compilelog, "ERROR") || strstr(compilelog, "Error")) || ((strstr(compilelog, "WARNING") || strstr(compilelog, "warning") || strstr(compilelog, "Warning")) && developer.integer) || developer_extra.integer)) { int i, j, pretextlines = 0; for (i = 0;i < numstrings - 1;i++) diff --git a/misc/source/darkplaces-src/gl_draw.c b/misc/source/darkplaces-src/gl_draw.c index 05d6c925..17213e56 100644 --- a/misc/source/darkplaces-src/gl_draw.c +++ b/misc/source/darkplaces-src/gl_draw.c @@ -42,6 +42,8 @@ cvar_t r_font_postprocess_shadow_y = {CVAR_SAVE, "r_font_postprocess_shadow_y", cvar_t r_font_postprocess_shadow_z = {CVAR_SAVE, "r_font_postprocess_shadow_z", "0", "font shadow Z shift amount, applied during blurring"}; cvar_t r_font_hinting = {CVAR_SAVE, "r_font_hinting", "3", "0 = no hinting, 1 = light autohinting, 2 = full autohinting, 3 = full hinting"}; cvar_t r_font_antialias = {CVAR_SAVE, "r_font_antialias", "1", "0 = monochrome, 1 = grey" /* , 2 = rgb, 3 = bgr" */}; +cvar_t r_nearest_2d = {CVAR_SAVE, "r_nearest_2d", "0", "use nearest filtering on all 2d textures (including conchars)"}; +cvar_t r_nearest_conchars = {CVAR_SAVE, "r_nearest_conchars", "0", "use nearest filtering on conchars texture"}; extern cvar_t v_glslgamma; @@ -109,7 +111,7 @@ static rtexture_t *draw_generateconchars(void) Image_WriteTGABGRA ("gfx/generated_conchars.tga", 256, 256, data); #endif - tex = R_LoadTexture2D(drawtexturepool, "conchars", 256, 256, data, TEXTYPE_BGRA, TEXF_ALPHA, -1, NULL); + tex = R_LoadTexture2D(drawtexturepool, "conchars", 256, 256, data, TEXTYPE_BGRA, TEXF_ALPHA | (r_nearest_conchars.integer ? TEXF_FORCENEAREST : 0), -1, NULL); Mem_Free(data); return tex; } @@ -328,8 +330,12 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags) texflags = TEXF_ALPHA; if (!(cachepicflags & CACHEPICFLAG_NOCLAMP)) texflags |= TEXF_CLAMP; + if (cachepicflags & CACHEPICFLAG_MIPMAP) + texflags |= TEXF_MIPMAP; if (!(cachepicflags & CACHEPICFLAG_NOCOMPRESSION) && gl_texturecompression_2d.integer && gl_texturecompression.integer) texflags |= TEXF_COMPRESS; + if ((cachepicflags & CACHEPICFLAG_NEAREST) || r_nearest_2d.integer) + texflags |= TEXF_FORCENEAREST; // check whether the picture has already been cached crc = CRC_Block((unsigned char *)path, strlen(path)); @@ -341,7 +347,7 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags) // if it was created (or replaced) by Draw_NewPic, just return it if(pic->flags & CACHEPICFLAG_NEWPIC) return pic; - if (!((pic->texflags ^ texflags) & ~(TEXF_COMPRESS))) // ignore TEXF_COMPRESS when comparing, because fallback pics remove the flag + if (!((pic->texflags ^ texflags) & ~(TEXF_COMPRESS | TEXF_MIPMAP))) // ignore TEXF_COMPRESS when comparing, because fallback pics remove the flag, and ignore TEXF_MIPMAP because QC specifies that { if(!(cachepicflags & CACHEPICFLAG_NOTPERSISTENT)) { @@ -393,7 +399,7 @@ reload: pic->lastusedframe = draw_frame; // load a high quality image from disk if possible - if (!loaded && r_texture_dds_load.integer != 0 && (pic->tex = R_LoadTextureDDSFile(drawtexturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), vid.sRGB2D, pic->texflags, &ddshasalpha, ddsavgcolor, 0))) + if (!loaded && r_texture_dds_load.integer != 0 && (pic->tex = R_LoadTextureDDSFile(drawtexturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), vid.sRGB2D, pic->texflags, &ddshasalpha, ddsavgcolor, 0, false))) { // note this loads even if autoload is true, otherwise we can't get the width/height loaded = true; @@ -519,7 +525,7 @@ rtexture_t *Draw_GetPicTexture(cachepic_t *pic) { qboolean ddshasalpha; float ddsavgcolor[4]; - pic->tex = R_LoadTextureDDSFile(drawtexturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), vid.sRGB2D, pic->texflags, &ddshasalpha, ddsavgcolor, 0); + pic->tex = R_LoadTextureDDSFile(drawtexturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), vid.sRGB2D, pic->texflags, &ddshasalpha, ddsavgcolor, 0, false); } if (pic->tex == NULL) { @@ -673,20 +679,20 @@ void LoadFont(qboolean override, const char *name, dp_font_t *fnt, float scale, Con_DPrintf("Failed to load font-file for '%s', it will not support as many characters.\n", fnt->texpath); } - fnt->tex = Draw_CachePic_Flags(fnt->texpath, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION)->tex; + fnt->tex = Draw_CachePic_Flags(fnt->texpath, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION | (r_nearest_conchars.integer ? CACHEPICFLAG_NEAREST : 0))->tex; if(fnt->tex == r_texture_notexture) { for (i = 0; i < MAX_FONT_FALLBACKS; ++i) { if (!fnt->fallbacks[i][0]) break; - fnt->tex = Draw_CachePic_Flags(fnt->fallbacks[i], CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION)->tex; + fnt->tex = Draw_CachePic_Flags(fnt->fallbacks[i], CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION | (r_nearest_conchars.integer ? CACHEPICFLAG_NEAREST : 0))->tex; if(fnt->tex != r_texture_notexture) break; } if(fnt->tex == r_texture_notexture) { - fnt->tex = Draw_CachePic_Flags("gfx/conchars", CACHEPICFLAG_NOCOMPRESSION)->tex; + fnt->tex = Draw_CachePic_Flags("gfx/conchars", CACHEPICFLAG_NOCOMPRESSION | (r_nearest_conchars.integer ? CACHEPICFLAG_NEAREST : 0))->tex; strlcpy(widthfile, "gfx/conchars.width", sizeof(widthfile)); } else @@ -1012,7 +1018,7 @@ static void gl_draw_start(void) LoadFont(false, va(vabuf, sizeof(vabuf), "gfx/font_%s", dp_fonts.f[i].title), &dp_fonts.f[i], 1, 0); // draw the loading screen so people have something to see in the newly opened window - SCR_UpdateLoadingScreen(true); + SCR_UpdateLoadingScreen(true, true); } static void gl_draw_shutdown(void) @@ -1044,6 +1050,8 @@ void GL_Draw_Init (void) Cvar_RegisterVariable(&r_textshadow); Cvar_RegisterVariable(&r_textbrightness); Cvar_RegisterVariable(&r_textcontrast); + Cvar_RegisterVariable(&r_nearest_2d); + Cvar_RegisterVariable(&r_nearest_conchars); // allocate fonts storage fonts_mempool = Mem_AllocPool("FONTS", 0, NULL); @@ -1709,10 +1717,20 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma //thisw = fnt->width_of[num]; thisw = fnt->width_of[ch]; // FIXME make these smaller to just include the occupied part of the character for slightly faster rendering - s = (ch & 15)*0.0625f + (0.5f / tw); - t = (ch >> 4)*0.0625f + (0.5f / th); - u = 0.0625f * thisw - (1.0f / tw); - v = 0.0625f - (1.0f / th); + if (r_nearest_conchars.integer) + { + s = (ch & 15)*0.0625f; + t = (ch >> 4)*0.0625f; + u = 0.0625f * thisw; + v = 0.0625f; + } + else + { + s = (ch & 15)*0.0625f + (0.5f / tw); + t = (ch >> 4)*0.0625f + (0.5f / th); + u = 0.0625f * thisw - (1.0f / tw); + v = 0.0625f - (1.0f / th); + } ac[ 0] = DrawQ_Color[0];ac[ 1] = DrawQ_Color[1];ac[ 2] = DrawQ_Color[2];ac[ 3] = DrawQ_Color[3]; ac[ 4] = DrawQ_Color[0];ac[ 5] = DrawQ_Color[1];ac[ 6] = DrawQ_Color[2];ac[ 7] = DrawQ_Color[3]; ac[ 8] = DrawQ_Color[0];ac[ 9] = DrawQ_Color[1];ac[10] = DrawQ_Color[2];ac[11] = DrawQ_Color[3]; @@ -1913,10 +1931,10 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height width = pic->width; if (height == 0) height = pic->height; - R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false); + R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, (flags & (DRAWFLAGS_BLEND | DRAWFLAG_NOGAMMA)) ? false : true, true, false); } else - R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true); + R_SetupShader_Generic_NoTexture((flags & (DRAWFLAGS_BLEND | DRAWFLAG_NOGAMMA)) ? false : true, true); floats[2] = floats[5] = floats[8] = floats[11] = 0; floats[0] = floats[9] = x; diff --git a/misc/source/darkplaces-src/gl_rmain.c b/misc/source/darkplaces-src/gl_rmain.c index 6c26b8de..184aa423 100644 --- a/misc/source/darkplaces-src/gl_rmain.c +++ b/misc/source/darkplaces-src/gl_rmain.c @@ -645,9 +645,6 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] = {"#define USEOFFSETMAPPING\n", " offsetmapping"}, {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"}, {"#define USESHADOWMAP2D\n", " shadowmap2d"}, - {"#define USESHADOWMAPPCF 1\n", " shadowmappcf"}, // TODO make this a static parm - {"#define USESHADOWMAPPCF 2\n", " shadowmappcf2"}, // TODO make this a static parm - {"#define USESHADOWSAMPLER\n", " shadowsampler"}, // TODO make this a static parm {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm {"#define USESHADOWMAPORTHO\n", " shadowmaportho"}, {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"}, @@ -658,6 +655,7 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] = {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm {"#define USETRIPPY\n", " trippy"}, {"#define USEDEPTHRGB\n", " depthrgb"}, + {"#define USEALPHAGENVERTEX\n", "alphagenvertex"} }; // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS! @@ -852,15 +850,21 @@ enum SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5, ///< postprocess uservec4 is enabled SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7, ///< LOD for offsetmapping + SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1 + SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2 + SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler }; -#define SHADERSTATICPARMS_COUNT 8 +#define SHADERSTATICPARMS_COUNT 11 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT]; static int shaderstaticparms_count = 0; static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0}; #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F)) -static qboolean R_CompileShader_CheckStaticParms(void) + +extern qboolean r_shadow_shadowmapsampler; +extern int r_shadow_shadowmappcf; +qboolean R_CompileShader_CheckStaticParms(void) { static int r_compileshader_staticparms_save[1]; memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms)); @@ -886,6 +890,14 @@ static qboolean R_CompileShader_CheckStaticParms(void) } if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0) R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD); + + if (r_shadow_shadowmapsampler) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER); + if (r_shadow_shadowmappcf > 1) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2); + else if (r_shadow_shadowmappcf) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1); + return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0; } @@ -907,6 +919,9 @@ static void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permu R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4"); R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS"); R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER"); } /// information about each possible shader permutation @@ -1786,7 +1801,7 @@ static void R_SetupShader_SetPermutationSoft(unsigned int mode, unsigned int per DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_ClientTime, cl.time); } -static void R_GLSL_Restart_f(void) +void R_GLSL_Restart_f(void) { unsigned int i, limit; if (glslshaderstring && glslshaderstring != builtinshaderstring) @@ -2047,8 +2062,6 @@ extern qboolean r_shadow_usingshadowmaportho; extern float r_shadow_shadowmap_texturescale[2]; extern float r_shadow_shadowmap_parameters[4]; extern qboolean r_shadow_shadowmapvsdct; -extern qboolean r_shadow_shadowmapsampler; -extern int r_shadow_shadowmappcf; extern rtexture_t *r_shadow_shadowmap2ddepthbuffer; extern rtexture_t *r_shadow_shadowmap2ddepthtexture; extern rtexture_t *r_shadow_shadowmapvsdcttexture; @@ -2133,6 +2146,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER) { mode = SHADERMODE_WATER; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; if((r_wateralpha.value < 1) && (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERALPHA)) { // this is the right thing to do for wateralpha @@ -2149,15 +2164,17 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFRACTION) { mode = SHADERMODE_REFRACTION; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { mode = SHADERMODE_GENERIC; - permutation |= SHADERPERMUTATION_DIFFUSE; - GL_BlendFunc(GL_ONE, GL_ZERO); - blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO); + permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL; + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } if (vid.allowalphatocoverage) GL_AlphaToCoverage(false); @@ -2197,6 +2214,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; // light source mode = SHADERMODE_LIGHTSOURCE; if (rsurface.rtlight->currentcubemap != r_texture_whitecube) @@ -2215,12 +2234,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, if(r_shadow_shadowmapvsdct) permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT; - if (r_shadow_shadowmapsampler) - permutation |= SHADERPERMUTATION_SHADOWSAMPLER; - if (r_shadow_shadowmappcf > 1) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF2; - else if (r_shadow_shadowmappcf) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF; if (r_shadow_shadowmap2ddepthbuffer) permutation |= SHADERPERMUTATION_DEPTHRGB; } @@ -2245,10 +2258,12 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; // unshaded geometry (fullbright or ambient model lighting) mode = SHADERMODE_FLATCOLOR; ambientscale = diffusescale = specularscale = 0; - if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) + if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) permutation |= SHADERPERMUTATION_GLOW; if (r_refdef.fogenabled) permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE); @@ -2259,12 +2274,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, permutation |= SHADERPERMUTATION_SHADOWMAPORTHO; permutation |= SHADERPERMUTATION_SHADOWMAP2D; - if (r_shadow_shadowmapsampler) - permutation |= SHADERPERMUTATION_SHADOWSAMPLER; - if (r_shadow_shadowmappcf > 1) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF2; - else if (r_shadow_shadowmappcf) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF; if (r_shadow_shadowmap2ddepthbuffer) permutation |= SHADERPERMUTATION_DEPTHRGB; } @@ -2300,9 +2309,11 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; // directional model lighting mode = SHADERMODE_LIGHTDIRECTION; - if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) + if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) permutation |= SHADERPERMUTATION_GLOW; permutation |= SHADERPERMUTATION_DIFFUSE; if (specularscale > 0) @@ -2316,12 +2327,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, permutation |= SHADERPERMUTATION_SHADOWMAPORTHO; permutation |= SHADERPERMUTATION_SHADOWMAP2D; - if (r_shadow_shadowmapsampler) - permutation |= SHADERPERMUTATION_SHADOWSAMPLER; - if (r_shadow_shadowmappcf > 1) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF2; - else if (r_shadow_shadowmappcf) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF; if (r_shadow_shadowmap2ddepthbuffer) permutation |= SHADERPERMUTATION_DEPTHRGB; } @@ -2365,9 +2370,11 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; // ambient model lighting mode = SHADERMODE_LIGHTDIRECTION; - if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) + if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) permutation |= SHADERPERMUTATION_GLOW; if (r_refdef.fogenabled) permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE); @@ -2378,12 +2385,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, permutation |= SHADERPERMUTATION_SHADOWMAPORTHO; permutation |= SHADERPERMUTATION_SHADOWMAP2D; - if (r_shadow_shadowmapsampler) - permutation |= SHADERPERMUTATION_SHADOWSAMPLER; - if (r_shadow_shadowmappcf > 1) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF2; - else if (r_shadow_shadowmappcf) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF; if (r_shadow_shadowmap2ddepthbuffer) permutation |= SHADERPERMUTATION_DEPTHRGB; } @@ -2427,8 +2428,10 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, } if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; // lightmapped wall - if (rsurface.texture->glowtexture && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) + if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) permutation |= SHADERPERMUTATION_GLOW; if (r_refdef.fogenabled) permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE); @@ -2439,12 +2442,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, permutation |= SHADERPERMUTATION_SHADOWMAPORTHO; permutation |= SHADERPERMUTATION_SHADOWMAP2D; - if (r_shadow_shadowmapsampler) - permutation |= SHADERPERMUTATION_SHADOWSAMPLER; - if (r_shadow_shadowmappcf > 1) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF2; - else if (r_shadow_shadowmappcf) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF; if (r_shadow_shadowmap2ddepthbuffer) permutation |= SHADERPERMUTATION_DEPTHRGB; } @@ -2621,7 +2618,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer) ); - hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer); + hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality); hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_Bias, rsurface.texture->offsetbias); hlslPSSetParameter2f(D3DPSREGISTER_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]); hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height); @@ -2782,7 +2779,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer) ); - if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer); + if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality); if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, rsurface.texture->offsetbias); if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]); if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height); @@ -2928,7 +2925,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer) ); - DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality); DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_Bias, rsurface.texture->offsetbias); DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]); DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height); @@ -3008,12 +3005,6 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight) if (r_shadow_shadowmapvsdct) permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT; - if (r_shadow_shadowmapsampler) - permutation |= SHADERPERMUTATION_SHADOWSAMPLER; - if (r_shadow_shadowmappcf > 1) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF2; - else if (r_shadow_shadowmappcf) - permutation |= SHADERPERMUTATION_SHADOWMAPPCF; if (r_shadow_shadowmap2ddepthbuffer) permutation |= SHADERPERMUTATION_DEPTHRGB; } @@ -3309,7 +3300,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole Image_StripImageExtension(name, basename, sizeof(basename)); // check for DDS texture file first - if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel))) + if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false))) { basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel); if (basepixels == NULL) @@ -3343,7 +3334,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole skinframe->hasalpha = ddshasalpha; VectorCopy(ddsavgcolor, skinframe->avgcolor); if (r_loadfog && skinframe->hasalpha) - skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel); + skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true); //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); } else @@ -3390,13 +3381,13 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole { mymiplevel = savemiplevel; if (r_loadnormalmap) - skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel); - skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel); + skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true); + skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); if (r_loadgloss) - skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel); - skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel); - skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel); - skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel); + skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); + skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); + skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); + skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); } // _norm is the name used by tenebrae and has been adopted as standard @@ -4740,12 +4731,12 @@ static void R_View_UpdateEntityLighting (void) { ent = r_refdef.scene.entities[i]; - // skip unseen models and models that updated by CSQC - if ((!r_refdef.viewcache.entityvisible[i] && skipunseen) || ent->flags & RENDER_CUSTOMIZEDMODELLIGHT) + // skip unseen models + if ((!r_refdef.viewcache.entityvisible[i] && skipunseen)) continue; // skip bsp models - if (ent->model && (ent->model == cl.worldmodel || ent->model->brush.parentmodel == cl.worldmodel)) + if (ent->model && ent->model == cl.worldmodel) { // TODO: use modellight for r_ambient settings on world? VectorSet(ent->modellight_ambient, 0, 0, 0); @@ -4753,74 +4744,83 @@ static void R_View_UpdateEntityLighting (void) VectorSet(ent->modellight_lightdir, 0, 0, 1); continue; } - - // fetch the lighting from the worldmodel data - VectorClear(ent->modellight_ambient); - VectorClear(ent->modellight_diffuse); - VectorClear(tempdiffusenormal); - if (ent->flags & RENDER_LIGHT) + + if (ent->flags & RENDER_CUSTOMIZEDMODELLIGHT) { - vec3_t org; - Matrix4x4_OriginFromMatrix(&ent->matrix, org); - - // complete lightning for lit sprites - // todo: make a EF_ field so small ents could be lit purely by modellight and skipping real rtlight pass (like EF_NORTLIGHT)? - if (ent->model->type == mod_sprite && !(ent->model->data_textures[0].basematerialflags & MATERIALFLAG_FULLBRIGHT)) + // aleady updated by CSQC + // TODO: force modellight on BSP models in this case? + VectorCopy(ent->modellight_lightdir, tempdiffusenormal); + } + else + { + // fetch the lighting from the worldmodel data + VectorClear(ent->modellight_ambient); + VectorClear(ent->modellight_diffuse); + VectorClear(tempdiffusenormal); + if (ent->flags & RENDER_LIGHT) { - if (ent->model->sprite.sprnum_type == SPR_OVERHEAD) // apply offset for overhead sprites - org[2] = org[2] + r_overheadsprites_pushback.value; - R_LightPoint(ent->modellight_ambient, org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT); - } - else - R_CompleteLightPoint(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal, org, LP_LIGHTMAP); + vec3_t org; + Matrix4x4_OriginFromMatrix(&ent->matrix, org); - if(ent->flags & RENDER_EQUALIZE) - { - // first fix up ambient lighting... - if(r_equalize_entities_minambient.value > 0) + // complete lightning for lit sprites + // todo: make a EF_ field so small ents could be lit purely by modellight and skipping real rtlight pass (like EF_NORTLIGHT)? + if (ent->model->type == mod_sprite && !(ent->model->data_textures[0].basematerialflags & MATERIALFLAG_FULLBRIGHT)) + { + if (ent->model->sprite.sprnum_type == SPR_OVERHEAD) // apply offset for overhead sprites + org[2] = org[2] + r_overheadsprites_pushback.value; + R_LightPoint(ent->modellight_ambient, org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT); + } + else + R_CompleteLightPoint(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal, org, LP_LIGHTMAP); + + if(ent->flags & RENDER_EQUALIZE) { - fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2]; - if(fd > 0) + // first fix up ambient lighting... + if(r_equalize_entities_minambient.value > 0) { - fa = (0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]); - if(fa < r_equalize_entities_minambient.value * fd) + fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2]; + if(fd > 0) { - // solve: - // fa'/fd' = minambient - // fa'+0.25*fd' = fa+0.25*fd - // ... - // fa' = fd' * minambient - // fd'*(0.25+minambient) = fa+0.25*fd - // ... - // fd' = (fa+0.25*fd) * 1 / (0.25+minambient) - // fa' = (fa+0.25*fd) * minambient / (0.25+minambient) - // ... - fdd = (fa + 0.25f * fd) / (0.25f + r_equalize_entities_minambient.value); - f = fdd / fd; // f>0 because all this is additive; f<1 because fddmodellight_ambient, (1-f)*0.25f, ent->modellight_diffuse, ent->modellight_ambient); - VectorScale(ent->modellight_diffuse, f, ent->modellight_diffuse); + fa = (0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]); + if(fa < r_equalize_entities_minambient.value * fd) + { + // solve: + // fa'/fd' = minambient + // fa'+0.25*fd' = fa+0.25*fd + // ... + // fa' = fd' * minambient + // fd'*(0.25+minambient) = fa+0.25*fd + // ... + // fd' = (fa+0.25*fd) * 1 / (0.25+minambient) + // fa' = (fa+0.25*fd) * minambient / (0.25+minambient) + // ... + fdd = (fa + 0.25f * fd) / (0.25f + r_equalize_entities_minambient.value); + f = fdd / fd; // f>0 because all this is additive; f<1 because fddmodellight_ambient, (1-f)*0.25f, ent->modellight_diffuse, ent->modellight_ambient); + VectorScale(ent->modellight_diffuse, f, ent->modellight_diffuse); + } } } - } - if(r_equalize_entities_to.value > 0 && r_equalize_entities_by.value != 0) - { - fa = 0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]; - fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2]; - f = fa + 0.25 * fd; - if(f > 0) + if(r_equalize_entities_to.value > 0 && r_equalize_entities_by.value != 0) { - // adjust brightness and saturation to target - avg[0] = avg[1] = avg[2] = fa / f; - VectorLerp(ent->modellight_ambient, r_equalize_entities_by.value, avg, ent->modellight_ambient); - avg[0] = avg[1] = avg[2] = fd / f; - VectorLerp(ent->modellight_diffuse, r_equalize_entities_by.value, avg, ent->modellight_diffuse); + fa = 0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]; + fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2]; + f = fa + 0.25 * fd; + if(f > 0) + { + // adjust brightness and saturation to target + avg[0] = avg[1] = avg[2] = fa / f; + VectorLerp(ent->modellight_ambient, r_equalize_entities_by.value, avg, ent->modellight_ambient); + avg[0] = avg[1] = avg[2] = fd / f; + VectorLerp(ent->modellight_diffuse, r_equalize_entities_by.value, avg, ent->modellight_diffuse); + } } } } + else // highly rare + VectorSet(ent->modellight_ambient, 1, 1, 1); } - else // highly rare - VectorSet(ent->modellight_ambient, 1, 1, 1); // move the light direction into modelspace coordinates for lighting code Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir); @@ -5281,7 +5281,6 @@ static void R_View_UpdateWithScissor(const int *myscissor) R_View_WorldVisibility(r_refdef.view.useclipplane); R_View_UpdateEntityVisible(); R_View_UpdateEntityLighting(); - R_AnimCache_CacheVisibleEntities(); } static void R_View_Update(void) @@ -5291,7 +5290,6 @@ static void R_View_Update(void) R_View_WorldVisibility(r_refdef.view.useclipplane); R_View_UpdateEntityVisible(); R_View_UpdateEntityLighting(); - R_AnimCache_CacheVisibleEntities(); } float viewscalefpsadjusted = 1.0f; @@ -5835,6 +5833,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t R_View_UpdateWithScissor(myscissor); else R_View_Update(); + R_AnimCache_CacheVisibleEntities(); if(r_water_scissormode.integer & 1) GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]); R_RenderScene(p->fbo_reflection, r_fb.water.depthtexture, p->texture_reflection); @@ -5883,6 +5882,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t R_View_UpdateWithScissor(myscissor); else R_View_Update(); + R_AnimCache_CacheVisibleEntities(); if(r_water_scissormode.integer & 1) GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]); R_RenderScene(p->fbo_refraction, r_fb.water.depthtexture, p->texture_refraction); @@ -5937,6 +5937,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t R_ResetViewRendering3D(p->fbo_camera, r_fb.water.depthtexture, p->texture_camera); R_ClearScreen(r_refdef.fogenabled); R_View_Update(); + R_AnimCache_CacheVisibleEntities(); R_RenderScene(p->fbo_camera, r_fb.water.depthtexture, p->texture_camera); if (!p->fbo_camera) @@ -5952,6 +5953,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t if (!r_fb.water.depthtexture) R_ClearScreen(r_refdef.fogenabled); R_View_Update(); + R_AnimCache_CacheVisibleEntities(); goto finish; error: r_refdef.view = originalview; @@ -6045,7 +6047,7 @@ static void R_Bloom_StartFrame(void) // set bloomwidth and bloomheight to the bloom resolution that will be // used (often less than the screen resolution for faster rendering) - r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.height); + r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width); r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width; r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height); r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d); @@ -6151,7 +6153,7 @@ static void R_Bloom_StartFrame(void) } // bloom texture is a different resolution - r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.height); + r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width); r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width; r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height); r_fb.bloomwidth = bound(1, r_fb.bloomwidth, r_fb.bloomtexturewidth); @@ -6168,6 +6170,14 @@ static void R_Bloom_StartFrame(void) r_fb.screentexcoord2f[6] = 0; r_fb.screentexcoord2f[7] = 0; + if(r_fb.fbo) + { + for (i = 1;i < 8;i += 2) + { + r_fb.screentexcoord2f[i] += 1 - (float)(viewheight + r_refdef.view.y) / (float)r_fb.screentextureheight; + } + } + // set up a texcoord array for the reduced resolution bloom image // (which will be additive blended over the screen image) r_fb.bloomtexcoord2f[0] = 0; @@ -6191,20 +6201,17 @@ static void R_Bloom_StartFrame(void) case RENDERPATH_D3D9: case RENDERPATH_D3D10: case RENDERPATH_D3D11: + for (i = 0;i < 4;i++) { - int i; - for (i = 0;i < 4;i++) - { - r_fb.screentexcoord2f[i*2+0] += 0.5f / (float)r_fb.screentexturewidth; - r_fb.screentexcoord2f[i*2+1] += 0.5f / (float)r_fb.screentextureheight; - r_fb.bloomtexcoord2f[i*2+0] += 0.5f / (float)r_fb.bloomtexturewidth; - r_fb.bloomtexcoord2f[i*2+1] += 0.5f / (float)r_fb.bloomtextureheight; - } + r_fb.screentexcoord2f[i*2+0] += 0.5f / (float)r_fb.screentexturewidth; + r_fb.screentexcoord2f[i*2+1] += 0.5f / (float)r_fb.screentextureheight; + r_fb.bloomtexcoord2f[i*2+0] += 0.5f / (float)r_fb.bloomtexturewidth; + r_fb.bloomtexcoord2f[i*2+1] += 0.5f / (float)r_fb.bloomtextureheight; } break; } - R_Viewport_InitOrtho(&r_fb.bloomviewport, &identitymatrix, r_refdef.view.x, (r_fb.bloomfbo[0] ? r_fb.bloomtextureheight : vid.height) - r_fb.bloomheight - r_refdef.view.y, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL); + R_Viewport_InitOrtho(&r_fb.bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL); if (r_fb.fbo) r_refdef.view.clear = true; @@ -6218,18 +6225,22 @@ static void R_Bloom_MakeTexture(void) float colorscale = r_bloom_colorscale.value; r_refdef.stats.bloom++; - + +#if 0 + // this copy is unnecessary since it happens in R_BlendView already if (!r_fb.fbo) { R_Mesh_CopyToTexture(r_fb.colortexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height; } +#endif // scale down screen texture to the bloom texture size CHECKGLERROR r_fb.bloomindex = 0; R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL); R_SetViewport(&r_fb.bloomviewport); + GL_DepthTest(false); GL_BlendFunc(GL_ONE, GL_ZERO); GL_Color(colorscale, colorscale, colorscale, 1); // D3D has upside down Y coords, the easiest way to flip this is to flip the screen vertices rather than the texcoords, so we just use a different array for that... @@ -6269,9 +6280,19 @@ static void R_Bloom_MakeTexture(void) r_fb.bloomindex ^= 1; R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL); x *= 2; - r = bound(0, r_bloom_colorexponent.value / x, 1); - GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); - GL_Color(r,r,r,1); + r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1 + if (!r_fb.bloomfbo[r_fb.bloomindex]) + { + GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); // square it and multiply by two + GL_Color(r,r,r,1); // apply fix factor + } + else + { + if(x <= 2) + GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128); + GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it + GL_Color(1,1,1,1); // no fix factor supported here + } R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.bloomtexcoord2f); R_SetupShader_Generic(intex, NULL, GL_MODULATE, 1, false, true, false); R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); @@ -6308,14 +6329,14 @@ static void R_Bloom_MakeTexture(void) xoffset /= (float)r_fb.bloomtexturewidth; yoffset /= (float)r_fb.bloomtextureheight; // compute a texcoord array with the specified x and y offset - r_fb.offsettexcoord2f[0] = xoffset+0; - r_fb.offsettexcoord2f[1] = yoffset+(float)r_fb.bloomheight / (float)r_fb.bloomtextureheight; - r_fb.offsettexcoord2f[2] = xoffset+(float)r_fb.bloomwidth / (float)r_fb.bloomtexturewidth; - r_fb.offsettexcoord2f[3] = yoffset+(float)r_fb.bloomheight / (float)r_fb.bloomtextureheight; - r_fb.offsettexcoord2f[4] = xoffset+(float)r_fb.bloomwidth / (float)r_fb.bloomtexturewidth; - r_fb.offsettexcoord2f[5] = yoffset+0; - r_fb.offsettexcoord2f[6] = xoffset+0; - r_fb.offsettexcoord2f[7] = yoffset+0; + r_fb.offsettexcoord2f[0] = xoffset+r_fb.bloomtexcoord2f[0]; + r_fb.offsettexcoord2f[1] = yoffset+r_fb.bloomtexcoord2f[1]; + r_fb.offsettexcoord2f[2] = xoffset+r_fb.bloomtexcoord2f[2]; + r_fb.offsettexcoord2f[3] = yoffset+r_fb.bloomtexcoord2f[3]; + r_fb.offsettexcoord2f[4] = xoffset+r_fb.bloomtexcoord2f[4]; + r_fb.offsettexcoord2f[5] = yoffset+r_fb.bloomtexcoord2f[5]; + r_fb.offsettexcoord2f[6] = xoffset+r_fb.bloomtexcoord2f[6]; + r_fb.offsettexcoord2f[7] = yoffset+r_fb.bloomtexcoord2f[7]; // this r value looks like a 'dot' particle, fading sharply to // black at the edges // (probably not realistic but looks good enough) @@ -6682,6 +6703,10 @@ void R_UpdateVariables(void) { r_refdef.lightmapintensity *= r_fakelight_intensity.value; } + else if (r_refdef.scene.worldmodel) + { + r_refdef.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale; + } if (r_showsurfaces.integer) { r_refdef.scene.rtworld = false; @@ -6908,6 +6933,10 @@ void R_RenderView(void) if (r_timereport_active) R_TimeReport("visibility"); + R_AnimCache_CacheVisibleEntities(); + if (r_timereport_active) + R_TimeReport("animcache"); + R_Shadow_UpdateBounceGridTexture(); if (r_timereport_active && r_shadow_bouncegrid.integer) R_TimeReport("bouncegrid"); @@ -7276,6 +7305,7 @@ static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtligh case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break; case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break; case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break; + case SOLID_CORPSE: Vector4Set(color, 1, 0.5, 0, 0.05);break; default: Vector4Set(color, 0, 0, 0, 0.50);break; } color[3] *= r_showbboxes.value; @@ -7727,7 +7757,7 @@ texture_t *R_GetCurrentTexture(texture_t *t) dp_model_t *model = ent->model; q3shaderinfo_layer_tcmod_t *tcmod; - if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent) + if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate) return t->currentframe; t->update_lastrenderframe = r_textureframe; t->update_lastrenderentity = (void *)ent; @@ -7800,7 +7830,7 @@ texture_t *R_GetCurrentTexture(texture_t *t) { // no modellight if using fakelight for the map } - else if (rsurface.modeltexcoordlightmap2f == NULL && !(t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) + else if ((rsurface.modeltexcoordlightmap2f == NULL || (rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT))) && !(t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) { // pick a model lighting mode if (VectorLength2(rsurface.modellight_diffuse) >= (1.0f / 256.0f)) @@ -7876,6 +7906,11 @@ texture_t *R_GetCurrentTexture(texture_t *t) t->backgroundglowtexture = t->backgroundcurrentskinframe->glow; if (!t->backgroundnmaptexture) t->backgroundnmaptexture = r_texture_blanknormalmap; + // make sure that if glow is going to be used, both textures are not NULL + if (!t->backgroundglowtexture && t->glowtexture) + t->backgroundglowtexture = r_texture_black; + if (!t->glowtexture && t->backgroundglowtexture) + t->glowtexture = r_texture_black; } else { @@ -7959,7 +7994,7 @@ texture_t *R_GetCurrentTexture(texture_t *t) blendfunc2 = GL_ZERO; } // don't colormod evilblend textures - if(!R_BlendFuncFlags(blendfunc1, blendfunc2) & BLENDFUNC_ALLOWS_COLORMOD) + if(!(R_BlendFuncFlags(blendfunc1, blendfunc2) & BLENDFUNC_ALLOWS_COLORMOD)) VectorSet(t->lightmapcolor, 1, 1, 1); depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED); if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) @@ -8137,6 +8172,7 @@ void RSurf_ActiveWorldEntity(void) rsurface.passcolor4f = NULL; rsurface.passcolor4f_vertexbuffer = NULL; rsurface.passcolor4f_bufferoffset = 0; + rsurface.forcecurrenttextureupdate = false; } void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass) @@ -8310,6 +8346,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q rsurface.passcolor4f = NULL; rsurface.passcolor4f_vertexbuffer = NULL; rsurface.passcolor4f_bufferoffset = 0; + rsurface.forcecurrenttextureupdate = false; } void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents) @@ -8433,6 +8470,7 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve rsurface.passcolor4f = NULL; rsurface.passcolor4f_vertexbuffer = NULL; rsurface.passcolor4f_bufferoffset = 0; + rsurface.forcecurrenttextureupdate = true; if (rsurface.modelnumvertices && rsurface.modelelement3i) { @@ -11779,10 +11817,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr } } } - if (update) - for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++) - if (update[j]) - R_BuildLightMap(ent, surfaces + j); + R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass); // add to stats if desired diff --git a/misc/source/darkplaces-src/gl_rsurf.c b/misc/source/darkplaces-src/gl_rsurf.c index bc378401..2d0f4795 100644 --- a/misc/source/darkplaces-src/gl_rsurf.c +++ b/misc/source/darkplaces-src/gl_rsurf.c @@ -1586,7 +1586,6 @@ static void R_ReplaceWorldTexture (void) if ((skinframe = R_SkinFrame_LoadExternal(newt, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PICMIP, true))) { // t->skinframes[0] = skinframe; - t->currentskinframe = skinframe; t->currentskinframe = skinframe; Con_Printf("%s replaced with %s\n", r, newt); } diff --git a/misc/source/darkplaces-src/gl_textures.c b/misc/source/darkplaces-src/gl_textures.c index 2a81cf50..57c257f2 100644 --- a/misc/source/darkplaces-src/gl_textures.c +++ b/misc/source/darkplaces-src/gl_textures.c @@ -38,7 +38,7 @@ cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_re cvar_t gl_texturecompression_sprites = {CVAR_SAVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"}; cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "0", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"}; cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambiguous, 2: texture format only"}; -cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log"}; +cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log, 0: done log, 1: log with no optional textures (_norm, glow etc.). 2: log all"}; cvar_t r_texture_dds_swdecode = {0, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"}; qboolean gl_filter_force = false; @@ -2069,7 +2069,7 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco mipinfo[0][0] = glt->tilewidth; mipinfo[0][1] = glt->tileheight; mipmaps = 1; - if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tilewidth == 1)) + if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1)) { for (mip = 1;mip < 16;mip++) { @@ -2148,7 +2148,7 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco #endif } -rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint +rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel, qboolean optionaltexture) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint { int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height; //int dds_flags; @@ -2167,7 +2167,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen unsigned char *dds; fs_offset_t ddsfilesize; unsigned int ddssize; - qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1); + qboolean force_swdecode, npothack; if (cls.state == ca_dedicated) return NULL; @@ -2177,7 +2177,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen if (!dds) { - if(r_texture_dds_load_logfailure.integer) + if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture)) Log_Printf("ddstexturefailures.log", "%s\n", filename); return NULL; // not found } @@ -2344,9 +2344,17 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen } force_swdecode = false; + npothack = + (!vid.support.arb_texture_non_power_of_two && + ( + (dds_width & (dds_width - 1)) + || + (dds_height & (dds_height - 1)) + ) + ); if(bytesperblock) { - if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc) + if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && !npothack) { if(r_texture_dds_swdecode.integer > 1) force_swdecode = true; @@ -2457,7 +2465,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F); avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F); if(textype == TEXTYPE_DXT5) - avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]); + avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f); else if(textype == TEXTYPE_DXT3) avgcolor[3] += ( (mippixels_start[i-8] & 0x0F) @@ -2468,11 +2476,11 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen + (mippixels_start[i-6] >> 4) + (mippixels_start[i-5] & 0x0F) + (mippixels_start[i-5] >> 4) - ) * (0.125f / 15.0f * 255.0f); + ) * (0.125f / 15.0f); else - avgcolor[3] += 255; + avgcolor[3] += 1.0f; } - f = (float)bytesperblock / size; + f = (float)bytesperblock / mipsize; avgcolor[0] *= (0.5f / 31.0f) * f; avgcolor[1] *= (0.5f / 63.0f) * f; avgcolor[2] *= (0.5f / 31.0f) * f; @@ -2487,7 +2495,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen avgcolor[2] += mippixels[i]; avgcolor[3] += mippixels[i+3]; } - f = (1.0f / 255.0f) * bytesperpixel / size; + f = (1.0f / 255.0f) * bytesperpixel / mipsize; avgcolor[0] *= f; avgcolor[1] *= f; avgcolor[2] *= f; @@ -2624,6 +2632,12 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen glt->tiledepth = 1; glt->miplevels = dds_miplevels; + if(npothack) + { + for (glt->tilewidth = 1;glt->tilewidth < mipwidth;glt->tilewidth <<= 1); + for (glt->tileheight = 1;glt->tileheight < mipheight;glt->tileheight <<= 1); + } + // texture uploading can take a while, so make sure we're sending keepalives CL_KeepaliveMessage(false); @@ -2678,9 +2692,25 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel { + unsigned char *upload_mippixels = mippixels; + int upload_mipwidth = mipwidth; + int upload_mipheight = mipheight; mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel; if (mippixels + mipsize > mippixels_start + mipsize_total) break; + if(npothack) + { + upload_mipwidth = (glt->tilewidth >> mip); + upload_mipheight = (glt->tileheight >> mip); + if(upload_mipwidth != mipwidth || upload_mipheight != mipheight) + // I _think_ they always mismatch, but I was too lazy + // to properly check, and this test here is really + // harmless + { + upload_mippixels = (unsigned char *) Mem_Alloc(tempmempool, 4 * upload_mipwidth * upload_mipheight); + Image_Resample32(mippixels, mipwidth, mipheight, 1, upload_mippixels, upload_mipwidth, upload_mipheight, 1, r_lerpimages.integer); + } + } switch(vid.renderpath) { case RENDERPATH_GL11: @@ -2690,11 +2720,11 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen case RENDERPATH_GLES2: if (bytesperblock) { - qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR + qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR } else { - qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR + qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR } break; case RENDERPATH_D3D9: @@ -2703,7 +2733,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen D3DLOCKED_RECT d3dlockedrect; if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits) { - memcpy(d3dlockedrect.pBits, mippixels, mipsize); + memcpy(d3dlockedrect.pBits, upload_mippixels, mipsize); IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip); } break; @@ -2720,11 +2750,13 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen if (bytesperblock) Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); else - DPSOFTRAST_Texture_UpdateFull(glt->texnum, mippixels); + DPSOFTRAST_Texture_UpdateFull(glt->texnum, upload_mippixels); // DPSOFTRAST calculates its own mipmaps mip = dds_miplevels; break; } + if(upload_mippixels != mippixels) + Mem_Free(upload_mippixels); mippixels += mipsize; if (mipwidth <= 1 && mipheight <= 1) { diff --git a/misc/source/darkplaces-src/host.c b/misc/source/darkplaces-src/host.c index a8a8e0de..2e503035 100644 --- a/misc/source/darkplaces-src/host.c +++ b/misc/source/darkplaces-src/host.c @@ -66,11 +66,13 @@ cvar_t cl_maxphysicsframesperserverframe = {0, "cl_maxphysicsframesperserverfram cvar_t host_speeds = {0, "host_speeds","0", "reports how much time is used in server/graphics/sound"}; cvar_t host_maxwait = {0, "host_maxwait","1000", "maximum sleep time requested from the operating system in millisecond. Larger sleeps will be done using multiple host_maxwait length sleeps. Lowering this value will increase CPU load, but may help working around problems with accuracy of sleep times."}; cvar_t cl_minfps = {CVAR_SAVE, "cl_minfps", "40", "minimum fps target - while the rendering performance is below this, it will drift toward lower quality"}; -cvar_t cl_minfps_fade = {CVAR_SAVE, "cl_minfps_fade", "0.2", "how fast the quality adapts to varying framerate"}; +cvar_t cl_minfps_fade = {CVAR_SAVE, "cl_minfps_fade", "1", "how fast the quality adapts to varying framerate"}; cvar_t cl_minfps_qualitymax = {CVAR_SAVE, "cl_minfps_qualitymax", "1", "highest allowed drawdistance multiplier"}; cvar_t cl_minfps_qualitymin = {CVAR_SAVE, "cl_minfps_qualitymin", "0.25", "lowest allowed drawdistance multiplier"}; -cvar_t cl_minfps_qualitypower = {CVAR_SAVE, "cl_minfps_qualitypower", "4", "raises quality value to a power of itself, higher values make quality drop more sharply in relation to framerate"}; -cvar_t cl_minfps_qualityscale = {CVAR_SAVE, "cl_minfps_qualityscale", "0.5", "multiplier for quality"}; +cvar_t cl_minfps_qualitymultiply = {CVAR_SAVE, "cl_minfps_qualitymultiply", "0.2", "multiplier for quality changes in quality change per second render time (1 assumes linearity of quality and render time)"}; +cvar_t cl_minfps_qualityhysteresis = {CVAR_SAVE, "cl_minfps_qualityhysteresis", "0.05", "reduce all quality increments by this to reduce flickering"}; +cvar_t cl_minfps_qualitystepmax = {CVAR_SAVE, "cl_minfps_qualitystepmax", "0.1", "maximum quality change in a single frame"}; +cvar_t cl_minfps_force = {0, "cl_minfps_force", "0", "also apply quality reductions in timedemo/capturevideo"}; cvar_t cl_maxfps = {CVAR_SAVE, "cl_maxfps", "0", "maximum fps cap, 0 = unlimited, if game is running faster than this it will wait before running another frame (useful to make cpu time available to other programs)"}; cvar_t cl_maxfps_alwayssleep = {0, "cl_maxfps_alwayssleep","1", "gives up some processing time to other applications each frame, value in milliseconds, disabled if cl_maxfps is 0"}; cvar_t cl_maxidlefps = {CVAR_SAVE, "cl_maxidlefps", "20", "maximum fps cap when the game is not the active window (makes cpu time available to other programs"}; @@ -240,8 +242,10 @@ static void Host_InitLocal (void) Cvar_RegisterVariable (&cl_minfps_fade); Cvar_RegisterVariable (&cl_minfps_qualitymax); Cvar_RegisterVariable (&cl_minfps_qualitymin); - Cvar_RegisterVariable (&cl_minfps_qualitypower); - Cvar_RegisterVariable (&cl_minfps_qualityscale); + Cvar_RegisterVariable (&cl_minfps_qualitystepmax); + Cvar_RegisterVariable (&cl_minfps_qualityhysteresis); + Cvar_RegisterVariable (&cl_minfps_qualitymultiply); + Cvar_RegisterVariable (&cl_minfps_force); Cvar_RegisterVariable (&cl_maxfps); Cvar_RegisterVariable (&cl_maxfps_alwayssleep); Cvar_RegisterVariable (&cl_maxidlefps); @@ -663,6 +667,7 @@ void Host_Main(void) double wait; int pass1, pass2, pass3, i; char vabuf[1024]; + qboolean playing; Host_Init(); @@ -702,14 +707,15 @@ void Host_Main(void) svs.perf_acc_realtime += deltacleantime; // Look for clients who have spawned + playing = false; for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) if(host_client->spawned) if(host_client->netconnection) - break; - if(i == svs.maxclients) + playing = true; + if(sv.time < 10) { - // Nobody is looking? Then we won't do timing... - // Instead, reset it to zero + // don't accumulate time for the first 10 seconds of a match + // so things can settle svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0; } else if(svs.perf_acc_realtime > 5) @@ -723,7 +729,8 @@ void Host_Main(void) svs.perf_offset_sdev = sqrt(svs.perf_acc_offset_squared / svs.perf_acc_offset_samples - svs.perf_offset_avg * svs.perf_offset_avg); } if(svs.perf_lost > 0 && developer_extra.integer) - Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf))); + if(playing) // only complain if anyone is looking + Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf))); svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0; } } @@ -1100,17 +1107,19 @@ void Host_LockSession(void) if(locksession.integer != 0) { char vabuf[1024]; - locksession_fh = FS_SysOpen(va(vabuf, sizeof(vabuf), "%slock%s", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string), "wl", false); + char *p = va(vabuf, sizeof(vabuf), "%slock%s", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string); + FS_CreatePath(p); + locksession_fh = FS_SysOpen(p, "wl", false); // TODO maybe write the pid into the lockfile, while we are at it? may help server management tools if(!locksession_fh) { if(locksession.integer == 2) { - Con_Printf("WARNING: session lock %slock%s could not be acquired. Please run with -sessionid and an unique session name. Continuing anyway.\n", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string); + Con_Printf("WARNING: session lock %s could not be acquired. Please run with -sessionid and an unique session name. Continuing anyway.\n", p); } else { - Sys_Error("session lock %slock%s could not be acquired. Please run with -sessionid and an unique session name.\n", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string); + Sys_Error("session lock %s could not be acquired. Please run with -sessionid and an unique session name.\n", p); } } } @@ -1291,7 +1300,7 @@ static void Host_Init (void) } // put up the loading image so the user doesn't stare at a black screen... - SCR_BeginLoadingPlaque(); + SCR_BeginLoadingPlaque(true); if (cls.state != ca_dedicated) { @@ -1336,7 +1345,7 @@ static void Host_Init (void) if (!sv.active && !cls.demoplayback && !cls.connect_trying) { - Cbuf_AddText("togglemenu\n"); + Cbuf_AddText("togglemenu 1\n"); Cbuf_Execute(); } diff --git a/misc/source/darkplaces-src/host_cmd.c b/misc/source/darkplaces-src/host_cmd.c index e5d477cb..350cef0d 100644 --- a/misc/source/darkplaces-src/host_cmd.c +++ b/misc/source/darkplaces-src/host_cmd.c @@ -1716,7 +1716,7 @@ static void Host_Pause_f (void) { if (cmd_source == src_client) { - if(cls.state == ca_dedicated || host_client == &svs.clients[0]) // non-admin + if(cls.state == ca_dedicated || host_client != &svs.clients[0]) // non-admin { print("Pause not allowed.\n"); return; diff --git a/misc/source/darkplaces-src/image.c b/misc/source/darkplaces-src/image.c index 988fbef8..4f85e83e 100644 --- a/misc/source/darkplaces-src/image.c +++ b/misc/source/darkplaces-src/image.c @@ -966,11 +966,13 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo { int mymiplevel2 = miplevel ? *miplevel : 0; data2 = format->loadfunc(f, (int)filesize, &mymiplevel2); - if(mymiplevel != mymiplevel2) - Host_Error("loadimagepixelsbgra: miplevels differ"); + if(data2 && mymiplevel == mymiplevel2) + Image_CopyAlphaFromBlueBGRA(data, data2, image_width, image_height); + else + Con_Printf("loadimagepixelsrgba: corrupt or invalid alpha image %s_alpha\n", basename); + if(data2) + Mem_Free(data2); Mem_Free(f); - Image_CopyAlphaFromBlueBGRA(data, data2, image_width, image_height); - Mem_Free(data2); } } if (developer_loading.integer) diff --git a/misc/source/darkplaces-src/image_png.c b/misc/source/darkplaces-src/image_png.c index 9c03f8f3..f71dfdea 100644 --- a/misc/source/darkplaces-src/image_png.c +++ b/misc/source/darkplaces-src/image_png.c @@ -30,6 +30,7 @@ #include "image.h" #include "image_png.h" + static void (*qpng_set_sig_bytes) (void*, int); static int (*qpng_sig_cmp) (const unsigned char*, size_t, size_t); static void* (*qpng_create_read_struct) (const char*, void*, void(*)(void *png, const char *message), void(*)(void *png, const char *message)); @@ -64,6 +65,18 @@ static void (*qpng_write_info) (void*, void*); static void (*qpng_write_row) (void*, unsigned char*); static void (*qpng_write_end) (void*, void*); +// libpng 1.4+ longjmp hack +typedef void (*qpng_longjmp_ptr) (jmp_buf, int); +static jmp_buf* (*qpng_set_longjmp_fn) (void *, qpng_longjmp_ptr, size_t); +#define qpng_jmpbuf_14(png_ptr) (*qpng_set_longjmp_fn((png_ptr), longjmp, sizeof (jmp_buf))) + +// libpng 1.2 longjmp hack +#define qpng_jmpbuf_12(png_ptr) (*((jmp_buf *) png_ptr)) + +// all version support +#define qpng_jmpbuf(png_ptr) \ + (qpng_set_longjmp_fn ? qpng_jmpbuf_14(png_ptr) : qpng_jmpbuf_12(png_ptr)) + static dllfunction_t pngfuncs[] = { {"png_set_sig_bytes", (void **) &qpng_set_sig_bytes}, @@ -101,9 +114,15 @@ static dllfunction_t pngfuncs[] = {"png_write_end", (void **) &qpng_write_end}, {NULL, NULL} }; +static dllfunction_t png14funcs[] = +{ + {"png_set_longjmp_fn", (void **) &qpng_set_longjmp_fn}, + {NULL, NULL} +}; // Handle for PNG DLL dllhandle_t png_dll = NULL; +dllhandle_t png14_dll = NULL; /* @@ -126,13 +145,17 @@ qboolean PNG_OpenLibrary (void) const char* dllnames [] = { #if WIN32 + "libpng15-15.dll", + "libpng15.dll", "libpng14-14.dll", "libpng14.dll", "libpng12.dll", #elif defined(MACOSX) + "libpng15.15.dylib", "libpng14.14.dylib", "libpng12.0.dylib", #else + "libpng15.so.15", // WTF libtool guidelines anyone? "libpng14.so.14", // WTF libtool guidelines anyone? "libpng12.so.0", "libpng.so", // FreeBSD @@ -145,7 +168,15 @@ qboolean PNG_OpenLibrary (void) return true; // Load the DLL - return Sys_LoadLibrary (dllnames, &png_dll, pngfuncs); + if(!Sys_LoadLibrary (dllnames, &png_dll, pngfuncs)) + return false; + if(qpng_access_version_number() / 100 >= 104) + if(!Sys_LoadLibrary (dllnames, &png14_dll, png14funcs)) + { + Sys_UnloadLibrary (&png_dll); + return false; + } + return true; } @@ -158,6 +189,7 @@ Unload the PNG DLL */ void PNG_CloseLibrary (void) { + Sys_UnloadLibrary (&png14_dll); Sys_UnloadLibrary (&png_dll); } @@ -171,6 +203,7 @@ void PNG_CloseLibrary (void) #define PNG_LIBPNG_VER_STRING_12 "1.2.4" #define PNG_LIBPNG_VER_STRING_14 "1.4.0" +#define PNG_LIBPNG_VER_STRING_15 "1.5.0" #define PNG_COLOR_MASK_PALETTE 1 #define PNG_COLOR_MASK_COLOR 2 @@ -273,7 +306,9 @@ unsigned char *PNG_LoadImage_BGRA (const unsigned char *raw, int filesize, int * if(qpng_sig_cmp(raw, 0, filesize)) return NULL; png = (void *)qpng_create_read_struct( - (qpng_access_version_number() / 100 == 102) ? PNG_LIBPNG_VER_STRING_12 : PNG_LIBPNG_VER_STRING_14, // nasty hack to support both libpng12 and libpng14 + (qpng_access_version_number() / 100 == 102) ? PNG_LIBPNG_VER_STRING_12 : + (qpng_access_version_number() / 100 == 104) ? PNG_LIBPNG_VER_STRING_14 : + PNG_LIBPNG_VER_STRING_15, // nasty hack... whatever 0, PNG_error_fn, PNG_warning_fn ); if(!png) @@ -285,17 +320,7 @@ unsigned char *PNG_LoadImage_BGRA (const unsigned char *raw, int filesize, int * // NOTE: this relies on jmp_buf being the first thing in the png structure // created by libpng! (this is correct for libpng 1.2.x) -#ifdef __cplusplus -#ifdef WIN64 - if (setjmp((_JBTYPE *)png)) -#elif defined(MACOSX) || defined(WIN32) - if (setjmp((int *)png)) -#else - if (setjmp((__jmp_buf_tag *)png)) -#endif -#else - if (setjmp(png)) -#endif + if (setjmp(qpng_jmpbuf(png))) { if (my_png.Data) Mem_Free(my_png.Data); diff --git a/misc/source/darkplaces-src/lhnet.c b/misc/source/darkplaces-src/lhnet.c index cb87b6d3..c07866ad 100644 --- a/misc/source/darkplaces-src/lhnet.c +++ b/misc/source/darkplaces-src/lhnet.c @@ -154,7 +154,7 @@ int LHNETADDRESS_FromPort(lhnetaddress_t *vaddress, lhnetaddresstype_t addressty } #ifdef SUPPORTIPV6 -int LHNETADDRESS_Resolve(lhnetaddressnative_t *address, const char *name, int port) +static int LHNETADDRESS_Resolve(lhnetaddressnative_t *address, const char *name, int port) { char port_buff [16]; struct addrinfo hints; diff --git a/misc/source/darkplaces-src/libcurl.c b/misc/source/darkplaces-src/libcurl.c index 637a649d..3baa91b4 100644 --- a/misc/source/darkplaces-src/libcurl.c +++ b/misc/source/darkplaces-src/libcurl.c @@ -9,6 +9,8 @@ static cvar_t sv_curl_defaulturl = {CVAR_SAVE, "sv_curl_defaulturl","", "default static cvar_t sv_curl_serverpackages = {CVAR_SAVE, "sv_curl_serverpackages","", "list of required files for the clients, separated by spaces"}; static cvar_t sv_curl_maxspeed = {CVAR_SAVE, "sv_curl_maxspeed","0", "maximum download speed for clients downloading from sv_curl_defaulturl (KiB/s)"}; static cvar_t cl_curl_enabled = {CVAR_SAVE, "cl_curl_enabled","1", "whether client's download support is enabled"}; +static cvar_t cl_curl_useragent = {0, "cl_curl_useragent","1", "send the User-Agent string (note: turning this off may break stuff)"}; +static cvar_t cl_curl_useragent_append = {0, "cl_curl_useragent_append","", "a string to append to the User-Agent string (useful for name and version number of your mod)"}; /* ================================================================= @@ -637,7 +639,27 @@ static void CheckPendingDownloads(void) di->curle = qcurl_easy_init(); di->slist = NULL; qcurl_easy_setopt(di->curle, CURLOPT_URL, di->url); - qcurl_easy_setopt(di->curle, CURLOPT_USERAGENT, engineversion); + if(cl_curl_useragent.integer) + { + const char *ua +#ifdef HTTP_USER_AGENT + = HTTP_USER_AGENT; +#else + = engineversion; +#endif + if(!ua) + ua = ""; + if(*cl_curl_useragent_append.string) + ua = va(vabuf, sizeof(vabuf), "%s%s%s", + ua, + (ua[0] && ua[strlen(ua)-1] != ' ') + ? " " + : "", + cl_curl_useragent_append.string); + qcurl_easy_setopt(di->curle, CURLOPT_USERAGENT, ua); + } + else + qcurl_easy_setopt(di->curle, CURLOPT_USERAGENT, ""); qcurl_easy_setopt(di->curle, CURLOPT_REFERER, di->referer); qcurl_easy_setopt(di->curle, CURLOPT_RESUME_FROM, (long) di->startpos); qcurl_easy_setopt(di->curle, CURLOPT_FOLLOWLOCATION, 1); @@ -1395,6 +1417,8 @@ void Curl_Init_Commands(void) Cvar_RegisterVariable (&sv_curl_defaulturl); Cvar_RegisterVariable (&sv_curl_serverpackages); Cvar_RegisterVariable (&sv_curl_maxspeed); + Cvar_RegisterVariable (&cl_curl_useragent); + Cvar_RegisterVariable (&cl_curl_useragent_append); Cmd_AddCommand ("curl", Curl_Curl_f, "download data from an URL and add to search path"); //Cmd_AddCommand ("curlcat", Curl_CurlCat_f, "display data from an URL (debugging command)"); } diff --git a/misc/source/darkplaces-src/makefile b/misc/source/darkplaces-src/makefile index 7a8a4cfb..35de3283 100644 --- a/misc/source/darkplaces-src/makefile +++ b/misc/source/darkplaces-src/makefile @@ -326,3 +326,10 @@ include makefile.inc ##### Dependency files ##### -include *.d + +# hack to deal with no-longer-needed .h files +%.h: + @echo + @echo "NOTE: file $@ mentioned in dependencies missing, continuing..." + @echo "HINT: consider 'make clean'" + @echo diff --git a/misc/source/darkplaces-src/makefile.inc b/misc/source/darkplaces-src/makefile.inc index 409cd2ec..d04e5f86 100644 --- a/misc/source/darkplaces-src/makefile.inc +++ b/misc/source/darkplaces-src/makefile.inc @@ -218,7 +218,7 @@ LDFLAGS_RELEASE=$(OPTIM_RELEASE) -DSVNREVISION=`{ test -d .svn && svnversion; } OBJ_GLX= builddate.c sys_linux.o vid_glx.o thread_pthread.o keysym2ucs.o $(OBJ_SOUND) $(OBJ_CD) $(OBJ_COMMON) LDFLAGS_UNIXCOMMON=-lm $(LIB_ODE) $(LIB_JPEG) $(LIB_CRYPTO) $(LIB_CRYPTO_RIJNDAEL) -LDFLAGS_UNIXCL=-L$(UNIX_X11LIBPATH) -lX11 -lXpm -lXext -lXxf86dga -lXxf86vm -pthread $(LIB_SOUND) +LDFLAGS_UNIXCL=-L$(UNIX_X11LIBPATH) -lX11 -lXpm -lXext -lXxf86vm -pthread $(LIB_SOUND) LDFLAGS_UNIXCL_PRELOAD=-lz -ljpeg -lpng -logg -ltheora -lvorbis -lvorbisenc -lvorbisfile -lcurl -lmodplug LDFLAGS_UNIXSV_PRELOAD=-lz -ljpeg -lpng -lcurl LDFLAGS_UNIXSDL_PRELOAD=-lz -ljpeg -lpng -logg -ltheora -lvorbis -lvorbisenc -lvorbisfile -lcurl -lmodplug @@ -489,6 +489,11 @@ snd_modplug.o: snd_modplug.c $(CHECKLEVEL2) $(DO_CC) $(CFLAGS_SND_MODPLUG) +#this checks ODE_DYNAMIC and ODE_STATIC when compiling so it needs the ODE flags as well +prvm_cmd.o: prvm_cmd.c + $(CHECKLEVEL2) + $(DO_CC) $(CFLAGS_ODE) + world.o: world.c $(CHECKLEVEL2) $(DO_CC) $(CFLAGS_ODE) @@ -586,4 +591,3 @@ clean: clean-profile: clean -$(CMD_RM) *.gcda -$(CMD_RM) *.gcno - diff --git a/misc/source/darkplaces-src/mathlib.c b/misc/source/darkplaces-src/mathlib.c index dae0de50..b4a1b6a0 100644 --- a/misc/source/darkplaces-src/mathlib.c +++ b/misc/source/darkplaces-src/mathlib.c @@ -198,30 +198,61 @@ void PerpendicularVector( vec3_t dst, const vec3_t src ) // LordHavoc: like AngleVectors, but taking a forward vector instead of angles, useful! void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up) { - float d; - - right[0] = forward[2]; - right[1] = -forward[0]; - right[2] = forward[1]; - - d = DotProduct(forward, right); - VectorMA(right, -d, forward, right); - VectorNormalize(right); - CrossProduct(right, forward, up); + // NOTE: this is consistent to AngleVectors applied to AnglesFromVectors + if (forward[0] == 0 && forward[1] == 0) + { + if(forward[2] > 0) + { + VectorSet(right, 0, -1, 0); + VectorSet(up, -1, 0, 0); + } + else + { + VectorSet(right, 0, -1, 0); + VectorSet(up, 1, 0, 0); + } + } + else + { + right[0] = forward[1]; + right[1] = -forward[0]; + right[2] = 0; + VectorNormalize(right); + + up[0] = (-forward[2]*forward[0]); + up[1] = (-forward[2]*forward[1]); + up[2] = (forward[0]*forward[0] + forward[1]*forward[1]); + VectorNormalize(up); + } } void VectorVectorsDouble(const double *forward, double *right, double *up) { - double d; - - right[0] = forward[2]; - right[1] = -forward[0]; - right[2] = forward[1]; - - d = DotProduct(forward, right); - VectorMA(right, -d, forward, right); - VectorNormalize(right); - CrossProduct(right, forward, up); + if (forward[0] == 0 && forward[1] == 0) + { + if(forward[2] > 0) + { + VectorSet(right, 0, -1, 0); + VectorSet(up, -1, 0, 0); + } + else + { + VectorSet(right, 0, -1, 0); + VectorSet(up, 1, 0, 0); + } + } + else + { + right[0] = forward[1]; + right[1] = -forward[0]; + right[2] = 0; + VectorNormalize(right); + + up[0] = (-forward[2]*forward[0]); + up[1] = (-forward[2]*forward[1]); + up[2] = (forward[0]*forward[0] + forward[1]*forward[1]); + VectorNormalize(up); + } } void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ) @@ -539,9 +570,11 @@ void AnglesFromVectors (vec3_t angles, const vec3_t forward, const vec3_t up, qb { angles[YAW] = atan2(forward[1], forward[0]); angles[PITCH] = -atan2(forward[2], sqrt(forward[0]*forward[0] + forward[1]*forward[1])); + // note: we know that angles[PITCH] is in ]-pi/2..pi/2[ due to atan2(anything, positive) if (up) { vec_t cp = cos(angles[PITCH]), sp = sin(angles[PITCH]); + // note: we know cp > 0, due to the range angles[pitch] is in vec_t cy = cos(angles[YAW]), sy = sin(angles[YAW]); vec3_t tleft, tup; tleft[0] = -sy; @@ -551,9 +584,14 @@ void AnglesFromVectors (vec3_t angles, const vec3_t forward, const vec3_t up, qb tup[1] = sp*sy; tup[2] = cp; angles[ROLL] = -atan2(DotProduct(up, tleft), DotProduct(up, tup)); + // for up == '0 0 1', this is + // angles[ROLL] = -atan2(0, cp); + // which is 0 } else angles[ROLL] = 0; + + // so no up vector is equivalent to '1 0 0'! } // now convert radians to degrees, and make all values positive diff --git a/misc/source/darkplaces-src/matrixlib.c b/misc/source/darkplaces-src/matrixlib.c index f84e922d..78c859cf 100644 --- a/misc/source/darkplaces-src/matrixlib.c +++ b/misc/source/darkplaces-src/matrixlib.c @@ -146,54 +146,54 @@ void Matrix4x4_Transpose (matrix4x4_t *out, const matrix4x4_t *in1) // added helper for common subexpression elimination by eihrul, and other optimizations by div0 int Matrix4x4_Invert_Full (matrix4x4_t *out, const matrix4x4_t *in1) { - float det; - - // note: orientation does not matter, as transpose(invert(transpose(m))) == invert(m), proof: - // transpose(invert(transpose(m))) * m - // = transpose(invert(transpose(m))) * transpose(transpose(m)) - // = transpose(transpose(m) * invert(transpose(m))) - // = transpose(identity) - // = identity - - // this seems to help gcc's common subexpression elimination, and also makes the code look nicer - float m00 = in1->m[0][0], m01 = in1->m[0][1], m02 = in1->m[0][2], m03 = in1->m[0][3], - m10 = in1->m[1][0], m11 = in1->m[1][1], m12 = in1->m[1][2], m13 = in1->m[1][3], - m20 = in1->m[2][0], m21 = in1->m[2][1], m22 = in1->m[2][2], m23 = in1->m[2][3], - m30 = in1->m[3][0], m31 = in1->m[3][1], m32 = in1->m[3][2], m33 = in1->m[3][3]; - - // calculate the adjoint - out->m[0][0] = (m11*(m22*m33 - m23*m32) - m21*(m12*m33 - m13*m32) + m31*(m12*m23 - m13*m22)); - out->m[0][1] = -(m01*(m22*m33 - m23*m32) - m21*(m02*m33 - m03*m32) + m31*(m02*m23 - m03*m22)); - out->m[0][2] = (m01*(m12*m33 - m13*m32) - m11*(m02*m33 - m03*m32) + m31*(m02*m13 - m03*m12)); - out->m[0][3] = -(m01*(m12*m23 - m13*m22) - m11*(m02*m23 - m03*m22) + m21*(m02*m13 - m03*m12)); - out->m[1][0] = -(m10*(m22*m33 - m23*m32) - m20*(m12*m33 - m13*m32) + m30*(m12*m23 - m13*m22)); - out->m[1][1] = (m00*(m22*m33 - m23*m32) - m20*(m02*m33 - m03*m32) + m30*(m02*m23 - m03*m22)); - out->m[1][2] = -(m00*(m12*m33 - m13*m32) - m10*(m02*m33 - m03*m32) + m30*(m02*m13 - m03*m12)); - out->m[1][3] = (m00*(m12*m23 - m13*m22) - m10*(m02*m23 - m03*m22) + m20*(m02*m13 - m03*m12)); - out->m[2][0] = (m10*(m21*m33 - m23*m31) - m20*(m11*m33 - m13*m31) + m30*(m11*m23 - m13*m21)); - out->m[2][1] = -(m00*(m21*m33 - m23*m31) - m20*(m01*m33 - m03*m31) + m30*(m01*m23 - m03*m21)); - out->m[2][2] = (m00*(m11*m33 - m13*m31) - m10*(m01*m33 - m03*m31) + m30*(m01*m13 - m03*m11)); - out->m[2][3] = -(m00*(m11*m23 - m13*m21) - m10*(m01*m23 - m03*m21) + m20*(m01*m13 - m03*m11)); - out->m[3][0] = -(m10*(m21*m32 - m22*m31) - m20*(m11*m32 - m12*m31) + m30*(m11*m22 - m12*m21)); - out->m[3][1] = (m00*(m21*m32 - m22*m31) - m20*(m01*m32 - m02*m31) + m30*(m01*m22 - m02*m21)); - out->m[3][2] = -(m00*(m11*m32 - m12*m31) - m10*(m01*m32 - m02*m31) + m30*(m01*m12 - m02*m11)); - out->m[3][3] = (m00*(m11*m22 - m12*m21) - m10*(m01*m22 - m02*m21) + m20*(m01*m12 - m02*m11)); - - // calculate the determinant (as inverse == 1/det * adjoint, adjoint * m == identity * det, so this calculates the det) - det = m00*out->m[0][0] + m10*out->m[0][1] + m20*out->m[0][2] + m30*out->m[0][3]; - if (det == 0.0f) - return 0; - - // multiplications are faster than divisions, usually - det = 1.0f / det; - - // manually unrolled loop to multiply all matrix elements by 1/det - out->m[0][0] *= det; out->m[0][1] *= det; out->m[0][2] *= det; out->m[0][3] *= det; - out->m[1][0] *= det; out->m[1][1] *= det; out->m[1][2] *= det; out->m[1][3] *= det; - out->m[2][0] *= det; out->m[2][1] *= det; out->m[2][2] *= det; out->m[2][3] *= det; - out->m[3][0] *= det; out->m[3][1] *= det; out->m[3][2] *= det; out->m[3][3] *= det; - - return 1; + float det; + + // note: orientation does not matter, as transpose(invert(transpose(m))) == invert(m), proof: + // transpose(invert(transpose(m))) * m + // = transpose(invert(transpose(m))) * transpose(transpose(m)) + // = transpose(transpose(m) * invert(transpose(m))) + // = transpose(identity) + // = identity + + // this seems to help gcc's common subexpression elimination, and also makes the code look nicer + float m00 = in1->m[0][0], m01 = in1->m[0][1], m02 = in1->m[0][2], m03 = in1->m[0][3], + m10 = in1->m[1][0], m11 = in1->m[1][1], m12 = in1->m[1][2], m13 = in1->m[1][3], + m20 = in1->m[2][0], m21 = in1->m[2][1], m22 = in1->m[2][2], m23 = in1->m[2][3], + m30 = in1->m[3][0], m31 = in1->m[3][1], m32 = in1->m[3][2], m33 = in1->m[3][3]; + + // calculate the adjoint + out->m[0][0] = (m11*(m22*m33 - m23*m32) - m21*(m12*m33 - m13*m32) + m31*(m12*m23 - m13*m22)); + out->m[0][1] = -(m01*(m22*m33 - m23*m32) - m21*(m02*m33 - m03*m32) + m31*(m02*m23 - m03*m22)); + out->m[0][2] = (m01*(m12*m33 - m13*m32) - m11*(m02*m33 - m03*m32) + m31*(m02*m13 - m03*m12)); + out->m[0][3] = -(m01*(m12*m23 - m13*m22) - m11*(m02*m23 - m03*m22) + m21*(m02*m13 - m03*m12)); + out->m[1][0] = -(m10*(m22*m33 - m23*m32) - m20*(m12*m33 - m13*m32) + m30*(m12*m23 - m13*m22)); + out->m[1][1] = (m00*(m22*m33 - m23*m32) - m20*(m02*m33 - m03*m32) + m30*(m02*m23 - m03*m22)); + out->m[1][2] = -(m00*(m12*m33 - m13*m32) - m10*(m02*m33 - m03*m32) + m30*(m02*m13 - m03*m12)); + out->m[1][3] = (m00*(m12*m23 - m13*m22) - m10*(m02*m23 - m03*m22) + m20*(m02*m13 - m03*m12)); + out->m[2][0] = (m10*(m21*m33 - m23*m31) - m20*(m11*m33 - m13*m31) + m30*(m11*m23 - m13*m21)); + out->m[2][1] = -(m00*(m21*m33 - m23*m31) - m20*(m01*m33 - m03*m31) + m30*(m01*m23 - m03*m21)); + out->m[2][2] = (m00*(m11*m33 - m13*m31) - m10*(m01*m33 - m03*m31) + m30*(m01*m13 - m03*m11)); + out->m[2][3] = -(m00*(m11*m23 - m13*m21) - m10*(m01*m23 - m03*m21) + m20*(m01*m13 - m03*m11)); + out->m[3][0] = -(m10*(m21*m32 - m22*m31) - m20*(m11*m32 - m12*m31) + m30*(m11*m22 - m12*m21)); + out->m[3][1] = (m00*(m21*m32 - m22*m31) - m20*(m01*m32 - m02*m31) + m30*(m01*m22 - m02*m21)); + out->m[3][2] = -(m00*(m11*m32 - m12*m31) - m10*(m01*m32 - m02*m31) + m30*(m01*m12 - m02*m11)); + out->m[3][3] = (m00*(m11*m22 - m12*m21) - m10*(m01*m22 - m02*m21) + m20*(m01*m12 - m02*m11)); + + // calculate the determinant (as inverse == 1/det * adjoint, adjoint * m == identity * det, so this calculates the det) + det = m00*out->m[0][0] + m10*out->m[0][1] + m20*out->m[0][2] + m30*out->m[0][3]; + if (det == 0.0f) + return 0; + + // multiplications are faster than divisions, usually + det = 1.0f / det; + + // manually unrolled loop to multiply all matrix elements by 1/det + out->m[0][0] *= det; out->m[0][1] *= det; out->m[0][2] *= det; out->m[0][3] *= det; + out->m[1][0] *= det; out->m[1][1] *= det; out->m[1][2] *= det; out->m[1][3] *= det; + out->m[2][0] *= det; out->m[2][1] *= det; out->m[2][2] *= det; out->m[2][3] *= det; + out->m[3][0] *= det; out->m[3][1] *= det; out->m[3][2] *= det; out->m[3][3] *= det; + + return 1; } #elif 1 // Adapted from code contributed to Mesa by David Moore (Mesa 7.6 under SGI Free License B - which is MIT/X11-type) @@ -1550,22 +1550,22 @@ void Matrix4x4_FromDoom3Joint(matrix4x4_t *m, double ox, double oy, double oz, d #endif } -void Matrix4x4_FromBonePose6s(matrix4x4_t *m, float originscale, const short *pose6s) +void Matrix4x4_FromBonePose7s(matrix4x4_t *m, float originscale, const short *pose7s) { float origin[3]; float quat[4]; - origin[0] = pose6s[0] * originscale; - origin[1] = pose6s[1] * originscale; - origin[2] = pose6s[2] * originscale; - quat[0] = pose6s[3] * (1.0f / 32767.0f); - quat[1] = pose6s[4] * (1.0f / 32767.0f); - quat[2] = pose6s[5] * (1.0f / 32767.0f); - quat[3] = 1.0f - (quat[0]*quat[0]+quat[1]*quat[1]+quat[2]*quat[2]); - quat[3] = quat[3] > 0.0f ? -sqrt(quat[3]) : 0.0f; + float quatscale = pose7s[6] > 0 ? -1.0f / 32767.0f : 1.0f / 32767.0f; + origin[0] = pose7s[0] * originscale; + origin[1] = pose7s[1] * originscale; + origin[2] = pose7s[2] * originscale; + quat[0] = pose7s[3] * quatscale; + quat[1] = pose7s[4] * quatscale; + quat[2] = pose7s[5] * quatscale; + quat[3] = pose7s[6] * quatscale; Matrix4x4_FromOriginQuat(m, origin[0], origin[1], origin[2], quat[0], quat[1], quat[2], quat[3]); } -void Matrix4x4_ToBonePose6s(const matrix4x4_t *m, float origininvscale, short *pose6s) +void Matrix4x4_ToBonePose7s(const matrix4x4_t *m, float origininvscale, short *pose7s) { float origin[3]; float quat[4]; @@ -1577,12 +1577,13 @@ void Matrix4x4_ToBonePose6s(const matrix4x4_t *m, float origininvscale, short *p quatscale = (quat[3] >= 0 ? -32767.0f : 32767.0f) / sqrt(quatscale); // use a negative scale on the quat because the above function produces a // positive quat[3] and canonical quaternions have negative quat[3] - pose6s[0] = origin[0] * origininvscale; - pose6s[1] = origin[1] * origininvscale; - pose6s[2] = origin[2] * origininvscale; - pose6s[3] = quat[0] * quatscale; - pose6s[4] = quat[1] * quatscale; - pose6s[5] = quat[2] * quatscale; + pose7s[0] = origin[0] * origininvscale; + pose7s[1] = origin[1] * origininvscale; + pose7s[2] = origin[2] * origininvscale; + pose7s[3] = quat[0] * quatscale; + pose7s[4] = quat[1] * quatscale; + pose7s[5] = quat[2] * quatscale; + pose7s[6] = quat[3] * quatscale; } void Matrix4x4_Blend (matrix4x4_t *out, const matrix4x4_t *in1, const matrix4x4_t *in2, double blend) @@ -1811,14 +1812,14 @@ void Matrix4x4_Scale (matrix4x4_t *out, double rotatescale, double originscale) void Matrix4x4_Abs (matrix4x4_t *out) { - out->m[0][0] = fabs(out->m[0][0]); - out->m[0][1] = fabs(out->m[0][1]); - out->m[0][2] = fabs(out->m[0][2]); - out->m[1][0] = fabs(out->m[1][0]); - out->m[1][1] = fabs(out->m[1][1]); - out->m[1][2] = fabs(out->m[1][2]); - out->m[2][0] = fabs(out->m[2][0]); - out->m[2][1] = fabs(out->m[2][1]); - out->m[2][2] = fabs(out->m[2][2]); + out->m[0][0] = fabs(out->m[0][0]); + out->m[0][1] = fabs(out->m[0][1]); + out->m[0][2] = fabs(out->m[0][2]); + out->m[1][0] = fabs(out->m[1][0]); + out->m[1][1] = fabs(out->m[1][1]); + out->m[1][2] = fabs(out->m[1][2]); + out->m[2][0] = fabs(out->m[2][0]); + out->m[2][1] = fabs(out->m[2][1]); + out->m[2][2] = fabs(out->m[2][2]); } diff --git a/misc/source/darkplaces-src/matrixlib.h b/misc/source/darkplaces-src/matrixlib.h index ae83c1d6..eb926a10 100644 --- a/misc/source/darkplaces-src/matrixlib.h +++ b/misc/source/darkplaces-src/matrixlib.h @@ -120,10 +120,10 @@ void Matrix4x4_ToOrigin3Quat4Float(const matrix4x4_t *m, float *origin, float *q // creates a matrix4x4 from an origin and canonical unit-length quaternion (used mostly with skeletal model formats such as MD5) void Matrix4x4_FromDoom3Joint(matrix4x4_t *m, double ox, double oy, double oz, double x, double y, double z); -// creates a matrix4x4_t from an origin and canonical unit-length quaternion in short[6] normalized format -void Matrix4x4_FromBonePose6s(matrix4x4_t *m, float originscale, const short *pose6s); -// creates a short[6] representation from normalized matrix4x4_t -void Matrix4x4_ToBonePose6s(const matrix4x4_t *m, float origininvscale, short *pose6s); +// creates a matrix4x4_t from an origin and canonical unit-length quaternion in short[7] normalized format +void Matrix4x4_FromBonePose7s(matrix4x4_t *m, float originscale, const short *pose7s); +// creates a short[7] representation from normalized matrix4x4_t +void Matrix4x4_ToBonePose7s(const matrix4x4_t *m, float origininvscale, short *pose7s); // blends two matrices together, at a given percentage (blend controls percentage of in2) void Matrix4x4_Blend (matrix4x4_t *out, const matrix4x4_t *in1, const matrix4x4_t *in2, double blend); diff --git a/misc/source/darkplaces-src/menu.c b/misc/source/darkplaces-src/menu.c index eb741b2a..149e8421 100644 --- a/misc/source/darkplaces-src/menu.c +++ b/misc/source/darkplaces-src/menu.c @@ -5313,7 +5313,7 @@ static void MP_ToggleMenu(int mode) prvm_prog_t *prog = MVM_prog; prog->globals.generic[OFS_PARM0] = (float) mode; - prog->ExecuteProgram(prog, PRVM_menufunction(m_toggle),"m_toggle() required"); + prog->ExecuteProgram(prog, PRVM_menufunction(m_toggle),"m_toggle(float mode) required"); } static void MP_NewMap(void) diff --git a/misc/source/darkplaces-src/mod_skeletal_animatevertices_generic.c b/misc/source/darkplaces-src/mod_skeletal_animatevertices_generic.c index 00ab435d..bc268117 100644 --- a/misc/source/darkplaces-src/mod_skeletal_animatevertices_generic.c +++ b/misc/source/darkplaces-src/mod_skeletal_animatevertices_generic.c @@ -41,38 +41,57 @@ void Mod_Skeletal_AnimateVertices_Generic(const dp_model_t * RESTRICT model, con } else { - float originscale = model->num_posescale; - float x,y,z,w,lerp; - const short * RESTRICT pose6s; - for (i = 0;i < model->num_bones;i++) { - memset(m, 0, sizeof(m)); - for (blends = 0;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++) + const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i); + float lerp = frameblend[0].lerp, + tx = pose7s[0], ty = pose7s[1], tz = pose7s[2], + rx = pose7s[3] * lerp, + ry = pose7s[4] * lerp, + rz = pose7s[5] * lerp, + rw = pose7s[6] * lerp, + dx = tx*rw + ty*rz - tz*ry, + dy = -tx*rz + ty*rw + tz*rx, + dz = tx*ry - ty*rx + tz*rw, + dw = -tx*rx - ty*ry - tz*rz, + scale, sx, sy, sz, sw; + for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++) { - pose6s = model->data_poses6s + 6 * (frameblend[blends].subframe * model->num_bones + i); - lerp = frameblend[blends].lerp; - x = pose6s[3] * (1.0f / 32767.0f); - y = pose6s[4] * (1.0f / 32767.0f); - z = pose6s[5] * (1.0f / 32767.0f); - w = 1.0f - (x*x+y*y+z*z); - w = w > 0.0f ? -sqrt(w) : 0.0f; - m[ 0] += (1-2*(y*y+z*z)) * lerp; - m[ 1] += ( 2*(x*y-z*w)) * lerp; - m[ 2] += ( 2*(x*z+y*w)) * lerp; - m[ 3] += (pose6s[0] * originscale) * lerp; - m[ 4] += ( 2*(x*y+z*w)) * lerp; - m[ 5] += (1-2*(x*x+z*z)) * lerp; - m[ 6] += ( 2*(y*z-x*w)) * lerp; - m[ 7] += (pose6s[1] * originscale) * lerp; - m[ 8] += ( 2*(x*z-y*w)) * lerp; - m[ 9] += ( 2*(y*z+x*w)) * lerp; - m[10] += (1-2*(x*x+y*y)) * lerp; - m[11] += (pose6s[2] * originscale) * lerp; + const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i); + float lerp = frameblend[blends].lerp, + tx = pose7s[0], ty = pose7s[1], tz = pose7s[2], + qx = pose7s[3], qy = pose7s[4], qz = pose7s[5], qw = pose7s[6]; + if(rx*qx + ry*qy + rz*qz + rw*qw < 0) lerp = -lerp; + qx *= lerp; + qy *= lerp; + qz *= lerp; + qw *= lerp; + rx += qx; + ry += qy; + rz += qz; + rw += qw; + dx += tx*qw + ty*qz - tz*qy; + dy += -tx*qz + ty*qw + tz*qx; + dz += tx*qy - ty*qx + tz*qw; + dw += -tx*qx - ty*qy - tz*qz; } - VectorNormalize(m ); - VectorNormalize(m + 4); - VectorNormalize(m + 8); + scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw); + sx = rx * scale; + sy = ry * scale; + sz = rz * scale; + sw = rw * scale; + m[0] = sw*rw + sx*rx - sy*ry - sz*rz; + m[1] = 2*(sx*ry - sw*rz); + m[2] = 2*(sx*rz + sw*ry); + m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx); + m[4] = 2*(sx*ry + sw*rz); + m[5] = sw*rw + sy*ry - sx*rx - sz*rz; + m[6] = 2*(sy*rz - sw*rx); + m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy); + m[8] = 2*(sx*rz - sw*ry); + m[9] = 2*(sy*rz + sw*rx); + m[10] = sw*rw + sz*rz - sx*rx - sy*ry; + m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz); if (i == r_skeletal_debugbone.integer) m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value; m[3] *= r_skeletal_debugtranslatex.value; diff --git a/misc/source/darkplaces-src/mod_skeletal_animatevertices_sse.c b/misc/source/darkplaces-src/mod_skeletal_animatevertices_sse.c index f575d245..648ab31a 100644 --- a/misc/source/darkplaces-src/mod_skeletal_animatevertices_sse.c +++ b/misc/source/darkplaces-src/mod_skeletal_animatevertices_sse.c @@ -16,7 +16,6 @@ void Mod_Skeletal_AnimateVertices_SSE(const dp_model_t * RESTRICT model, const f matrix4x4_t *bonepose; matrix4x4_t *boneposerelative; float m[12]; - matrix4x4_t mm, mm2; const blendweights_t * RESTRICT weights; int num_vertices_minus_one; @@ -34,69 +33,189 @@ void Mod_Skeletal_AnimateVertices_SSE(const dp_model_t * RESTRICT model, const f { for (i = 0;i < model->num_bones;i++) { - // relativetransforms is in GL column-major order, which is what we need for SSE - // transposed style processing + const float * RESTRICT n = model->data_baseboneposeinverse + i * 12; + matrix4x4_t * RESTRICT s = &skeleton->relativetransforms[i]; + matrix4x4_t * RESTRICT b = &bonepose[i]; + matrix4x4_t * RESTRICT r = &boneposerelative[i]; + __m128 b0, b1, b2, b3, r0, r1, r2, r3, nr; if (model->data_bones[i].parent >= 0) - Matrix4x4_Concat(&bonepose[i], &bonepose[model->data_bones[i].parent], &skeleton->relativetransforms[i]); + { + const matrix4x4_t * RESTRICT p = &bonepose[model->data_bones[i].parent]; + __m128 s0 = _mm_loadu_ps(s->m[0]), s1 = _mm_loadu_ps(s->m[1]), s2 = _mm_loadu_ps(s->m[2]); +#ifdef OPENGLORIENTATION + __m128 s3 = _mm_loadu_ps(s->m[3]); +#define SKELETON_MATRIX(r, c) _mm_shuffle_ps(s##c, s##c, _MM_SHUFFLE(r, r, r, r)) +#else +#define SKELETON_MATRIX(r, c) _mm_shuffle_ps(s##r, s##r, _MM_SHUFFLE(c, c, c, c)) +#endif + __m128 pr = _mm_load_ps(p->m[0]); + b0 = _mm_mul_ps(pr, SKELETON_MATRIX(0, 0)); + b1 = _mm_mul_ps(pr, SKELETON_MATRIX(0, 1)); + b2 = _mm_mul_ps(pr, SKELETON_MATRIX(0, 2)); + b3 = _mm_mul_ps(pr, SKELETON_MATRIX(0, 3)); + pr = _mm_load_ps(p->m[1]); + b0 = _mm_add_ps(b0, _mm_mul_ps(pr, SKELETON_MATRIX(1, 0))); + b1 = _mm_add_ps(b1, _mm_mul_ps(pr, SKELETON_MATRIX(1, 1))); + b2 = _mm_add_ps(b2, _mm_mul_ps(pr, SKELETON_MATRIX(1, 2))); + b3 = _mm_add_ps(b3, _mm_mul_ps(pr, SKELETON_MATRIX(1, 3))); + pr = _mm_load_ps(p->m[2]); + b0 = _mm_add_ps(b0, _mm_mul_ps(pr, SKELETON_MATRIX(2, 0))); + b1 = _mm_add_ps(b1, _mm_mul_ps(pr, SKELETON_MATRIX(2, 1))); + b2 = _mm_add_ps(b2, _mm_mul_ps(pr, SKELETON_MATRIX(2, 2))); + b3 = _mm_add_ps(b3, _mm_mul_ps(pr, SKELETON_MATRIX(2, 3))); + b3 = _mm_add_ps(b3, _mm_load_ps(p->m[3])); + } else - memcpy(&bonepose[i], &skeleton->relativetransforms[i], sizeof(matrix4x4_t)); - - // create a relative deformation matrix to describe displacement - // from the base mesh, which is used by the actual weighting - Matrix4x4_FromArray12FloatD3D(&mm, model->data_baseboneposeinverse + i * 12); // baseboneposeinverse is 4x3 row-major - Matrix4x4_Concat(&mm2, &bonepose[i], &mm); - Matrix4x4_Transpose(&boneposerelative[i], &mm2); // TODO: Eliminate this transpose + { + b0 = _mm_loadu_ps(s->m[0]); + b1 = _mm_loadu_ps(s->m[1]); + b2 = _mm_loadu_ps(s->m[2]); + b3 = _mm_loadu_ps(s->m[3]); +#ifndef OPENGLORIENTATION + _MM_TRANSPOSE4_PS(b0, b1, b2, b3); +#endif + } + _mm_store_ps(b->m[0], b0); + _mm_store_ps(b->m[1], b1); + _mm_store_ps(b->m[2], b2); + _mm_store_ps(b->m[3], b3); + nr = _mm_loadu_ps(n); + r0 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(0, 0, 0, 0))); + r1 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(1, 1, 1, 1))); + r2 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(2, 2, 2, 2))); + r3 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(3, 3, 3, 3))); + nr = _mm_loadu_ps(n+4); + r0 = _mm_add_ps(r0, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(0, 0, 0, 0)))); + r1 = _mm_add_ps(r1, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(1, 1, 1, 1)))); + r2 = _mm_add_ps(r2, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(2, 2, 2, 2)))); + r3 = _mm_add_ps(r3, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(3, 3, 3, 3)))); + nr = _mm_loadu_ps(n+8); + r0 = _mm_add_ps(r0, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(0, 0, 0, 0)))); + r1 = _mm_add_ps(r1, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(1, 1, 1, 1)))); + r2 = _mm_add_ps(r2, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(2, 2, 2, 2)))); + r3 = _mm_add_ps(r3, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(3, 3, 3, 3)))); + r3 = _mm_add_ps(r3, b3); + _mm_store_ps(r->m[0], r0); + _mm_store_ps(r->m[1], r1); + _mm_store_ps(r->m[2], r2); + _mm_store_ps(r->m[3], r3); } } else { - float originscale = model->num_posescale; - float x,y,z,w,lerp; - const short * RESTRICT pose6s; - for (i = 0;i < model->num_bones;i++) { - memset(m, 0, sizeof(m)); - for (blends = 0;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++) + const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i); + float lerp = frameblend[0].lerp, + tx = pose7s[0], ty = pose7s[1], tz = pose7s[2], + rx = pose7s[3] * lerp, + ry = pose7s[4] * lerp, + rz = pose7s[5] * lerp, + rw = pose7s[6] * lerp, + dx = tx*rw + ty*rz - tz*ry, + dy = -tx*rz + ty*rw + tz*rx, + dz = tx*ry - ty*rx + tz*rw, + dw = -tx*rx - ty*ry - tz*rz, + scale, sx, sy, sz, sw; + for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++) { - pose6s = model->data_poses6s + 6 * (frameblend[blends].subframe * model->num_bones + i); - lerp = frameblend[blends].lerp; - x = pose6s[3] * (1.0f / 32767.0f); - y = pose6s[4] * (1.0f / 32767.0f); - z = pose6s[5] * (1.0f / 32767.0f); - w = 1.0f - (x*x+y*y+z*z); - w = w > 0.0f ? -sqrt(w) : 0.0f; - m[ 0] += (1-2*(y*y+z*z)) * lerp; - m[ 1] += ( 2*(x*y-z*w)) * lerp; - m[ 2] += ( 2*(x*z+y*w)) * lerp; - m[ 3] += (pose6s[0] * originscale) * lerp; - m[ 4] += ( 2*(x*y+z*w)) * lerp; - m[ 5] += (1-2*(x*x+z*z)) * lerp; - m[ 6] += ( 2*(y*z-x*w)) * lerp; - m[ 7] += (pose6s[1] * originscale) * lerp; - m[ 8] += ( 2*(x*z-y*w)) * lerp; - m[ 9] += ( 2*(y*z+x*w)) * lerp; - m[10] += (1-2*(x*x+y*y)) * lerp; - m[11] += (pose6s[2] * originscale) * lerp; + const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i); + float lerp = frameblend[blends].lerp, + tx = pose7s[0], ty = pose7s[1], tz = pose7s[2], + qx = pose7s[3], qy = pose7s[4], qz = pose7s[5], qw = pose7s[6]; + if(rx*qx + ry*qy + rz*qz + rw*qw < 0) lerp = -lerp; + qx *= lerp; + qy *= lerp; + qz *= lerp; + qw *= lerp; + rx += qx; + ry += qy; + rz += qz; + rw += qw; + dx += tx*qw + ty*qz - tz*qy; + dy += -tx*qz + ty*qw + tz*qx; + dz += tx*qy - ty*qx + tz*qw; + dw += -tx*qx - ty*qy - tz*qz; } - VectorNormalize(m ); - VectorNormalize(m + 4); - VectorNormalize(m + 8); + scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw); + sx = rx * scale; + sy = ry * scale; + sz = rz * scale; + sw = rw * scale; + m[0] = sw*rw + sx*rx - sy*ry - sz*rz; + m[1] = 2*(sx*ry - sw*rz); + m[2] = 2*(sx*rz + sw*ry); + m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx); + m[4] = 2*(sx*ry + sw*rz); + m[5] = sw*rw + sy*ry - sx*rx - sz*rz; + m[6] = 2*(sy*rz - sw*rx); + m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy); + m[8] = 2*(sx*rz - sw*ry); + m[9] = 2*(sy*rz + sw*rx); + m[10] = sw*rw + sz*rz - sx*rx - sy*ry; + m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz); if (i == r_skeletal_debugbone.integer) m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value; m[3] *= r_skeletal_debugtranslatex.value; m[7] *= r_skeletal_debugtranslatey.value; m[11] *= r_skeletal_debugtranslatez.value; - Matrix4x4_FromArray12FloatD3D(&mm, m); - if (model->data_bones[i].parent >= 0) - Matrix4x4_Concat(&bonepose[i], &bonepose[model->data_bones[i].parent], &mm); - else - memcpy(&bonepose[i], &mm, sizeof(mm)); - // create a relative deformation matrix to describe displacement - // from the base mesh, which is used by the actual weighting - Matrix4x4_FromArray12FloatD3D(&mm, model->data_baseboneposeinverse + i * 12); // baseboneposeinverse is 4x3 row-major - Matrix4x4_Concat(&mm2, &bonepose[i], &mm); - Matrix4x4_Transpose(&boneposerelative[i], &mm2); // TODO: Eliminate this transpose + { + const float * RESTRICT n = model->data_baseboneposeinverse + i * 12; + matrix4x4_t * RESTRICT b = &bonepose[i]; + matrix4x4_t * RESTRICT r = &boneposerelative[i]; + __m128 b0, b1, b2, b3, r0, r1, r2, r3, nr; + if (model->data_bones[i].parent >= 0) + { + const matrix4x4_t * RESTRICT p = &bonepose[model->data_bones[i].parent]; + __m128 pr = _mm_load_ps(p->m[0]); + b0 = _mm_mul_ps(pr, _mm_set1_ps(m[0])); + b1 = _mm_mul_ps(pr, _mm_set1_ps(m[1])); + b2 = _mm_mul_ps(pr, _mm_set1_ps(m[2])); + b3 = _mm_mul_ps(pr, _mm_set1_ps(m[3])); + pr = _mm_load_ps(p->m[1]); + b0 = _mm_add_ps(b0, _mm_mul_ps(pr, _mm_set1_ps(m[4]))); + b1 = _mm_add_ps(b1, _mm_mul_ps(pr, _mm_set1_ps(m[5]))); + b2 = _mm_add_ps(b2, _mm_mul_ps(pr, _mm_set1_ps(m[6]))); + b3 = _mm_add_ps(b3, _mm_mul_ps(pr, _mm_set1_ps(m[7]))); + pr = _mm_load_ps(p->m[2]); + b0 = _mm_add_ps(b0, _mm_mul_ps(pr, _mm_set1_ps(m[8]))); + b1 = _mm_add_ps(b1, _mm_mul_ps(pr, _mm_set1_ps(m[9]))); + b2 = _mm_add_ps(b2, _mm_mul_ps(pr, _mm_set1_ps(m[10]))); + b3 = _mm_add_ps(b3, _mm_mul_ps(pr, _mm_set1_ps(m[11]))); + b3 = _mm_add_ps(b3, _mm_load_ps(p->m[3])); + } + else + { + b0 = _mm_setr_ps(m[0], m[4], m[8], 0.0f); + b1 = _mm_setr_ps(m[1], m[5], m[9], 0.0f); + b2 = _mm_setr_ps(m[2], m[6], m[10], 0.0f); + b3 = _mm_setr_ps(m[3], m[7], m[11], 1.0f); + } + _mm_store_ps(b->m[0], b0); + _mm_store_ps(b->m[1], b1); + _mm_store_ps(b->m[2], b2); + _mm_store_ps(b->m[3], b3); + nr = _mm_loadu_ps(n); + r0 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(0, 0, 0, 0))); + r1 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(1, 1, 1, 1))); + r2 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(2, 2, 2, 2))); + r3 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(3, 3, 3, 3))); + nr = _mm_loadu_ps(n+4); + r0 = _mm_add_ps(r0, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(0, 0, 0, 0)))); + r1 = _mm_add_ps(r1, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(1, 1, 1, 1)))); + r2 = _mm_add_ps(r2, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(2, 2, 2, 2)))); + r3 = _mm_add_ps(r3, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(3, 3, 3, 3)))); + nr = _mm_loadu_ps(n+8); + r0 = _mm_add_ps(r0, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(0, 0, 0, 0)))); + r1 = _mm_add_ps(r1, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(1, 1, 1, 1)))); + r2 = _mm_add_ps(r2, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(2, 2, 2, 2)))); + r3 = _mm_add_ps(r3, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(3, 3, 3, 3)))); + r3 = _mm_add_ps(r3, b3); + _mm_store_ps(r->m[0], r0); + _mm_store_ps(r->m[1], r1); + _mm_store_ps(r->m[2], r2); + _mm_store_ps(r->m[3], r3); + } } } diff --git a/misc/source/darkplaces-src/model_alias.c b/misc/source/darkplaces-src/model_alias.c index 7a53d59e..6c212aa5 100644 --- a/misc/source/darkplaces-src/model_alias.c +++ b/misc/source/darkplaces-src/model_alias.c @@ -37,6 +37,7 @@ cvar_t r_skeletal_debugtranslatex = {0, "r_skeletal_debugtranslatex", "1", "deve cvar_t r_skeletal_debugtranslatey = {0, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"}; cvar_t r_skeletal_debugtranslatez = {0, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"}; cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"}; +cvar_t mod_alias_force_animated = {0, "mod_alias_force_animated", "", "if set to an non-empty string, overrides the is-animated flag of any alias models (for benchmarking)"}; float mod_md3_sin[320]; @@ -97,6 +98,7 @@ void Mod_AliasInit (void) Cvar_RegisterVariable(&r_skeletal_debugtranslatey); Cvar_RegisterVariable(&r_skeletal_debugtranslatez); Cvar_RegisterVariable(&mod_alias_supporttagscale); + Cvar_RegisterVariable(&mod_alias_force_animated); for (i = 0;i < 320;i++) mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0); #ifdef SSE_POSSIBLE @@ -391,11 +393,11 @@ int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameble for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++) { lerp = frameblend[blendindex].lerp; - Matrix4x4_FromBonePose6s(&bonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + tagindex)); + Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex)); parenttagindex = tagindex; while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0) { - Matrix4x4_FromBonePose6s(&parentbonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex)); + Matrix4x4_FromBonePose7s(&parentbonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex)); tempbonematrix = bonematrix; Matrix4x4_Concat(&bonematrix, &parentbonematrix, &tempbonematrix); } @@ -454,7 +456,7 @@ int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int s for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++) { lerp = frameblend[blendindex].lerp; - Matrix4x4_FromBonePose6s(&bonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + tagindex)); + Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex)); Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp); } *tag_localmatrix = blendmatrix; @@ -510,7 +512,7 @@ static void Mod_BuildBaseBonePoses(void) basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t)); for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++) { - Matrix4x4_FromBonePose6s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses6s + 6 * boneindex); + Matrix4x4_FromBonePose7s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses7s + 7 * boneindex); if (loadmodel->data_bones[boneindex].parent >= 0) { tempbonematrix = bonematrix; @@ -1020,8 +1022,8 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend) for (i = 0;i < numverts;i++) { vertonseam[i] = LittleLong(pinstverts[i].onseam); - vertst[i*2+0] = (LittleLong(pinstverts[i].s) + 0.5) * scales; - vertst[i*2+1] = (LittleLong(pinstverts[i].t) + 0.5) * scalet; + vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales; + vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet; vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5; vertst[(i+numverts)*2+1] = vertst[i*2+1]; } @@ -1093,7 +1095,6 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend) Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); Mod_Alias_CalculateBoundingBox(); Mod_Alias_MorphMesh_CompileFrames(); - loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL; Mem_Free(vertst); Mem_Free(vertremap); @@ -1213,6 +1214,8 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend) surface->num_vertices = loadmodel->surfmesh.num_vertices; loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1); + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer; loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL; if (!loadmodel->surfmesh.isanimated) @@ -1472,6 +1475,8 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend) Mem_Free(vertremap); loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1); + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer; loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; // needed during loading, may be cleared by code later in this function if (loadmodel->surfmesh.data_neighbor3i) Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); @@ -1672,6 +1677,8 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend) for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1); + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer; loadmodel->AnimateVertices = Mod_MD3_AnimateVertices; // needed during loading, may be cleared by code later in this function if (loadmodel->surfmesh.data_neighbor3i) Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); @@ -1876,11 +1883,13 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) meshtriangles = pheader->numtris; loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1); + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer; loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL; loadmodel->nummodelsurfaces = loadmodel->num_surfaces; loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; loadmodel->num_texturesperskin = loadmodel->num_surfaces; - data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[14]) + meshvertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + loadmodel->num_bones * sizeof(float[12])); + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[14]) + meshvertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12])); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); @@ -1903,7 +1912,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) { loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]); } - loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]); + loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]); loadmodel->surfmesh.data_blendweights = NULL; //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data @@ -1944,7 +1953,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) VectorNormalize(pose + 4); VectorNormalize(pose + 8); Matrix4x4_FromArray12FloatD3D(&posematrix, pose); - Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j)); + Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j)); } } @@ -2197,9 +2206,11 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; loadmodel->num_texturesperskin = loadmodel->num_surfaces; loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1); + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer; loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL; // do most allocations as one merged chunk - data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short)) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t)); + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short)) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t)); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); @@ -2225,7 +2236,7 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) { loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]); } - loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]); + loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]); loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t)); for (i = 0;i < loadmodel->numskins;i++) @@ -2295,7 +2306,7 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) VectorNormalize(pose + 4); VectorNormalize(pose + 8); Matrix4x4_FromArray12FloatD3D(&posematrix, pose); - Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j)); + Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j)); } } @@ -2852,9 +2863,11 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->surfmesh.num_vertices = meshvertices; loadmodel->surfmesh.num_triangles = meshtriangles; loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1); + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer; loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL; // do most allocations as one merged chunk - size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + (r_enableshadowvolumes.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0); + size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + (r_enableshadowvolumes.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0); data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); @@ -2879,7 +2892,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) { loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]); } - loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]); + loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]); loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t)); for (i = 0;i < loadmodel->numskins;i++) @@ -3033,13 +3046,14 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) if (quat[3] > 0) Vector4Negate(quat, quat); Vector4Normalize2(quat, quat); - // compress poses to the short[6] format for longterm storage - loadmodel->data_poses6s[index*6+0] = k->origin[0] * loadmodel->num_poseinvscale; - loadmodel->data_poses6s[index*6+1] = k->origin[1] * loadmodel->num_poseinvscale; - loadmodel->data_poses6s[index*6+2] = k->origin[2] * loadmodel->num_poseinvscale; - loadmodel->data_poses6s[index*6+3] = quat[0] * 32767.0f; - loadmodel->data_poses6s[index*6+4] = quat[1] * 32767.0f; - loadmodel->data_poses6s[index*6+5] = quat[2] * 32767.0f; + // compress poses to the short[7] format for longterm storage + loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale; + loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale; + loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale; + loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f; + loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f; + loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f; + loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f; } } else @@ -3071,13 +3085,14 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) if (quat[3] > 0) Vector4Negate(quat, quat); Vector4Normalize2(quat, quat); - // compress poses to the short[6] format for longterm storage - loadmodel->data_poses6s[index*6+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale; - loadmodel->data_poses6s[index*6+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale; - loadmodel->data_poses6s[index*6+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale; - loadmodel->data_poses6s[index*6+3] = quat[0] * 32767.0f; - loadmodel->data_poses6s[index*6+4] = quat[1] * 32767.0f; - loadmodel->data_poses6s[index*6+5] = quat[2] * 32767.0f; + // compress poses to the short[7] format for longterm storage + loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale; + loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale; + loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale; + loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f; + loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f; + loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f; + loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f; } } @@ -3336,7 +3351,7 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) meshtriangles = header.num_triangles; // do most allocations as one merged chunk - data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + meshvertices * (sizeof(float[14]) + (vcolor4f || vcolor4ub ? sizeof(float[4]) : 0)) + (vblendindexes && vblendweights ? meshvertices * sizeof(unsigned short) : 0) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t)); + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + meshvertices * (sizeof(float[14]) + (vcolor4f || vcolor4ub ? sizeof(float[4]) : 0)) + (vblendindexes && vblendweights ? meshvertices * sizeof(unsigned short) : 0) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t)); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); @@ -3369,7 +3384,7 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) { loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]); } - loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]); + loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]); if (vblendindexes && vblendweights) loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t)); @@ -3474,6 +3489,8 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) } loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1); + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer; loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL; biggestorigin = 0; @@ -3555,12 +3572,19 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) { for (j = 0;j < (int)header.num_poses;j++, k++) { - loadmodel->data_poses6s[k*6 + 0] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[0] + (pose1[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[0] : 0)); - loadmodel->data_poses6s[k*6 + 1] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[1] + (pose1[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[1] : 0)); - loadmodel->data_poses6s[k*6 + 2] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[2] + (pose1[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[2] : 0)); - loadmodel->data_poses6s[k*6 + 3] = 32767.0f * (pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0)); - loadmodel->data_poses6s[k*6 + 4] = 32767.0f * (pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0)); - loadmodel->data_poses6s[k*6 + 5] = 32767.0f * (pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0)); + float qx, qy, qz, qw; + loadmodel->data_poses7s[k*7 + 0] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[0] + (pose1[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[0] : 0)); + loadmodel->data_poses7s[k*7 + 1] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[1] + (pose1[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[1] : 0)); + loadmodel->data_poses7s[k*7 + 2] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[2] + (pose1[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[2] : 0)); + qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0); + qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0); + qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0); + qw = 1.0f - (qx*qx + qy*qy + qz*qz); + qw = qw > 0.0f ? -sqrt(qw) : 0.0f; + loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx; + loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy; + loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz; + loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw; // skip scale data for now if(pose1[j].channelmask&64) framedata++; if(pose1[j].channelmask&128) framedata++; @@ -3571,12 +3595,19 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) { for (i = 0;i < loadmodel->num_bones;i++) { - loadmodel->data_poses6s[i*6 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0]; - loadmodel->data_poses6s[i*6 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1]; - loadmodel->data_poses6s[i*6 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2]; - loadmodel->data_poses6s[i*6 + 3] = 32767.0f * joint1[i].rotation[0]; - loadmodel->data_poses6s[i*6 + 4] = 32767.0f * joint1[i].rotation[1]; - loadmodel->data_poses6s[i*6 + 5] = 32767.0f * joint1[i].rotation[2]; + float qx, qy, qz, qw; + loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0]; + loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1]; + loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2]; + qx = joint1[i].rotation[0]; + qy = joint1[i].rotation[1]; + qz = joint1[i].rotation[2]; + qw = 1.0f - (qx*qx + qy*qy + qz*qz); + qw = qw > 0.0f ? -sqrt(qw) : 0.0f; + loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx; + loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy; + loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz; + loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw; } } } @@ -3587,9 +3618,9 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) for (j = 0;j < (int)header.num_poses;j++, k++) { float rot[4]; - loadmodel->data_poses6s[k*6 + 0] = loadmodel->num_poseinvscale * (pose[j].channeloffset[0] + (pose[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[0] : 0)); - loadmodel->data_poses6s[k*6 + 1] = loadmodel->num_poseinvscale * (pose[j].channeloffset[1] + (pose[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[1] : 0)); - loadmodel->data_poses6s[k*6 + 2] = loadmodel->num_poseinvscale * (pose[j].channeloffset[2] + (pose[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[2] : 0)); + loadmodel->data_poses7s[k*7 + 0] = loadmodel->num_poseinvscale * (pose[j].channeloffset[0] + (pose[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[0] : 0)); + loadmodel->data_poses7s[k*7 + 1] = loadmodel->num_poseinvscale * (pose[j].channeloffset[1] + (pose[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[1] : 0)); + loadmodel->data_poses7s[k*7 + 2] = loadmodel->num_poseinvscale * (pose[j].channeloffset[2] + (pose[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[2] : 0)); rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0); rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0); rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0); @@ -3597,9 +3628,10 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) if (rot[3] > 0) Vector4Negate(rot, rot); Vector4Normalize2(rot, rot); - loadmodel->data_poses6s[k*6 + 3] = 32767.0f * rot[0]; - loadmodel->data_poses6s[k*6 + 4] = 32767.0f * rot[1]; - loadmodel->data_poses6s[k*6 + 5] = 32767.0f * rot[2]; + loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0]; + loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1]; + loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2]; + loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3]; // skip scale data for now if(pose[j].channelmask&128) framedata++; if(pose[j].channelmask&256) framedata++; @@ -3610,12 +3642,13 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) { for (i = 0;i < loadmodel->num_bones;i++) { - loadmodel->data_poses6s[i*6 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0]; - loadmodel->data_poses6s[i*6 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1]; - loadmodel->data_poses6s[i*6 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2]; - loadmodel->data_poses6s[i*6 + 3] = 32767.0f * joint[i].rotation[0]; - loadmodel->data_poses6s[i*6 + 4] = 32767.0f * joint[i].rotation[1]; - loadmodel->data_poses6s[i*6 + 5] = 32767.0f * joint[i].rotation[2]; + loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0]; + loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1]; + loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2]; + loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0]; + loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1]; + loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2]; + loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3]; } } } diff --git a/misc/source/darkplaces-src/model_brush.c b/misc/source/darkplaces-src/model_brush.c index eca65464..23fa6d48 100644 --- a/misc/source/darkplaces-src/model_brush.c +++ b/misc/source/darkplaces-src/model_brush.c @@ -40,6 +40,7 @@ cvar_t r_subdivisions_collision_maxtess = {0, "r_subdivisions_collision_maxtess" cvar_t r_subdivisions_collision_maxvertices = {0, "r_subdivisions_collision_maxvertices", "4225", "maximum vertices allowed per subdivided curve"}; cvar_t r_trippy = {0, "r_trippy", "0", "easter egg"}; cvar_t mod_noshader_default_offsetmapping = {CVAR_SAVE, "mod_noshader_default_offsetmapping", "1", "use offsetmapping by default on all surfaces that are not using q3 shader files"}; +cvar_t mod_obj_orientation = {0, "mod_obj_orientation", "1", "fix orientation of OBJ models to the usual conventions (if zero, use coordinates as is)"}; cvar_t mod_q3bsp_curves_collisions = {0, "mod_q3bsp_curves_collisions", "1", "enables collisions with curves (SLOW)"}; cvar_t mod_q3bsp_curves_collisions_stride = {0, "mod_q3bsp_curves_collisions_stride", "16", "collisions against curves: optimize performance by doing a combined collision check for this triangle amount first (-1 avoids any box tests)"}; cvar_t mod_q3bsp_curves_stride = {0, "mod_q3bsp_curves_stride", "16", "particle effect collisions against curves: optimize performance by doing a combined collision check for this triangle amount first (-1 avoids any box tests)"}; @@ -81,6 +82,7 @@ void Mod_BrushInit(void) Cvar_RegisterVariable(&r_subdivisions_collision_maxvertices); Cvar_RegisterVariable(&r_trippy); Cvar_RegisterVariable(&mod_noshader_default_offsetmapping); + Cvar_RegisterVariable(&mod_obj_orientation); Cvar_RegisterVariable(&mod_q3bsp_curves_collisions); Cvar_RegisterVariable(&mod_q3bsp_curves_collisions_stride); Cvar_RegisterVariable(&mod_q3bsp_curves_stride); @@ -1598,18 +1600,17 @@ static void R_Q1BSP_LoadSplitSky (unsigned char *src, int width, int height, int Mem_Free(alphapixels); } -static void Mod_Q1BSP_LoadTextures(lump_t *l) +static void Mod_Q1BSP_LoadTextures(sizebuf_t *sb) { - int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs, incomplete; + int i, j, k, num, max, altmax, mtwidth, mtheight, doffset, incomplete, nummiptex = 0; skinframe_t *skinframe; - miptex_t *dmiptex; texture_t *tx, *tx2, *anims[10], *altanims[10]; texture_t backuptex; - dmiptexlump_t *m; unsigned char *data, *mtdata; const char *s; char mapname[MAX_QPATH], name[MAX_QPATH]; unsigned char zeroopaque[4], zerotrans[4]; + sizebuf_t miptexsb; char vabuf[1024]; Vector4Set(zeroopaque, 0, 0, 0, 255); Vector4Set(zerotrans, 0, 0, 0, 128); @@ -1617,16 +1618,14 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) loadmodel->data_textures = NULL; // add two slots for notexture walls and notexture liquids - if (l->filelen) + if (sb->cursize) { - m = (dmiptexlump_t *)(mod_base + l->fileofs); - m->nummiptex = LittleLong (m->nummiptex); - loadmodel->num_textures = m->nummiptex + 2; + nummiptex = MSG_ReadLittleLong(sb); + loadmodel->num_textures = nummiptex + 2; loadmodel->num_texturesperskin = loadmodel->num_textures; } else { - m = NULL; loadmodel->num_textures = 2; loadmodel->num_texturesperskin = loadmodel->num_textures; } @@ -1679,7 +1678,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) tx->specularpowermod = 1; } - if (!m) + if (!sb->cursize) { Con_Printf("%s: no miptex lump to load textures from\n", loadmodel->name); return; @@ -1691,26 +1690,29 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) FS_StripExtension(s, mapname, sizeof(mapname)); // just to work around bounds checking when debugging with it (array index out of bounds error thing) - dofs = m->dataofs; // LordHavoc: mostly rewritten map texture loader - for (i = 0;i < m->nummiptex;i++) + for (i = 0;i < nummiptex;i++) { - dofs[i] = LittleLong(dofs[i]); + doffset = MSG_ReadLittleLong(sb); if (r_nosurftextures.integer) continue; - if (dofs[i] == -1) + if (doffset == -1) { Con_DPrintf("%s: miptex #%i missing\n", loadmodel->name, i); continue; } - dmiptex = (miptex_t *)((unsigned char *)m + dofs[i]); + + MSG_InitReadBuffer(&miptexsb, sb->data + doffset, sb->cursize - doffset); // copy name, but only up to 16 characters // (the output buffer can hold more than this, but the input buffer is // only 16) - for (j = 0;j < 16 && dmiptex->name[j];j++) - name[j] = dmiptex->name[j]; + for (j = 0;j < 16;j++) + name[j] = MSG_ReadByte(&miptexsb); name[j] = 0; + // pretty up the buffer (replacing any trailing garbage with 0) + for (j = strlen(name);j < 16;j++) + name[j] = 0; if (!name[0]) { @@ -1718,23 +1720,23 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) Con_DPrintf("%s: warning: renaming unnamed texture to %s\n", loadmodel->name, name); } - mtwidth = LittleLong(dmiptex->width); - mtheight = LittleLong(dmiptex->height); + mtwidth = MSG_ReadLittleLong(&miptexsb); + mtheight = MSG_ReadLittleLong(&miptexsb); mtdata = NULL; - j = LittleLong(dmiptex->offsets[0]); + j = MSG_ReadLittleLong(&miptexsb); if (j) { // texture included - if (j < 40 || j + mtwidth * mtheight > l->filelen) + if (j < 40 || j + mtwidth * mtheight > miptexsb.cursize) { - Con_Printf("%s: Texture \"%s\" is corrupt or incomplete\n", loadmodel->name, dmiptex->name); + Con_Printf("%s: Texture \"%s\" is corrupt or incomplete\n", loadmodel->name, name); continue; } - mtdata = (unsigned char *)dmiptex + j; + mtdata = miptexsb.data + j; } if ((mtwidth & 15) || (mtheight & 15)) - Con_DPrintf("%s: warning: texture \"%s\" is not 16 aligned\n", loadmodel->name, dmiptex->name); + Con_DPrintf("%s: warning: texture \"%s\" is not 16 aligned\n", loadmodel->name, name); // LordHavoc: force all names to lowercase for (j = 0;name[j];j++) @@ -1743,7 +1745,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) // LordHavoc: backup the texture_t because q3 shader loading overwrites it backuptex = loadmodel->data_textures[i]; - if (dmiptex->name[0] && Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i, name, false, false, 0)) + if (name[0] && Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i, name, false, false, 0)) continue; loadmodel->data_textures[i] = backuptex; @@ -1814,7 +1816,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) unsigned char *pixels, *freepixels; pixels = freepixels = NULL; if (mtdata) - pixels = W_ConvertWAD3TextureBGRA(dmiptex); + pixels = W_ConvertWAD3TextureBGRA(&miptexsb); if (pixels == NULL) pixels = freepixels = W_GetTextureBGRA(tx->name); if (pixels != NULL) @@ -1874,7 +1876,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) } // sequence the animations - for (i = 0;i < m->nummiptex;i++) + for (i = 0;i < nummiptex;i++) { tx = loadmodel->data_textures + i; if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0) @@ -1886,7 +1888,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) memset(anims, 0, sizeof(anims)); memset(altanims, 0, sizeof(altanims)); - for (j = i;j < m->nummiptex;j++) + for (j = i;j < nummiptex;j++) { tx2 = loadmodel->data_textures + j; if (!tx2 || tx2->name[0] != '+' || strcmp(tx2->name+2, tx->name+2)) @@ -1975,7 +1977,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) } } -static void Mod_Q1BSP_LoadLighting(lump_t *l) +static void Mod_Q1BSP_LoadLighting(sizebuf_t *sb) { int i; unsigned char *in, *out, *data, d; @@ -1984,9 +1986,9 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l) fs_offset_t filesize; if (loadmodel->brush.ishlbsp) // LordHavoc: load the colored lighting data straight { - loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, l->filelen); - for (i=0; ifilelen; i++) - loadmodel->brushq1.lightdata[i] = mod_base[l->fileofs+i] >>= 1; + loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, sb->cursize); + for (i = 0;i < sb->cursize;i++) + loadmodel->brushq1.lightdata[i] = sb->data[i] >>= 1; } else // LordHavoc: bsp version 29 (normal white lighting) { @@ -1999,7 +2001,7 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l) data = (unsigned char*) FS_LoadFile(litfilename, tempmempool, false, &filesize); if (data) { - if (filesize == (fs_offset_t)(8 + l->filelen * 3) && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') + if (filesize == (fs_offset_t)(8 + sb->cursize * 3) && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') { i = LittleLong(((int *)data)[1]); if (i == 1) @@ -2012,7 +2014,7 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l) data = (unsigned char*) FS_LoadFile(dlitfilename, tempmempool, false, &filesize); if (data) { - if (filesize == (fs_offset_t)(8 + l->filelen * 3) && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') + if (filesize == (fs_offset_t)(8 + sb->cursize * 3) && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') { i = LittleLong(((int *)data)[1]); if (i == 1) @@ -2036,7 +2038,7 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l) else if (filesize == 8) Con_Print("Empty .lit file, ignoring\n"); else - Con_Printf("Corrupt .lit file (file size %i bytes, should be %i bytes), ignoring\n", (int) filesize, (int) (8 + l->filelen * 3)); + Con_Printf("Corrupt .lit file (file size %i bytes, should be %i bytes), ignoring\n", (int) filesize, (int) (8 + sb->cursize * 3)); if (data) { Mem_Free(data); @@ -2044,12 +2046,12 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l) } } // LordHavoc: oh well, expand the white lighting data - if (!l->filelen) + if (!sb->cursize) return; - loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, l->filelen*3); - in = mod_base + l->fileofs; + loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, sb->cursize*3); + in = sb->data; out = loadmodel->brushq1.lightdata; - for (i = 0;i < l->filelen;i++) + for (i = 0;i < sb->cursize;i++) { d = *in++; *out++ = d; @@ -2059,15 +2061,15 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l) } } -static void Mod_Q1BSP_LoadVisibility(lump_t *l) +static void Mod_Q1BSP_LoadVisibility(sizebuf_t *sb) { loadmodel->brushq1.num_compressedpvs = 0; loadmodel->brushq1.data_compressedpvs = NULL; - if (!l->filelen) + if (!sb->cursize) return; - loadmodel->brushq1.num_compressedpvs = l->filelen; - loadmodel->brushq1.data_compressedpvs = (unsigned char *)Mem_Alloc(loadmodel->mempool, l->filelen); - memcpy(loadmodel->brushq1.data_compressedpvs, mod_base + l->fileofs, l->filelen); + loadmodel->brushq1.num_compressedpvs = sb->cursize; + loadmodel->brushq1.data_compressedpvs = (unsigned char *)Mem_Alloc(loadmodel->mempool, sb->cursize); + MSG_ReadBytes(sb, sb->cursize, loadmodel->brushq1.data_compressedpvs); } // used only for HalfLife maps @@ -2127,78 +2129,52 @@ static void Mod_Q1BSP_ParseWadsFromEntityLump(const char *data) } } -static void Mod_Q1BSP_LoadEntities(lump_t *l) +static void Mod_Q1BSP_LoadEntities(sizebuf_t *sb) { loadmodel->brush.entities = NULL; - if (!l->filelen) + if (!sb->cursize) return; - loadmodel->brush.entities = (char *)Mem_Alloc(loadmodel->mempool, l->filelen + 1); - memcpy(loadmodel->brush.entities, mod_base + l->fileofs, l->filelen); - loadmodel->brush.entities[l->filelen] = 0; + loadmodel->brush.entities = (char *)Mem_Alloc(loadmodel->mempool, sb->cursize + 1); + MSG_ReadBytes(sb, sb->cursize, (unsigned char *)loadmodel->brush.entities); + loadmodel->brush.entities[sb->cursize] = 0; if (loadmodel->brush.ishlbsp) Mod_Q1BSP_ParseWadsFromEntityLump(loadmodel->brush.entities); } -static void Mod_Q1BSP_LoadVertexes(lump_t *l) +static void Mod_Q1BSP_LoadVertexes(sizebuf_t *sb) { - dvertex_t *in; mvertex_t *out; int i, count; + size_t structsize = 12; - in = (dvertex_t *)(mod_base + l->fileofs); - if (l->filelen % sizeof(*in)) + if (sb->cursize % structsize) Host_Error("Mod_Q1BSP_LoadVertexes: funny lump size in %s",loadmodel->name); - count = l->filelen / sizeof(*in); + count = sb->cursize / structsize; out = (mvertex_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(*out)); loadmodel->brushq1.vertexes = out; loadmodel->brushq1.numvertexes = count; - for ( i=0 ; iposition[0] = LittleFloat(in->point[0]); - out->position[1] = LittleFloat(in->point[1]); - out->position[2] = LittleFloat(in->point[2]); + out->position[0] = MSG_ReadLittleFloat(sb); + out->position[1] = MSG_ReadLittleFloat(sb); + out->position[2] = MSG_ReadLittleFloat(sb); } } -// The following two functions should be removed and MSG_* or SZ_* function sets adjusted so they -// can be used for this -// REMOVEME -static int SB_ReadInt (unsigned char **buffer) +static void Mod_Q1BSP_LoadSubmodels(sizebuf_t *sb, hullinfo_t *hullinfo) { - int i; - i = ((*buffer)[0]) + 256*((*buffer)[1]) + 65536*((*buffer)[2]) + 16777216*((*buffer)[3]); - (*buffer) += 4; - return i; -} - -// REMOVEME -static float SB_ReadFloat (unsigned char **buffer) -{ - union - { - int i; - float f; - } u; - - u.i = SB_ReadInt (buffer); - return u.f; -} - -static void Mod_Q1BSP_LoadSubmodels(lump_t *l, hullinfo_t *hullinfo) -{ - unsigned char *index; - dmodel_t *out; + mmodel_t *out; int i, j, count; + size_t structsize = (48+4*hullinfo->filehulls); - index = (unsigned char *)(mod_base + l->fileofs); - if (l->filelen % (48+4*hullinfo->filehulls)) + if (sb->cursize % structsize) Host_Error ("Mod_Q1BSP_LoadSubmodels: funny lump size in %s", loadmodel->name); - count = l->filelen / (48+4*hullinfo->filehulls); - out = (dmodel_t *)Mem_Alloc (loadmodel->mempool, count*sizeof(*out)); + count = sb->cursize / structsize; + out = (mmodel_t *)Mem_Alloc (loadmodel->mempool, count*sizeof(*out)); loadmodel->brushq1.submodels = out; loadmodel->brush.numsubmodels = count; @@ -2206,42 +2182,49 @@ static void Mod_Q1BSP_LoadSubmodels(lump_t *l, hullinfo_t *hullinfo) for (i = 0; i < count; i++, out++) { // spread out the mins / maxs by a pixel - out->mins[0] = SB_ReadFloat (&index) - 1; - out->mins[1] = SB_ReadFloat (&index) - 1; - out->mins[2] = SB_ReadFloat (&index) - 1; - out->maxs[0] = SB_ReadFloat (&index) + 1; - out->maxs[1] = SB_ReadFloat (&index) + 1; - out->maxs[2] = SB_ReadFloat (&index) + 1; - out->origin[0] = SB_ReadFloat (&index); - out->origin[1] = SB_ReadFloat (&index); - out->origin[2] = SB_ReadFloat (&index); + out->mins[0] = MSG_ReadLittleFloat(sb) - 1; + out->mins[1] = MSG_ReadLittleFloat(sb) - 1; + out->mins[2] = MSG_ReadLittleFloat(sb) - 1; + out->maxs[0] = MSG_ReadLittleFloat(sb) + 1; + out->maxs[1] = MSG_ReadLittleFloat(sb) + 1; + out->maxs[2] = MSG_ReadLittleFloat(sb) + 1; + out->origin[0] = MSG_ReadLittleFloat(sb); + out->origin[1] = MSG_ReadLittleFloat(sb); + out->origin[2] = MSG_ReadLittleFloat(sb); for (j = 0; j < hullinfo->filehulls; j++) - out->headnode[j] = SB_ReadInt (&index); - out->visleafs = SB_ReadInt (&index); - out->firstface = SB_ReadInt (&index); - out->numfaces = SB_ReadInt (&index); + out->headnode[j] = MSG_ReadLittleLong(sb); + out->visleafs = MSG_ReadLittleLong(sb); + out->firstface = MSG_ReadLittleLong(sb); + out->numfaces = MSG_ReadLittleLong(sb); } } -static void Mod_Q1BSP_LoadEdges(lump_t *l) +static void Mod_Q1BSP_LoadEdges(sizebuf_t *sb) { - dedge_t *in; medge_t *out; int i, count; + size_t structsize = loadmodel->brush.isbsp2 ? 8 : 4; - in = (dedge_t *)(mod_base + l->fileofs); - if (l->filelen % sizeof(*in)) + if (sb->cursize % structsize) Host_Error("Mod_Q1BSP_LoadEdges: funny lump size in %s",loadmodel->name); - count = l->filelen / sizeof(*in); + count = sb->cursize / structsize; out = (medge_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); loadmodel->brushq1.edges = out; loadmodel->brushq1.numedges = count; - for ( i=0 ; iv[0] = (unsigned short)LittleShort(in->v[0]); - out->v[1] = (unsigned short)LittleShort(in->v[1]); + if (loadmodel->brush.isbsp2) + { + out->v[0] = (unsigned int)MSG_ReadLittleLong(sb); + out->v[1] = (unsigned int)MSG_ReadLittleLong(sb); + } + else + { + out->v[0] = (unsigned short)MSG_ReadLittleShort(sb); + out->v[1] = (unsigned short)MSG_ReadLittleShort(sb); + } if (out->v[0] >= loadmodel->brushq1.numvertexes || out->v[1] >= loadmodel->brushq1.numvertexes) { Con_Printf("Mod_Q1BSP_LoadEdges: %s has invalid vertex indices in edge %i (vertices %i %i >= numvertices %i)\n", loadmodel->name, i, out->v[0], out->v[1], loadmodel->brushq1.numvertexes); @@ -2254,29 +2237,28 @@ static void Mod_Q1BSP_LoadEdges(lump_t *l) } } -static void Mod_Q1BSP_LoadTexinfo(lump_t *l) +static void Mod_Q1BSP_LoadTexinfo(sizebuf_t *sb) { - texinfo_t *in; mtexinfo_t *out; int i, j, k, count, miptex; + size_t structsize = 40; - in = (texinfo_t *)(mod_base + l->fileofs); - if (l->filelen % sizeof(*in)) + if (sb->cursize % structsize) Host_Error("Mod_Q1BSP_LoadTexinfo: funny lump size in %s",loadmodel->name); - count = l->filelen / sizeof(*in); + count = sb->cursize / structsize; out = (mtexinfo_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); loadmodel->brushq1.texinfo = out; loadmodel->brushq1.numtexinfo = count; - for (i = 0;i < count;i++, in++, out++) + for (i = 0;i < count;i++, out++) { for (k = 0;k < 2;k++) for (j = 0;j < 4;j++) - out->vecs[k][j] = LittleFloat(in->vecs[k][j]); + out->vecs[k][j] = MSG_ReadLittleFloat(sb); - miptex = LittleLong(in->miptex); - out->flags = LittleLong(in->flags); + miptex = MSG_ReadLittleLong(sb); + out->flags = MSG_ReadLittleLong(sb); out->texture = NULL; if (loadmodel->data_textures) @@ -2455,19 +2437,18 @@ static void Mod_Q1BSP_GenerateWarpMesh(msurface_t *surface) #endif extern cvar_t gl_max_lightmapsize; -static void Mod_Q1BSP_LoadFaces(lump_t *l) +static void Mod_Q1BSP_LoadFaces(sizebuf_t *sb) { - dface_t *in; msurface_t *surface; - int i, j, count, surfacenum, planenum, smax, tmax, ssize, tsize, firstedge, numedges, totalverts, totaltris, lightmapnumber, lightmapsize, totallightmapsamples; + int i, j, count, surfacenum, planenum, smax, tmax, ssize, tsize, firstedge, numedges, totalverts, totaltris, lightmapnumber, lightmapsize, totallightmapsamples, lightmapoffset, texinfoindex; float texmins[2], texmaxs[2], val; rtexture_t *lightmaptexture, *deluxemaptexture; char vabuf[1024]; + size_t structsize = loadmodel->brush.isbsp2 ? 28 : 20; - in = (dface_t *)(mod_base + l->fileofs); - if (l->filelen % sizeof(*in)) + if (sb->cursize % structsize) Host_Error("Mod_Q1BSP_LoadFaces: funny lump size in %s",loadmodel->name); - count = l->filelen / sizeof(*in); + count = sb->cursize / structsize; loadmodel->data_surfaces = (msurface_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(msurface_t)); loadmodel->data_surfaces_lightmapinfo = (msurface_lightmapinfo_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(msurface_lightmapinfo_t)); @@ -2478,9 +2459,12 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) totalverts = 0; totaltris = 0; - for (surfacenum = 0, in = (dface_t *)(mod_base + l->fileofs);surfacenum < count;surfacenum++, in++) + for (surfacenum = 0;surfacenum < count;surfacenum++) { - numedges = (unsigned short)LittleShort(in->numedges); + if (loadmodel->brush.isbsp2) + numedges = BuffLittleLong(sb->data + structsize * surfacenum + 12); + else + numedges = BuffLittleShort(sb->data + structsize * surfacenum + 8); totalverts += numedges; totaltris += numedges - 2; } @@ -2495,25 +2479,29 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) totalverts = 0; totaltris = 0; - for (surfacenum = 0, in = (dface_t *)(mod_base + l->fileofs), surface = loadmodel->data_surfaces;surfacenum < count;surfacenum++, in++, surface++) + for (surfacenum = 0, surface = loadmodel->data_surfaces;surfacenum < count;surfacenum++, surface++) { surface->lightmapinfo = loadmodel->data_surfaces_lightmapinfo + surfacenum; + planenum = loadmodel->brush.isbsp2 ? MSG_ReadLittleLong(sb) : (unsigned short)MSG_ReadLittleShort(sb); + /*side = */loadmodel->brush.isbsp2 ? MSG_ReadLittleLong(sb) : (unsigned short)MSG_ReadLittleShort(sb); + firstedge = MSG_ReadLittleLong(sb); + numedges = loadmodel->brush.isbsp2 ? MSG_ReadLittleLong(sb) : (unsigned short)MSG_ReadLittleShort(sb); + texinfoindex = loadmodel->brush.isbsp2 ? MSG_ReadLittleLong(sb) : (unsigned short)MSG_ReadLittleShort(sb); + for (i = 0;i < MAXLIGHTMAPS;i++) + surface->lightmapinfo->styles[i] = MSG_ReadByte(sb); + lightmapoffset = MSG_ReadLittleLong(sb); // FIXME: validate edges, texinfo, etc? - firstedge = LittleLong(in->firstedge); - numedges = (unsigned short)LittleShort(in->numedges); if ((unsigned int) firstedge > (unsigned int) loadmodel->brushq1.numsurfedges || (unsigned int) numedges > (unsigned int) loadmodel->brushq1.numsurfedges || (unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->brushq1.numsurfedges) Host_Error("Mod_Q1BSP_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)", firstedge, numedges, loadmodel->brushq1.numsurfedges); - i = (unsigned short)LittleShort(in->texinfo); - if ((unsigned int) i >= (unsigned int) loadmodel->brushq1.numtexinfo) - Host_Error("Mod_Q1BSP_LoadFaces: invalid texinfo index %i(model has %i texinfos)", i, loadmodel->brushq1.numtexinfo); - surface->lightmapinfo->texinfo = loadmodel->brushq1.texinfo + i; - surface->texture = surface->lightmapinfo->texinfo->texture; - - planenum = (unsigned short)LittleShort(in->planenum); + if ((unsigned int) texinfoindex >= (unsigned int) loadmodel->brushq1.numtexinfo) + Host_Error("Mod_Q1BSP_LoadFaces: invalid texinfo index %i(model has %i texinfos)", texinfoindex, loadmodel->brushq1.numtexinfo); if ((unsigned int) planenum >= (unsigned int) loadmodel->brush.num_planes) Host_Error("Mod_Q1BSP_LoadFaces: invalid plane index %i (model has %i planes)", planenum, loadmodel->brush.num_planes); + surface->lightmapinfo->texinfo = loadmodel->brushq1.texinfo + texinfoindex; + surface->texture = surface->lightmapinfo->texinfo->texture; + //surface->flags = surface->texture->flags; //if (LittleShort(in->side)) // surface->flags |= SURF_PLANEBACK; @@ -2581,12 +2569,9 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) tsize = (surface->lightmapinfo->extents[1] >> 4) + 1; // lighting info - for (i = 0;i < MAXLIGHTMAPS;i++) - surface->lightmapinfo->styles[i] = in->styles[i]; surface->lightmaptexture = NULL; surface->deluxemaptexture = r_texture_blanknormalmap; - i = LittleLong(in->lightofs); - if (i == -1) + if (lightmapoffset == -1) { surface->lightmapinfo->samples = NULL; #if 1 @@ -2600,12 +2585,12 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) #endif } else if (loadmodel->brush.ishlbsp) // LordHavoc: HalfLife map (bsp version 30) - surface->lightmapinfo->samples = loadmodel->brushq1.lightdata + i; + surface->lightmapinfo->samples = loadmodel->brushq1.lightdata + lightmapoffset; else // LordHavoc: white lighting (bsp version 29) { - surface->lightmapinfo->samples = loadmodel->brushq1.lightdata + (i * 3); + surface->lightmapinfo->samples = loadmodel->brushq1.lightdata + (lightmapoffset * 3); if (loadmodel->brushq1.nmaplightdata) - surface->lightmapinfo->nmapsamples = loadmodel->brushq1.nmaplightdata + (i * 3); + surface->lightmapinfo->nmapsamples = loadmodel->brushq1.nmaplightdata + (lightmapoffset * 3); } // check if we should apply a lightmap to this @@ -2763,16 +2748,15 @@ static void Mod_Q1BSP_LoadNodes_RecursiveSetParent(mnode_t *node, mnode_t *paren } } -static void Mod_Q1BSP_LoadNodes(lump_t *l) +static void Mod_Q1BSP_LoadNodes(sizebuf_t *sb) { - int i, j, count, p; - dnode_t *in; + int i, j, count, p, child[2]; mnode_t *out; + size_t structsize = loadmodel->brush.isbsp2 ? 44 : 24; - in = (dnode_t *)(mod_base + l->fileofs); - if (l->filelen % sizeof(*in)) + if (sb->cursize % structsize) Host_Error("Mod_Q1BSP_LoadNodes: funny lump size in %s",loadmodel->name); - count = l->filelen / sizeof(*in); + count = sb->cursize / structsize; if (count == 0) Host_Error("Mod_Q1BSP_LoadNodes: missing BSP tree in %s",loadmodel->name); out = (mnode_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(*out)); @@ -2780,19 +2764,43 @@ static void Mod_Q1BSP_LoadNodes(lump_t *l) loadmodel->brush.data_nodes = out; loadmodel->brush.num_nodes = count; - for ( i=0 ; iplane = loadmodel->brush.data_planes + p; + + if (loadmodel->brush.isbsp2) { - out->mins[j] = LittleShort(in->mins[j]); - out->maxs[j] = LittleShort(in->maxs[j]); + child[0] = MSG_ReadLittleLong(sb); + child[1] = MSG_ReadLittleLong(sb); + out->mins[0] = MSG_ReadLittleFloat(sb); + out->mins[1] = MSG_ReadLittleFloat(sb); + out->mins[2] = MSG_ReadLittleFloat(sb); + out->maxs[0] = MSG_ReadLittleFloat(sb); + out->maxs[1] = MSG_ReadLittleFloat(sb); + out->maxs[2] = MSG_ReadLittleFloat(sb); + out->firstsurface = MSG_ReadLittleLong(sb); + out->numsurfaces = MSG_ReadLittleLong(sb); } + else + { + child[0] = (unsigned short)MSG_ReadLittleShort(sb); + child[1] = (unsigned short)MSG_ReadLittleShort(sb); + if (child[0] >= count) + child[0] -= 65536; + if (child[1] >= count) + child[1] -= 65536; - p = LittleLong(in->planenum); - out->plane = loadmodel->brush.data_planes + p; + out->mins[0] = MSG_ReadLittleShort(sb); + out->mins[1] = MSG_ReadLittleShort(sb); + out->mins[2] = MSG_ReadLittleShort(sb); + out->maxs[0] = MSG_ReadLittleShort(sb); + out->maxs[1] = MSG_ReadLittleShort(sb); + out->maxs[2] = MSG_ReadLittleShort(sb); - out->firstsurface = (unsigned short)LittleShort(in->firstface); - out->numsurfaces = (unsigned short)LittleShort(in->numfaces); + out->firstsurface = (unsigned short)MSG_ReadLittleShort(sb); + out->numsurfaces = (unsigned short)MSG_ReadLittleShort(sb); + } for (j=0 ; j<2 ; j++) { @@ -2800,8 +2808,8 @@ static void Mod_Q1BSP_LoadNodes(lump_t *l) // arguire qbsp which can produce more than 32768 nodes, any value // below count is assumed to be a node number, any other value is // assumed to be a leaf number - p = (unsigned short)LittleShort(in->children[j]); - if (p < count) + p = child[j]; + if (p >= 0) { if (p < loadmodel->brush.num_nodes) out->children[j] = loadmodel->brush.data_nodes + p; @@ -2814,8 +2822,8 @@ static void Mod_Q1BSP_LoadNodes(lump_t *l) } else { - // note this uses 65535 intentionally, -1 is leaf 0 - p = 65535 - p; + // get leaf index as a positive value starting at 0 (-1 becomes 0, -2 becomes 1, etc) + p = -(p+1); if (p < loadmodel->brush.num_leafs) out->children[j] = (mnode_t *)(loadmodel->brush.data_leafs + p); else @@ -2831,16 +2839,15 @@ static void Mod_Q1BSP_LoadNodes(lump_t *l) Mod_Q1BSP_LoadNodes_RecursiveSetParent(loadmodel->brush.data_nodes, NULL); // sets nodes and leafs } -static void Mod_Q1BSP_LoadLeafs(lump_t *l) +static void Mod_Q1BSP_LoadLeafs(sizebuf_t *sb) { - dleaf_t *in; mleaf_t *out; - int i, j, count, p; + int i, j, count, p, firstmarksurface, nummarksurfaces; + size_t structsize = loadmodel->brush.isbsp2 ? 44 : 28; - in = (dleaf_t *)(mod_base + l->fileofs); - if (l->filelen % sizeof(*in)) + if (sb->cursize % structsize) Host_Error("Mod_Q1BSP_LoadLeafs: funny lump size in %s",loadmodel->name); - count = l->filelen / sizeof(*in); + count = sb->cursize / structsize; out = (mleaf_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(*out)); loadmodel->brush.data_leafs = out; @@ -2851,32 +2858,16 @@ static void Mod_Q1BSP_LoadLeafs(lump_t *l) loadmodel->brush.data_pvsclusters = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->brush.num_pvsclusters * loadmodel->brush.num_pvsclusterbytes); memset(loadmodel->brush.data_pvsclusters, 0xFF, loadmodel->brush.num_pvsclusters * loadmodel->brush.num_pvsclusterbytes); - for ( i=0 ; imins[j] = LittleShort(in->mins[j]); - out->maxs[j] = LittleShort(in->maxs[j]); - } - - // FIXME: this function could really benefit from some error checking - - out->contents = LittleLong(in->contents); - - out->firstleafsurface = loadmodel->brush.data_leafsurfaces + (unsigned short)LittleShort(in->firstmarksurface); - out->numleafsurfaces = (unsigned short)LittleShort(in->nummarksurfaces); - if ((unsigned short)LittleShort(in->firstmarksurface) + out->numleafsurfaces > loadmodel->brush.num_leafsurfaces) - { - Con_Printf("Mod_Q1BSP_LoadLeafs: invalid leafsurface range %i:%i outside range %i:%i\n", (int)(out->firstleafsurface - loadmodel->brush.data_leafsurfaces), (int)(out->firstleafsurface + out->numleafsurfaces - loadmodel->brush.data_leafsurfaces), 0, loadmodel->brush.num_leafsurfaces); - out->firstleafsurface = NULL; - out->numleafsurfaces = 0; - } + out->contents = MSG_ReadLittleLong(sb); out->clusterindex = i - 1; if (out->clusterindex >= loadmodel->brush.num_pvsclusters) out->clusterindex = -1; - p = LittleLong(in->visofs); + p = MSG_ReadLittleLong(sb); // ignore visofs errors on leaf 0 (solid) if (p >= 0 && out->clusterindex >= 0) { @@ -2886,10 +2877,45 @@ static void Mod_Q1BSP_LoadLeafs(lump_t *l) Mod_Q1BSP_DecompressVis(loadmodel->brushq1.data_compressedpvs + p, loadmodel->brushq1.data_compressedpvs + loadmodel->brushq1.num_compressedpvs, loadmodel->brush.data_pvsclusters + out->clusterindex * loadmodel->brush.num_pvsclusterbytes, loadmodel->brush.data_pvsclusters + (out->clusterindex + 1) * loadmodel->brush.num_pvsclusterbytes); } - for (j = 0;j < 4;j++) - out->ambient_sound_level[j] = in->ambient_level[j]; + if (loadmodel->brush.isbsp2) + { + out->mins[0] = MSG_ReadLittleFloat(sb); + out->mins[1] = MSG_ReadLittleFloat(sb); + out->mins[2] = MSG_ReadLittleFloat(sb); + out->maxs[0] = MSG_ReadLittleFloat(sb); + out->maxs[1] = MSG_ReadLittleFloat(sb); + out->maxs[2] = MSG_ReadLittleFloat(sb); + + firstmarksurface = MSG_ReadLittleLong(sb); + nummarksurfaces = MSG_ReadLittleLong(sb); + } + else + { + out->mins[0] = MSG_ReadLittleShort(sb); + out->mins[1] = MSG_ReadLittleShort(sb); + out->mins[2] = MSG_ReadLittleShort(sb); + out->maxs[0] = MSG_ReadLittleShort(sb); + out->maxs[1] = MSG_ReadLittleShort(sb); + out->maxs[2] = MSG_ReadLittleShort(sb); + + firstmarksurface = (unsigned short)MSG_ReadLittleShort(sb); + nummarksurfaces = (unsigned short)MSG_ReadLittleShort(sb); + } + + if (firstmarksurface >= 0 && firstmarksurface + nummarksurfaces <= loadmodel->brush.num_leafsurfaces) + { + out->firstleafsurface = loadmodel->brush.data_leafsurfaces + firstmarksurface; + out->numleafsurfaces = nummarksurfaces; + } + else + { + Con_Printf("Mod_Q1BSP_LoadLeafs: invalid leafsurface range %i:%i outside range %i:%i\n", firstmarksurface, firstmarksurface+nummarksurfaces, 0, loadmodel->brush.num_leafsurfaces); + out->firstleafsurface = NULL; + out->numleafsurfaces = 0; + } - // FIXME: Insert caustics here + for (j = 0;j < 4;j++) + out->ambient_sound_level[j] = MSG_ReadByte(sb); } } @@ -2916,17 +2942,16 @@ static qboolean Mod_Q1BSP_CheckWaterAlphaSupport(void) return false; } -static void Mod_Q1BSP_LoadClipnodes(lump_t *l, hullinfo_t *hullinfo) +static void Mod_Q1BSP_LoadClipnodes(sizebuf_t *sb, hullinfo_t *hullinfo) { - dclipnode_t *in; mclipnode_t *out; int i, count; hull_t *hull; + size_t structsize = loadmodel->brush.isbsp2 ? 12 : 8; - in = (dclipnode_t *)(mod_base + l->fileofs); - if (l->filelen % sizeof(*in)) + if (sb->cursize % structsize) Host_Error("Mod_Q1BSP_LoadClipnodes: funny lump size in %s",loadmodel->name); - count = l->filelen / sizeof(*in); + count = sb->cursize / structsize; out = (mclipnode_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(*out)); loadmodel->brushq1.clipnodes = out; @@ -2948,18 +2973,30 @@ static void Mod_Q1BSP_LoadClipnodes(lump_t *l, hullinfo_t *hullinfo) VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size); } - for (i=0 ; iplanenum = LittleLong(in->planenum); - // LordHavoc: this code supports arguire qbsp's broken clipnodes indices (more than 32768 clipnodes), values above count are assumed to be contents values - out->children[0] = (unsigned short)LittleShort(in->children[0]); - out->children[1] = (unsigned short)LittleShort(in->children[1]); - if (out->children[0] >= count) - out->children[0] -= 65536; - if (out->children[1] >= count) - out->children[1] -= 65536; + out->planenum = MSG_ReadLittleLong(sb); if (out->planenum < 0 || out->planenum >= loadmodel->brush.num_planes) - Host_Error("Corrupt clipping hull(out of range planenum)"); + Host_Error("%s: Corrupt clipping hull(out of range planenum)", loadmodel->name); + if (loadmodel->brush.isbsp2) + { + out->children[0] = MSG_ReadLittleLong(sb); + out->children[1] = MSG_ReadLittleLong(sb); + if (out->children[0] >= count) + Host_Error("%s: Corrupt clipping hull (invalid child index)", loadmodel->name); + if (out->children[1] >= count) + Host_Error("%s: Corrupt clipping hull (invalid child index)", loadmodel->name); + } + else + { + // LordHavoc: this code supports arguire qbsp's broken clipnodes indices (more than 32768 clipnodes), values above count are assumed to be contents values + out->children[0] = (unsigned short)MSG_ReadLittleShort(sb); + out->children[1] = (unsigned short)MSG_ReadLittleShort(sb); + if (out->children[0] >= count) + out->children[0] -= 65536; + if (out->children[1] >= count) + out->children[1] -= 65536; + } } } @@ -2989,62 +3026,71 @@ static void Mod_Q1BSP_MakeHull0(void) } } -static void Mod_Q1BSP_LoadLeaffaces(lump_t *l) +static void Mod_Q1BSP_LoadLeaffaces(sizebuf_t *sb) { int i, j; - short *in; + size_t structsize = loadmodel->brush.isbsp2 ? 4 : 2; - in = (short *)(mod_base + l->fileofs); - if (l->filelen % sizeof(*in)) + if (sb->cursize % structsize) Host_Error("Mod_Q1BSP_LoadLeaffaces: funny lump size in %s",loadmodel->name); - loadmodel->brush.num_leafsurfaces = l->filelen / sizeof(*in); + loadmodel->brush.num_leafsurfaces = sb->cursize / structsize; loadmodel->brush.data_leafsurfaces = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->brush.num_leafsurfaces * sizeof(int)); - for (i = 0;i < loadmodel->brush.num_leafsurfaces;i++) + if (loadmodel->brush.isbsp2) { - j = (unsigned short) LittleShort(in[i]); - if (j >= loadmodel->num_surfaces) - Host_Error("Mod_Q1BSP_LoadLeaffaces: bad surface number"); - loadmodel->brush.data_leafsurfaces[i] = j; + for (i = 0;i < loadmodel->brush.num_leafsurfaces;i++) + { + j = MSG_ReadLittleLong(sb); + if (j < 0 || j >= loadmodel->num_surfaces) + Host_Error("Mod_Q1BSP_LoadLeaffaces: bad surface number"); + loadmodel->brush.data_leafsurfaces[i] = j; + } + } + else + { + for (i = 0;i < loadmodel->brush.num_leafsurfaces;i++) + { + j = (unsigned short) MSG_ReadLittleShort(sb); + if (j >= loadmodel->num_surfaces) + Host_Error("Mod_Q1BSP_LoadLeaffaces: bad surface number"); + loadmodel->brush.data_leafsurfaces[i] = j; + } } } -static void Mod_Q1BSP_LoadSurfedges(lump_t *l) +static void Mod_Q1BSP_LoadSurfedges(sizebuf_t *sb) { int i; - int *in; + size_t structsize = 4; - in = (int *)(mod_base + l->fileofs); - if (l->filelen % sizeof(*in)) + if (sb->cursize % structsize) Host_Error("Mod_Q1BSP_LoadSurfedges: funny lump size in %s",loadmodel->name); - loadmodel->brushq1.numsurfedges = l->filelen / sizeof(*in); + loadmodel->brushq1.numsurfedges = sb->cursize / structsize; loadmodel->brushq1.surfedges = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->brushq1.numsurfedges * sizeof(int)); for (i = 0;i < loadmodel->brushq1.numsurfedges;i++) - loadmodel->brushq1.surfedges[i] = LittleLong(in[i]); + loadmodel->brushq1.surfedges[i] = MSG_ReadLittleLong(sb); } -static void Mod_Q1BSP_LoadPlanes(lump_t *l) +static void Mod_Q1BSP_LoadPlanes(sizebuf_t *sb) { int i; mplane_t *out; - dplane_t *in; + size_t structsize = 20; - in = (dplane_t *)(mod_base + l->fileofs); - if (l->filelen % sizeof(*in)) + if (sb->cursize % structsize) Host_Error("Mod_Q1BSP_LoadPlanes: funny lump size in %s", loadmodel->name); - - loadmodel->brush.num_planes = l->filelen / sizeof(*in); + loadmodel->brush.num_planes = sb->cursize / structsize; loadmodel->brush.data_planes = out = (mplane_t *)Mem_Alloc(loadmodel->mempool, loadmodel->brush.num_planes * sizeof(*out)); - for (i = 0;i < loadmodel->brush.num_planes;i++, in++, out++) + for (i = 0;i < loadmodel->brush.num_planes;i++, out++) { - out->normal[0] = LittleFloat(in->normal[0]); - out->normal[1] = LittleFloat(in->normal[1]); - out->normal[2] = LittleFloat(in->normal[2]); - out->dist = LittleFloat(in->dist); - + out->normal[0] = MSG_ReadLittleFloat(sb); + out->normal[1] = MSG_ReadLittleFloat(sb); + out->normal[2] = MSG_ReadLittleFloat(sb); + out->dist = MSG_ReadLittleFloat(sb); + MSG_ReadLittleLong(sb); // type is not used, we use PlaneClassify PlaneClassify(out); } } @@ -3662,33 +3708,47 @@ void Mod_CollisionBIH_TraceLineAgainstSurfaces(dp_model_t *model, const frameble void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) { int i, j, k; - dheader_t *header; - dmodel_t *bm; + sizebuf_t lumpsb[HEADER_LUMPS]; + mmodel_t *bm; float dist, modelyawradius, modelradius; msurface_t *surface; hullinfo_t hullinfo; int totalstylesurfaces, totalstyles, stylecounts[256], remapstyles[256]; model_brush_lightstyleinfo_t styleinfo[256]; unsigned char *datapointer; + sizebuf_t sb; - mod->modeldatatypestring = "Q1BSP"; + MSG_InitReadBuffer(&sb, (unsigned char *)buffer, (unsigned char *)bufferend - (unsigned char *)buffer); mod->type = mod_brushq1; - header = (dheader_t *)buffer; - - i = LittleLong(header->version); - if (i != BSPVERSION && i != 30) - Host_Error("Mod_Q1BSP_Load: %s has wrong version number(%i should be %i(Quake) or 30(HalfLife)", mod->name, i, BSPVERSION); - mod->brush.ishlbsp = i == 30; + mod->brush.isbsp2 = false; + mod->brush.ishlbsp = false; + i = MSG_ReadLittleLong(&sb); + switch(i) + { + case BSPVERSION: + mod->modeldatatypestring = "Q1BSP"; + break; + case 30: + mod->brush.ishlbsp = true; + mod->modeldatatypestring = "HLBSP"; + break; + case ('B' + 'S' * 256 + 'P' * 65536 + '2' * 16777216): + mod->brush.isbsp2 = true; + mod->modeldatatypestring = "Q1BSP2"; + break; + default: + mod->modeldatatypestring = "Unknown BSP"; + Host_Error("Mod_Q1BSP_Load: %s has wrong version number %i: supported versions are 29 (Quake), 30 (Half-Life), \"BSP2\"", mod->name, i); + return; + } // fill in hull info VectorClear (hullinfo.hullsizes[0][0]); VectorClear (hullinfo.hullsizes[0][1]); if (mod->brush.ishlbsp) { - mod->modeldatatypestring = "HLBSP"; - hullinfo.filehulls = 4; VectorSet (hullinfo.hullsizes[1][0], -16, -16, -36); VectorSet (hullinfo.hullsizes[1][1], 16, 16, 36); @@ -3707,11 +3767,13 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) } // read lumps - mod_base = (unsigned char*)buffer; for (i = 0; i < HEADER_LUMPS; i++) { - header->lumps[i].fileofs = LittleLong(header->lumps[i].fileofs); - header->lumps[i].filelen = LittleLong(header->lumps[i].filelen); + int offset = MSG_ReadLittleLong(&sb); + int size = MSG_ReadLittleLong(&sb); + if (offset < 0 || offset + size > sb.cursize) + Host_Error("Mod_Q1BSP_Load: %s has invalid lump %i (offset %i, size %i, file size %i)\n", mod->name, i, offset, size, (int)sb.cursize); + MSG_InitReadBuffer(&lumpsb[i], sb.data + offset, size); } mod->soundfromcenter = true; @@ -3757,30 +3819,33 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) int temp; if (i == LUMP_ENTITIES) continue; - temp = Com_BlockChecksum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen); + temp = Com_BlockChecksum(lumpsb[i].data, lumpsb[i].cursize); mod->brush.qw_md4sum ^= LittleLong(temp); if (i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES) continue; - temp = Com_BlockChecksum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen); mod->brush.qw_md4sum2 ^= LittleLong(temp); } - Mod_Q1BSP_LoadEntities(&header->lumps[LUMP_ENTITIES]); - Mod_Q1BSP_LoadVertexes(&header->lumps[LUMP_VERTEXES]); - Mod_Q1BSP_LoadEdges(&header->lumps[LUMP_EDGES]); - Mod_Q1BSP_LoadSurfedges(&header->lumps[LUMP_SURFEDGES]); - Mod_Q1BSP_LoadTextures(&header->lumps[LUMP_TEXTURES]); - Mod_Q1BSP_LoadLighting(&header->lumps[LUMP_LIGHTING]); - Mod_Q1BSP_LoadPlanes(&header->lumps[LUMP_PLANES]); - Mod_Q1BSP_LoadTexinfo(&header->lumps[LUMP_TEXINFO]); - Mod_Q1BSP_LoadFaces(&header->lumps[LUMP_FACES]); - Mod_Q1BSP_LoadLeaffaces(&header->lumps[LUMP_MARKSURFACES]); - Mod_Q1BSP_LoadVisibility(&header->lumps[LUMP_VISIBILITY]); + Mod_Q1BSP_LoadEntities(&lumpsb[LUMP_ENTITIES]); + Mod_Q1BSP_LoadVertexes(&lumpsb[LUMP_VERTEXES]); + Mod_Q1BSP_LoadEdges(&lumpsb[LUMP_EDGES]); + Mod_Q1BSP_LoadSurfedges(&lumpsb[LUMP_SURFEDGES]); + Mod_Q1BSP_LoadTextures(&lumpsb[LUMP_TEXTURES]); + Mod_Q1BSP_LoadLighting(&lumpsb[LUMP_LIGHTING]); + Mod_Q1BSP_LoadPlanes(&lumpsb[LUMP_PLANES]); + Mod_Q1BSP_LoadTexinfo(&lumpsb[LUMP_TEXINFO]); + Mod_Q1BSP_LoadFaces(&lumpsb[LUMP_FACES]); + Mod_Q1BSP_LoadLeaffaces(&lumpsb[LUMP_MARKSURFACES]); + Mod_Q1BSP_LoadVisibility(&lumpsb[LUMP_VISIBILITY]); // load submodels before leafs because they contain the number of vis leafs - Mod_Q1BSP_LoadSubmodels(&header->lumps[LUMP_MODELS], &hullinfo); - Mod_Q1BSP_LoadLeafs(&header->lumps[LUMP_LEAFS]); - Mod_Q1BSP_LoadNodes(&header->lumps[LUMP_NODES]); - Mod_Q1BSP_LoadClipnodes(&header->lumps[LUMP_CLIPNODES], &hullinfo); + Mod_Q1BSP_LoadSubmodels(&lumpsb[LUMP_MODELS], &hullinfo); + Mod_Q1BSP_LoadLeafs(&lumpsb[LUMP_LEAFS]); + Mod_Q1BSP_LoadNodes(&lumpsb[LUMP_NODES]); + Mod_Q1BSP_LoadClipnodes(&lumpsb[LUMP_CLIPNODES], &hullinfo); + + for (i = 0; i < HEADER_LUMPS; i++) + if (lumpsb[i].readcount != lumpsb[i].cursize && i != LUMP_TEXTURES && i != LUMP_LIGHTING) + Host_Error("Lump %i incorrectly loaded (readcount %i, size %i)\n", i, lumpsb[i].readcount, lumpsb[i].cursize); // check if the map supports transparent water rendering loadmodel->brush.supportwateralpha = Mod_Q1BSP_CheckWaterAlphaSupport(); @@ -4735,13 +4800,10 @@ static void Mod_Q3BSP_LoadVertices(lump_t *l) // working like this may be odd, but matches q3map2 -gamma 2.2 if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) { - // actually we do: Image_sRGBFloatFromLinear_Lightmap(Image_LinearFloatFromsRGBFloat(x)) - // neutral point is at Image_sRGBFloatFromLinearFloat(0.5) - // so we need to map Image_sRGBFloatFromLinearFloat(0.5) to 0.5 - // factor is 0.5 / Image_sRGBFloatFromLinearFloat(0.5) - loadmodel->brushq3.data_color4f[i * 4 + 0] = in->color4ub[0] * (1.0f / 255.0f) * 0.679942f; // fixes neutral level - loadmodel->brushq3.data_color4f[i * 4 + 1] = in->color4ub[1] * (1.0f / 255.0f) * 0.679942f; // fixes neutral level - loadmodel->brushq3.data_color4f[i * 4 + 2] = in->color4ub[2] * (1.0f / 255.0f) * 0.679942f; // fixes neutral level + loadmodel->brushq3.data_color4f[i * 4 + 0] = in->color4ub[0] * (1.0f / 255.0f); + loadmodel->brushq3.data_color4f[i * 4 + 1] = in->color4ub[1] * (1.0f / 255.0f); + loadmodel->brushq3.data_color4f[i * 4 + 2] = in->color4ub[2] * (1.0f / 255.0f); + // we fix the brightness consistently via lightmapscale } else { @@ -5055,20 +5117,8 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump) textype_t t; if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) { - // TODO (should we do this, or should we instead knowingly render brighter in sRGB fallback mode?) - int n = mergedwidth * mergedheight * 4; - int i; - for(i = 0; i < n; i += 4) - { - // actually we do: Image_sRGBFloatFromLinear_Lightmap(Image_LinearFloatFromsRGBFloat(x)) - // neutral point is at Image_sRGBFloatFromLinearFloat(0.5) - // so we need to map Image_sRGBFloatFromLinearFloat(0.5) to 0.5 - // factor is 0.5 / Image_sRGBFloatFromLinearFloat(0.5) - mergedpixels[i+0] = (mergedpixels[i+0] * (int)173 + 128) / 255; - mergedpixels[i+1] = (mergedpixels[i+1] * (int)173 + 128) / 255; - mergedpixels[i+2] = (mergedpixels[i+2] * (int)173 + 128) / 255; - } t = TEXTYPE_BGRA; // in stupid fallback mode, we upload lightmaps in sRGB form and just fix their brightness + // we fix the brightness consistently via lightmapscale } else t = TEXTYPE_SRGB_BGRA; // normally, we upload lightmaps in sRGB form (possibly downconverted to linear) @@ -5871,20 +5921,7 @@ static void Mod_Q3BSP_LoadLightGrid(lump_t *l) { if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) { - // TODO (should we do this, or should we instead knowingly render brighter in sRGB fallback mode?) - for(i = 0; i < count; ++i) - { - // actually we do: Image_sRGBFloatFromLinear_Lightmap(Image_LinearFloatFromsRGBFloat(x)) - // neutral point is at Image_sRGBFloatFromLinearFloat(0.5) - // so we need to map Image_sRGBFloatFromLinearFloat(0.5) to 0.5 - // factor is 0.5 / Image_sRGBFloatFromLinearFloat(0.5) - out[i].ambientrgb[0] = (out[i].ambientrgb[0] * (int)173 + 128) / 255; // fixes neutral level - out[i].ambientrgb[1] = (out[i].ambientrgb[1] * (int)173 + 128) / 255; // fixes neutral level - out[i].ambientrgb[2] = (out[i].ambientrgb[2] * (int)173 + 128) / 255; // fixes neutral level - out[i].diffusergb[0] = (out[i].diffusergb[0] * (int)173 + 128) / 255; // fixes neutral level - out[i].diffusergb[1] = (out[i].diffusergb[1] * (int)173 + 128) / 255; // fixes neutral level - out[i].diffusergb[2] = (out[i].diffusergb[2] * (int)173 + 128) / 255; // fixes neutral level - } + // we fix the brightness consistently via lightmapscale } else { @@ -7322,6 +7359,30 @@ static void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) Mod_BuildVBOs(); } + if (mod_q3bsp_sRGBlightmaps.integer) + { + if (vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + { + // actually we do in sRGB fallback with sRGB lightmaps: Image_sRGBFloatFromLinear_Lightmap(Image_LinearFloatFromsRGBFloat(x)) + // neutral point is at Image_sRGBFloatFromLinearFloat(0.5) + // so we need to map Image_sRGBFloatFromLinearFloat(0.5) to 0.5 + // factor is 0.5 / Image_sRGBFloatFromLinearFloat(0.5) + //loadmodel->lightmapscale *= 0.679942f; // fixes neutral level + } + else // if this is NOT set, regular rendering looks right by this requirement anyway + { + /* + // we want color 1 to do the same as without sRGB + // so, we want to map 1 to Image_LinearFloatFromsRGBFloat(2) instead of to 2 + loadmodel->lightmapscale *= 2.476923f; // fixes max level + */ + + // neutral level 0.5 gets uploaded as sRGB and becomes Image_LinearFloatFromsRGBFloat(0.5) + // we need to undo that + loadmodel->lightmapscale *= 2.336f; // fixes neutral level + } + } + Con_DPrintf("Stats for q3bsp model \"%s\": %i faces, %i nodes, %i leafs, %i clusters, %i clusterportals, mesh: %i vertices, %i triangles, %i surfaces\n", loadmodel->name, loadmodel->num_surfaces, loadmodel->brush.num_nodes, loadmodel->brush.num_leafs, mod->brush.num_pvsclusters, loadmodel->brush.num_portals, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->num_surfaces); } @@ -7500,9 +7561,18 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) maxv = max(maxv * 2, 1024); v = (float *)Mem_Realloc(tempmempool, v, maxv * sizeof(float[3])); } - v[numv*3+0] = atof(argv[1]); - v[numv*3+2] = atof(argv[2]); - v[numv*3+1] = atof(argv[3]); + if(mod_obj_orientation.integer) + { + v[numv*3+0] = atof(argv[1]); + v[numv*3+2] = atof(argv[2]); + v[numv*3+1] = atof(argv[3]); + } + else + { + v[numv*3+0] = atof(argv[1]); + v[numv*3+1] = atof(argv[2]); + v[numv*3+2] = atof(argv[3]); + } numv++; } else if (!strcmp(argv[0], "vt")) @@ -7523,9 +7593,18 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) maxvn = max(maxvn * 2, 1024); vn = (float *)Mem_Realloc(tempmempool, vn, maxvn * sizeof(float[3])); } - vn[numvn*3+0] = atof(argv[1]); - vn[numvn*3+2] = atof(argv[2]); - vn[numvn*3+1] = atof(argv[3]); + if(mod_obj_orientation.integer) + { + vn[numvn*3+0] = atof(argv[1]); + vn[numvn*3+2] = atof(argv[2]); + vn[numvn*3+1] = atof(argv[3]); + } + else + { + vn[numvn*3+0] = atof(argv[1]); + vn[numvn*3+1] = atof(argv[2]); + vn[numvn*3+2] = atof(argv[3]); + } numvn++; } else if (!strcmp(argv[0], "f")) @@ -7594,9 +7673,18 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) maxtriangles = max(maxtriangles * 2, 32768); vertices = (objvertex_t*)Mem_Realloc(loadmodel->mempool, vertices, maxtriangles * sizeof(objvertex_t[3])); } - vertices[numtriangles*3+0] = vfirst; - vertices[numtriangles*3+1] = vprev; - vertices[numtriangles*3+2] = vcurrent; + if(mod_obj_orientation.integer) + { + vertices[numtriangles*3+0] = vfirst; + vertices[numtriangles*3+1] = vprev; + vertices[numtriangles*3+2] = vcurrent; + } + else + { + vertices[numtriangles*3+0] = vfirst; + vertices[numtriangles*3+2] = vprev; + vertices[numtriangles*3+1] = vcurrent; + } numtriangles++; } vprev = vcurrent; diff --git a/misc/source/darkplaces-src/model_brush.h b/misc/source/darkplaces-src/model_brush.h index f1b60e0e..8020d14a 100644 --- a/misc/source/darkplaces-src/model_brush.h +++ b/misc/source/darkplaces-src/model_brush.h @@ -118,6 +118,8 @@ mplane_t; #define MATERIALFLAG_CAMERA 67108864 // disable rtlight on surface, use R_LightPoint instead #define MATERIALFLAG_NORTLIGHT 134217728 +// alphagen vertex +#define MATERIALFLAG_ALPHAGEN_VERTEX 268435456 // combined mask of all attributes that require depth sorted rendering #define MATERIALFLAGMASK_DEPTHSORTED (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST) // combined mask of all attributes that cause some sort of transparency diff --git a/misc/source/darkplaces-src/model_shared.c b/misc/source/darkplaces-src/model_shared.c index 2afe928b..5c000bfa 100644 --- a/misc/source/darkplaces-src/model_shared.c +++ b/misc/source/darkplaces-src/model_shared.c @@ -467,6 +467,9 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk) // errors can prevent the corresponding mod->loaded = true; mod->loaded = false; + // default lightmap scale + mod->lightmapscale = 1; + // default model radius and bounding box (mainly for missing models) mod->radius = 16; VectorSet(mod->normalmins, -mod->radius, -mod->radius, -mod->radius); @@ -504,7 +507,7 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk) else if (!memcmp(buf, "ACTRHEAD", 8)) Mod_PSKMODEL_Load(mod, buf, bufend); else if (!memcmp(buf, "INTERQUAKEMODEL", 16)) Mod_INTERQUAKEMODEL_Load(mod, buf, bufend); else if (strlen(mod->name) >= 4 && !strcmp(mod->name + strlen(mod->name) - 4, ".map")) Mod_MAP_Load(mod, buf, bufend); - else if (num == BSPVERSION || num == 30) Mod_Q1BSP_Load(mod, buf, bufend); + else if (num == BSPVERSION || num == 30 || !memcmp(buf, "BSP2", 4)) Mod_Q1BSP_Load(mod, buf, bufend); else Con_Printf("Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name); Mem_Free(buf); @@ -1388,7 +1391,7 @@ void Mod_CreateCollisionMesh(dp_model_t *mod) for (k = 0;k < mod->nummodelsurfaces;k++) { surface = mod->data_surfaces + mod->firstmodelsurface + k; - if (!strcmp(surface->texture->name, "collision")) // found collision mesh + if (!strcmp(surface->texture->name, "collision") || !strcmp(surface->texture->name, "collisionconvex")) // found collision mesh { usesinglecollisionmesh = true; numcollisionmeshtriangles = surface->num_triangles; @@ -1662,8 +1665,8 @@ void Mod_LoadQ3Shaders(void) int numparameters; char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH]; char *custsurfaceparmnames[256]; // VorteX: q3map2 has 64 but well, someone will need more - unsigned long custsurfaceparms[256]; - int numcustsurfaceparms; + unsigned long custsurfaceflags[256]; + int numcustsurfaceflags; qboolean dpshaderkill; Mod_FreeQ3Shaders(); @@ -1677,7 +1680,7 @@ void Mod_LoadQ3Shaders(void) q3shaders_mem, sizeof (char**), 256); // parse custinfoparms.txt - numcustsurfaceparms = 0; + numcustsurfaceflags = 0; if ((text = f = (char *)FS_LoadFile("scripts/custinfoparms.txt", tempmempool, false, NULL)) != NULL) { if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{")) @@ -1697,21 +1700,21 @@ void Mod_LoadQ3Shaders(void) if (!strcasecmp(com_token, "}")) break; // register surfaceflag - if (numcustsurfaceparms >= 256) + if (numcustsurfaceflags >= 256) { Con_Printf("scripts/custinfoparms.txt: surfaceflags section parsing error - max 256 surfaceflags exceeded\n"); break; } // name j = strlen(com_token)+1; - custsurfaceparmnames[numcustsurfaceparms] = (char *)Mem_Alloc(tempmempool, j); - strlcpy(custsurfaceparmnames[numcustsurfaceparms], com_token, j+1); + custsurfaceparmnames[numcustsurfaceflags] = (char *)Mem_Alloc(tempmempool, j); + strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1); // value if (COM_ParseToken_QuakeC(&text, false)) - custsurfaceparms[numcustsurfaceparms] = strtol(com_token, NULL, 0); + custsurfaceflags[numcustsurfaceflags] = strtol(com_token, NULL, 0); else - custsurfaceparms[numcustsurfaceparms] = 0; - numcustsurfaceparms++; + custsurfaceflags[numcustsurfaceflags] = 0; + numcustsurfaceflags++; } } } @@ -2126,19 +2129,21 @@ void Mod_LoadQ3Shaders(void) shader.surfaceparms |= Q3SURFACEPARM_POINTLIGHT; else if (!strcasecmp(parameter[1], "antiportal")) shader.surfaceparms |= Q3SURFACEPARM_ANTIPORTAL; + else if (!strcasecmp(parameter[1], "skip")) + ; // shader.surfaceparms |= Q3SURFACEPARM_SKIP; FIXME we don't have enough #defines for this any more, and the engine doesn't need this one anyway else { // try custom surfaceparms - for (j = 0; j < numcustsurfaceparms; j++) + for (j = 0; j < numcustsurfaceflags; j++) { if (!strcasecmp(custsurfaceparmnames[j], parameter[1])) { - shader.surfaceparms |= custsurfaceparms[j]; + shader.surfaceflags |= custsurfaceflags[j]; break; } } // failed all - if (j == numcustsurfaceparms) + if (j == numcustsurfaceflags) Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]); } } @@ -2385,7 +2390,7 @@ void Mod_LoadQ3Shaders(void) } FS_FreeSearch(search); // free custinfoparm values - for (j = 0; j < numcustsurfaceparms; j++) + for (j = 0; j < numcustsurfaceflags; j++) Mem_Free(custsurfaceparmnames[j]); } @@ -2569,6 +2574,8 @@ nothing GL_ZERO GL_ONE texture->basematerialflags |= MATERIALFLAG_NOSHADOW; if (shader->dpnortlight) texture->basematerialflags |= MATERIALFLAG_NORTLIGHT; + if (shader->vertexalpha) + texture->basematerialflags |= MATERIALFLAG_ALPHAGEN_VERTEX; memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms)); texture->reflectmin = shader->reflectmin; texture->reflectmax = shader->reflectmax; @@ -2630,7 +2637,7 @@ nothing GL_ZERO GL_ONE // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->supercontents |= SUPERCONTENTS_LIGHTGRID ; // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->supercontents |= SUPERCONTENTS_ANTIPORTAL ; - texture->surfaceflags = 0; + texture->surfaceflags = shader->surfaceflags; if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->surfaceflags |= Q3SURFACEFLAG_ALPHASHADOW ; // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_AREAPORTAL ; // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->surfaceflags |= Q3SURFACEFLAG_CLUSTERPORTAL; @@ -3038,6 +3045,7 @@ void Mod_BuildVBOs(void) } } +extern cvar_t mod_obj_orientation; static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename) { int submodelindex, vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0; @@ -3105,7 +3113,10 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha memcpy(outbuffer, oldbuffer, outbufferpos); Z_Free(oldbuffer); } - l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "v %f %f %f\nvn %f %f %f\nvt %f %f\n", v[0], v[2], v[1], vn[0], vn[2], vn[1], vt[0], 1-vt[1]); + if(mod_obj_orientation.integer) + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "v %f %f %f\nvn %f %f %f\nvt %f %f\n", v[0], v[2], v[1], vn[0], vn[2], vn[1], vt[0], 1-vt[1]); + else + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "v %f %f %f\nvn %f %f %f\nvt %f %f\n", v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1-vt[1]); if (l > 0) outbufferpos += l; } @@ -3135,7 +3146,10 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha a = e[0]+1; b = e[1]+1; c = e[2]+1; - l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,b,b,b,c,c,c); + if(mod_obj_orientation.integer) + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,b,b,b,c,c,c); + else + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,c,c,c,b,b,b); if (l > 0) outbufferpos += l; } @@ -3210,7 +3224,7 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first // strangely the smd angles are for a transposed matrix, so we // have to generate a transposed matrix, then convert that... - Matrix4x4_FromBonePose6s(&posematrix, model->num_posescale, model->data_poses6s + 6*(model->num_bones * poseindex + transformindex)); + Matrix4x4_FromBonePose7s(&posematrix, model->num_posescale, model->data_poses7s + 7*(model->num_bones * poseindex + transformindex)); Matrix4x4_ToArray12FloatGL(&posematrix, mtest[0]); AnglesFromVectors(angles, mtest[0], mtest[2], false); if (angles[0] >= 180) angles[0] -= 360; diff --git a/misc/source/darkplaces-src/model_shared.h b/misc/source/darkplaces-src/model_shared.h index 747bec0c..07e840d3 100644 --- a/misc/source/darkplaces-src/model_shared.h +++ b/misc/source/darkplaces-src/model_shared.h @@ -432,6 +432,7 @@ typedef struct q3shaderinfo_s char name[Q3PATHLENGTH]; #define Q3SHADERINFO_COMPARE_START surfaceparms int surfaceparms; + int surfaceflags; int textureflags; int numlayers; qboolean lighting; @@ -723,6 +724,8 @@ typedef struct model_brush_s { // true if this model is a HalfLife .bsp file qboolean ishlbsp; + // true if this model is a BSP2 .bsp file (expanded 32bit bsp format for DarkPlaces, RMQ, others?) + qboolean isbsp2; // string of entity definitions (.map format) char *entities; @@ -820,7 +823,7 @@ model_brush_t; typedef struct model_brushq1_s { - dmodel_t *submodels; + mmodel_t *submodels; int numvertexes; mvertex_t *vertexes; @@ -978,10 +981,10 @@ typedef struct model_s // for skeletal models int num_bones; aliasbone_t *data_bones; - float num_posescale; // scaling factor from origin in poses6s format (includes divide by 32767) - float num_poseinvscale; // scaling factor to origin in poses6s format (includes multiply by 32767) + float num_posescale; // scaling factor from origin in poses7s format (includes divide by 32767) + float num_poseinvscale; // scaling factor to origin in poses7s format (includes multiply by 32767) int num_poses; - short *data_poses6s; // origin xyz, quat xyz, w implied negative, unit length, values normalized to +/-32767 range + short *data_poses7s; // origin xyz, quat xyzw, unit length, values normalized to +/-32767 range float *data_baseboneposeinverse; // textures of this model int num_textures; @@ -1048,6 +1051,7 @@ typedef struct model_s // if set, the model contains light information (lightmap, or vertexlight) qboolean lit; + float lightmapscale; } dp_model_t; diff --git a/misc/source/darkplaces-src/mvm_cmds.c b/misc/source/darkplaces-src/mvm_cmds.c index e90dcdec..79edacfb 100644 --- a/misc/source/darkplaces-src/mvm_cmds.c +++ b/misc/source/darkplaces-src/mvm_cmds.c @@ -812,7 +812,7 @@ static void VM_M_crypto_getmykeyfp(prvm_prog_t *prog) VM_SAFEPARMCOUNT(1,VM_M_crypto_getmykey); i = PRVM_G_FLOAT( OFS_PARM0 ); - switch(Crypto_RetrieveLocalKey(i, keyfp, sizeof(keyfp), NULL, 0)) + switch(Crypto_RetrieveLocalKey(i, keyfp, sizeof(keyfp), NULL, 0, NULL)) { case -1: PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, ""); @@ -834,7 +834,7 @@ static void VM_M_crypto_getmyidfp(prvm_prog_t *prog) VM_SAFEPARMCOUNT(1,VM_M_crypto_getmykey); i = PRVM_G_FLOAT( OFS_PARM0 ); - switch(Crypto_RetrieveLocalKey(i, NULL, 0, idfp, sizeof(idfp))) + switch(Crypto_RetrieveLocalKey(i, NULL, 0, idfp, sizeof(idfp), NULL)) { case -1: PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, ""); @@ -848,6 +848,28 @@ static void VM_M_crypto_getmyidfp(prvm_prog_t *prog) break; } } +static void VM_M_crypto_getmyidstatus(prvm_prog_t *prog) +{ + int i; + qboolean issigned; + + VM_SAFEPARMCOUNT(1,VM_M_crypto_getmykey); + + i = PRVM_G_FLOAT( OFS_PARM0 ); + switch(Crypto_RetrieveLocalKey(i, NULL, 0, NULL, 0, &issigned)) + { + case -1: + PRVM_G_FLOAT( OFS_RETURN ) = 0; // have no ID there + break; + case 0: + PRVM_G_FLOAT( OFS_RETURN ) = -1; // out of range + break; + default: + case 1: + PRVM_G_FLOAT( OFS_RETURN ) = issigned ? 2 : 1; + break; + } +} prvm_builtin_t vm_m_builtins[] = { NULL, // #0 NULL function (not callable) @@ -1517,6 +1539,8 @@ VM_M_crypto_getmykeyfp, // #636 string(float addr) crypto_getmykeyfp VM_M_crypto_getmyidfp, // #637 string(float addr) crypto_getmyidfp NULL, // #638 VM_digest_hex, // #639 +NULL, // #640 +VM_M_crypto_getmyidstatus, // #641 float(float i) crypto_getmyidstatus NULL }; diff --git a/misc/source/darkplaces-src/netconn.c b/misc/source/darkplaces-src/netconn.c index c5858c80..395f6d33 100644 --- a/misc/source/darkplaces-src/netconn.c +++ b/misc/source/darkplaces-src/netconn.c @@ -48,7 +48,7 @@ static cvar_t sv_masters [] = {0, "sv_masterextra2", "64.22.107.125", "dpmaster.deathmask.net - default master server 2 (admin: Willis)"}, // admin: Willis {0, "sv_masterextra3", "92.62.40.73", "dpmaster.tchr.no - default master server 3 (admin: tChr)"}, // admin: tChr #ifdef SUPPORTIPV6 - {0, "sv_masterextra4", "[2001:41d0:2:1628::4450]:27950", "dpmaster.div0.qc.to - default master server 4 (admin: divVerent)"}, // admin: divVerent + {0, "sv_masterextra4", "[2a03:4000:1::2e26:f351:3]:27950", "dpmaster.sudo.rm-f.org - default master server 4 (admin: divVerent)"}, // admin: divVerent #endif {0, NULL, NULL, NULL} }; @@ -78,7 +78,9 @@ char sv_readstring[MAX_INPUTLINE]; cvar_t net_messagetimeout = {0, "net_messagetimeout","300", "drops players who have not sent any packets for this many seconds"}; cvar_t net_connecttimeout = {0, "net_connecttimeout","15", "after requesting a connection, the client must reply within this many seconds or be dropped (cuts down on connect floods). Must be above 10 seconds."}; -cvar_t net_connectfloodblockingtimeout = {0, "net_connectfloodblockingtimeout", "5", "when a connection packet is received, it will block all future connect packets from that IP address for this many seconds (cuts down on connect floods)"}; +cvar_t net_connectfloodblockingtimeout = {0, "net_connectfloodblockingtimeout", "5", "when a connection packet is received, it will block all future connect packets from that IP address for this many seconds (cuts down on connect floods). Note that this does not include retries from the same IP; these are handled earlier and let in."}; +cvar_t net_challengefloodblockingtimeout = {0, "net_challengefloodblockingtimeout", "0.5", "when a challenge packet is received, it will block all future challenge packets from that IP address for this many seconds (cuts down on challenge floods). DarkPlaces clients retry once per second, so this should be <= 1. Failure here may lead to connect attempts failing."}; +cvar_t net_getstatusfloodblockingtimeout = {0, "net_getstatusfloodblockingtimeout", "1", "when a getstatus packet is received, it will block all future getstatus packets from that IP address for this many seconds (cuts down on getstatus floods). DarkPlaces retries every 4 seconds, and qstat retries once per second, so this should be <= 1. Failure here may lead to server not showing up in the server list."}; cvar_t hostname = {CVAR_SAVE, "hostname", "UNNAMED", "server message to show in server browser"}; cvar_t developer_networking = {0, "developer_networking", "0", "prints all received and sent packets (recommended only for debugging)"}; @@ -1056,14 +1058,14 @@ netconn_t *NetConn_Open(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress) return conn; } -void NetConn_ClearConnectFlood(lhnetaddress_t *peeraddress); +void NetConn_ClearFlood(lhnetaddress_t *peeraddress, server_floodaddress_t *floodlist, size_t floodlength); void NetConn_Close(netconn_t *conn) { netconn_t *c; // remove connection from list // allow the client to reconnect immediately - NetConn_ClearConnectFlood(&(conn->peeraddress)); + NetConn_ClearFlood(&(conn->peeraddress), sv.connectfloodaddresses, sizeof(sv.connectfloodaddresses) / sizeof(sv.connectfloodaddresses[0])); if (conn == netconn_list) netconn_list = conn->next; @@ -1588,7 +1590,7 @@ static qboolean NetConn_ClientParsePacket_ServerList_PrepareQuery( int protocol, entry = &serverlist_cache[n]; - memset(entry, 0, sizeof(entry)); + memset(entry, 0, sizeof(*entry)); entry->protocol = protocol; // store the data the engine cares about (address and ping) strlcpy (entry->info.cname, ipstring, sizeof(entry->info.cname)); @@ -1685,7 +1687,7 @@ static void NetConn_ClientParsePacket_ServerList_ParseDPList(lhnetaddress_t *sen static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *data, int length, lhnetaddress_t *peeraddress) { qboolean fromserver; - int ret, c, control; + int ret, c; const char *s; char *string, addressstring2[128], ipstring[32]; char stringbuf[16384]; @@ -2064,7 +2066,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat return ret; } // netquake control packets, supported for compatibility only - if (length >= 5 && (control = BuffBigLong(data)) && (control & (~NETFLAG_LENGTH_MASK)) == (int)NETFLAG_CTL && (control & NETFLAG_LENGTH_MASK) == length && !ENCRYPTION_REQUIRED) + if (length >= 5 && BuffBigLong(data) == ((int)NETFLAG_CTL | length) && !ENCRYPTION_REQUIRED) { int n; serverlist_info_t *info; @@ -2496,31 +2498,34 @@ bad: return false; } -static qboolean NetConn_PreventConnectFlood(lhnetaddress_t *peeraddress) +static qboolean NetConn_PreventFlood(lhnetaddress_t *peeraddress, server_floodaddress_t *floodlist, size_t floodlength, double floodtime, qboolean renew) { - int floodslotnum, bestfloodslotnum; + size_t floodslotnum, bestfloodslotnum; double bestfloodtime; lhnetaddress_t noportpeeraddress; // see if this is a connect flood noportpeeraddress = *peeraddress; LHNETADDRESS_SetPort(&noportpeeraddress, 0); bestfloodslotnum = 0; - bestfloodtime = sv.connectfloodaddresses[bestfloodslotnum].lasttime; - for (floodslotnum = 0;floodslotnum < MAX_CONNECTFLOODADDRESSES;floodslotnum++) + bestfloodtime = floodlist[bestfloodslotnum].lasttime; + for (floodslotnum = 0;floodslotnum < floodlength;floodslotnum++) { - if (bestfloodtime >= sv.connectfloodaddresses[floodslotnum].lasttime) + if (bestfloodtime >= floodlist[floodslotnum].lasttime) { - bestfloodtime = sv.connectfloodaddresses[floodslotnum].lasttime; + bestfloodtime = floodlist[floodslotnum].lasttime; bestfloodslotnum = floodslotnum; } - if (sv.connectfloodaddresses[floodslotnum].lasttime && LHNETADDRESS_Compare(&noportpeeraddress, &sv.connectfloodaddresses[floodslotnum].address) == 0) + if (floodlist[floodslotnum].lasttime && LHNETADDRESS_Compare(&noportpeeraddress, &floodlist[floodslotnum].address) == 0) { // this address matches an ongoing flood address - if (realtime < sv.connectfloodaddresses[floodslotnum].lasttime + net_connectfloodblockingtimeout.value) + if (realtime < floodlist[floodslotnum].lasttime + floodtime) { - // renew the ban on this address so it does not expire - // until the flood has subsided - sv.connectfloodaddresses[floodslotnum].lasttime = realtime; + if(renew) + { + // renew the ban on this address so it does not expire + // until the flood has subsided + floodlist[floodslotnum].lasttime = realtime; + } //Con_Printf("Flood detected!\n"); return true; } @@ -2530,27 +2535,27 @@ static qboolean NetConn_PreventConnectFlood(lhnetaddress_t *peeraddress) } } // begin a new timeout on this address - sv.connectfloodaddresses[bestfloodslotnum].address = noportpeeraddress; - sv.connectfloodaddresses[bestfloodslotnum].lasttime = realtime; + floodlist[bestfloodslotnum].address = noportpeeraddress; + floodlist[bestfloodslotnum].lasttime = realtime; //Con_Printf("Flood detection initiated!\n"); return false; } -void NetConn_ClearConnectFlood(lhnetaddress_t *peeraddress) +void NetConn_ClearFlood(lhnetaddress_t *peeraddress, server_floodaddress_t *floodlist, size_t floodlength) { - int floodslotnum; + size_t floodslotnum; lhnetaddress_t noportpeeraddress; // see if this is a connect flood noportpeeraddress = *peeraddress; LHNETADDRESS_SetPort(&noportpeeraddress, 0); - for (floodslotnum = 0;floodslotnum < MAX_CONNECTFLOODADDRESSES;floodslotnum++) + for (floodslotnum = 0;floodslotnum < floodlength;floodslotnum++) { - if (sv.connectfloodaddresses[floodslotnum].lasttime && LHNETADDRESS_Compare(&noportpeeraddress, &sv.connectfloodaddresses[floodslotnum].address) == 0) + if (floodlist[floodslotnum].lasttime && LHNETADDRESS_Compare(&noportpeeraddress, &floodlist[floodslotnum].address) == 0) { // this address matches an ongoing flood address // remove the ban - sv.connectfloodaddresses[floodslotnum].address.addresstype = LHNETADDRESSTYPE_NONE; - sv.connectfloodaddresses[floodslotnum].lasttime = 0; + floodlist[floodslotnum].address.addresstype = LHNETADDRESSTYPE_NONE; + floodlist[floodslotnum].lasttime = 0; //Con_Printf("Flood cleared!\n"); } } @@ -2835,6 +2840,12 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat challenge[i].address = *peeraddress; NetConn_BuildChallengeString(challenge[i].string, sizeof(challenge[i].string)); } + else + { + // flood control: drop if requesting challenge too often + if(challenge[i].time > realtime - net_challengefloodblockingtimeout.value) + return true; + } challenge[i].time = realtime; // send the challenge dpsnprintf(response, sizeof(response), "\377\377\377\377challenge %s", challenge[i].string); @@ -2964,7 +2975,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat } } - if (NetConn_PreventConnectFlood(peeraddress)) + if (NetConn_PreventFlood(peeraddress, sv.connectfloodaddresses, sizeof(sv.connectfloodaddresses) / sizeof(sv.connectfloodaddresses[0]), net_connectfloodblockingtimeout.value, true)) return true; // find an empty client slot for this new client @@ -2997,6 +3008,9 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat { const char *challenge = NULL; + if (NetConn_PreventFlood(peeraddress, sv.getstatusfloodaddresses, sizeof(sv.getstatusfloodaddresses) / sizeof(sv.getstatusfloodaddresses[0]), net_getstatusfloodblockingtimeout.value, false)) + return true; + // If there was a challenge in the getinfo message if (length > 8 && string[7] == ' ') challenge = string + 8; @@ -3013,6 +3027,9 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat { const char *challenge = NULL; + if (NetConn_PreventFlood(peeraddress, sv.getstatusfloodaddresses, sizeof(sv.getstatusfloodaddresses) / sizeof(sv.getstatusfloodaddresses[0]), net_getstatusfloodblockingtimeout.value, false)) + return true; + // If there was a challenge in the getinfo message if (length > 10 && string[9] == ' ') challenge = string + 10; @@ -3166,6 +3183,22 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat // or coming back from a timeout // (if so, keep their stuff intact) + crypto_t *crypto = Crypto_ServerGetInstance(peeraddress); + if((crypto && crypto->authenticated) || client->netconnection->crypto.authenticated) + { + if (developer_extra.integer) + Con_Printf("Datagram_ParseConnectionless: sending CCREP_REJECT \"Attempt to downgrade crypto.\" to %s.\n", addressstring2); + SZ_Clear(&sv_message); + // save space for the header, filled in later + MSG_WriteLong(&sv_message, 0); + MSG_WriteByte(&sv_message, CCREP_REJECT); + MSG_WriteString(&sv_message, "Attempt to downgrade crypto.\n"); + StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress); + SZ_Clear(&sv_message); + return true; + } + // send a reply if (developer_extra.integer) Con_DPrintf("Datagram_ParseConnectionless: sending duplicate CCREP_ACCEPT to %s.\n", addressstring2); @@ -3187,7 +3220,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat } // this is a new client, check for connection flood - if (NetConn_PreventConnectFlood(peeraddress)) + if (NetConn_PreventFlood(peeraddress, sv.connectfloodaddresses, sizeof(sv.connectfloodaddresses) / sizeof(sv.connectfloodaddresses[0]), net_connectfloodblockingtimeout.value, true)) break; // find a slot for the new client @@ -3234,6 +3267,10 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_SERVER_INFO from %s.\n", addressstring2); if(!(islocal || sv_public.integer > -1)) break; + + if (NetConn_PreventFlood(peeraddress, sv.getstatusfloodaddresses, sizeof(sv.getstatusfloodaddresses) / sizeof(sv.getstatusfloodaddresses[0]), net_getstatusfloodblockingtimeout.value, false)) + break; + if (sv.active && !strcmp(MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring)), "QUAKE")) { int numclients; @@ -3265,6 +3302,10 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_PLAYER_INFO from %s.\n", addressstring2); if(!(islocal || sv_public.integer > -1)) break; + + if (NetConn_PreventFlood(peeraddress, sv.getstatusfloodaddresses, sizeof(sv.getstatusfloodaddresses) / sizeof(sv.getstatusfloodaddresses[0]), net_getstatusfloodblockingtimeout.value, false)) + break; + if (sv.active) { int playerNumber, activeNumber, clientNumber; @@ -3301,6 +3342,9 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_RULE_INFO from %s.\n", addressstring2); if(!(islocal || sv_public.integer > -1)) break; + + // no flood check here, as it only returns one cvar for one cvar and clients may iterate quickly + if (sv.active) { char *prevCvarName; @@ -3645,6 +3689,8 @@ void NetConn_Init(void) Cvar_RegisterVariable(&net_messagetimeout); Cvar_RegisterVariable(&net_connecttimeout); Cvar_RegisterVariable(&net_connectfloodblockingtimeout); + Cvar_RegisterVariable(&net_challengefloodblockingtimeout); + Cvar_RegisterVariable(&net_getstatusfloodblockingtimeout); Cvar_RegisterVariable(&cl_netlocalping); Cvar_RegisterVariable(&cl_netpacketloss_send); Cvar_RegisterVariable(&cl_netpacketloss_receive); diff --git a/misc/source/darkplaces-src/progs.h b/misc/source/darkplaces-src/progs.h index 72813bbf..ed097893 100644 --- a/misc/source/darkplaces-src/progs.h +++ b/misc/source/darkplaces-src/progs.h @@ -25,17 +25,37 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define ENTITYGRIDAREAS 16 #define MAX_ENTITYCLUSTERS 16 -#define JOINTTYPE_POINT 1 -#define JOINTTYPE_HINGE 2 -#define JOINTTYPE_SLIDER 3 +#define GEOMTYPE_NONE -1 +#define GEOMTYPE_SOLID 0 +#define GEOMTYPE_BOX 1 +#define GEOMTYPE_SPHERE 2 +#define GEOMTYPE_CAPSULE 3 +#define GEOMTYPE_TRIMESH 4 +#define GEOMTYPE_CYLINDER 5 +#define GEOMTYPE_CAPSULE_X 6 +#define GEOMTYPE_CAPSULE_Y 7 +#define GEOMTYPE_CAPSULE_Z 8 +#define GEOMTYPE_CYLINDER_X 9 +#define GEOMTYPE_CYLINDER_Y 10 +#define GEOMTYPE_CYLINDER_Z 11 + +#define JOINTTYPE_NONE 0 +#define JOINTTYPE_POINT 1 +#define JOINTTYPE_HINGE 2 +#define JOINTTYPE_SLIDER 3 #define JOINTTYPE_UNIVERSAL 4 -#define JOINTTYPE_HINGE2 5 -#define JOINTTYPE_FIXED -1 +#define JOINTTYPE_HINGE2 5 +#define JOINTTYPE_FIXED -1 -#define ODEFUNC_ENABLE 1 -#define ODEFUNC_DISABLE 2 -#define ODEFUNC_RELFORCEATPOS 3 -#define ODEFUNC_RELTORQUE 4 +#define FORCETYPE_NONE 0 +#define FORCETYPE_FORCE 1 +#define FORCETYPE_FORCEATPOS 2 +#define FORCETYPE_TORQUE 3 + +#define ODEFUNC_ENABLE 1 +#define ODEFUNC_DISABLE 2 +#define ODEFUNC_FORCE 3 +#define ODEFUNC_TORQUE 4 typedef struct edict_odefunc_s { @@ -105,6 +125,7 @@ typedef struct edict_engineprivate_s edict_odefunc_t *ode_func; vec3_t ode_mins; vec3_t ode_maxs; + vec3_t ode_scale; vec_t ode_mass; float ode_friction; vec3_t ode_origin; diff --git a/misc/source/darkplaces-src/protocol.c b/misc/source/darkplaces-src/protocol.c index d63d0918..29999302 100644 --- a/misc/source/darkplaces-src/protocol.c +++ b/misc/source/darkplaces-src/protocol.c @@ -2241,19 +2241,20 @@ void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbi { int numbones = s->skeletonobject.model->num_bones; int bonenum; - short pose6s[6]; + short pose7s[7]; MSG_WriteByte(msg, 4); MSG_WriteShort(msg, s->modelindex); MSG_WriteByte(msg, numbones); for (bonenum = 0;bonenum < numbones;bonenum++) { - Matrix4x4_ToBonePose6s(s->skeletonobject.relativetransforms + bonenum, 64, pose6s); - MSG_WriteShort(msg, pose6s[0]); - MSG_WriteShort(msg, pose6s[1]); - MSG_WriteShort(msg, pose6s[2]); - MSG_WriteShort(msg, pose6s[3]); - MSG_WriteShort(msg, pose6s[4]); - MSG_WriteShort(msg, pose6s[5]); + Matrix4x4_ToBonePose7s(s->skeletonobject.relativetransforms + bonenum, 64, pose7s); + MSG_WriteShort(msg, pose7s[0]); + MSG_WriteShort(msg, pose7s[1]); + MSG_WriteShort(msg, pose7s[2]); + MSG_WriteShort(msg, pose7s[3]); + MSG_WriteShort(msg, pose7s[4]); + MSG_WriteShort(msg, pose7s[5]); + MSG_WriteShort(msg, pose7s[6]); } } else @@ -2316,6 +2317,8 @@ void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbi static void EntityState5_ReadUpdate(entity_state_t *s, int number) { int bits; + int startoffset = cl_message.readcount; + int bytes = 0; bits = MSG_ReadByte(&cl_message); if (bits & E5_EXTEND1) { @@ -2434,7 +2437,7 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number) int type; int bonenum; int numbones; - short pose6s[6]; + short pose7s[7]; type = MSG_ReadByte(&cl_message); switch(type) { @@ -2512,13 +2515,14 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number) } for (bonenum = 0;bonenum < numbones;bonenum++) { - pose6s[0] = (short)MSG_ReadShort(&cl_message); - pose6s[1] = (short)MSG_ReadShort(&cl_message); - pose6s[2] = (short)MSG_ReadShort(&cl_message); - pose6s[3] = (short)MSG_ReadShort(&cl_message); - pose6s[4] = (short)MSG_ReadShort(&cl_message); - pose6s[5] = (short)MSG_ReadShort(&cl_message); - Matrix4x4_FromBonePose6s(skeleton->relativetransforms + bonenum, 1.0f / 64.0f, pose6s); + pose7s[0] = (short)MSG_ReadShort(&cl_message); + pose7s[1] = (short)MSG_ReadShort(&cl_message); + pose7s[2] = (short)MSG_ReadShort(&cl_message); + pose7s[3] = (short)MSG_ReadShort(&cl_message); + pose7s[4] = (short)MSG_ReadShort(&cl_message); + pose7s[5] = (short)MSG_ReadShort(&cl_message); + pose7s[6] = (short)MSG_ReadShort(&cl_message); + Matrix4x4_FromBonePose7s(skeleton->relativetransforms + bonenum, 1.0f / 64.0f, pose7s); } s->skeletonobject = *skeleton; break; @@ -2531,9 +2535,10 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number) s->traileffectnum = (unsigned short) MSG_ReadShort(&cl_message); + bytes = cl_message.readcount - startoffset; if (developer_networkentities.integer >= 2) { - Con_Printf("ReadFields e%i", number); + Con_Printf("ReadFields e%i (%i bytes)", number, bytes); if (bits & E5_ORIGIN) Con_Printf(" E5_ORIGIN %f %f %f", s->origin[0], s->origin[1], s->origin[2]); @@ -2586,6 +2591,10 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number) Con_Printf(" E5_COLORMOD %f:%f:%f", s->colormod[0] / 32.0f, s->colormod[1] / 32.0f, s->colormod[2] / 32.0f); if (bits & E5_GLOWMOD) Con_Printf(" E5_GLOWMOD %f:%f:%f", s->glowmod[0] / 32.0f, s->glowmod[1] / 32.0f, s->glowmod[2] / 32.0f); + if (bits & E5_COMPLEXANIMATION) + Con_Printf(" E5_COMPLEXANIMATION"); + if (bits & E5_TRAILEFFECTNUM) + Con_Printf(" E5_TRAILEFFECTNUM %i", s->traileffectnum); Con_Print("\n"); } } diff --git a/misc/source/darkplaces-src/protocol.h b/misc/source/darkplaces-src/protocol.h index 9d694f0f..3c0c6ce6 100644 --- a/misc/source/darkplaces-src/protocol.h +++ b/misc/source/darkplaces-src/protocol.h @@ -58,7 +58,7 @@ void Protocol_Names(char *buffer, size_t buffersize); #define EF_SELECTABLE 16384 // LordHavoc: highlights when PRYDON_CLIENTCURSOR mouse is over it #define EF_DOUBLESIDED 32768 //[515]: disable cull face for this entity #define EF_NOSELFSHADOW 65536 // LordHavoc: does not cast a shadow on itself (or any other EF_NOSELFSHADOW entities) -#define EF_UNUSED17 131072 +#define EF_DYNAMICMODELLIGHT 131072 #define EF_UNUSED18 262144 #define EF_UNUSED19 524288 #define EF_RESTARTANIM_BIT 1048576 // div0: restart animation bit (like teleport bit, but lerps between end and start of the anim, and doesn't stop player lerping) @@ -345,6 +345,7 @@ void Protocol_Names(char *buffer, size_t buffersize); #define RENDER_ADDITIVE 2097152 #define RENDER_DOUBLESIDED 4194304 #define RENDER_CUSTOMIZEDMODELLIGHT 4096 +#define RENDER_DYNAMICMODELLIGHT 8388608 // origin dependent model light #define MAX_FRAMEGROUPBLENDS 4 typedef struct framegroupblend_s @@ -746,7 +747,7 @@ void EntityFrame4_CL_ReadFrame(void); // byte type=1 short frames[2] short times[2] byte lerps[2] // byte type=2 short frames[3] short times[3] byte lerps[3] // byte type=3 short frames[4] short times[4] byte lerps[4] -// byte type=4 short modelindex byte numbones {short pose6s[6]} +// byte type=4 short modelindex byte numbones {short pose7s[7]} // see also RENDER_COMPLEXANIMATION #define E5_COMPLEXANIMATION (1<<25) // ushort traileffectnum diff --git a/misc/source/darkplaces-src/prvm_cmds.c b/misc/source/darkplaces-src/prvm_cmds.c index 7f1900d9..b7ae1881 100644 --- a/misc/source/darkplaces-src/prvm_cmds.c +++ b/misc/source/darkplaces-src/prvm_cmds.c @@ -17,6 +17,7 @@ #include "mdfour.h" extern cvar_t prvm_backtraceforwarnings; +extern dllhandle_t ode_dll; // LordHavoc: changed this to NOT use a return statement, so that it can be used in functions that must return a value void VM_Warning(prvm_prog_t *prog, const char *fmt, ...) @@ -277,10 +278,14 @@ static qboolean checkextension(prvm_prog_t *prog, const char *name) // special sheck for ODE if (!strncasecmp("DP_PHYSICS_ODE", name, 14)) { -#ifdef USEODE +#ifdef ODE_DYNAMIC return ode_dll ? true : false; +#else +#ifdef ODE_STATIC + return true; #else return false; +#endif #endif } @@ -3241,18 +3246,34 @@ VM_precache_pic string precache_pic(string pic) ========= */ +#define PRECACHE_PIC_FROMWAD 1 /* FTEQW, not supported here */ +#define PRECACHE_PIC_NOTPERSISTENT 2 +//#define PRECACHE_PIC_NOCLAMP 4 +#define PRECACHE_PIC_MIPMAP 8 void VM_precache_pic(prvm_prog_t *prog) { const char *s; + int flags = 0; - VM_SAFEPARMCOUNT(1, VM_precache_pic); + VM_SAFEPARMCOUNTRANGE(1, 2, VM_precache_pic); s = PRVM_G_STRING(OFS_PARM0); PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); VM_CheckEmptyString(prog, s); + if(prog->argc >= 2) + { + int f = PRVM_G_FLOAT(OFS_PARM1); + if(f & PRECACHE_PIC_NOTPERSISTENT) + flags |= CACHEPICFLAG_NOTPERSISTENT; + //if(f & PRECACHE_PIC_NOCLAMP) + // flags |= CACHEPICFLAG_NOCLAMP; + if(f & PRECACHE_PIC_MIPMAP) + flags |= CACHEPICFLAG_MIPMAP; + } + // AK Draw_CachePic is supposed to always return a valid pointer - if( Draw_CachePic_Flags(s, 0)->tex == r_texture_notexture ) + if( Draw_CachePic_Flags(s, flags)->tex == r_texture_notexture ) PRVM_G_INT(OFS_RETURN) = OFS_NULL; } @@ -3911,9 +3932,16 @@ void VM_getimagesize(prvm_prog_t *prog) VM_CheckEmptyString(prog, p); pic = Draw_CachePic_Flags (p, CACHEPICFLAG_NOTPERSISTENT); - - PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width; - PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height; + if( pic->tex == r_texture_notexture ) + { + PRVM_G_VECTOR(OFS_RETURN)[0] = 0; + PRVM_G_VECTOR(OFS_RETURN)[1] = 0; + } + else + { + PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width; + PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height; + } PRVM_G_VECTOR(OFS_RETURN)[2] = 0; } @@ -5873,7 +5901,7 @@ out1: out2: handle->postdata = NULL; handle->postlen = 0; - ret = Curl_Begin_ToMemory(url, 0, (unsigned char *) handle->buffer, sizeof(handle->buffer), uri_to_string_callback, handle); + ret = Curl_Begin_ToMemory_POST(url, handle->sigdata, 0, NULL, NULL, 0, (unsigned char *) handle->buffer, sizeof(handle->buffer), uri_to_string_callback, handle); } if(ret) { @@ -6326,7 +6354,10 @@ nolength: { if(precision < 0) // not set precision = end - o - 1; - o += u8_strpad(o, end - o, GETARG_STRING(thisarg), (flags & PRINTF_LEFT) != 0, width, precision); + if(flags & PRINTF_SIGNPOSITIVE) + o += u8_strpad(o, end - o, GETARG_STRING(thisarg), (flags & PRINTF_LEFT) != 0, width, precision); + else + o += u8_strpad_colorcodes(o, end - o, GETARG_STRING(thisarg), (flags & PRINTF_LEFT) != 0, width, precision); } break; default: @@ -6826,9 +6857,9 @@ void VM_physics_addforce(prvm_prog_t *prog) VM_Warning(prog, "VM_physics_addforce: entity is not MOVETYPE_PHYSICS!\n"); return; } - f.type = ODEFUNC_RELFORCEATPOS; + f.type = ODEFUNC_FORCE; VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f.v1); - VectorSubtract(PRVM_serveredictvector(ed, origin), PRVM_G_VECTOR(OFS_PARM2), f.v2); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), f.v2); VM_physics_ApplyCmd(ed, &f); } @@ -6852,7 +6883,7 @@ void VM_physics_addtorque(prvm_prog_t *prog) VM_Warning(prog, "VM_physics_addtorque: entity is not MOVETYPE_PHYSICS!\n"); return; } - f.type = ODEFUNC_RELTORQUE; + f.type = ODEFUNC_TORQUE; VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f.v1); VM_physics_ApplyCmd(ed, &f); } diff --git a/misc/source/darkplaces-src/prvm_edict.c b/misc/source/darkplaces-src/prvm_edict.c index 25f9899a..6dc2a6e8 100644 --- a/misc/source/darkplaces-src/prvm_edict.c +++ b/misc/source/darkplaces-src/prvm_edict.c @@ -1606,7 +1606,7 @@ static void PRVM_PO_UnparseString(char *out, const char *in, size_t outsize) *out++ = '\\'; *out++ = '0' + ((*in & 0700) >> 6); *out++ = '0' + ((*in & 0070) >> 3); - *out++ = '0' + ((*in & 0007)); + *out++ = '0' + (*in & 0007) ; outsize -= 4; } } @@ -2726,9 +2726,7 @@ int PRVM_SetEngineString(prvm_prog_t *prog, const char *s) // if it's in the tempstrings area, use a reserved range // (otherwise we'd get millions of useless string offsets cluttering the database) if (s >= (char *)prog->tempstringsbuf.data && s < (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.maxsize) -#if 1 return prog->stringssize + (s - (char *)prog->tempstringsbuf.data); -#endif // see if it's a known string address for (i = 0;i < prog->numknownstrings;i++) if (prog->knownstrings[i] == s) diff --git a/misc/source/darkplaces-src/prvm_offsets.h b/misc/source/darkplaces-src/prvm_offsets.h index 09ac75ed..f6c118a0 100644 --- a/misc/source/darkplaces-src/prvm_offsets.h +++ b/misc/source/darkplaces-src/prvm_offsets.h @@ -24,13 +24,17 @@ PRVM_DECLARE_clientfieldfloat(frame4time) PRVM_DECLARE_clientfieldfloat(gravity) PRVM_DECLARE_clientfieldfloat(ideal_yaw) PRVM_DECLARE_clientfieldfloat(idealpitch) +PRVM_DECLARE_clientfieldfloat(geomtype) PRVM_DECLARE_clientfieldfloat(jointtype) +PRVM_DECLARE_clientfieldfloat(forcetype) PRVM_DECLARE_clientfieldfloat(lerpfrac) PRVM_DECLARE_clientfieldfloat(lerpfrac3) PRVM_DECLARE_clientfieldfloat(lerpfrac4) PRVM_DECLARE_clientfieldfloat(mass) PRVM_DECLARE_clientfieldvector(massofs) PRVM_DECLARE_clientfieldfloat(friction) +PRVM_DECLARE_clientfieldfloat(maxcontacts) +PRVM_DECLARE_clientfieldfloat(erp) PRVM_DECLARE_clientfieldfloat(modelindex) PRVM_DECLARE_clientfieldfloat(movetype) PRVM_DECLARE_clientfieldfloat(nextthink) @@ -38,6 +42,7 @@ PRVM_DECLARE_clientfieldfloat(pitch_speed) PRVM_DECLARE_clientfieldfloat(pmove_flags) PRVM_DECLARE_clientfieldfloat(renderflags) PRVM_DECLARE_clientfieldfloat(scale) +PRVM_DECLARE_clientfieldvector(modelscale_vec) PRVM_DECLARE_clientfieldfloat(shadertime) PRVM_DECLARE_clientfieldfloat(skeletonindex) PRVM_DECLARE_clientfieldfloat(skin) @@ -186,6 +191,8 @@ PRVM_DECLARE_clientglobalvector(pmove_inwater) PRVM_DECLARE_clientglobalvector(pmove_maxs) PRVM_DECLARE_clientglobalvector(pmove_mins) PRVM_DECLARE_clientglobalvector(pmove_onground) +PRVM_DECLARE_clientglobalfloat(pmove_waterjumptime) +PRVM_DECLARE_clientglobalfloat(pmove_jump_held) PRVM_DECLARE_clientglobalvector(pmove_org) PRVM_DECLARE_clientglobalvector(pmove_vel) PRVM_DECLARE_clientglobalvector(trace_endpos) @@ -300,7 +307,9 @@ PRVM_DECLARE_field(idealpitch) PRVM_DECLARE_field(impulse) PRVM_DECLARE_field(items) PRVM_DECLARE_field(items2) +PRVM_DECLARE_field(geomtype) PRVM_DECLARE_field(jointtype) +PRVM_DECLARE_field(forcetype) PRVM_DECLARE_field(lerpfrac) PRVM_DECLARE_field(lerpfrac3) PRVM_DECLARE_field(lerpfrac4) @@ -309,6 +318,8 @@ PRVM_DECLARE_field(ltime) PRVM_DECLARE_field(mass) PRVM_DECLARE_field(massofs) PRVM_DECLARE_field(friction) +PRVM_DECLARE_field(maxcontacts) +PRVM_DECLARE_field(erp) PRVM_DECLARE_field(max_health) PRVM_DECLARE_field(maxs) PRVM_DECLARE_field(message) @@ -346,6 +357,7 @@ PRVM_DECLARE_field(punchvector) PRVM_DECLARE_field(renderamt) PRVM_DECLARE_field(renderflags) PRVM_DECLARE_field(scale) +PRVM_DECLARE_field(modelscale_vec) PRVM_DECLARE_field(sendcomplexanimation) PRVM_DECLARE_field(shadertime) PRVM_DECLARE_field(size) @@ -522,6 +534,8 @@ PRVM_DECLARE_global(pmove_inwater) PRVM_DECLARE_global(pmove_maxs) PRVM_DECLARE_global(pmove_mins) PRVM_DECLARE_global(pmove_onground) +PRVM_DECLARE_global(pmove_waterjumptime) +PRVM_DECLARE_global(pmove_jump_held) PRVM_DECLARE_global(pmove_org) PRVM_DECLARE_global(pmove_vel) PRVM_DECLARE_global(require_spawnfunc_prefix) @@ -657,7 +671,9 @@ PRVM_DECLARE_serverfieldfloat(idealpitch) PRVM_DECLARE_serverfieldfloat(impulse) PRVM_DECLARE_serverfieldfloat(items) PRVM_DECLARE_serverfieldfloat(items2) +PRVM_DECLARE_serverfieldfloat(geomtype) PRVM_DECLARE_serverfieldfloat(jointtype) +PRVM_DECLARE_serverfieldfloat(forcetype) PRVM_DECLARE_serverfieldfloat(lerpfrac) PRVM_DECLARE_serverfieldfloat(lerpfrac3) PRVM_DECLARE_serverfieldfloat(lerpfrac4) @@ -666,6 +682,8 @@ PRVM_DECLARE_serverfieldfloat(ltime) PRVM_DECLARE_serverfieldfloat(mass) PRVM_DECLARE_serverfieldvector(massofs) PRVM_DECLARE_serverfieldfloat(friction) +PRVM_DECLARE_serverfieldfloat(maxcontacts) +PRVM_DECLARE_serverfieldfloat(erp) PRVM_DECLARE_serverfieldfloat(max_health) PRVM_DECLARE_serverfieldfloat(modelflags) PRVM_DECLARE_serverfieldfloat(modelindex) @@ -679,6 +697,7 @@ PRVM_DECLARE_serverfieldfloat(pitch_speed) PRVM_DECLARE_serverfieldfloat(pmodel) PRVM_DECLARE_serverfieldfloat(renderamt) PRVM_DECLARE_serverfieldfloat(scale) +PRVM_DECLARE_serverfieldvector(modelscale_vec) PRVM_DECLARE_serverfieldfloat(sendcomplexanimation) PRVM_DECLARE_serverfieldfloat(skeletonindex) PRVM_DECLARE_serverfieldfloat(skin) diff --git a/misc/source/darkplaces-src/quakedef.h b/misc/source/darkplaces-src/quakedef.h index 65f24159..66fdfb30 100644 --- a/misc/source/darkplaces-src/quakedef.h +++ b/misc/source/darkplaces-src/quakedef.h @@ -484,10 +484,7 @@ extern cvar_t sessionid; # undef SSE2_PRESENT #endif -#ifdef SSE2_PRESENT -#define Sys_HaveSSE() true -#define Sys_HaveSSE2() true -#elif defined(SSE_POSSIBLE) +#ifdef SSE_POSSIBLE // runtime detection of SSE/SSE2 capabilities for x86 qboolean Sys_HaveSSE(void); qboolean Sys_HaveSSE2(void); diff --git a/misc/source/darkplaces-src/r_shadow.c b/misc/source/darkplaces-src/r_shadow.c index adec83e1..bdf4f2c5 100644 --- a/misc/source/darkplaces-src/r_shadow.c +++ b/misc/source/darkplaces-src/r_shadow.c @@ -196,6 +196,7 @@ int r_shadow_shadowmapdepthbits; int r_shadow_shadowmapmaxsize; qboolean r_shadow_shadowmapvsdct; qboolean r_shadow_shadowmapsampler; +qboolean r_shadow_shadowmapshadowsampler; int r_shadow_shadowmappcf; int r_shadow_shadowmapborder; matrix4x4_t r_shadow_shadowmapmatrix; @@ -303,6 +304,7 @@ cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_wor cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"}; cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"}; cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"}; +cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"}; cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"}; cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"}; cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"}; @@ -427,6 +429,7 @@ static void R_Shadow_SetShadowMode(void) r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4); r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20; r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer; + r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0; r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer; r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16); r_shadow_shadowmaplod = -1; @@ -447,23 +450,23 @@ static void R_Shadow_SetShadowMode(void) r_shadow_shadowmappcf = 1; else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) { - r_shadow_shadowmapsampler = vid.support.arb_shadow; + r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler; r_shadow_shadowmappcf = 1; } - else if(strstr(gl_vendor, "ATI")) + else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa")) r_shadow_shadowmappcf = 1; else - r_shadow_shadowmapsampler = vid.support.arb_shadow; + r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler; } else { switch (r_shadow_shadowmapfilterquality) { case 1: - r_shadow_shadowmapsampler = vid.support.arb_shadow; + r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler; break; case 2: - r_shadow_shadowmapsampler = vid.support.arb_shadow; + r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler; r_shadow_shadowmappcf = 1; break; case 3: @@ -493,6 +496,9 @@ static void R_Shadow_SetShadowMode(void) break; } } + + if(R_CompileShader_CheckStaticParms()) + R_GLSL_Restart_f(); } qboolean R_Shadow_ShadowMappingEnabled(void) @@ -725,6 +731,7 @@ void R_Shadow_Init(void) Cvar_RegisterVariable(&r_shadow_shadowmapping); Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct); Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality); + Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler); Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits); Cvar_RegisterVariable(&r_shadow_shadowmapping_precision); Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize); @@ -3917,6 +3924,18 @@ static void R_Shadow_PrepareLight(rtlight_t *rtlight) qboolean nolight; rtlight->draw = false; + rtlight->cached_numlightentities = 0; + rtlight->cached_numlightentities_noselfshadow = 0; + rtlight->cached_numshadowentities = 0; + rtlight->cached_numshadowentities_noselfshadow = 0; + rtlight->cached_numsurfaces = 0; + rtlight->cached_lightentities = NULL; + rtlight->cached_lightentities_noselfshadow = NULL; + rtlight->cached_shadowentities = NULL; + rtlight->cached_shadowentities_noselfshadow = NULL; + rtlight->cached_shadowtrispvs = NULL; + rtlight->cached_lighttrispvs = NULL; + rtlight->cached_surfacelist = NULL; // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights) // skip lights that are basically invisible (color 0 0 0) @@ -3964,6 +3983,10 @@ static void R_Shadow_PrepareLight(rtlight_t *rtlight) R_Shadow_ComputeShadowCasterCullingPlanes(rtlight); + // don't allow lights to be drawn if using r_shadow_bouncegrid 2, except if we're using static bouncegrid where dynamic lights still need to draw + if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer)) + return; + if (rtlight->compiled && r_shadow_realtime_world_compile.integer) { // compiled light, world available and can receive realtime lighting @@ -4491,6 +4514,7 @@ void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *color (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) || r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) || r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || + r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) || r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16)) R_Shadow_FreeShadowMaps(); @@ -4562,25 +4586,22 @@ void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *color R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles); flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE; - if (r_shadow_bouncegrid.integer != 2) + if (r_shadow_debuglight.integer >= 0) { - if (r_shadow_debuglight.integer >= 0) + lightindex = r_shadow_debuglight.integer; + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (light) + R_Shadow_PrepareLight(&light->rtlight); + } + else + { + range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + for (lightindex = 0;lightindex < range;lightindex++) { - lightindex = r_shadow_debuglight.integer; light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); - if (light) + if (light && (light->flags & flag)) R_Shadow_PrepareLight(&light->rtlight); } - else - { - range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked - for (lightindex = 0;lightindex < range;lightindex++) - { - light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); - if (light && (light->flags & flag)) - R_Shadow_PrepareLight(&light->rtlight); - } - } } if (r_refdef.scene.rtdlight) { @@ -4611,26 +4632,23 @@ void R_Shadow_DrawLights(void) R_Shadow_RenderMode_Begin(); - if (r_shadow_bouncegrid.integer != 2) + flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE; + if (r_shadow_debuglight.integer >= 0) { - flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE; - if (r_shadow_debuglight.integer >= 0) + lightindex = r_shadow_debuglight.integer; + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (light) + R_Shadow_DrawLight(&light->rtlight); + } + else + { + range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + for (lightindex = 0;lightindex < range;lightindex++) { - lightindex = r_shadow_debuglight.integer; light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); - if (light) + if (light && (light->flags & flag)) R_Shadow_DrawLight(&light->rtlight); } - else - { - range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked - for (lightindex = 0;lightindex < range;lightindex++) - { - light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); - if (light && (light->flags & flag)) - R_Shadow_DrawLight(&light->rtlight); - } - } } if (r_refdef.scene.rtdlight) for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++) diff --git a/misc/source/darkplaces-src/r_textures.h b/misc/source/darkplaces-src/r_textures.h index 594fcad2..e9c9aaba 100644 --- a/misc/source/darkplaces-src/r_textures.h +++ b/misc/source/darkplaces-src/r_textures.h @@ -172,7 +172,7 @@ rtexture_t *R_LoadTexture3D(rtexturepool_t *rtexturepool, const char *identifier rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *identifier, int width, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette); rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter); rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype); -rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel); +rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel, qboolean optionaltexture); // saves a texture to a DDS file int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha); diff --git a/misc/source/darkplaces-src/render.h b/misc/source/darkplaces-src/render.h index c869615a..7e60e504 100644 --- a/misc/source/darkplaces-src/render.h +++ b/misc/source/darkplaces-src/render.h @@ -244,6 +244,7 @@ typedef struct rsurfacestate_s // // this indicates the model* arrays are pointed at array_model* buffers // (in other words, the model has been animated in software) + qboolean forcecurrenttextureupdate; // set for RSurf_ActiveCustomEntity to force R_GetCurrentTexture to recalculate the texture parameters (such as entity alpha) qboolean modelgeneratedvertex; float *modelvertex3f; const r_meshbuffer_t *modelvertex3f_vertexbuffer; @@ -578,5 +579,7 @@ void R_LightningBeams_Init(void); void Mod_RenderInit(void); void Font_Init(void); -#endif +qboolean R_CompileShader_CheckStaticParms(void); +void R_GLSL_Restart_f(void); +#endif diff --git a/misc/source/darkplaces-src/screen.h b/misc/source/darkplaces-src/screen.h index b88a80d5..68a2998d 100644 --- a/misc/source/darkplaces-src/screen.h +++ b/misc/source/darkplaces-src/screen.h @@ -26,10 +26,10 @@ void CL_Screen_Init (void); void CL_UpdateScreen (void); void SCR_CenterPrint(const char *str); -void SCR_BeginLoadingPlaque (void); +void SCR_BeginLoadingPlaque (qboolean startup); // invoke refresh of loading plaque (nothing else seen) -void SCR_UpdateLoadingScreen(qboolean clear); +void SCR_UpdateLoadingScreen(qboolean clear, qboolean startup); void SCR_UpdateLoadingScreenIfShown(void); // pushes an item on the loading screen diff --git a/misc/source/darkplaces-src/server.h b/misc/source/darkplaces-src/server.h index 5d399607..3be5510e 100644 --- a/misc/source/darkplaces-src/server.h +++ b/misc/source/darkplaces-src/server.h @@ -66,12 +66,13 @@ typedef struct server_static_s typedef enum server_state_e {ss_loading, ss_active} server_state_t; #define MAX_CONNECTFLOODADDRESSES 16 -typedef struct server_connectfloodaddress_s +#define MAX_GETSTATUSFLOODADDRESSES 128 +typedef struct server_floodaddress_s { double lasttime; lhnetaddress_t address; } -server_connectfloodaddress_t; +server_floodaddress_t; typedef struct server_s { @@ -137,7 +138,8 @@ typedef struct server_s /// connection flood blocking /// note this is in server_t rather than server_static_t so that it is /// reset on each map command (such as New Game in singleplayer) - server_connectfloodaddress_t connectfloodaddresses[MAX_CONNECTFLOODADDRESSES]; + server_floodaddress_t connectfloodaddresses[MAX_CONNECTFLOODADDRESSES]; + server_floodaddress_t getstatusfloodaddresses[MAX_GETSTATUSFLOODADDRESSES]; #define SV_MAX_PARTICLEEFFECTNAME 256 qboolean particleeffectnamesloaded; @@ -302,6 +304,10 @@ typedef struct client_s // number of skipped entity frames // if it exceeds a limit, an empty entity frame is sent int num_skippedentityframes; + + // last sent move sequence + // if the move sequence changed, an empty entity frame is sent + int lastmovesequence; } client_t; @@ -334,6 +340,7 @@ typedef struct client_s // LordHavoc: corpse code #define SOLID_CORPSE 5 ///< same as SOLID_BBOX, except it behaves as SOLID_NOT against SOLID_SLIDEBOX objects (players/monsters) // LordHavoc: physics +// VorteX: now these fields are deprecated, as geomtype is more flexible #define SOLID_PHYSICS_BOX 32 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) #define SOLID_PHYSICS_SPHERE 33 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) #define SOLID_PHYSICS_CAPSULE 34 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) @@ -589,8 +596,8 @@ void SV_GetEntityMatrix(prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, void SV_StartThread(void); void SV_StopThread(void); -#define SV_LockThreadMutex() (svs.threaded ? Thread_LockMutex(svs.threadmutex),1 : 0) -#define SV_UnlockThreadMutex() (svs.threaded ? Thread_UnlockMutex(svs.threadmutex),1 : 0) +#define SV_LockThreadMutex() (void)(svs.threaded ? Thread_LockMutex(svs.threadmutex) : 0) +#define SV_UnlockThreadMutex() (void)(svs.threaded ? Thread_UnlockMutex(svs.threadmutex) : 0) void VM_CustomStats_Clear(void); void VM_SV_UpdateCustomStats(client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats); diff --git a/misc/source/darkplaces-src/shader_glsl.h b/misc/source/darkplaces-src/shader_glsl.h index c133ba28..41dac64e 100644 --- a/misc/source/darkplaces-src/shader_glsl.h +++ b/misc/source/darkplaces-src/shader_glsl.h @@ -310,6 +310,7 @@ "#ifdef USESPECULAR\n" "dp_varying mediump vec2 TexCoord2;\n" "#endif\n" +"uniform myhalf Alpha;\n" "#ifdef VERTEX_SHADER\n" "void main(void)\n" "{\n" @@ -371,6 +372,9 @@ " dp_FragColor.g = dp_texture2D(Texture_GammaRamps, vec2(dp_FragColor.g, 0)).g;\n" " dp_FragColor.b = dp_texture2D(Texture_GammaRamps, vec2(dp_FragColor.b, 0)).b;\n" "#endif\n" +"#ifdef USEALPHAKILL\n" +" dp_FragColor.a *= Alpha;\n" +"#endif\n" "}\n" "#endif\n" "#else // !MODE_GENERIC\n" @@ -416,6 +420,9 @@ "\n" "void main(void)\n" "{\n" +"#ifdef USEALPHAGENVERTEX\n" +" VertexColor = Attrib_Color;\n" +"#endif\n" " TexCoord = vec2(TexMatrix * Attrib_TexCoord0);\n" " gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n" " ModelViewProjectionPosition = gl_Position;\n" @@ -444,12 +451,19 @@ " vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n" " //vec2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(vec3(dp_texture2D(Texture_Normal, TexCoord)) - vec3(0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n" " vec2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n" +"#ifdef USEALPHAGENVERTEX\n" +" vec2 distort = DistortScaleRefractReflect.xy * VertexColor.a;\n" +" vec4 refractcolor = mix(RefractColor, vec4(1.0, 1.0, 1.0, 1.0), VertexColor.a);\n" +"#else\n" +" vec2 distort = DistortScaleRefractReflect.xy;\n" +" vec4 refractcolor = RefractColor;\n" +"#endif\n" " #ifdef USENORMALMAPSCROLLBLEND\n" " vec3 normal = dp_texture2D(Texture_Normal, (TexCoord + vec2(0.08, 0.08)*ClientTime*NormalmapScrollBlend.x*0.5)*NormalmapScrollBlend.y).rgb - vec3(1.0);\n" " normal += dp_texture2D(Texture_Normal, (TexCoord + vec2(-0.06, -0.09)*ClientTime*NormalmapScrollBlend.x)*NormalmapScrollBlend.y*0.75).rgb;\n" -" vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(cast_myhalf3(normal))).xy * DistortScaleRefractReflect.xy;\n" +" vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(cast_myhalf3(normal))).xy * distort;\n" " #else\n" -" vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(cast_myhalf3(dp_texture2D(Texture_Normal, TexCoord)) - cast_myhalf3(0.5))).xy * DistortScaleRefractReflect.xy;\n" +" vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(cast_myhalf3(dp_texture2D(Texture_Normal, TexCoord)) - cast_myhalf3(0.5))).xy * distort;\n" " #endif\n" " // FIXME temporary hack to detect the case that the reflection\n" " // gets blackened at edges due to leaving the area that contains actual\n" @@ -461,7 +475,7 @@ " f *= min(1.0, length(dp_texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, 0.01)).rgb) / 0.05);\n" " f *= min(1.0, length(dp_texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, -0.01)).rgb) / 0.05);\n" " ScreenTexCoord = mix(SafeScreenTexCoord, ScreenTexCoord, f);\n" -" dp_FragColor = vec4(dp_texture2D(Texture_Refraction, ScreenTexCoord).rgb, 1.0) * RefractColor;\n" +" dp_FragColor = vec4(dp_texture2D(Texture_Refraction, ScreenTexCoord).rgb, 1.0) * refractcolor;\n" "}\n" "#endif\n" "#else // !MODE_REFRACTION\n" @@ -479,6 +493,9 @@ "\n" "void main(void)\n" "{\n" +"#ifdef USEALPHAGENVERTEX\n" +" VertexColor = Attrib_Color;\n" +"#endif\n" " TexCoord = vec2(TexMatrix * Attrib_TexCoord0);\n" " vec3 EyeRelative = EyePosition - Attrib_Position.xyz;\n" " EyeVector.x = dot(EyeRelative, Attrib_TexCoord1.xyz);\n" @@ -516,12 +533,23 @@ " vec4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n" " //SafeScreenTexCoord = gl_FragCoord.xyxy * vec4(1.0 / 1920.0, 1.0 / 1200.0, 1.0 / 1920.0, 1.0 / 1200.0);\n" " // slight water animation via 2 layer scrolling (todo: tweak)\n" +"#ifdef USEALPHAGENVERTEX\n" +" vec4 distort = DistortScaleRefractReflect * VertexColor.a;\n" +" float reflectoffset = ReflectOffset * VertexColor.a;\n" +" float reflectfactor = ReflectFactor * VertexColor.a;\n" +" vec4 refractcolor = mix(RefractColor, vec4(1.0, 1.0, 1.0, 1.0), VertexColor.a);\n" +"#else\n" +" vec4 distort = DistortScaleRefractReflect;\n" +" float reflectoffset = ReflectOffset;\n" +" float reflectfactor = ReflectFactor;\n" +" vec4 refractcolor = RefractColor;\n" +"#endif\n" " #ifdef USENORMALMAPSCROLLBLEND\n" " vec3 normal = dp_texture2D(Texture_Normal, (TexCoord + vec2(0.08, 0.08)*ClientTime*NormalmapScrollBlend.x*0.5)*NormalmapScrollBlend.y).rgb - vec3(1.0);\n" " normal += dp_texture2D(Texture_Normal, (TexCoord + vec2(-0.06, -0.09)*ClientTime*NormalmapScrollBlend.x)*NormalmapScrollBlend.y*0.75).rgb;\n" -" vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(normal) + vec3(0.15)).xyxy * DistortScaleRefractReflect;\n" +" vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(normal) + vec3(0.15)).xyxy * distort;\n" " #else\n" -" vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(vec3(dp_texture2D(Texture_Normal, TexCoord)) - vec3(0.5))).xyxy * DistortScaleRefractReflect;\n" +" vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(vec3(dp_texture2D(Texture_Normal, TexCoord)) - vec3(0.5))).xyxy * distort;\n" " #endif\n" " // FIXME temporary hack to detect the case that the reflection\n" " // gets blackened at edges due to leaving the area that contains actual\n" @@ -538,8 +566,8 @@ " f *= min(1.0, length(dp_texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.005, 0.005)).rgb) / 0.002);\n" " f *= min(1.0, length(dp_texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.005, -0.005)).rgb) / 0.002);\n" " ScreenTexCoord.zw = mix(SafeScreenTexCoord.zw, ScreenTexCoord.zw, f);\n" -" float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * ReflectFactor + ReflectOffset;\n" -" dp_FragColor = mix(vec4(dp_texture2D(Texture_Refraction, ScreenTexCoord.xy).rgb, 1) * RefractColor, vec4(dp_texture2D(Texture_Reflection, ScreenTexCoord.zw).rgb, 1) * ReflectColor, Fresnel);\n" +" float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * reflectfactor + reflectoffset;\n" +" dp_FragColor = mix(vec4(dp_texture2D(Texture_Refraction, ScreenTexCoord.xy).rgb, 1) * refractcolor, vec4(dp_texture2D(Texture_Reflection, ScreenTexCoord.zw).rgb, 1) * ReflectColor, Fresnel);\n" "}\n" "#endif\n" "#else // !MODE_WATER\n" @@ -702,8 +730,17 @@ " float i;\n" " // distance-based LOD\n" "#ifdef USEOFFSETMAPPING_LOD\n" -" mediump float LODFactor = min(1.0, OffsetMapping_LodDistance / EyeVectorFogDepth.z);\n" -" mediump vec4 ScaleSteps = vec4(OffsetMapping_ScaleSteps.x, OffsetMapping_ScaleSteps.y * LODFactor, OffsetMapping_ScaleSteps.z / LODFactor, OffsetMapping_ScaleSteps.w * LODFactor);\n" +" //mediump float LODFactor = min(1.0, OffsetMapping_LodDistance / EyeVectorFogDepth.z);\n" +" //mediump vec4 ScaleSteps = vec4(OffsetMapping_ScaleSteps.x, OffsetMapping_ScaleSteps.y * LODFactor, OffsetMapping_ScaleSteps.z / LODFactor, OffsetMapping_ScaleSteps.w * LODFactor);\n" +" mediump float GuessLODFactor = min(1.0, OffsetMapping_LodDistance / EyeVectorFogDepth.z);\n" +"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n" +" // stupid workaround because 1-step and 2-step reliefmapping is void\n" +" mediump float LODSteps = max(3.0, ceil(GuessLODFactor * OffsetMapping_ScaleSteps.y));\n" +"#else\n" +" mediump float LODSteps = ceil(GuessLODFactor * OffsetMapping_ScaleSteps.y);\n" +"#endif\n" +" mediump float LODFactor = LODSteps / OffsetMapping_ScaleSteps.y;\n" +" mediump vec4 ScaleSteps = vec4(OffsetMapping_ScaleSteps.x, LODSteps, 1.0 / LODSteps, OffsetMapping_ScaleSteps.w * LODFactor);\n" "#else\n" " #define ScaleSteps OffsetMapping_ScaleSteps\n" "#endif\n" @@ -769,11 +806,11 @@ "{\n" " vec3 adir = abs(dir);\n" " float m = max(max(adir.x, adir.y), adir.z);\n" -" vec2 mparams = ShadowMap_Parameters.xy / m;\n" " vec4 proj = dp_textureCube(Texture_CubeProjection, dir);\n" "#ifdef USEDEPTHRGB\n" -" return vec3(mix(dir.xy, dir.zz, proj.xy) * mparams.x + proj.zw * ShadowMap_Parameters.z, m + 64 * ShadowMap_Parameters.w);\n" +" return vec3(mix(dir.xy, dir.zz, proj.xy) * (ShadowMap_Parameters.x / m) + proj.zw * ShadowMap_Parameters.z, m + 64.0 * ShadowMap_Parameters.w);\n" "#else\n" +" vec2 mparams = ShadowMap_Parameters.xy / m;\n" " return vec3(mix(dir.xy, dir.zz, proj.xy) * mparams.x + proj.zw * ShadowMap_Parameters.z, mparams.y + ShadowMap_Parameters.w);\n" "#endif\n" "}\n" @@ -785,7 +822,7 @@ " if (adir.x > adir.y) { m = adir.x; proj = vec4(dir.zyx, 0.5); } else { m = adir.y; proj = vec4(dir.xzy, 1.5); }\n" " if (adir.z > m) { m = adir.z; proj = vec4(dir, 2.5); }\n" "#ifdef USEDEPTHRGB\n" -" return vec3(proj.xy * ShadowMap_Parameters.x / m + vec2(0.5,0.5) + vec2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, m + 64 * ShadowMap_Parameters.w);\n" +" return vec3(proj.xy * (ShadowMap_Parameters.x / m) + vec2(0.5,0.5) + vec2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, m + 64.0 * ShadowMap_Parameters.w);\n" "#else\n" " vec2 mparams = ShadowMap_Parameters.xy / m;\n" " return vec3(proj.xy * mparams.x + vec2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, mparams.y + ShadowMap_Parameters.w);\n" @@ -1096,7 +1133,7 @@ "#endif\n" "void main(void)\n" "{\n" -"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND) || defined(MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR)\n" +"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND) || defined(MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR) || defined(USEALPHAGENVERTEX)\n" " VertexColor = Attrib_Color;\n" "#endif\n" " // copy the surface texcoord\n" @@ -1265,6 +1302,9 @@ " color.a = 1.0;\n" " //color = mix(cast_myhalf4(1, 0, 0, 1), color, terrainblend);\n" "#endif\n" +"#ifdef USEALPHAGENVERTEX\n" +" color.a *= VertexColor.a;\n" +"#endif\n" "\n" " // get the surface normal\n" "#ifdef USEVERTEXTEXTUREBLEND\n" diff --git a/misc/source/darkplaces-src/shader_hlsl.h b/misc/source/darkplaces-src/shader_hlsl.h index f20f8329..20770d18 100644 --- a/misc/source/darkplaces-src/shader_hlsl.h +++ b/misc/source/darkplaces-src/shader_hlsl.h @@ -298,6 +298,7 @@ "#ifdef USEGAMMARAMPS\n" "uniform sampler Texture_GammaRamps : register(s2),\n" "#endif\n" +"uniform half Alpha : register(c0),\n" "out float4 dp_FragColor : COLOR\n" ")\n" "{\n" @@ -332,6 +333,9 @@ " dp_FragColor.g = tex2D(Texture_GammaRamps, vec2(dp_FragColor.g, 0)).g;\n" " dp_FragColor.b = tex2D(Texture_GammaRamps, vec2(dp_FragColor.b, 0)).b;\n" "#endif\n" +"#ifdef USEALPHAKILL\n" +" dp_FragColor.a *= Alpha;\n" +"#endif\n" "}\n" "#endif\n" "#else // !MODE_GENERIC\n" @@ -384,15 +388,24 @@ "(\n" "float4 gl_Vertex : POSITION,\n" "uniform float4x4 ModelViewProjectionMatrix : register(c8),\n" +"#ifdef USEALPHAGENVERTEX\n" +"float4 gl_Color : COLOR0,\n" +"#endif\n" "float4 gl_MultiTexCoord0 : TEXCOORD0,\n" "uniform float4x4 TexMatrix : register(c0),\n" "uniform float3 EyePosition : register(c24),\n" +"#ifdef USEALPHAGENVERTEX\n" +"out float4 gl_FrontColor : COLOR,\n" +"#endif\n" "out float4 gl_Position : POSITION,\n" "out float2 TexCoord : TEXCOORD0,\n" "out float3 EyeVector : TEXCOORD1,\n" "out float4 ModelViewProjectionPosition : TEXCOORD2\n" ")\n" "{\n" +"#ifdef USEALPHAGENVERTEX\n" +" gl_FrontColor = gl_Color;\n" +"#endif\n" " TexCoord = mul(TexMatrix, gl_MultiTexCoord0).xy;\n" " gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n" " ModelViewProjectionPosition = gl_Position;\n" @@ -405,6 +418,9 @@ "#ifdef FRAGMENT_SHADER\n" "void main\n" "(\n" +"#ifdef USEALPHAGENVERTEX\n" +"float4 gl_FrontColor : COLOR,\n" +"#endif\n" "float2 TexCoord : TEXCOORD0,\n" "float3 EyeVector : TEXCOORD1,\n" "float4 ModelViewProjectionPosition : TEXCOORD2,\n" @@ -421,7 +437,14 @@ " float2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n" " //float2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(tex2D(Texture_Normal, TexCoord).rgb - float3(0.5,0.5,0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n" " float2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n" -" float2 ScreenTexCoord = SafeScreenTexCoord + normalize(tex2D(Texture_Normal, TexCoord).rgb - float3(0.5,0.5,0.5)).xy * DistortScaleRefractReflect.xy;\n" +"#ifdef USEALPHAGENVERTEX\n" +" float2 distort = DistortScaleRefractReflect.xy * gl_FrontColor.a;\n" +" float4 refractcolor = mix(RefractColor, vec4(1.0, 1.0, 1.0, 1.0), gl_FrontColor.a);\n" +"#else\n" +" float2 distort = DistortScaleRefractReflect.xy;\n" +" float4 refractcolor = RefractColor;\n" +"#endif\n" +" float2 ScreenTexCoord = SafeScreenTexCoord + normalize(tex2D(Texture_Normal, TexCoord).rgb - float3(0.5,0.5,0.5)).xy * distort;\n" " // FIXME temporary hack to detect the case that the reflection\n" " // gets blackened at edges due to leaving the area that contains actual\n" " // content.\n" @@ -432,7 +455,7 @@ " f *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord + float2(-0.01, 0.01)).rgb) / 0.05);\n" " f *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord + float2(-0.01, -0.01)).rgb) / 0.05);\n" " ScreenTexCoord = lerp(SafeScreenTexCoord, ScreenTexCoord, f);\n" -" dp_FragColor = float4(tex2D(Texture_Refraction, ScreenTexCoord).rgb, 1) * RefractColor;\n" +" dp_FragColor = float4(tex2D(Texture_Refraction, ScreenTexCoord).rgb, 1) * refractcolor;\n" "}\n" "#endif\n" "#else // !MODE_REFRACTION\n" @@ -447,18 +470,27 @@ "(\n" "float4 gl_Vertex : POSITION,\n" "uniform float4x4 ModelViewProjectionMatrix : register(c8),\n" +"#ifdef USEALPHAGENVERTEX\n" +"float4 gl_Color : COLOR0,\n" +"#endif\n" "float4 gl_MultiTexCoord0 : TEXCOORD0,\n" "float4 gl_MultiTexCoord1 : TEXCOORD1,\n" "float4 gl_MultiTexCoord2 : TEXCOORD2,\n" "float4 gl_MultiTexCoord3 : TEXCOORD3,\n" "uniform float4x4 TexMatrix : register(c0),\n" "uniform float3 EyePosition : register(c24),\n" +"#ifdef USEALPHAGENVERTEX\n" +"out float4 gl_FrontColor : COLOR,\n" +"#endif\n" "out float4 gl_Position : POSITION,\n" "out float2 TexCoord : TEXCOORD0,\n" "out float3 EyeVector : TEXCOORD1,\n" "out float4 ModelViewProjectionPosition : TEXCOORD2\n" ")\n" "{\n" +"#ifdef USEALPHAGENVERTEX\n" +" gl_FrontColor = gl_Color;\n" +"#endif\n" " TexCoord = mul(TexMatrix, gl_MultiTexCoord0).xy;\n" " float3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n" " EyeVector = float3(dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz), dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz), dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz));\n" @@ -473,6 +505,9 @@ "#ifdef FRAGMENT_SHADER\n" "void main\n" "(\n" +"#ifdef USEALPHAGENVERTEX\n" +"float4 gl_FrontColor : COLOR,\n" +"#endif\n" "float2 TexCoord : TEXCOORD0,\n" "float3 EyeVector : TEXCOORD1,\n" "float4 ModelViewProjectionPosition : TEXCOORD2,\n" @@ -493,7 +528,18 @@ " //float4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(tex2D(Texture_Normal, TexCoord).rgb - float3(0.5,0.5,0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n" " float4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n" " //SafeScreenTexCoord = gl_FragCoord.xyxy * float4(1.0 / 1920.0, 1.0 / 1200.0, 1.0 / 1920.0, 1.0 / 1200.0);\n" -" float4 ScreenTexCoord = SafeScreenTexCoord + float2(normalize(tex2D(Texture_Normal, TexCoord).rgb - float3(0.5,0.5,0.5)).xy).xyxy * DistortScaleRefractReflect;\n" +"#ifdef USEALPHAGENVERTEX\n" +" float4 distort = DistortScaleRefractReflect * gl_FrontColor.a;\n" +" float reflectoffset = ReflectOffset * gl_FrontColor.a;\n" +" float reflectfactor = ReflectFactor * gl_FrontColor.a;\n" +" float4 refractcolor = mix(RefractColor, vec4(1.0, 1.0, 1.0, 1.0), gl_FrontColor.a);\n" +"#else\n" +" float4 distort = DistortScaleRefractReflect;\n" +" float reflectoffset = ReflectOffset;\n" +" float reflectfactor = ReflectFactor;\n" +" float4 refractcolor = RefractColor;\n" +"#endif\n" +" float4 ScreenTexCoord = SafeScreenTexCoord + float2(normalize(tex2D(Texture_Normal, TexCoord).rgb - float3(0.5,0.5,0.5)).xy).xyxy * distort;\n" " // FIXME temporary hack to detect the case that the reflection\n" " // gets blackened at edges due to leaving the area that contains actual\n" " // content.\n" @@ -509,8 +555,8 @@ " f *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord.zw + float2(-0.01, 0.01)).rgb) / 0.05);\n" " f *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord.zw + float2(-0.01, -0.01)).rgb) / 0.05);\n" " ScreenTexCoord.zw = lerp(SafeScreenTexCoord.zw, ScreenTexCoord.zw, f);\n" -" float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * ReflectFactor + ReflectOffset;\n" -" dp_FragColor = lerp(float4(tex2D(Texture_Refraction, ScreenTexCoord.xy).rgb, 1) * RefractColor, float4(tex2D(Texture_Reflection, ScreenTexCoord.zw).rgb, 1) * ReflectColor, Fresnel);\n" +" float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * reflectfactor + reflectoffset;\n" +" dp_FragColor = lerp(float4(tex2D(Texture_Refraction, ScreenTexCoord.xy).rgb, 1) * refractcolor, float4(tex2D(Texture_Reflection, ScreenTexCoord.zw).rgb, 1) * ReflectColor, Fresnel);\n" "}\n" "#endif\n" "#else // !MODE_WATER\n" @@ -552,8 +598,17 @@ " float i;\n" " // distance-based LOD\n" "#ifdef USEOFFSETMAPPING_LOD\n" -" float LODFactor = min(1.0, OffsetMapping_LodDistance / EyeVectorFogDepth.z);\n" -" mediump vec4 ScaleSteps = float4(OffsetMapping_ScaleSteps.x, OffsetMapping_ScaleSteps.y * LODFactor, OffsetMapping_ScaleSteps.z / LODFactor, OffsetMapping_ScaleSteps.w * LODFactor);\n" +" //float LODFactor = min(1.0, OffsetMapping_LodDistance / EyeVectorFogDepth.z);\n" +" //float4 ScaleSteps = float4(OffsetMapping_ScaleSteps.x, OffsetMapping_ScaleSteps.y * LODFactor, OffsetMapping_ScaleSteps.z / LODFactor, OffsetMapping_ScaleSteps.w * LODFactor);\n" +" float GuessLODFactor = min(1.0, OffsetMapping_LodDistance / EyeVectorFogDepth.z);\n" +"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n" +" // stupid workaround because 1-step and 2-step reliefmapping is void\n" +" float LODSteps = max(3.0, ceil(GuessLODFactor * OffsetMapping_ScaleSteps.y));\n" +"#else\n" +" float LODSteps = ceil(GuessLODFactor * OffsetMapping_ScaleSteps.y);\n" +"#endif\n" +" float LODFactor = LODSteps / OffsetMapping_ScaleSteps.y;\n" +" float4 ScaleSteps = float4(OffsetMapping_ScaleSteps.x, LODSteps, 1.0 / LODSteps, OffsetMapping_ScaleSteps.w * LODFactor);\n" "#else\n" " #define ScaleSteps OffsetMapping_ScaleSteps\n" "#endif\n" @@ -1007,7 +1062,7 @@ "#ifdef USESHADOWMAPORTHO\n" "uniform float4x4 ShadowMapMatrix : register(c16),\n" "#endif\n" -"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND)\n" +"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND) || defined(MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR) || defined(USEALPHAGENVERTEX)\n" "out float4 gl_FrontColor : COLOR,\n" "#endif\n" "out float4 TexCoordBoth : TEXCOORD0,\n" @@ -1040,7 +1095,7 @@ "out float4 gl_Position : POSITION\n" ")\n" "{\n" -"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND)\n" +"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND) || defined(MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR) || defined(USEALPHAGENVERTEX)\n" " gl_FrontColor = gl_Color;\n" "#endif\n" " // copy the surface texcoord\n" @@ -1308,6 +1363,9 @@ " //color = half4(lerp(float4(1, 0, 0, 1), color, terrainblend));\n" "#endif\n" "#endif\n" +"#ifdef USEALPHAGENVERTEX\n" +" color.a *= gl_FrontColor.a;\n" +"#endif\n" "\n" " // get the surface normal\n" "#ifdef USEVERTEXTEXTUREBLEND\n" diff --git a/misc/source/darkplaces-src/snd_main.c b/misc/source/darkplaces-src/snd_main.c index 71f8b4d7..1fb7cd54 100644 --- a/misc/source/darkplaces-src/snd_main.c +++ b/misc/source/darkplaces-src/snd_main.c @@ -1262,7 +1262,7 @@ static channel_t *SND_PickChannel(int entnum, int entchannel) } // don't let monster sounds override player sounds - if (ch->entnum == cl.viewentity && entnum != cl.viewentity) + if ((ch->entnum == cl.viewentity || ch->entnum == CL_VM_GetViewEntity()) && !(entnum == cl.viewentity || entnum == CL_VM_GetViewEntity())) continue; // don't override looped sounds @@ -1459,7 +1459,7 @@ static void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx) // anything coming from the view entity will always be full volume // LordHavoc: make sounds with ATTN_NONE have no spatialization - if (ch->entnum == cl.viewentity || ch->distfade == 0) + if (ch->entnum == cl.viewentity || ch->entnum == CL_VM_GetViewEntity() || ch->distfade == 0) { ch->prologic_invert = 1; if (snd_spatialization_prologic.integer != 0) @@ -1765,17 +1765,17 @@ void S_StopChannel (unsigned int channel_ind, qboolean lockmutex, qboolean frees ch = &channels[channel_ind]; sfx = ch->sfx; - if (ch->sfx != NULL) + if (sfx != NULL) { if (sfx->fetcher != NULL && sfx->fetcher->stopchannel != NULL) sfx->fetcher->stopchannel(ch); ch->fetcher_data = NULL; ch->sfx = NULL; + if (freesfx) + S_FreeSfx(sfx, true); } if (lockmutex && !simsound) SndSys_UnlockRenderBuffer(); - if (freesfx) - S_FreeSfx(sfx, true); } diff --git a/misc/source/darkplaces-src/snd_wav.c b/misc/source/darkplaces-src/snd_wav.c index 258b501c..6f861913 100644 --- a/misc/source/darkplaces-src/snd_wav.c +++ b/misc/source/darkplaces-src/snd_wav.c @@ -303,19 +303,6 @@ qboolean S_LoadWavFile (const char *filename, sfx_t *sfx) //if (info.channels == 2) // Log_Printf("stereosounds.log", "%s\n", sfx->name); - // We must convert the WAV data from little endian - // to the machine endianess before resampling it - if (info.width == 2 && mem_bigendian) - { - unsigned int len, i; - short* ptr; - - len = info.samples * info.channels; - ptr = (short*)(data + info.dataofs); - for (i = 0; i < len; i++) - ptr[i] = LittleShort (ptr[i]); - } - sfx->format.speed = info.rate; sfx->format.width = info.width; sfx->format.channels = info.channels; diff --git a/misc/source/darkplaces-src/sv_main.c b/misc/source/darkplaces-src/sv_main.c index 27befbcf..b2e70f3b 100644 --- a/misc/source/darkplaces-src/sv_main.c +++ b/misc/source/darkplaces-src/sv_main.c @@ -1895,8 +1895,17 @@ static void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, size else EntityFrameCSQC_WriteFrame(msg, maxsize, numcsqcsendstates, sv.writeentitiestoclient_csqcsendstates, 0); - if(client->num_skippedentityframes >= 10) - need_empty = true; // force every 10th frame to be not empty (or cl_movement replay takes too long) + // force every 16th frame to be not empty (or cl_movement replay takes + // too long) + // BTW, this should normally not kick in any more due to the check + // below, except if the client stopped sending movement frames + if(client->num_skippedentityframes >= 16) + need_empty = true; + + // help cl_movement a bit more + if(client->movesequence != client->lastmovesequence) + need_empty = true; + client->lastmovesequence = client->movesequence; if (client->entitydatabase5) success = EntityFrame5_WriteFrame(msg, maxsize, client->entitydatabase5, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1, client->movesequence, need_empty); @@ -1999,15 +2008,10 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t host_client->fixangle_angles_set = FALSE; } - // stuff the sigil bits into the high bits of items for sbar, or else - // mix in items2 - // LordHavoc: detecting items2 turned out to be tricky, check if the field - // was forcefully declared, we want to override serverflags if it was - // declared by the qc intentionally, but not if we added it in the engine. - if (prog->fieldoffsets.items2 < (int)(prog->numfielddefs - SV_REQGLOBALS)) - items = (int)PRVM_serveredictfloat(ent, items) | ((int)PRVM_serveredictfloat(ent, items2) << 23); - else - items = (int)PRVM_serveredictfloat(ent, items) | ((int)PRVM_serverglobalfloat(serverflags) << 28); + // the runes are in serverflags, pack them into the items value, also pack + // in the items2 value for mission pack huds + // (used only in the mission packs, which do not use serverflags) + items = (int)PRVM_serveredictfloat(ent, items) | ((int)PRVM_serveredictfloat(ent, items2) << 23) | ((int)PRVM_serverglobalfloat(serverflags) << 28); VectorCopy(PRVM_serveredictvector(ent, punchvector), punchvector); @@ -3237,7 +3241,7 @@ void SV_SpawnServer (const char *server) if (cls.state != ca_dedicated) { - SCR_BeginLoadingPlaque(); + SCR_BeginLoadingPlaque(false); S_StopAllSounds(); } @@ -3895,10 +3899,10 @@ static int SV_ThreadFunc(void *voiddata) if(host_client->spawned) if(host_client->netconnection) playing = true; - if(!playing) + if(sv.time < 10) { - // Nobody is looking? Then we won't do timing... - // Instead, reset it to zero + // don't accumulate time for the first 10 seconds of a match + // so things can settle svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0; } else if(svs.perf_acc_realtime > 5) @@ -3912,7 +3916,8 @@ static int SV_ThreadFunc(void *voiddata) svs.perf_offset_sdev = sqrt(svs.perf_acc_offset_squared / svs.perf_acc_offset_samples - svs.perf_offset_avg * svs.perf_offset_avg); } if(svs.perf_lost > 0 && developer_extra.integer) - Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf))); + if(playing) + Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf))); svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0; } diff --git a/misc/source/darkplaces-src/sv_phys.c b/misc/source/darkplaces-src/sv_phys.c index c88ff4c4..e063526f 100644 --- a/misc/source/darkplaces-src/sv_phys.c +++ b/misc/source/darkplaces-src/sv_phys.c @@ -1235,23 +1235,19 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo return 0; gravity = 0; - if(sv_gameplayfix_nogravityonground.integer) - if((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND) - applygravity = false; - - if (applygravity) + if(applygravity) { - if (sv_gameplayfix_gravityunaffectedbyticrate.integer) - { - gravity = SV_Gravity(ent) * 0.5f; - PRVM_serveredictvector(ent, velocity)[2] -= gravity; - } - else + gravity = SV_Gravity(ent); + + if(!sv_gameplayfix_nogravityonground.integer || !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)) { - applygravity = false; - PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent); + if (sv_gameplayfix_gravityunaffectedbyticrate.integer) + PRVM_serveredictvector(ent, velocity)[2] -= gravity * 0.5f; + else + PRVM_serveredictvector(ent, velocity)[2] -= gravity; } } + blocked = 0; VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity); VectorCopy(PRVM_serveredictvector(ent, velocity), primal_velocity); @@ -1437,8 +1433,16 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo // LordHavoc: this came from QW and allows you to get out of water more easily if (sv_gameplayfix_easierwaterjump.integer && ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP) && !(blocked & 8)) VectorCopy(primal_velocity, PRVM_serveredictvector(ent, velocity)); - if (applygravity && !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)) - PRVM_serveredictvector(ent, velocity)[2] -= gravity; + + if(applygravity) + { + if(!sv_gameplayfix_nogravityonground.integer || !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)) + { + if (sv_gameplayfix_gravityunaffectedbyticrate.integer) + PRVM_serveredictvector(ent, velocity)[2] -= gravity * 0.5f; + } + } + return blocked; } diff --git a/misc/source/darkplaces-src/svn-eol-style-from-gitattributes.sh b/misc/source/darkplaces-src/svn-eol-style-from-gitattributes.sh new file mode 100644 index 00000000..7c1085cd --- /dev/null +++ b/misc/source/darkplaces-src/svn-eol-style-from-gitattributes.sh @@ -0,0 +1,22 @@ +for F in *; do + exec 3<.gitattributes + while read <&3 -r L S; do + if [ -z "${F##$L}" ]; then + s=$S + fi + done + case "$s" in + '-diff -crlf') + svn propdel svn:eol-style "$F" + ;; + '-crlf') + svn propdel svn:eol-style "$F" + ;; + 'crlf=input') + svn propset svn:eol-style native "$F" + ;; + *) + echo "UNKNOWN: $s" + ;; + esac +done diff --git a/misc/source/darkplaces-src/svvm_cmds.c b/misc/source/darkplaces-src/svvm_cmds.c index 3bb77ef6..a850abe3 100644 --- a/misc/source/darkplaces-src/svvm_cmds.c +++ b/misc/source/darkplaces-src/svvm_cmds.c @@ -25,15 +25,19 @@ const char *vm_sv_extensions = "DP_CSQC_ENTITYMODELLIGHT " "DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET " "DP_CSQC_MAINVIEW " +"DP_CSQC_MINFPS_QUALITY " "DP_CSQC_MULTIFRAME_INTERPOLATION " "DP_CSQC_BOXPARTICLES " "DP_CSQC_SPAWNPARTICLE " "DP_CSQC_QUERYRENDERENTITY " "DP_CSQC_ROTATEMOVES " "DP_CSQC_SETPAUSE " +"DP_CSQC_V_CALCREFDEF_WIP1 " +"DP_CSQC_V_CALCREFDEF_WIP2 " "DP_EF_ADDITIVE " "DP_EF_BLUE " "DP_EF_DOUBLESIDED " +"DP_EF_DYNAMICMODELLIGHT " "DP_EF_FLAME " "DP_EF_FULLBRIGHT " "DP_EF_NODEPTHTEST " @@ -2863,7 +2867,7 @@ static void VM_SV_skel_create(prvm_prog_t *prog) break; if (i == MAX_EDICTS) return; - prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(cls.levelmempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t)); + prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(prog->progs_mempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t)); PRVM_G_FLOAT(OFS_RETURN) = i + 1; skeleton->model = model; skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1); @@ -2908,7 +2912,7 @@ static void VM_SV_skel_build(prvm_prog_t *prog) Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac); for (blendindex = 0;blendindex < numblends;blendindex++) { - Matrix4x4_FromBonePose6s(&matrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + bonenum)); + Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum)); Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp); } skeleton->relativetransforms[bonenum] = blendedmatrix; diff --git a/misc/source/darkplaces-src/sys_shared.c b/misc/source/darkplaces-src/sys_shared.c index d033323a..10f5a60e 100644 --- a/misc/source/darkplaces-src/sys_shared.c +++ b/misc/source/darkplaces-src/sys_shared.c @@ -536,18 +536,24 @@ static int CPUID_Features(void) # endif return features; } +#endif +#ifdef SSE_POSSIBLE qboolean Sys_HaveSSE(void) { // COMMANDLINEOPTION: SSE: -nosse disables SSE support and detection if(COM_CheckParm("-nosse")) return false; +#ifdef SSE_PRESENT + return true; +#else // COMMANDLINEOPTION: SSE: -forcesse enables SSE support and disables detection if(COM_CheckParm("-forcesse") || COM_CheckParm("-forcesse2")) return true; if(CPUID_Features() & (1 << 25)) return true; return false; +#endif } qboolean Sys_HaveSSE2(void) @@ -555,12 +561,16 @@ qboolean Sys_HaveSSE2(void) // COMMANDLINEOPTION: SSE2: -nosse2 disables SSE2 support and detection if(COM_CheckParm("-nosse") || COM_CheckParm("-nosse2")) return false; +#ifdef SSE2_PRESENT + return true; +#else // COMMANDLINEOPTION: SSE2: -forcesse2 enables SSE2 support and disables detection if(COM_CheckParm("-forcesse2")) return true; if((CPUID_Features() & (3 << 25)) == (3 << 25)) // SSE is 1<<25, SSE2 is 1<<26 return true; return false; +#endif } #endif diff --git a/misc/source/darkplaces-src/thread.h b/misc/source/darkplaces-src/thread.h index 5ba9be8f..7f590a47 100644 --- a/misc/source/darkplaces-src/thread.h +++ b/misc/source/darkplaces-src/thread.h @@ -2,6 +2,7 @@ // enable Sys_PrintfToTerminal calls on nearly every threading call //#define THREADDEBUG +//#define THREADDISABLE // use recursive mutex (non-posix) extensions in thread_pthread #define THREADRECURSIVE @@ -16,6 +17,9 @@ #define Thread_CondWait(cond, mutex) (_Thread_CondWait(cond, mutex, __FILE__, __LINE__)) #define Thread_CreateThread(fn, data) (_Thread_CreateThread(fn, data, __FILE__, __LINE__)) #define Thread_WaitThread(thread, retval) (_Thread_WaitThread(thread, retval, __FILE__, __LINE__)) +#define Thread_CreateBarrier(count) (_Thread_CreateBarrier(count, __FILE__, __LINE__)) +#define Thread_DestroyBarrier(barrier) (_Thread_DestroyBarrier(barrier, __FILE__, __LINE__)) +#define Thread_WaitBarrier(barrier) (_Thread_WaitBarrier(barrier, __FILE__, __LINE__)) int Thread_Init(void); void Thread_Shutdown(void); @@ -31,6 +35,8 @@ int _Thread_CondBroadcast(void *cond, const char *filename, int fileline); int _Thread_CondWait(void *cond, void *mutex, const char *filename, int fileline); void *_Thread_CreateThread(int (*fn)(void *), void *data, const char *filename, int fileline); int _Thread_WaitThread(void *thread, int retval, const char *filename, int fileline); +void *_Thread_CreateBarrier(unsigned int count, const char *filename, int fileline); +void _Thread_DestroyBarrier(void *barrier, const char *filename, int fileline); +void _Thread_WaitBarrier(void *barrier, const char *filename, int fileline); #endif - diff --git a/misc/source/darkplaces-src/thread_null.c b/misc/source/darkplaces-src/thread_null.c index c7d439c9..35c4e4b5 100644 --- a/misc/source/darkplaces-src/thread_null.c +++ b/misc/source/darkplaces-src/thread_null.c @@ -67,3 +67,16 @@ int _Thread_WaitThread(void *thread, int retval, const char *filename, int filel { return retval; } + +void *_Thread_CreateBarrier(unsigned int count, const char *filename, int fileline) +{ + return NULL; +} + +void _Thread_DestroyBarrier(void *barrier, const char *filename, int fileline) +{ +} + +void _Thread_WaitBarrier(void *barrier, const char *filename, int fileline) +{ +} diff --git a/misc/source/darkplaces-src/thread_pthread.c b/misc/source/darkplaces-src/thread_pthread.c index 9340403e..e86b2c38 100644 --- a/misc/source/darkplaces-src/thread_pthread.c +++ b/misc/source/darkplaces-src/thread_pthread.c @@ -142,4 +142,83 @@ int _Thread_WaitThread(void *thread, int retval, const char *filename, int filel return (int) (intptr_t) status; } +#ifdef PTHREAD_BARRIER_SERIAL_THREAD +void *_Thread_CreateBarrier(unsigned int count, const char *filename, int fileline) +{ + pthread_barrier_t *b = (pthread_barrier_t *) Z_Malloc(sizeof(pthread_barrier_t)); +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier create(%d) %s:%i\n", b, count, filename, fileline); +#endif + pthread_barrier_init(b, NULL, count); + return (void *) b; +} + +void _Thread_DestroyBarrier(void *barrier, const char *filename, int fileline) +{ + pthread_barrier_t *b = (pthread_barrier_t *) barrier; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier destroy %s:%i\n", b, filename, fileline); +#endif + pthread_barrier_destroy(b); +} + +void _Thread_WaitBarrier(void *barrier, const char *filename, int fileline) +{ + pthread_barrier_t *b = (pthread_barrier_t *) barrier; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier wait %s:%i\n", b, filename, fileline); +#endif + pthread_barrier_wait(b); +} +#else +// standard barrier implementation using conds and mutexes +// see: http://www.howforge.com/implementing-barrier-in-pthreads +typedef struct { + unsigned int needed; + unsigned int called; + void *mutex; + void *cond; +} barrier_t; + +void *_Thread_CreateBarrier(unsigned int count, const char *filename, int fileline) +{ + volatile barrier_t *b = (volatile barrier_t *) Z_Malloc(sizeof(barrier_t)); +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier create(%d) %s:%i\n", b, count, filename, fileline); +#endif + b->needed = count; + b->called = 0; + b->mutex = Thread_CreateMutex(); + b->cond = Thread_CreateCond(); + return (void *) b; +} +void _Thread_DestroyBarrier(void *barrier, const char *filename, int fileline) +{ + volatile barrier_t *b = (volatile barrier_t *) barrier; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier destroy %s:%i\n", b, filename, fileline); +#endif + Thread_DestroyMutex(b->mutex); + Thread_DestroyCond(b->cond); +} + +void _Thread_WaitBarrier(void *barrier, const char *filename, int fileline) +{ + volatile barrier_t *b = (volatile barrier_t *) barrier; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier wait %s:%i\n", b, filename, fileline); +#endif + Thread_LockMutex(b->mutex); + b->called++; + if (b->called == b->needed) { + b->called = 0; + Thread_CondBroadcast(b->cond); + } else { + do { + Thread_CondWait(b->cond, b->mutex); + } while(b->called); + } + Thread_UnlockMutex(b->mutex); +} +#endif diff --git a/misc/source/darkplaces-src/thread_sdl.c b/misc/source/darkplaces-src/thread_sdl.c index 64006dbf..d7fd1737 100644 --- a/misc/source/darkplaces-src/thread_sdl.c +++ b/misc/source/darkplaces-src/thread_sdl.c @@ -5,6 +5,9 @@ int Thread_Init(void) { +#ifdef THREADDISABLE + Con_Printf("Threading disabled in this build\n"); +#endif return 0; } @@ -14,7 +17,11 @@ void Thread_Shutdown(void) qboolean Thread_HasThreads(void) { +#ifdef THREADDISABLE + return false; +#else return true; +#endif } void *_Thread_CreateMutex(const char *filename, int fileline) @@ -93,7 +100,11 @@ int _Thread_CondWait(void *cond, void *mutex, const char *filename, int fileline void *_Thread_CreateThread(int (*fn)(void *), void *data, const char *filename, int fileline) { +#if SDL_MAJOR_VERSION == 1 void *thread = (void *)SDL_CreateThread(fn, data); +#else + void *thread = (void *)SDL_CreateThread(fn, filename, data); +#endif #ifdef THREADDEBUG Sys_PrintfToTerminal("%p thread create %s:%i\n" , thread, filename, fileline); #endif @@ -110,4 +121,53 @@ int _Thread_WaitThread(void *thread, int retval, const char *filename, int filel return status; } - +// standard barrier implementation using conds and mutexes +// see: http://www.howforge.com/implementing-barrier-in-pthreads +typedef struct { + unsigned int needed; + unsigned int called; + void *mutex; + void *cond; +} barrier_t; + +void *_Thread_CreateBarrier(unsigned int count, const char *filename, int fileline) +{ + volatile barrier_t *b = (volatile barrier_t *) Z_Malloc(sizeof(barrier_t)); +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier create(%d) %s:%i\n", b, count, filename, fileline); +#endif + b->needed = count; + b->called = 0; + b->mutex = Thread_CreateMutex(); + b->cond = Thread_CreateCond(); + return (void *) b; +} + +void _Thread_DestroyBarrier(void *barrier, const char *filename, int fileline) +{ + volatile barrier_t *b = (volatile barrier_t *) barrier; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier destroy %s:%i\n", b, filename, fileline); +#endif + Thread_DestroyMutex(b->mutex); + Thread_DestroyCond(b->cond); +} + +void _Thread_WaitBarrier(void *barrier, const char *filename, int fileline) +{ + volatile barrier_t *b = (volatile barrier_t *) barrier; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier wait %s:%i\n", b, filename, fileline); +#endif + Thread_LockMutex(b->mutex); + b->called++; + if (b->called == b->needed) { + b->called = 0; + Thread_CondBroadcast(b->cond); + } else { + do { + Thread_CondWait(b->cond, b->mutex); + } while(b->called); + } + Thread_UnlockMutex(b->mutex); +} diff --git a/misc/source/darkplaces-src/thread_win.c b/misc/source/darkplaces-src/thread_win.c index 893e8306..8564ca19 100644 --- a/misc/source/darkplaces-src/thread_win.c +++ b/misc/source/darkplaces-src/thread_win.c @@ -4,6 +4,9 @@ int Thread_Init(void) { +#ifdef THREADDISABLE + Con_Printf("Threading disabled in this build\n"); +#endif return 0; } @@ -13,7 +16,11 @@ void Thread_Shutdown(void) qboolean Thread_HasThreads(void) { +#ifdef THREADDISABLE + return false; +#else return true; +#endif } void *_Thread_CreateMutex(const char *filename, int fileline) @@ -243,3 +250,54 @@ int _Thread_WaitThread(void *d, int retval, const char *filename, int fileline) free(w); return retval; } + +// standard barrier implementation using conds and mutexes +// see: http://www.howforge.com/implementing-barrier-in-pthreads +typedef struct { + unsigned int needed; + unsigned int called; + void *mutex; + void *cond; +} barrier_t; + +void *_Thread_CreateBarrier(unsigned int count, const char *filename, int fileline) +{ + volatile barrier_t *b = (volatile barrier_t *) Z_Malloc(sizeof(barrier_t)); +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier create(%d) %s:%i\n", b, count, filename, fileline); +#endif + b->needed = count; + b->called = 0; + b->mutex = Thread_CreateMutex(); + b->cond = Thread_CreateCond(); + return (void *) b; +} + +void _Thread_DestroyBarrier(void *barrier, const char *filename, int fileline) +{ + volatile barrier_t *b = (volatile barrier_t *) barrier; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier destroy %s:%i\n", b, filename, fileline); +#endif + Thread_DestroyMutex(b->mutex); + Thread_DestroyCond(b->cond); +} + +void _Thread_WaitBarrier(void *barrier, const char *filename, int fileline) +{ + volatile barrier_t *b = (volatile barrier_t *) barrier; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier wait %s:%i\n", b, filename, fileline); +#endif + Thread_LockMutex(b->mutex); + b->called++; + if (b->called == b->needed) { + b->called = 0; + Thread_CondBroadcast(b->cond); + } else { + do { + Thread_CondWait(b->cond, b->mutex); + } while(b->called); + } + Thread_UnlockMutex(b->mutex); +} diff --git a/misc/source/darkplaces-src/utf8lib.c b/misc/source/darkplaces-src/utf8lib.c index 8994bd7a..76cc8137 100644 --- a/misc/source/darkplaces-src/utf8lib.c +++ b/misc/source/darkplaces-src/utf8lib.c @@ -226,6 +226,29 @@ size_t u8_strlen(const char *_s) return len; } +static int colorcode_skipwidth(const unsigned char *s) +{ + if(*s == STRING_COLOR_TAG) + { + if(s[1] <= '9' && s[1] >= '0') // ^[0-9] found + { + return 2; + } + else if(s[1] == STRING_COLOR_RGB_TAG_CHAR && + ((s[2] >= '0' && s[2] <= '9') || (s[2] >= 'a' && s[2] <= 'f') || (s[2] >= 'A' && s[2] <= 'F')) && + ((s[3] >= '0' && s[3] <= '9') || (s[3] >= 'a' && s[3] <= 'f') || (s[3] >= 'A' && s[3] <= 'F')) && + ((s[4] >= '0' && s[4] <= '9') || (s[4] >= 'a' && s[4] <= 'f') || (s[4] >= 'A' && s[4] <= 'F'))) + { + return 5; + } + else if(s[1] == STRING_COLOR_TAG) + { + return 1; // special case, do NOT call colorcode_skipwidth for next char + } + } + return 0; +} + /** Get the number of characters in a part of an UTF-8 string. * @param _s An utf-8 encoded null-terminated string. * @param n The maximum number of bytes. @@ -274,6 +297,49 @@ size_t u8_strnlen(const char *_s, size_t n) return len; } +static size_t u8_strnlen_colorcodes(const char *_s, size_t n) +{ + size_t st, ln; + size_t len = 0; + const unsigned char *s = (const unsigned char*)_s; + + while (*s && n) + { + int w = colorcode_skipwidth(s); + n -= w; + s += w; + if(w > 1) // == 1 means single caret + continue; + + // ascii char, skip u8_analyze + if (*s < 0x80 || !utf8_enable.integer) + { + ++len; + ++s; + --n; + continue; + } + + // invalid, skip u8_analyze + if (*s < 0xC2) + { + ++s; + --n; + continue; + } + + if (!u8_analyze((const char*)s, &st, &ln, NULL, n)) + break; + // valid character, see if it's still inside the range specified by n: + if (n < st + ln) + return len; + ++len; + n -= st + ln; + s += st + ln; + } + return len; +} + /** Get the number of bytes used in a string to represent an amount of characters. * @param _s An utf-8 encoded null-terminated string. * @param n The number of characters we want to know the byte-size for. @@ -318,6 +384,46 @@ size_t u8_bytelen(const char *_s, size_t n) return len; } +static size_t u8_bytelen_colorcodes(const char *_s, size_t n) +{ + size_t st, ln; + size_t len = 0; + const unsigned char *s = (const unsigned char*)_s; + + while (*s && n) + { + int w = colorcode_skipwidth(s); + len += w; + s += w; + if(w > 1) // == 1 means single caret + continue; + + // ascii char, skip u8_analyze + if (*s < 0x80 || !utf8_enable.integer) + { + ++len; + ++s; + --n; + continue; + } + + // invalid, skip u8_analyze + if (*s < 0xC2) + { + ++s; + ++len; + continue; + } + + if (!u8_analyze((const char*)s, &st, &ln, NULL, U8_ANALYZE_INFINITY)) + break; + --n; + s += st + ln; + len += st + ln; + } + return len; +} + /** Get the byte-index for a character-index. * @param _s An utf-8 encoded string. * @param i The character-index for which you want the byte offset. @@ -798,6 +904,17 @@ size_t u8_strpad(char *out, size_t outsize, const char *in, qboolean leftalign, } } +size_t u8_strpad_colorcodes(char *out, size_t outsize, const char *in, qboolean leftalign, size_t minwidth, size_t maxwidth) +{ + size_t l = u8_bytelen_colorcodes(in, maxwidth); + size_t actual_width = u8_strnlen_colorcodes(in, l); + int pad = (actual_width >= minwidth) ? 0 : (minwidth - actual_width); + int prec = l; + int lpad = leftalign ? 0 : pad; + int rpad = leftalign ? pad : 0; + return dpsnprintf(out, outsize, "%*s%.*s%*s", lpad, "", prec, in, rpad, ""); +} + /* The two following functions (u8_toupper, u8_tolower) are derived from diff --git a/misc/source/darkplaces-src/utf8lib.h b/misc/source/darkplaces-src/utf8lib.h index 36c16fe1..543fbfc0 100644 --- a/misc/source/darkplaces-src/utf8lib.h +++ b/misc/source/darkplaces-src/utf8lib.h @@ -46,6 +46,7 @@ size_t u8_COM_StringLengthNoColors(const char *s, size_t size_s, qboolean *valid char *u8_encodech(Uchar ch, size_t*, char*buf16); size_t u8_strpad(char *out, size_t outsize, const char *in, qboolean leftalign, size_t minwidth, size_t maxwidth); +size_t u8_strpad_colorcodes(char *out, size_t outsize, const char *in, qboolean leftalign, size_t minwidth, size_t maxwidth); /* Careful: if we disable utf8 but not freetype, we wish to see freetype chars * for normal letters. So use E000+x for special chars, but leave the freetype stuff for the diff --git a/misc/source/darkplaces-src/vid_sdl.c b/misc/source/darkplaces-src/vid_sdl.c index 97433653..88c8e605 100644 --- a/misc/source/darkplaces-src/vid_sdl.c +++ b/misc/source/darkplaces-src/vid_sdl.c @@ -66,25 +66,12 @@ int cl_available = true; qboolean vid_supportrefreshrate = false; -#if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION == 2 -# define SETVIDEOMODE 1 -#else -# ifdef USE_GLES2 -# define SETVIDEOMODE 0 -# else -// LordHavoc: SDL 1.3's SDL_CreateWindow API is not finished enough to use yet, but you can set this to 0 if you want to try it... -# ifndef SETVIDEOMODE -# define SETVIDEOMODE 1 -# endif -# endif -# endif - static qboolean vid_usingmouse = false; +static qboolean vid_usingmouse_relativeworks = false; // SDL2 workaround for unimplemented RelativeMouse mode static qboolean vid_usinghidecursor = false; static qboolean vid_hasfocus = false; static qboolean vid_isfullscreen; -#if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION == 2 -#else +#if SDL_MAJOR_VERSION != 1 static qboolean vid_usingvsync = false; #endif static SDL_Joystick *vid_sdljoystick = NULL; @@ -93,7 +80,7 @@ static int win_half_width = 50; static int win_half_height = 50; static int video_bpp; -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 static SDL_Surface *screen; static int video_flags; #else @@ -213,8 +200,10 @@ static int MapKey( unsigned int sdlkey ) case SDLK_F10: return K_F10; case SDLK_F11: return K_F11; case SDLK_F12: return K_F12; +#if SDL_MAJOR_VERSION == 1 case SDLK_PRINTSCREEN: return K_PRINTSCREEN; case SDLK_SCROLLLOCK: return K_SCROLLOCK; +#endif case SDLK_PAUSE: return K_PAUSE; case SDLK_INSERT: return K_INS; case SDLK_HOME: return K_HOME; @@ -230,12 +219,15 @@ static int MapKey( unsigned int sdlkey ) case SDLK_LEFT: return K_LEFTARROW; case SDLK_DOWN: return K_DOWNARROW; case SDLK_UP: return K_UPARROW; +#if SDL_MAJOR_VERSION == 1 case SDLK_NUMLOCKCLEAR: return K_NUMLOCK; +#endif case SDLK_KP_DIVIDE: return K_KP_DIVIDE; case SDLK_KP_MULTIPLY: return K_KP_MULTIPLY; case SDLK_KP_MINUS: return K_KP_MINUS; case SDLK_KP_PLUS: return K_KP_PLUS; case SDLK_KP_ENTER: return K_KP_ENTER; +#if SDL_MAJOR_VERSION == 1 case SDLK_KP_1: return K_KP_1; case SDLK_KP_2: return K_KP_2; case SDLK_KP_3: return K_KP_3; @@ -246,6 +238,7 @@ static int MapKey( unsigned int sdlkey ) case SDLK_KP_8: return K_KP_8; case SDLK_KP_9: return K_KP_9; case SDLK_KP_0: return K_KP_0; +#endif case SDLK_KP_PERIOD: return K_KP_PERIOD; // case SDLK_APPLICATION: return K_APPLICATION; // case SDLK_POWER: return K_POWER; @@ -415,10 +408,11 @@ void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecurso { vid_usingmouse = relative; cl_ignoremousemoves = 2; -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 SDL_WM_GrabInput( relative ? SDL_GRAB_ON : SDL_GRAB_OFF ); #else - SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE); + vid_usingmouse_relativeworks = SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE) == 0; +// Con_Printf("VID_SetMouse(%i, %i, %i) relativeworks = %i\n", (int)fullscreengrab, (int)relative, (int)hidecursor, (int)vid_usingmouse_relativeworks); #endif #ifdef MACOSX if(relative) @@ -667,7 +661,7 @@ void IN_Move( void ) { if (vid_usingmouse) { - if (vid_stick_mouse.integer) + if (vid_stick_mouse.integer || !vid_usingmouse_relativeworks) { // have the mouse stuck in the middle, example use: prevent expose effect of beryl during the game when not using // window grabbing. --blub @@ -675,7 +669,7 @@ void IN_Move( void ) // we need 2 frames to initialize the center position if(!stuck) { -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 SDL_WarpMouse(win_half_width, win_half_height); #else SDL_WarpMouseInWindow(window, win_half_width, win_half_height); @@ -690,7 +684,7 @@ void IN_Move( void ) SDL_GetMouseState(&x, &y); old_x = x - win_half_width; old_y = y - win_half_height; -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 SDL_WarpMouse(win_half_width, win_half_height); #else SDL_WarpMouseInWindow(window, win_half_width, win_half_height); @@ -754,8 +748,8 @@ static keynum_t buttonremap[18] = }; #endif -#if SETVIDEOMODE -// SDL 1.2 +#if SDL_MAJOR_VERSION == 1 +// SDL void Sys_SendKeyEvents( void ) { static qboolean sound_active = true; @@ -825,13 +819,10 @@ void Sys_SendKeyEvents( void ) #endif } break; -#if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION == 2 -#else +#if SDL_MAJOR_VERSION != 1 case SDL_TEXTEDITING: - // unused when SETVIDEOMODE API is used break; case SDL_TEXTINPUT: - // this occurs with SETVIDEOMODE but we are not using it break; #endif case SDL_MOUSEMOTION: @@ -862,11 +853,10 @@ void Sys_SendKeyEvents( void ) #else -// SDL 1.3 +// SDL2 void Sys_SendKeyEvents( void ) { static qboolean sound_active = true; - static qboolean missingunicodehack = true; int keycode; int i; int j; @@ -898,8 +888,6 @@ void Sys_SendKeyEvents( void ) case SDL_JOYBALLMOTION: case SDL_JOYHATMOTION: break; - case SDL_VIDEOEXPOSE: - break; case SDL_WINDOWEVENT: //if (event.window.windowID == window) // how to compare? { @@ -925,7 +913,6 @@ void Sys_SendKeyEvents( void ) SDL_FreeSurface(vid_softsurface); vid_softsurface = SDL_CreateRGBSurface(SDL_SWSURFACE, vid.width, vid.height, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); vid.softpixels = (unsigned int *)vid_softsurface->pixels; - SDL_SetAlpha(vid_softsurface, 0, 255); if (vid.softdepthpixels) free(vid.softdepthpixels); vid.softdepthpixels = (unsigned int*)calloc(1, vid.width * vid.height * 4); @@ -968,7 +955,6 @@ void Sys_SendKeyEvents( void ) break; case SDL_TEXTINPUT: // we have some characters to parse - missingunicodehack = false; { unicode = 0; for (i = 0;event.text.text[i];) @@ -1305,7 +1291,7 @@ void wrapglGetVertexAttribiv(GLuint index, GLenum pname, GLint *params) {PRECALL void wrapglGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid **pointer) {PRECALL;glGetVertexAttribPointerv(index, pname, pointer);POSTCALL;} #endif -#if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION == 2 +#if SDL_MAJOR_VERSION == 1 #define SDL_GL_ExtensionSupported(x) (strstr(gl_extensions, x) || strstr(gl_platformextensions, x)) #endif @@ -1572,6 +1558,14 @@ void GLES_Init(void) vid.support.ext_blend_subtract = true; vid.support.ext_draw_range_elements = true; vid.support.ext_framebuffer_object = false;//true; + + // FIXME remove this workaround once FBO + npot texture mapping is fixed + if(!vid.support.arb_texture_non_power_of_two) + { + vid.support.arb_framebuffer_object = false; + vid.support.ext_framebuffer_object = false; + } + vid.support.ext_packed_depth_stencil = false; vid.support.ext_stencil_two_side = false; vid.support.ext_texture_3d = SDL_GL_ExtensionSupported("GL_OES_texture_3D"); @@ -1725,7 +1719,7 @@ void VID_EnableJoystick(qboolean enable) Cvar_SetValueQuick(&joy_active, success ? 1 : 0); } -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 // set the icon (we dont use SDL here since it would be too much a PITA) #ifdef WIN32 #include "resource.h" @@ -1943,7 +1937,7 @@ static SDL_Surface *VID_WrapSDL_SetVideoMode(int screenwidth, int screenheight, SDL_WM_SetCaption( gamename, NULL ); screen = SDL_SetVideoMode(screenwidth, screenheight, screenbpp, screenflags); -#if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION == 2 +#if SDL_MAJOR_VERSION == 1 // LordHavoc: info.info.x11.lock_func and accompanying code do not seem to compile with SDL 1.3 #if SDL_VIDEO_DRIVER_X11 && !SDL_VIDEO_DRIVER_QUARTZ @@ -2005,18 +1999,22 @@ static SDL_Surface *VID_WrapSDL_SetVideoMode(int screenwidth, int screenheight, static void VID_OutputVersion(void) { - const SDL_version *version; - version = SDL_Linked_Version(); + SDL_version version; +#if SDL_MAJOR_VERSION == 1 + version = *SDL_Linked_Version(); +#else + SDL_GetVersion(&version); +#endif Con_Printf( "Linked against SDL version %d.%d.%d\n" "Using SDL library version %d.%d.%d\n", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL, - version->major, version->minor, version->patch ); + version.major, version.minor, version.patch ); } static qboolean VID_InitModeGL(viddef_mode_t *mode) { int i; -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 static int notfirstvideomode = false; int flags = SDL_OPENGL; #else @@ -2028,7 +2026,7 @@ static qboolean VID_InitModeGL(viddef_mode_t *mode) win_half_height = mode->height>>1; if(vid_resizable.integer) -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 flags |= SDL_RESIZABLE; #else windowflags |= SDL_WINDOW_RESIZABLE; @@ -2036,7 +2034,7 @@ static qboolean VID_InitModeGL(viddef_mode_t *mode) VID_OutputVersion(); -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 /* SDL 1.2 Hack We cant switch from one OpenGL video mode to another. @@ -2081,7 +2079,7 @@ static qboolean VID_InitModeGL(viddef_mode_t *mode) vid_isfullscreen = false; if (mode->fullscreen) { -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 flags |= SDL_FULLSCREEN; #else windowflags |= SDL_WINDOW_FULLSCREEN; @@ -2115,7 +2113,7 @@ static qboolean VID_InitModeGL(viddef_mode_t *mode) SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, mode->samples); } -#if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION == 2 +#if SDL_MAJOR_VERSION == 1 if (vid_vsync.integer) SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 1); else @@ -2129,7 +2127,7 @@ static qboolean VID_InitModeGL(viddef_mode_t *mode) #endif video_bpp = mode->bitsperpixel; -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 video_flags = flags; screen = VID_WrapSDL_SetVideoMode(mode->width, mode->height, mode->bitsperpixel, flags); if (screen == NULL) @@ -2162,12 +2160,14 @@ static qboolean VID_InitModeGL(viddef_mode_t *mode) vid_softsurface = NULL; vid.softpixels = NULL; +#if SDL_MAJOR_VERSION == 1 // init keyboard SDL_EnableUNICODE( SDL_ENABLE ); // enable key repeat since everyone expects it SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); +#endif -#if !(SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION == 2) +#if SDL_MAJOR_VERSION != 1 SDL_GL_SetSwapInterval(vid_vsync.integer != 0); vid_usingvsync = (vid_vsync.integer != 0); #endif @@ -2187,7 +2187,7 @@ static qboolean VID_InitModeGL(viddef_mode_t *mode) vid_usingmouse = false; vid_usinghidecursor = false; -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 SDL_WM_GrabInput(SDL_GRAB_OFF); #endif return true; @@ -2202,7 +2202,7 @@ extern cvar_t gl_info_driver; static qboolean VID_InitModeSoft(viddef_mode_t *mode) { -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 int flags = SDL_HWSURFACE; if(!COM_CheckParm("-noasyncblit")) flags |= SDL_ASYNCBLIT; #else @@ -2213,7 +2213,7 @@ static qboolean VID_InitModeSoft(viddef_mode_t *mode) win_half_height = mode->height>>1; if(vid_resizable.integer) -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 flags |= SDL_RESIZABLE; #else windowflags |= SDL_WINDOW_RESIZABLE; @@ -2223,7 +2223,7 @@ static qboolean VID_InitModeSoft(viddef_mode_t *mode) vid_isfullscreen = false; if (mode->fullscreen) { -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 flags |= SDL_FULLSCREEN; #else windowflags |= SDL_WINDOW_FULLSCREEN; @@ -2232,7 +2232,7 @@ static qboolean VID_InitModeSoft(viddef_mode_t *mode) } video_bpp = mode->bitsperpixel; -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 video_flags = flags; screen = VID_WrapSDL_SetVideoMode(mode->width, mode->height, mode->bitsperpixel, flags); if (screen == NULL) @@ -2263,7 +2263,9 @@ static qboolean VID_InitModeSoft(viddef_mode_t *mode) VID_Shutdown(); return false; } +#if SDL_MAJOR_VERSION == 1 SDL_SetAlpha(vid_softsurface, 0, 255); +#endif vid.softpixels = (unsigned int *)vid_softsurface->pixels; vid.softdepthpixels = (unsigned int *)calloc(1, mode->width * mode->height * 4); @@ -2274,10 +2276,12 @@ static qboolean VID_InitModeSoft(viddef_mode_t *mode) return false; } +#if SDL_MAJOR_VERSION == 1 // init keyboard SDL_EnableUNICODE( SDL_ENABLE ); // enable key repeat since everyone expects it SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); +#endif VID_Soft_SharedSetup(); @@ -2287,7 +2291,7 @@ static qboolean VID_InitModeSoft(viddef_mode_t *mode) vid_usingmouse = false; vid_usinghidecursor = false; -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 SDL_WM_GrabInput(SDL_GRAB_OFF); #endif return true; @@ -2311,7 +2315,7 @@ void VID_Shutdown (void) VID_SetMouse(false, false, false); VID_RestoreSystemGamma(); -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 #ifndef WIN32 #ifndef MACOSX if (icon) @@ -2329,8 +2333,7 @@ void VID_Shutdown (void) free(vid.softdepthpixels); vid.softdepthpixels = NULL; -#if SETVIDEOMODE -#else +#if SDL_MAJOR_VERSION != 1 SDL_DestroyWindow(window); window = NULL; #endif @@ -2345,17 +2348,25 @@ void VID_Shutdown (void) int VID_SetGamma (unsigned short *ramps, int rampsize) { +#if SDL_MAJOR_VERSION == 1 return !SDL_SetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2); +#else + return !SDL_SetWindowGammaRamp (window, ramps, ramps + rampsize, ramps + rampsize*2); +#endif } int VID_GetGamma (unsigned short *ramps, int rampsize) { +#if SDL_MAJOR_VERSION == 1 return !SDL_GetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2); +#else + return !SDL_GetWindowGammaRamp (window, ramps, ramps + rampsize, ramps + rampsize*2); +#endif } void VID_Finish (void) { -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 Uint8 appstate; //react on appstate changes @@ -2380,8 +2391,7 @@ void VID_Finish (void) CHECKGLERROR if (r_speeds.integer == 2 || gl_finish.integer) GL_Finish(); -#if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION == 2 -#else +#if SDL_MAJOR_VERSION != 1 { qboolean vid_usevsync; vid_usevsync = (vid_vsync.integer && !cls.timedemo); @@ -2394,7 +2404,7 @@ void VID_Finish (void) } } #endif -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 SDL_GL_SwapBuffers(); #else SDL_GL_SwapWindow(window); @@ -2402,7 +2412,7 @@ void VID_Finish (void) break; case RENDERPATH_SOFT: DPSOFTRAST_Finish(); -#if SETVIDEOMODE +#if SDL_MAJOR_VERSION == 1 // if (!r_test.integer) { SDL_BlitSurface(vid_softsurface, NULL, screen, NULL); @@ -2428,11 +2438,11 @@ void VID_Finish (void) size_t VID_ListModes(vid_mode_t *modes, size_t maxcount) { - size_t k; + size_t k = 0; +#if SDL_MAJOR_VERSION == 1 SDL_Rect **vidmodes; int bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel; - k = 0; for(vidmodes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); vidmodes && vidmodes != (SDL_Rect**)(-1) && *vidmodes; ++vidmodes) { if(k >= maxcount) @@ -2445,5 +2455,24 @@ size_t VID_ListModes(vid_mode_t *modes, size_t maxcount) modes[k].pixelheight_denom = 1; // SDL does not provide this ++k; } +#else + int modenum; + int nummodes = SDL_GetNumDisplayModes(0); + SDL_DisplayMode mode; + for (modenum = 0;modenum < nummodes;modenum++) + { + if (k >= maxcount) + break; + if (SDL_GetDisplayMode(0, modenum, &mode)) + continue; + modes[k].width = mode.w; + modes[k].height = mode.h; + modes[k].refreshrate = mode.refresh_rate; + modes[k].pixelheight_num = 1; + modes[k].pixelheight_num = 1; + modes[k].pixelheight_denom = 1; // SDL does not provide this + k++; + } +#endif return k; } diff --git a/misc/source/darkplaces-src/vid_shared.c b/misc/source/darkplaces-src/vid_shared.c index 9f24869d..7d8485c3 100644 --- a/misc/source/darkplaces-src/vid_shared.c +++ b/misc/source/darkplaces-src/vid_shared.c @@ -867,26 +867,26 @@ static dllfunction_t vbofuncs[] = static dllfunction_t arbfbofuncs[] = { - {"glIsRenderbufferARB" , (void **) &qglIsRenderbuffer}, - {"glBindRenderbufferARB" , (void **) &qglBindRenderbuffer}, - {"glDeleteRenderbuffersARB" , (void **) &qglDeleteRenderbuffers}, - {"glGenRenderbuffersARB" , (void **) &qglGenRenderbuffers}, - {"glRenderbufferStorageARB" , (void **) &qglRenderbufferStorage}, - {"glRenderbufferStorageMultisampleARB" , (void **) &qglRenderbufferStorageMultisample}, // not in GL_EXT_framebuffer_object - {"glGetRenderbufferParameterivARB" , (void **) &qglGetRenderbufferParameteriv}, - {"glIsFramebufferARB" , (void **) &qglIsFramebuffer}, - {"glBindFramebufferARB" , (void **) &qglBindFramebuffer}, - {"glDeleteFramebuffersARB" , (void **) &qglDeleteFramebuffers}, - {"glGenFramebuffersARB" , (void **) &qglGenFramebuffers}, - {"glCheckFramebufferStatusARB" , (void **) &qglCheckFramebufferStatus}, - {"glFramebufferTexture1DARB" , (void **) &qglFramebufferTexture1D}, - {"glFramebufferTexture2DARB" , (void **) &qglFramebufferTexture2D}, - {"glFramebufferTexture3DARB" , (void **) &qglFramebufferTexture3D}, - {"glFramebufferTextureLayerARB" , (void **) &qglFramebufferTextureLayer}, // not in GL_EXT_framebuffer_object - {"glFramebufferRenderbufferARB" , (void **) &qglFramebufferRenderbuffer}, - {"glGetFramebufferAttachmentParameterivARB" , (void **) &qglGetFramebufferAttachmentParameteriv}, - {"glBlitFramebufferARB" , (void **) &qglBlitFramebuffer}, // not in GL_EXT_framebuffer_object - {"glGenerateMipmapARB" , (void **) &qglGenerateMipmap}, + {"glIsRenderbuffer" , (void **) &qglIsRenderbuffer}, + {"glBindRenderbuffer" , (void **) &qglBindRenderbuffer}, + {"glDeleteRenderbuffers" , (void **) &qglDeleteRenderbuffers}, + {"glGenRenderbuffers" , (void **) &qglGenRenderbuffers}, + {"glRenderbufferStorage" , (void **) &qglRenderbufferStorage}, + {"glRenderbufferStorageMultisample" , (void **) &qglRenderbufferStorageMultisample}, // not in GL_EXT_framebuffer_object + {"glGetRenderbufferParameteriv" , (void **) &qglGetRenderbufferParameteriv}, + {"glIsFramebuffer" , (void **) &qglIsFramebuffer}, + {"glBindFramebuffer" , (void **) &qglBindFramebuffer}, + {"glDeleteFramebuffers" , (void **) &qglDeleteFramebuffers}, + {"glGenFramebuffers" , (void **) &qglGenFramebuffers}, + {"glCheckFramebufferStatus" , (void **) &qglCheckFramebufferStatus}, + {"glFramebufferTexture1D" , (void **) &qglFramebufferTexture1D}, + {"glFramebufferTexture2D" , (void **) &qglFramebufferTexture2D}, + {"glFramebufferTexture3D" , (void **) &qglFramebufferTexture3D}, + {"glFramebufferTextureLayer" , (void **) &qglFramebufferTextureLayer}, // not in GL_EXT_framebuffer_object + {"glFramebufferRenderbuffer" , (void **) &qglFramebufferRenderbuffer}, + {"glGetFramebufferAttachmentParameteriv" , (void **) &qglGetFramebufferAttachmentParameteriv}, + {"glBlitFramebuffer" , (void **) &qglBlitFramebuffer}, // not in GL_EXT_framebuffer_object + {"glGenerateMipmap" , (void **) &qglGenerateMipmap}, {NULL, NULL} }; @@ -1038,6 +1038,14 @@ void VID_CheckExtensions(void) vid.support.ext_framebuffer_object = true; else vid.support.ext_framebuffer_object = GL_CheckExtension("GL_EXT_framebuffer_object", extfbofuncs, "-nofbo", false); + + // FIXME remove this workaround once FBO + npot texture mapping is fixed + if(!vid.support.arb_texture_non_power_of_two) + { + vid.support.arb_framebuffer_object = false; + vid.support.ext_framebuffer_object = false; + } + vid.support.ext_packed_depth_stencil = GL_CheckExtension("GL_EXT_packed_depth_stencil", NULL, "-nopackeddepthstencil", false); vid.support.ext_stencil_two_side = GL_CheckExtension("GL_EXT_stencil_two_side", stenciltwosidefuncs, "-nostenciltwoside", false); vid.support.ext_texture_3d = GL_CheckExtension("GL_EXT_texture3D", texture3dextfuncs, "-notexture3d", false); @@ -1865,7 +1873,7 @@ void VID_Restart_f(void) if (!vid_opened) { - SCR_BeginLoadingPlaque(); + SCR_BeginLoadingPlaque(false); return; } @@ -2042,6 +2050,14 @@ void VID_Soft_SharedSetup(void) vid.support.ext_blend_subtract = true; vid.support.ext_draw_range_elements = true; vid.support.ext_framebuffer_object = true; + + // FIXME remove this workaround once FBO + npot texture mapping is fixed + if(!vid.support.arb_texture_non_power_of_two) + { + vid.support.arb_framebuffer_object = false; + vid.support.ext_framebuffer_object = false; + } + vid.support.ext_texture_3d = true; //vid.support.ext_texture_compression_s3tc = true; vid.support.ext_texture_filter_anisotropic = true; diff --git a/misc/source/darkplaces-src/vid_wgl.c b/misc/source/darkplaces-src/vid_wgl.c index 3f7d177d..cb74dea9 100644 --- a/misc/source/darkplaces-src/vid_wgl.c +++ b/misc/source/darkplaces-src/vid_wgl.c @@ -1508,6 +1508,14 @@ qboolean VID_InitModeDX(viddef_mode_t *mode, int version) vid.support.ext_blend_subtract = true; vid.support.ext_draw_range_elements = true; vid.support.ext_framebuffer_object = true; + + // FIXME remove this workaround once FBO + npot texture mapping is fixed + if(!vid.support.arb_texture_non_power_of_two) + { + vid.support.arb_framebuffer_object = false; + vid.support.ext_framebuffer_object = false; + } + vid.support.ext_texture_3d = true; vid.support.ext_texture_compression_s3tc = true; vid.support.ext_texture_filter_anisotropic = true; diff --git a/misc/source/darkplaces-src/view.c b/misc/source/darkplaces-src/view.c index e5bdad59..851c57d1 100644 --- a/misc/source/darkplaces-src/view.c +++ b/misc/source/darkplaces-src/view.c @@ -120,7 +120,7 @@ V_CalcRoll Used by view and sv_user =============== */ -float V_CalcRoll (vec3_t angles, vec3_t velocity) +float V_CalcRoll (const vec3_t angles, const vec3_t velocity) { vec3_t right; float sign; @@ -428,7 +428,46 @@ static void highpass3_limited(vec3_t value, vec_t fracx, vec_t limitx, vec_t fra out[2] = highpass_limited(value[2], fracz, limitz, &store[2]); } -void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewangles, qboolean teleported, qboolean clonground, qboolean clcmdjump) +/* + * State: + * cl.bob2_smooth + * cl.bobfall_speed + * cl.bobfall_swing + * cl.gunangles_adjustment_highpass + * cl.gunangles_adjustment_lowpass + * cl.gunangles_highpass + * cl.gunangles_prev + * cl.gunorg_adjustment_highpass + * cl.gunorg_adjustment_lowpass + * cl.gunorg_highpass + * cl.gunorg_prev + * cl.hitgroundtime + * cl.lastongroundtime + * cl.oldongrounbd + * cl.stairsmoothtime + * cl.stairsmoothz + * cl.calcrefdef_prevtime + * Extra input: + * cl.movecmd[0].time + * cl.movevars_stepheight + * cl.movevars_timescale + * cl.oldtime + * cl.punchangle + * cl.punchvector + * cl.qw_intermission_angles + * cl.qw_intermission_origin + * cl.qw_weaponkick + * cls.protocol + * cl.time + * Output: + * cl.csqc_viewanglesfromengine + * cl.csqc_viewmodelmatrixfromengine + * cl.csqc_vieworiginfromengine + * r_refdef.view.matrix + * viewmodelmatrix_nobob + * viewmodelmatrix_withbob + */ +void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewangles, qboolean teleported, qboolean clonground, qboolean clcmdjump, float clstatsviewheight, qboolean cldead, qboolean clintermission, const vec3_t clvelocity) { float vieworg[3], viewangles[3], smoothtime; float gunorg[3], gunangles[3]; @@ -452,6 +491,7 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa cl.lastongroundtime = cl.movecmd[0].time; } cl.oldonground = clonground; + cl.calcrefdef_prevtime = max(cl.calcrefdef_prevtime, cl.oldtime); VectorClear(gunorg); viewmodelmatrix_nobob = identitymatrix; @@ -471,7 +511,7 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa if (v_dmg_time > 0) v_dmg_time -= bound(0, smoothtime, 0.1); - if (cl.intermission) + if (clintermission) { // entity is a fixed camera, just copy the matrix if (cls.protocol == PROTOCOL_QUAKEWORLD) @@ -479,11 +519,17 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa else { r_refdef.view.matrix = *entrendermatrix; - Matrix4x4_AdjustOrigin(&r_refdef.view.matrix, 0, 0, cl.stats[STAT_VIEWHEIGHT]); + Matrix4x4_AdjustOrigin(&r_refdef.view.matrix, 0, 0, clstatsviewheight); } Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix); Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value); Matrix4x4_Copy(&viewmodelmatrix_withbob, &viewmodelmatrix_nobob); + + VectorCopy(vieworg, cl.csqc_vieworiginfromengine); + VectorCopy(viewangles, cl.csqc_viewanglesfromengine); + + Matrix4x4_Invert_Simple(&tmpmatrix, &r_refdef.view.matrix); + Matrix4x4_CreateScale(&cl.csqc_viewmodelmatrixfromengine, cl_viewmodel_scale.value); } else { @@ -504,8 +550,8 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa // apply the viewofs (even if chasecam is used) // Samual: Lets add smoothing for this too so that things like crouching are done with a transition. - viewheight = bound(0, (cl.time - cl.oldtime) / max(0.0001, cl_smoothviewheight.value), 1); - viewheightavg = viewheightavg * (1 - viewheight) + cl.stats[STAT_VIEWHEIGHT] * viewheight; + viewheight = bound(0, (cl.time - cl.calcrefdef_prevtime) / max(0.0001, cl_smoothviewheight.value), 1); + viewheightavg = viewheightavg * (1 - viewheight) + clstatsviewheight * viewheight; vieworg[2] += viewheightavg; if (chase_active.value) @@ -596,10 +642,10 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa { // first person view from entity // angles - if (cl.stats[STAT_HEALTH] <= 0 && v_deathtilt.integer) + if (cldead && v_deathtilt.integer) viewangles[ROLL] = v_deathtiltangle.value; VectorAdd(viewangles, cl.punchangle, viewangles); - viewangles[ROLL] += V_CalcRoll(cl.viewangles, cl.velocity); + viewangles[ROLL] += V_CalcRoll(clviewangles, clvelocity); if (v_dmg_time > 0) { viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll; @@ -607,14 +653,13 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa } // origin VectorAdd(vieworg, cl.punchvector, vieworg); - if (cl.stats[STAT_HEALTH] > 0) + if (!cldead) { double xyspeed, bob, bobfall; float cycle; vec_t frametime; - //frametime = cl.realframetime * cl.movevars_timescale; - frametime = (cl.time - cl.oldtime) * cl.movevars_timescale; + frametime = (cl.time - cl.calcrefdef_prevtime) * cl.movevars_timescale; // 1. if we teleported, clear the frametime... the lowpass will recover the previous value then if(teleported) @@ -662,7 +707,7 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa VectorAdd(viewangles, gunangles, gunangles); // bounded XY speed, used by several effects below - xyspeed = bound (0, sqrt(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]), 400); + xyspeed = bound (0, sqrt(clvelocity[0]*clvelocity[0] + clvelocity[1]*clvelocity[1]), 400); // vertical view bobbing code if (cl_bob.value && cl_bobcycle.value) @@ -719,8 +764,8 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa // calculate the front and side of the player between the X and Y axes AngleVectors(viewangles, forward, right, up); // now get the speed based on those angles. The bounds should match the same value as xyspeed's - side = bound(-400, DotProduct (cl.velocity, right) * cl.bob2_smooth, 400); - front = bound(-400, DotProduct (cl.velocity, forward) * cl.bob2_smooth, 400); + side = bound(-400, DotProduct (clvelocity, right) * cl.bob2_smooth, 400); + front = bound(-400, DotProduct (clvelocity, forward) * cl.bob2_smooth, 400); VectorScale(forward, bob, forward); VectorScale(right, bob, right); // we use side with forward and front with right, so the bobbing goes @@ -742,8 +787,8 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa { if (!clonground) { - cl.bobfall_speed = bound(-400, cl.velocity[2], 0) * bound(0, cl_bobfall.value, 0.1); - if (cl.velocity[2] < -cl_bobfallminspeed.value) + cl.bobfall_speed = bound(-400, clvelocity[2], 0) * bound(0, cl_bobfall.value, 0.1); + if (clvelocity[2] < -cl_bobfallminspeed.value) cl.bobfall_swing = 1; else cl.bobfall_swing = 0; // TODO really? @@ -821,18 +866,22 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa Matrix4x4_Invert_Simple(&tmpmatrix, &r_refdef.view.matrix); Matrix4x4_Concat(&cl.csqc_viewmodelmatrixfromengine, &tmpmatrix, &viewmodelmatrix_withbob); } + + cl.calcrefdef_prevtime = cl.time; } void V_CalcRefdef (void) { entity_t *ent; + qboolean cldead; - if (cls.state == ca_connected && cls.signon == SIGNONS && !cl.csqc_server2csqcentitynumber[cl.playerentity]) + if (cls.state == ca_connected && cls.signon == SIGNONS && !cl.csqc_server2csqcentitynumber[cl.viewentity]) { // ent is the view entity (visible when out of body) ent = &cl.entities[cl.viewentity]; - V_CalcRefdefUsing(&ent->render.matrix, cl.viewangles, !ent->persistent.trail_allowed, cl.onground, cl.cmd.jump); // FIXME use a better way to detect teleport/warp than trail_allowed + cldead = (cl.stats[STAT_HEALTH] <= 0 && cl.stats[STAT_HEALTH] != -666 && cl.stats[STAT_HEALTH] != -2342); + V_CalcRefdefUsing(&ent->render.matrix, cl.viewangles, !ent->persistent.trail_allowed, cl.onground, cl.cmd.jump, cl.stats[STAT_VIEWHEIGHT], cldead, cl.intermission, cl.velocity); // FIXME use a better way to detect teleport/warp than trail_allowed } else { diff --git a/misc/source/darkplaces-src/wad.c b/misc/source/darkplaces-src/wad.c index a07f87bb..4e714b0b 100644 --- a/misc/source/darkplaces-src/wad.c +++ b/misc/source/darkplaces-src/wad.c @@ -217,23 +217,43 @@ void W_LoadTextureWadFile (char *filename, int complain) // leaves the file open } -unsigned char *W_ConvertWAD3TextureBGRA(miptex_t *tex) +unsigned char *W_ConvertWAD3TextureBGRA(sizebuf_t *sb) { unsigned char *in, *data, *out, *pal; int d, p; + unsigned char name[16]; + unsigned int mipoffset[4]; + + MSG_BeginReading(sb); + MSG_ReadBytes(sb, 16, name); + image_width = MSG_ReadLittleLong(sb); + image_height = MSG_ReadLittleLong(sb); + mipoffset[0] = MSG_ReadLittleLong(sb); + mipoffset[1] = MSG_ReadLittleLong(sb); // should be mipoffset[0] + image_width*image_height + mipoffset[2] = MSG_ReadLittleLong(sb); // should be mipoffset[1] + image_width*image_height/4 + mipoffset[3] = MSG_ReadLittleLong(sb); // should be mipoffset[2] + image_width*image_height/16 + pal = sb->data + mipoffset[3] + (image_width / 8 * image_height / 8) + 2; + + // bail if any data looks wrong + if (image_width < 0 + || image_width > 4096 + || image_height < 0 + || image_height > 4096 + || mipoffset[0] != 40 + || mipoffset[1] != mipoffset[0] + image_width * image_height + || mipoffset[2] != mipoffset[1] + image_width / 2 * image_height / 2 + || mipoffset[3] != mipoffset[2] + image_width / 4 * image_height / 4 + || (unsigned int)sb->cursize < (mipoffset[3] + image_width / 8 * image_height / 8 + 2 + 768)) + return NULL; - in = (unsigned char *)tex + tex->offsets[0]; - data = out = (unsigned char *)Mem_Alloc(tempmempool, tex->width * tex->height * 4); + in = (unsigned char *)sb->data + mipoffset[0]; + data = out = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); if (!data) return NULL; - image_width = tex->width; - image_height = tex->height; - pal = in + (((image_width * image_height) * 85) >> 6); - pal += 2; for (d = 0;d < image_width * image_height;d++) { p = *in++; - if (tex->name[0] == '{' && p == 255) + if (name[0] == '{' && p == 255) out[0] = out[1] = out[2] = out[3] = 0; else { @@ -250,8 +270,8 @@ unsigned char *W_ConvertWAD3TextureBGRA(miptex_t *tex) unsigned char *W_GetTextureBGRA(char *name) { - unsigned int i, j, k; - miptex_t *tex; + unsigned int i, k; + sizebuf_t sb; unsigned char *data; mwad_t *w; char texname[17]; @@ -274,18 +294,14 @@ unsigned char *W_GetTextureBGRA(char *name) if (FS_Seek(w->file, w->lumps[i].filepos, SEEK_SET)) {Con_Print("W_GetTexture: corrupt WAD3 file\n");return NULL;} - tex = (miptex_t *)Mem_Alloc(tempmempool, w->lumps[i].disksize); - if (!tex) + MSG_InitReadBuffer(&sb, (unsigned char *)Mem_Alloc(tempmempool, w->lumps[i].disksize), w->lumps[i].disksize); + if (!sb.data) return NULL; - if (FS_Read(w->file, tex, w->lumps[i].size) < w->lumps[i].disksize) + if (FS_Read(w->file, sb.data, w->lumps[i].size) < w->lumps[i].disksize) {Con_Print("W_GetTexture: corrupt WAD3 file\n");return NULL;} - tex->width = LittleLong(tex->width); - tex->height = LittleLong(tex->height); - for (j = 0;j < MIPLEVELS;j++) - tex->offsets[j] = LittleLong(tex->offsets[j]); - data = W_ConvertWAD3TextureBGRA(tex); - Mem_Free(tex); + data = W_ConvertWAD3TextureBGRA(&sb); + Mem_Free(sb.data); return data; } } diff --git a/misc/source/darkplaces-src/wad.h b/misc/source/darkplaces-src/wad.h index b5ab8dba..3c4297d9 100644 --- a/misc/source/darkplaces-src/wad.h +++ b/misc/source/darkplaces-src/wad.h @@ -71,7 +71,7 @@ unsigned char *W_GetLumpName(const char *name); // halflife texture wads void W_LoadTextureWadFile(char *filename, int complain); unsigned char *W_GetTextureBGRA(char *name); // returns tempmempool allocated image data, width and height are in image_width and image_height -unsigned char *W_ConvertWAD3TextureBGRA(miptex_t *tex); // returns tempmempool allocated image data, width and height are in image_width and image_height +unsigned char *W_ConvertWAD3TextureBGRA(sizebuf_t *sb); // returns tempmempool allocated image data, width and height are in image_width and image_height #endif diff --git a/misc/source/darkplaces-src/world.c b/misc/source/darkplaces-src/world.c index 1225090c..0becd8a8 100644 --- a/misc/source/darkplaces-src/world.c +++ b/misc/source/darkplaces-src/world.c @@ -327,41 +327,36 @@ void World_LinkEdict(world_t *world, prvm_edict_t *ent, const vec3_t mins, const // physics engine support //============================================================================ -#ifndef ODE_STATIC -# define ODE_DYNAMIC 1 -#endif - -#if defined(ODE_STATIC) || defined(ODE_DYNAMIC) -#define USEODE 1 -#endif - #ifdef USEODE cvar_t physics_ode_quadtree_depth = {0, "physics_ode_quadtree_depth","5", "desired subdivision level of quadtree culling space"}; +cvar_t physics_ode_allowconvex = {0, "physics_ode_allowconvex", "0", "allow usage of Convex Hull primitive type on trimeshes that have custom 'collisionconvex' mesh. If disabled, trimesh primitive type are used."}; cvar_t physics_ode_contactsurfacelayer = {0, "physics_ode_contactsurfacelayer","1", "allows objects to overlap this many units to reduce jitter"}; cvar_t physics_ode_worldstep_iterations = {0, "physics_ode_worldstep_iterations", "20", "parameter to dWorldQuickStep"}; cvar_t physics_ode_contact_mu = {0, "physics_ode_contact_mu", "1", "contact solver mu parameter - friction pyramid approximation 1 (see ODE User Guide)"}; cvar_t physics_ode_contact_erp = {0, "physics_ode_contact_erp", "0.96", "contact solver erp parameter - Error Restitution Percent (see ODE User Guide)"}; cvar_t physics_ode_contact_cfm = {0, "physics_ode_contact_cfm", "0", "contact solver cfm parameter - Constraint Force Mixing (see ODE User Guide)"}; +cvar_t physics_ode_contact_maxpoints = {0, "physics_ode_contact_maxpoints", "16", "maximal number of contact points between 2 objects, higher = stable (and slower), can be up to 32"}; cvar_t physics_ode_world_erp = {0, "physics_ode_world_erp", "-1", "world solver erp parameter - Error Restitution Percent (see ODE User Guide); use defaults when set to -1"}; cvar_t physics_ode_world_cfm = {0, "physics_ode_world_cfm", "-1", "world solver cfm parameter - Constraint Force Mixing (see ODE User Guide); not touched when -1"}; cvar_t physics_ode_world_damping = {0, "physics_ode_world_damping", "1", "enabled damping scale (see ODE User Guide), this scales all damping values, be aware that behavior depends of step type"}; -cvar_t physics_ode_world_damping_linear = {0, "physics_ode_world_damping_linear", "0.005", "world linear damping scale (see ODE User Guide); use defaults when set to -1"}; -cvar_t physics_ode_world_damping_linear_threshold = {0, "physics_ode_world_damping_linear_threshold", "0.01", "world linear damping threshold (see ODE User Guide); use defaults when set to -1"}; -cvar_t physics_ode_world_damping_angular = {0, "physics_ode_world_damping_angular", "0.005", "world angular damping scale (see ODE User Guide); use defaults when set to -1"}; -cvar_t physics_ode_world_damping_angular_threshold = {0, "physics_ode_world_damping_angular_threshold", "0.01", "world angular damping threshold (see ODE User Guide); use defaults when set to -1"}; +cvar_t physics_ode_world_damping_linear = {0, "physics_ode_world_damping_linear", "0.01", "world linear damping scale (see ODE User Guide); use defaults when set to -1"}; +cvar_t physics_ode_world_damping_linear_threshold = {0, "physics_ode_world_damping_linear_threshold", "0.1", "world linear damping threshold (see ODE User Guide); use defaults when set to -1"}; +cvar_t physics_ode_world_damping_angular = {0, "physics_ode_world_damping_angular", "0.05", "world angular damping scale (see ODE User Guide); use defaults when set to -1"}; +cvar_t physics_ode_world_damping_angular_threshold = {0, "physics_ode_world_damping_angular_threshold", "0.1", "world angular damping threshold (see ODE User Guide); use defaults when set to -1"}; cvar_t physics_ode_world_gravitymod = {0, "physics_ode_world_gravitymod", "1", "multiplies gravity got from sv_gravity, this may be needed to tweak if strong damping is used"}; cvar_t physics_ode_iterationsperframe = {0, "physics_ode_iterationsperframe", "1", "divisor for time step, runs multiple physics steps per frame"}; -cvar_t physics_ode_constantstep = {0, "physics_ode_constantstep", "1", "use constant step instead of variable step which tends to increase stability, if set to 1 uses sys_ticrate, instead uses it's own value"}; +cvar_t physics_ode_constantstep = {0, "physics_ode_constantstep", "0", "use constant step instead of variable step which tends to increase stability, if set to 1 uses sys_ticrate, instead uses it's own value"}; cvar_t physics_ode_autodisable = {0, "physics_ode_autodisable", "1", "automatic disabling of objects which dont move for long period of time, makes object stacking a lot faster"}; cvar_t physics_ode_autodisable_steps = {0, "physics_ode_autodisable_steps", "10", "how many steps object should be dormant to be autodisabled"}; cvar_t physics_ode_autodisable_time = {0, "physics_ode_autodisable_time", "0", "how many seconds object should be dormant to be autodisabled"}; -cvar_t physics_ode_autodisable_threshold_linear = {0, "physics_ode_autodisable_threshold_linear", "0.2", "body will be disabled if it's linear move below this value"}; -cvar_t physics_ode_autodisable_threshold_angular = {0, "physics_ode_autodisable_threshold_angular", "0.3", "body will be disabled if it's angular move below this value"}; +cvar_t physics_ode_autodisable_threshold_linear = {0, "physics_ode_autodisable_threshold_linear", "0.6", "body will be disabled if it's linear move below this value"}; +cvar_t physics_ode_autodisable_threshold_angular = {0, "physics_ode_autodisable_threshold_angular", "6", "body will be disabled if it's angular move below this value"}; cvar_t physics_ode_autodisable_threshold_samples = {0, "physics_ode_autodisable_threshold_samples", "5", "average threshold with this number of samples"}; cvar_t physics_ode_movelimit = {0, "physics_ode_movelimit", "0.5", "clamp velocity if a single move would exceed this percentage of object thickness, to prevent flying through walls, be aware that behavior depends of step type"}; cvar_t physics_ode_spinlimit = {0, "physics_ode_spinlimit", "10000", "reset spin velocity if it gets too large"}; cvar_t physics_ode_trick_fixnan = {0, "physics_ode_trick_fixnan", "1", "engine trick that checks and fixes NaN velocity/origin/angles on objects, a value of 2 makes console prints on each fix"}; cvar_t physics_ode_printstats = {0, "physics_ode_printstats", "0", "print ODE stats each frame"}; + cvar_t physics_ode = {0, "physics_ode", "0", "run ODE physics (VERY experimental and potentially buggy)"}; // LordHavoc: this large chunk of definitions comes from the ODE library @@ -551,7 +546,7 @@ typedef void dNearCallback (void *data, dGeomID o1, dGeomID o2); #define dSAP_AXES_ZXY ((2)|(0<<2)|(1<<4)) #define dSAP_AXES_ZYX ((2)|(1<<2)|(0<<4)) -//const char* (ODE_API *dGetConfiguration)(void); +const char* (ODE_API *dGetConfiguration)(void); int (ODE_API *dCheckConfiguration)( const char* token ); int (ODE_API *dInitODE)(void); //int (ODE_API *dInitODE2)(unsigned int uiInitFlags); @@ -659,12 +654,12 @@ const dReal * (ODE_API *dBodyGetLinearVel)(dBodyID); const dReal * (ODE_API *dBodyGetAngularVel)(dBodyID); void (ODE_API *dBodySetMass)(dBodyID, const dMass *mass); //void (ODE_API *dBodyGetMass)(dBodyID, dMass *mass); -//void (ODE_API *dBodyAddForce)(dBodyID, dReal fx, dReal fy, dReal fz); -//void (ODE_API *dBodyAddTorque)(dBodyID, dReal fx, dReal fy, dReal fz); +void (ODE_API *dBodyAddForce)(dBodyID, dReal fx, dReal fy, dReal fz); +void (ODE_API *dBodyAddTorque)(dBodyID, dReal fx, dReal fy, dReal fz); //void (ODE_API *dBodyAddRelForce)(dBodyID, dReal fx, dReal fy, dReal fz); -void (ODE_API *dBodyAddRelTorque)(dBodyID, dReal fx, dReal fy, dReal fz); -//void (ODE_API *dBodyAddForceAtPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); -void (ODE_API *dBodyAddForceAtRelPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); +//void (ODE_API *dBodyAddRelTorque)(dBodyID, dReal fx, dReal fy, dReal fz); +void (ODE_API *dBodyAddForceAtPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); +//void (ODE_API *dBodyAddForceAtRelPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); //void (ODE_API *dBodyAddRelForceAtPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); //void (ODE_API *dBodyAddRelForceAtRelPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); //const dReal * (ODE_API *dBodyGetForce)(dBodyID); @@ -937,7 +932,7 @@ dGeomID (ODE_API *dCreateSphere)(dSpaceID space, dReal radius); //dReal (ODE_API *dGeomSphereGetRadius)(dGeomID sphere); //dReal (ODE_API *dGeomSpherePointDepth)(dGeomID sphere, dReal x, dReal y, dReal z); // -//dGeomID (ODE_API *dCreateConvex)(dSpaceID space, dReal *_planes, unsigned int _planecount, dReal *_points, unsigned int _pointcount,unsigned int *_polygons); +dGeomID (ODE_API *dCreateConvex)(dSpaceID space, dReal *_planes, unsigned int _planecount, dReal *_points, unsigned int _pointcount,unsigned int *_polygons); //void (ODE_API *dGeomSetConvex)(dGeomID g, dReal *_planes, unsigned int _count, dReal *_points, unsigned int _pointcount,unsigned int *_polygons); // dGeomID (ODE_API *dCreateBox)(dSpaceID space, dReal lx, dReal ly, dReal lz); @@ -1017,7 +1012,7 @@ dGeomID (ODE_API *dCreateTriMesh)(dSpaceID space, dTriMeshDataID Data, d static dllfunction_t odefuncs[] = { -// {"dGetConfiguration", (void **) &dGetConfiguration}, + {"dGetConfiguration", (void **) &dGetConfiguration}, {"dCheckConfiguration", (void **) &dCheckConfiguration}, {"dInitODE", (void **) &dInitODE}, // {"dInitODE2", (void **) &dInitODE2}, @@ -1124,12 +1119,12 @@ static dllfunction_t odefuncs[] = {"dBodyGetAngularVel", (void **) &dBodyGetAngularVel}, {"dBodySetMass", (void **) &dBodySetMass}, // {"dBodyGetMass", (void **) &dBodyGetMass}, -// {"dBodyAddForce", (void **) &dBodyAddForce}, -// {"dBodyAddTorque", (void **) &dBodyAddTorque}, + {"dBodyAddForce", (void **) &dBodyAddForce}, + {"dBodyAddTorque", (void **) &dBodyAddTorque}, // {"dBodyAddRelForce", (void **) &dBodyAddRelForce}, - {"dBodyAddRelTorque", (void **) &dBodyAddRelTorque}, -// {"dBodyAddForceAtPos", (void **) &dBodyAddForceAtPos}, - {"dBodyAddForceAtRelPos", (void **) &dBodyAddForceAtRelPos}, +// {"dBodyAddRelTorque", (void **) &dBodyAddRelTorque}, + {"dBodyAddForceAtPos", (void **) &dBodyAddForceAtPos}, +// {"dBodyAddForceAtRelPos", (void **) &dBodyAddForceAtRelPos}, // {"dBodyAddRelForceAtPos", (void **) &dBodyAddRelForceAtPos}, // {"dBodyAddRelForceAtRelPos", (void **) &dBodyAddRelForceAtRelPos}, // {"dBodyGetForce", (void **) &dBodyGetForce}, @@ -1397,7 +1392,7 @@ static dllfunction_t odefuncs[] = // {"dGeomSphereSetRadius", (void **) &dGeomSphereSetRadius}, // {"dGeomSphereGetRadius", (void **) &dGeomSphereGetRadius}, // {"dGeomSpherePointDepth", (void **) &dGeomSpherePointDepth}, -// {"dCreateConvex", (void **) &dCreateConvex}, + {"dCreateConvex", (void **) &dCreateConvex}, // {"dGeomSetConvex", (void **) &dGeomSetConvex}, {"dCreateBox", (void **) &dCreateBox}, // {"dGeomBoxSetLengths", (void **) &dGeomBoxSetLengths}, @@ -1492,6 +1487,7 @@ static void World_Physics_Init(void) Cvar_RegisterVariable(&physics_ode_contact_mu); Cvar_RegisterVariable(&physics_ode_contact_erp); Cvar_RegisterVariable(&physics_ode_contact_cfm); + Cvar_RegisterVariable(&physics_ode_contact_maxpoints); Cvar_RegisterVariable(&physics_ode_world_erp); Cvar_RegisterVariable(&physics_ode_world_cfm); Cvar_RegisterVariable(&physics_ode_world_damping); @@ -1512,6 +1508,7 @@ static void World_Physics_Init(void) Cvar_RegisterVariable(&physics_ode_autodisable_threshold_angular); Cvar_RegisterVariable(&physics_ode_autodisable_threshold_samples); Cvar_RegisterVariable(&physics_ode_printstats); + Cvar_RegisterVariable(&physics_ode_allowconvex); Cvar_RegisterVariable(&physics_ode); #ifdef ODE_DYNAMIC @@ -1543,6 +1540,7 @@ static void World_Physics_Init(void) # else Con_Printf("ODE library loaded with double precision.\n"); # endif + Con_Printf("ODE configuration list: %s\n", dGetConfiguration()); } #endif } @@ -1726,13 +1724,13 @@ void World_Physics_ApplyCmd(prvm_edict_t *ed, edict_odefunc_t *f) case ODEFUNC_DISABLE: dBodyDisable(body); break; - case ODEFUNC_RELFORCEATPOS: + case ODEFUNC_FORCE: dBodyEnable(body); - dBodyAddForceAtRelPos(body, f->v1[0], f->v1[1], f->v1[2], f->v2[0], f->v2[1], f->v2[2]); + dBodyAddForceAtPos(body, f->v1[0], f->v1[1], f->v1[2], f->v2[0], f->v2[1], f->v2[2]); break; - case ODEFUNC_RELTORQUE: + case ODEFUNC_TORQUE: dBodyEnable(body); - dBodyAddRelTorque(body, f->v1[0], f->v1[1], f->v1[2]); + dBodyAddTorque(body, f->v1[0], f->v1[1], f->v1[2]); break; default: break; @@ -1844,6 +1842,45 @@ static void World_Physics_Frame_BodyToEntity(world_t *world, prvm_edict_t *ed) } } +static void World_Physics_Frame_ForceFromEntity(world_t *world, prvm_edict_t *ed) +{ + prvm_prog_t *prog = world->prog; + int forcetype = 0, movetype = 0, enemy = 0; + vec3_t movedir, origin; + + movetype = (int)PRVM_gameedictfloat(ed, movetype); + forcetype = (int)PRVM_gameedictfloat(ed, forcetype); + if (movetype == MOVETYPE_PHYSICS) + forcetype = FORCETYPE_NONE; // can't have both + if (!forcetype) + return; + enemy = PRVM_gameedictedict(ed, enemy); + if (enemy <= 0 || enemy >= prog->num_edicts || prog->edicts[enemy].priv.required->free || prog->edicts[enemy].priv.server->ode_body == 0) + return; + VectorCopy(PRVM_gameedictvector(ed, movedir), movedir); + VectorCopy(PRVM_gameedictvector(ed, origin), origin); + dBodyEnable((dBodyID)prog->edicts[enemy].priv.server->ode_body); + switch(forcetype) + { + case FORCETYPE_FORCE: + if (movedir[0] || movedir[1] || movedir[2]) + dBodyAddForce((dBodyID)prog->edicts[enemy].priv.server->ode_body, movedir[0], movedir[1], movedir[2]); + break; + case FORCETYPE_FORCEATPOS: + if (movedir[0] || movedir[1] || movedir[2]) + dBodyAddForceAtPos((dBodyID)prog->edicts[enemy].priv.server->ode_body, movedir[0], movedir[1], movedir[2], origin[0], origin[1], origin[2]); + break; + case FORCETYPE_TORQUE: + if (movedir[0] || movedir[1] || movedir[2]) + dBodyAddTorque((dBodyID)prog->edicts[enemy].priv.server->ode_body, movedir[0], movedir[1], movedir[2]); + break; + case FORCETYPE_NONE: + default: + // bad force + break; + } +} + static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed) { prvm_prog_t *prog = world->prog; @@ -1855,12 +1892,13 @@ static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed int enemy = 0, aiment = 0; vec3_t origin, velocity, angles, forward, left, up, movedir; vec_t CFM, ERP, FMax, Stop, Vel; + + movetype = (int)PRVM_gameedictfloat(ed, movetype); + jointtype = (int)PRVM_gameedictfloat(ed, jointtype); VectorClear(origin); VectorClear(velocity); VectorClear(angles); VectorClear(movedir); - movetype = (int)PRVM_gameedictfloat(ed, movetype); - jointtype = (int)PRVM_gameedictfloat(ed, jointtype); enemy = PRVM_gameedictedict(ed, enemy); aiment = PRVM_gameedictedict(ed, aiment); VectorCopy(PRVM_gameedictvector(ed, origin), origin); @@ -1868,7 +1906,7 @@ static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed VectorCopy(PRVM_gameedictvector(ed, angles), angles); VectorCopy(PRVM_gameedictvector(ed, movedir), movedir); if(movetype == MOVETYPE_PHYSICS) - jointtype = 0; // can't have both + jointtype = JOINTTYPE_NONE; // can't have both if(enemy <= 0 || enemy >= prog->num_edicts || prog->edicts[enemy].priv.required->free || prog->edicts[enemy].priv.server->ode_body == 0) enemy = 0; if(aiment <= 0 || aiment >= prog->num_edicts || prog->edicts[aiment].priv.required->free || prog->edicts[aiment].priv.server->ode_body == 0) @@ -1926,7 +1964,7 @@ static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed case JOINTTYPE_FIXED: j = dJointCreateFixed((dWorldID)world->physics.ode_world, 0); break; - case 0: + case JOINTTYPE_NONE: default: // no joint j = 0; @@ -2026,6 +2064,42 @@ static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed } } +// test convex geometry data +// planes for a cube, these should coincide with the +dReal test_convex_planes[] = +{ + 1.0f ,0.0f ,0.0f ,2.25f, + 0.0f ,1.0f ,0.0f ,2.25f, + 0.0f ,0.0f ,1.0f ,2.25f, + -1.0f,0.0f ,0.0f ,2.25f, + 0.0f ,-1.0f,0.0f ,2.25f, + 0.0f ,0.0f ,-1.0f,2.25f +}; +const unsigned int test_convex_planecount = 6; +// points for a cube +dReal test_convex_points[] = +{ + 2.25f,2.25f,2.25f, // point 0 + -2.25f,2.25f,2.25f, // point 1 + 2.25f,-2.25f,2.25f, // point 2 + -2.25f,-2.25f,2.25f, // point 3 + 2.25f,2.25f,-2.25f, // point 4 + -2.25f,2.25f,-2.25f, // point 5 + 2.25f,-2.25f,-2.25f, // point 6 + -2.25f,-2.25f,-2.25f, // point 7 +}; +const unsigned int test_convex_pointcount = 8; +// polygons for a cube (6 squares), index +unsigned int test_convex_polygons[] = +{ + 4,0,2,6,4, // positive X + 4,1,0,4,5, // positive Y + 4,0,1,3,2, // positive Z + 4,3,1,5,7, // negative X + 4,2,3,7,6, // negative Y + 4,5,4,6,7, // negative Z +}; + static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) { prvm_prog_t *prog = world->prog; @@ -2036,7 +2110,6 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) dReal test; const dReal *ovelocity, *ospinvelocity; void *dataID; - dVector3 capsulerot[3]; dp_model_t *model; float *ov; int *oe; @@ -2045,7 +2118,7 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) int movetype = MOVETYPE_NONE; int numtriangles; int numvertices; - int solid = SOLID_NOT; + int solid = SOLID_NOT, geomtype = 0; int triangleindex; int vertexindex; mempool_t *mempool; @@ -2067,27 +2140,61 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) vec_t massval = 1.0f; vec_t movelimit; vec_t radius; - vec_t scale = 1.0f; + vec3_t scale; vec_t spinlimit; qboolean gravity; + qboolean geom_modified = false; edict_odefunc_t *func, *nextf; + dReal *planes, *planesData, *pointsData; + unsigned int *polygons, *polygonsData, polyvert; + qboolean *mapped, *used, convex_compatible; + int numplanes = 0, numpoints = 0, i; + #ifdef ODE_DYNAMIC if (!ode_dll) return; #endif VectorClear(entmins); VectorClear(entmaxs); + solid = (int)PRVM_gameedictfloat(ed, solid); + geomtype = (int)PRVM_gameedictfloat(ed, geomtype); movetype = (int)PRVM_gameedictfloat(ed, movetype); - scale = PRVM_gameedictfloat(ed, scale);if (!scale) scale = 1.0f; + // support scale and q3map/radiant's modelscale_vec + if (PRVM_gameedictvector(ed, modelscale_vec)[0] != 0.0 || PRVM_gameedictvector(ed, modelscale_vec)[1] != 0.0 || PRVM_gameedictvector(ed, modelscale_vec)[2] != 0.0) + VectorCopy(PRVM_gameedictvector(ed, modelscale_vec), scale); + else if (PRVM_gameedictfloat(ed, scale)) + VectorSet(scale, PRVM_gameedictfloat(ed, scale), PRVM_gameedictfloat(ed, scale), PRVM_gameedictfloat(ed, scale)); + else + VectorSet(scale, 1.0f, 1.0f, 1.0f); modelindex = 0; + if (PRVM_gameedictfloat(ed, mass)) + massval = PRVM_gameedictfloat(ed, mass); + if (movetype != MOVETYPE_PHYSICS) + massval = 1.0f; mempool = prog->progs_mempool; model = NULL; - switch(solid) + if (!geomtype) + { + // VorteX: keep support for deprecated solid fields to not break mods + if (solid == SOLID_PHYSICS_TRIMESH || solid == SOLID_BSP) + geomtype = GEOMTYPE_TRIMESH; + else if (solid == SOLID_NOT || solid == SOLID_TRIGGER) + geomtype = GEOMTYPE_NONE; + else if (solid == SOLID_PHYSICS_SPHERE) + geomtype = GEOMTYPE_SPHERE; + else if (solid == SOLID_PHYSICS_CAPSULE) + geomtype = GEOMTYPE_CAPSULE; + else if (solid == SOLID_PHYSICS_CYLINDER) + geomtype = GEOMTYPE_CYLINDER; + else if (solid == SOLID_PHYSICS_BOX) + geomtype = GEOMTYPE_BOX; + else + geomtype = GEOMTYPE_BOX; + } + if (geomtype == GEOMTYPE_TRIMESH) { - case SOLID_BSP: - case SOLID_PHYSICS_TRIMESH: modelindex = (int)PRVM_gameedictfloat(ed, modelindex); if (world == &sv.world) model = SV_GetModelByIndex(modelindex); @@ -2097,27 +2204,33 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) model = NULL; if (model) { - VectorScale(model->normalmins, scale, entmins); - VectorScale(model->normalmaxs, scale, entmaxs); - massval = PRVM_gameedictfloat(ed, mass); + entmins[0] = model->normalmins[0] * scale[0]; + entmins[1] = model->normalmins[1] * scale[1]; + entmins[2] = model->normalmins[2] * scale[2]; + entmaxs[0] = model->normalmaxs[0] * scale[0]; + entmaxs[1] = model->normalmaxs[1] * scale[1]; + entmaxs[2] = model->normalmaxs[2] * scale[2]; + geom_modified = !VectorCompare(ed->priv.server->ode_scale, scale) || ed->priv.server->ode_modelindex != modelindex; } else { + Con_Printf("entity %i (classname %s) has no model\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(prog, PRVM_gameedictstring(ed, classname))); + geomtype = GEOMTYPE_BOX; + VectorCopy(PRVM_gameedictvector(ed, mins), entmins); + VectorCopy(PRVM_gameedictvector(ed, maxs), entmaxs); modelindex = 0; - massval = 1.0f; + geom_modified = !VectorCompare(ed->priv.server->ode_mins, entmins) || !VectorCompare(ed->priv.server->ode_maxs, entmaxs); } - break; - case SOLID_BBOX: - //case SOLID_SLIDEBOX: - case SOLID_CORPSE: - case SOLID_PHYSICS_BOX: - case SOLID_PHYSICS_SPHERE: - case SOLID_PHYSICS_CAPSULE: + } + else if (geomtype && geomtype != GEOMTYPE_NONE) + { VectorCopy(PRVM_gameedictvector(ed, mins), entmins); VectorCopy(PRVM_gameedictvector(ed, maxs), entmaxs); - massval = PRVM_gameedictfloat(ed, mass); - break; - default: + geom_modified = !VectorCompare(ed->priv.server->ode_mins, entmins) || !VectorCompare(ed->priv.server->ode_maxs, entmaxs); + } + else + { + // geometry type not set, falling back if (ed->priv.server->ode_physics) World_Physics_RemoveFromEntity(world, ed); return; @@ -2132,61 +2245,51 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) return; } - if (movetype != MOVETYPE_PHYSICS) - massval = 1.0f; + // get friction + ed->priv.server->ode_friction = PRVM_gameedictfloat(ed, friction) ? PRVM_gameedictfloat(ed, friction) : 1.0f; - // get friction from entity - if (PRVM_gameedictfloat(ed, friction)) - ed->priv.server->ode_friction = PRVM_gameedictfloat(ed, friction); - else - ed->priv.server->ode_friction = 1.0; - // check if we need to create or replace the geom - if (!ed->priv.server->ode_physics - || !VectorCompare(ed->priv.server->ode_mins, entmins) - || !VectorCompare(ed->priv.server->ode_maxs, entmaxs) - || ed->priv.server->ode_mass != massval - || ed->priv.server->ode_modelindex != modelindex) + if (!ed->priv.server->ode_physics || ed->priv.server->ode_mass != massval || geom_modified) { modified = true; World_Physics_RemoveFromEntity(world, ed); ed->priv.server->ode_physics = true; - VectorCopy(entmins, ed->priv.server->ode_mins); - VectorCopy(entmaxs, ed->priv.server->ode_maxs); - ed->priv.server->ode_mass = massval; - ed->priv.server->ode_modelindex = modelindex; VectorMAM(0.5f, entmins, 0.5f, entmaxs, geomcenter); if (PRVM_gameedictvector(ed, massofs)) VectorCopy(geomcenter, PRVM_gameedictvector(ed, massofs)); - else - VectorMAM(0.5f, entmins, 0.5f, entmaxs, geomcenter); - ed->priv.server->ode_movelimit = min(geomsize[0], min(geomsize[1], geomsize[2])); - if (massval * geomsize[0] * geomsize[1] * geomsize[2] == 0) + + // check geomsize + if (geomsize[0] * geomsize[1] * geomsize[2] == 0) { if (movetype == MOVETYPE_PHYSICS) Con_Printf("entity %i (classname %s) .mass * .size_x * .size_y * .size_z == 0\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(prog, PRVM_gameedictstring(ed, classname))); - massval = 1.0f; VectorSet(geomsize, 1.0f, 1.0f, 1.0f); } - switch(solid) + // greate geom + switch(geomtype) { - case SOLID_BSP: - case SOLID_PHYSICS_TRIMESH: - ed->priv.server->ode_offsetmatrix = identitymatrix; - if (!model) - { - Con_Printf("entity %i (classname %s) has no model\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(prog, PRVM_gameedictstring(ed, classname))); - goto treatasbox; - } + case GEOMTYPE_TRIMESH: // add an optimized mesh to the model containing only the SUPERCONTENTS_SOLID surfaces if (!model->brush.collisionmesh) Mod_CreateCollisionMesh(model); - if (!model->brush.collisionmesh || !model->brush.collisionmesh->numtriangles) + if (!model->brush.collisionmesh) { Con_Printf("entity %i (classname %s) has no geometry\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(prog, PRVM_gameedictstring(ed, classname))); goto treatasbox; } + + // check if trimesh can be defined with convex + convex_compatible = false; + for (i = 0;i < model->nummodelsurfaces;i++) + { + if (!strcmp(((msurface_t *)(model->data_surfaces + model->firstmodelsurface + i))->texture->name, "collisionconvex")) + { + convex_compatible = true; + break; + } + } + // ODE requires persistent mesh storage, so we need to copy out // the data from the model because renderer restarts could free it // during the game, additionally we need to flip the triangles... @@ -2194,11 +2297,36 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) // concave edges, etc., so this is not a lightweight operation ed->priv.server->ode_numvertices = numvertices = model->brush.collisionmesh->numverts; ed->priv.server->ode_vertex3f = (float *)Mem_Alloc(mempool, numvertices * sizeof(float[3])); + + // VorteX: rebuild geomsize based on entity's collision mesh, honor scale + VectorSet(entmins, 0, 0, 0); + VectorSet(entmaxs, 0, 0, 0); + for (vertexindex = 0, ov = ed->priv.server->ode_vertex3f, iv = model->brush.collisionmesh->vertex3f;vertexindex < numvertices;vertexindex++, ov += 3, iv += 3) + { + ov[0] = iv[0] * scale[0]; + ov[1] = iv[1] * scale[1]; + ov[2] = iv[2] * scale[2]; + entmins[0] = min(entmins[0], ov[0]); + entmins[1] = min(entmins[1], ov[1]); + entmins[2] = min(entmins[2], ov[2]); + entmaxs[0] = max(entmaxs[0], ov[0]); + entmaxs[1] = max(entmaxs[1], ov[1]); + entmaxs[2] = max(entmaxs[2], ov[2]); + } + if (!PRVM_gameedictvector(ed, massofs)) + VectorMAM(0.5f, entmins, 0.5f, entmaxs, geomcenter); for (vertexindex = 0, ov = ed->priv.server->ode_vertex3f, iv = model->brush.collisionmesh->vertex3f;vertexindex < numvertices;vertexindex++, ov += 3, iv += 3) { - ov[0] = iv[0] - geomcenter[0]; - ov[1] = iv[1] - geomcenter[1]; - ov[2] = iv[2] - geomcenter[2]; + ov[0] = ov[0] - geomcenter[0]; + ov[1] = ov[1] - geomcenter[1]; + ov[2] = ov[2] - geomcenter[2]; + } + VectorSubtract(entmaxs, entmins, geomsize); + if (VectorLength2(geomsize) == 0) + { + if (movetype == MOVETYPE_PHYSICS) + Con_Printf("entity %i collision mesh has null geomsize\n", PRVM_NUM_FOR_EDICT(ed)); + VectorSet(geomsize, 1.0f, 1.0f, 1.0f); } ed->priv.server->ode_numtriangles = numtriangles = model->brush.collisionmesh->numtriangles; ed->priv.server->ode_element3i = (int *)Mem_Alloc(mempool, numtriangles * sizeof(int[3])); @@ -2209,29 +2337,159 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) oe[1] = ie[1]; oe[2] = ie[0]; } + // create geom Matrix4x4_CreateTranslate(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]); - // now create the geom - dataID = dGeomTriMeshDataCreate(); - dGeomTriMeshDataBuildSingle((dTriMeshDataID)dataID, (void*)ed->priv.server->ode_vertex3f, sizeof(float[3]), ed->priv.server->ode_numvertices, ed->priv.server->ode_element3i, ed->priv.server->ode_numtriangles*3, sizeof(int[3])); - ed->priv.server->ode_geom = (void *)dCreateTriMesh((dSpaceID)world->physics.ode_space, (dTriMeshDataID)dataID, NULL, NULL, NULL); - dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]); + if (!convex_compatible || !physics_ode_allowconvex.integer) + { + // trimesh + dataID = dGeomTriMeshDataCreate(); + dGeomTriMeshDataBuildSingle((dTriMeshDataID)dataID, (void*)ed->priv.server->ode_vertex3f, sizeof(float[3]), ed->priv.server->ode_numvertices, ed->priv.server->ode_element3i, ed->priv.server->ode_numtriangles*3, sizeof(int[3])); + ed->priv.server->ode_geom = (void *)dCreateTriMesh((dSpaceID)world->physics.ode_space, (dTriMeshDataID)dataID, NULL, NULL, NULL); + dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]); + } + else + { + // VorteX: this code is unfinished in two ways + // - no duplicate vertex merging are done + // - triangles that shares same edge and havee sam plane are not merget into poly + // so, currently it only works for geosphere meshes with no UV + + Con_Printf("Build convex hull for model %s...\n", model->name); + // build convex geometry from trimesh data + // this ensures that trimesh's triangles can form correct convex geometry + // not many of error checking is performed + // ODE's conve hull data consist of: + // planes : an array of planes in the form: normal X, normal Y, normal Z, distance + // points : an array of points X,Y,Z + // polygons: an array of indices to the points of each polygon,it should be the number of vertices + // followed by that amount of indices to "points" in counter clockwise order + polygonsData = polygons = (unsigned int *)Mem_Alloc(mempool, numtriangles*sizeof(int)*4); + planesData = planes = (dReal *)Mem_Alloc(mempool, numtriangles*sizeof(dReal)*4); + mapped = (qboolean *)Mem_Alloc(mempool, numvertices*sizeof(qboolean)); + used = (qboolean *)Mem_Alloc(mempool, numtriangles*sizeof(qboolean)); + memset(mapped, 0, numvertices*sizeof(qboolean)); + memset(used, 0, numtriangles*sizeof(qboolean)); + numplanes = numpoints = polyvert = 0; + // build convex hull + // todo: merge duplicated verts here + Con_Printf("Building...\n"); + iv = ed->priv.server->ode_vertex3f; + for (triangleindex = 0; triangleindex < numtriangles; triangleindex++) + { + // already formed a polygon? + if (used[triangleindex]) + continue; + // init polygon + // switch clockwise->counterclockwise + ie = &model->brush.collisionmesh->element3i[triangleindex*3]; + used[triangleindex] = true; + TriangleNormal(&iv[ie[0]*3], &iv[ie[1]*3], &iv[ie[2]*3], planes); + VectorNormalize(planes); + polygons[0] = 3; + polygons[3] = (unsigned int)ie[0]; mapped[polygons[3]] = true; + polygons[2] = (unsigned int)ie[1]; mapped[polygons[2]] = true; + polygons[1] = (unsigned int)ie[2]; mapped[polygons[1]] = true; + + // now find and include concave triangles + for (i = triangleindex; i < numtriangles; i++) + { + if (used[i]) + continue; + // should share at least 2 vertexes + for (polyvert = 1; polyvert <= polygons[0]; polyvert++) + { + // todo: merge in triangles that shares an edge and have same plane here + } + } + + // add polygon to overall stats + planes[3] = DotProduct(&iv[polygons[1]*3], planes); + polygons += (polygons[0]+1); + planes += 4; + numplanes++; + } + Mem_Free(used); + // save points + for (vertexindex = 0, numpoints = 0; vertexindex < numvertices; vertexindex++) + if (mapped[vertexindex]) + numpoints++; + pointsData = (dReal *)Mem_Alloc(mempool, numpoints*sizeof(dReal)*3 + numplanes*sizeof(dReal)*4); // planes is appended + for (vertexindex = 0, numpoints = 0; vertexindex < numvertices; vertexindex++) + { + if (mapped[vertexindex]) + { + VectorCopy(&iv[vertexindex*3], &pointsData[numpoints*3]); + numpoints++; + } + } + Mem_Free(mapped); + Con_Printf("Points: \n"); + for (i = 0; i < (int)numpoints; i++) + Con_Printf("%3i: %3.1f %3.1f %3.1f\n", i, pointsData[i*3], pointsData[i*3+1], pointsData[i*3+2]); + // save planes + planes = planesData; + planesData = pointsData + numpoints*3; + memcpy(planesData, planes, numplanes*sizeof(dReal)*4); + Mem_Free(planes); + Con_Printf("planes...\n"); + for (i = 0; i < numplanes; i++) + Con_Printf("%3i: %1.1f %1.1f %1.1f %1.1f\n", i, planesData[i*4], planesData[i*4 + 1], planesData[i*4 + 2], planesData[i*4 + 3]); + // save polygons + polyvert = polygons - polygonsData; + polygons = polygonsData; + polygonsData = (unsigned int *)Mem_Alloc(mempool, polyvert*sizeof(int)); + memcpy(polygonsData, polygons, polyvert*sizeof(int)); + Mem_Free(polygons); + Con_Printf("Polygons: \n"); + polygons = polygonsData; + for (i = 0; i < numplanes; i++) + { + Con_Printf("%3i : %i ", i, polygons[0]); + for (triangleindex = 1; triangleindex <= (int)polygons[0]; triangleindex++) + Con_Printf("%3i ", polygons[triangleindex]); + polygons += (polygons[0]+1); + Con_Printf("\n"); + } + Mem_Free(ed->priv.server->ode_element3i); + ed->priv.server->ode_element3i = (int *)polygonsData; + Mem_Free(ed->priv.server->ode_vertex3f); + ed->priv.server->ode_vertex3f = (float *)pointsData; + // check for properly build polygons by calculating the determinant of the 3x3 matrix composed of the first 3 points in the polygon + // this code is picked from ODE Source + Con_Printf("Check...\n"); + polygons = polygonsData; + for (i = 0; i < numplanes; i++) + { + if((pointsData[(polygons[1]*3)+0]*pointsData[(polygons[2]*3)+1]*pointsData[(polygons[3]*3)+2] + + pointsData[(polygons[1]*3)+1]*pointsData[(polygons[2]*3)+2]*pointsData[(polygons[3]*3)+0] + + pointsData[(polygons[1]*3)+2]*pointsData[(polygons[2]*3)+0]*pointsData[(polygons[3]*3)+1] - + pointsData[(polygons[1]*3)+2]*pointsData[(polygons[2]*3)+1]*pointsData[(polygons[3]*3)+0] - + pointsData[(polygons[1]*3)+1]*pointsData[(polygons[2]*3)+0]*pointsData[(polygons[3]*3)+2] - + pointsData[(polygons[1]*3)+0]*pointsData[(polygons[2]*3)+2]*pointsData[(polygons[3]*3)+1]) < 0) + Con_Printf("WARNING: Polygon %d is not defined counterclockwise\n", i); + if (planesData[(i*4)+3] < 0) + Con_Printf("WARNING: Plane %d does not contain the origin\n", i); + polygons += (*polygons + 1); + } + // create geom + Con_Printf("Create geom...\n"); + ed->priv.server->ode_geom = (void *)dCreateConvex((dSpaceID)world->physics.ode_space, planesData, numplanes, pointsData, numpoints, polygonsData); + dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]); + Con_Printf("Done!\n"); + } break; - case SOLID_BBOX: - case SOLID_SLIDEBOX: - case SOLID_CORPSE: - case SOLID_PHYSICS_BOX: + case GEOMTYPE_BOX: treatasbox: Matrix4x4_CreateTranslate(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]); ed->priv.server->ode_geom = (void *)dCreateBox((dSpaceID)world->physics.ode_space, geomsize[0], geomsize[1], geomsize[2]); dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]); break; - case SOLID_PHYSICS_SPHERE: + case GEOMTYPE_SPHERE: Matrix4x4_CreateTranslate(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]); ed->priv.server->ode_geom = (void *)dCreateSphere((dSpaceID)world->physics.ode_space, geomsize[0] * 0.5f); dMassSetSphereTotal(&mass, massval, geomsize[0] * 0.5f); break; - case SOLID_PHYSICS_CAPSULE: - case SOLID_PHYSICS_CYLINDER: + case GEOMTYPE_CAPSULE: axisindex = 0; if (geomsize[axisindex] < geomsize[1]) axisindex = 1; @@ -2241,36 +2499,136 @@ treatasbox: // axis, since ODE doesn't like this idea we have to create a // capsule which uses the standard orientation, and apply a // transform to it - memset(capsulerot, 0, sizeof(capsulerot)); if (axisindex == 0) + { Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 90, 1); + radius = min(geomsize[1], geomsize[2]) * 0.5f; + } else if (axisindex == 1) + { Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 90, 0, 0, 1); + radius = min(geomsize[0], geomsize[2]) * 0.5f; + } else + { Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 0, 1); - radius = geomsize[!axisindex] * 0.5f; // any other axis is the radius + radius = min(geomsize[0], geomsize[1]) * 0.5f; + } length = geomsize[axisindex] - radius*2; // because we want to support more than one axisindex, we have to // create a transform, and turn on its cleanup setting (which will // cause the child to be destroyed when it is destroyed) - if (solid == SOLID_PHYSICS_CAPSULE) + ed->priv.server->ode_geom = (void *)dCreateCapsule((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCapsuleTotal(&mass, massval, axisindex+1, radius, length); + break; + case GEOMTYPE_CAPSULE_X: + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 90, 1); + radius = min(geomsize[1], geomsize[2]) * 0.5f; + length = geomsize[0] - radius*2; + // check if length is not enough, reduce radius then + if (length <= 0) + { + radius -= (1 - length)*0.5; + length = 1; + } + ed->priv.server->ode_geom = (void *)dCreateCapsule((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCapsuleTotal(&mass, massval, 1, radius, length); + break; + case GEOMTYPE_CAPSULE_Y: + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 90, 0, 0, 1); + radius = min(geomsize[0], geomsize[2]) * 0.5f; + length = geomsize[1] - radius*2; + // check if length is not enough, reduce radius then + if (length <= 0) + { + radius -= (1 - length)*0.5; + length = 1; + } + ed->priv.server->ode_geom = (void *)dCreateCapsule((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCapsuleTotal(&mass, massval, 2, radius, length); + break; + case GEOMTYPE_CAPSULE_Z: + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 0, 1); + radius = min(geomsize[1], geomsize[0]) * 0.5f; + length = geomsize[2] - radius*2; + // check if length is not enough, reduce radius then + if (length <= 0) { - ed->priv.server->ode_geom = (void *)dCreateCapsule((dSpaceID)world->physics.ode_space, radius, length); - dMassSetCapsuleTotal(&mass, massval, axisindex+1, radius, length); + radius -= (1 - length)*0.5; + length = 1; + } + ed->priv.server->ode_geom = (void *)dCreateCapsule((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCapsuleTotal(&mass, massval, 3, radius, length); + break; + case GEOMTYPE_CYLINDER: + axisindex = 0; + if (geomsize[axisindex] < geomsize[1]) + axisindex = 1; + if (geomsize[axisindex] < geomsize[2]) + axisindex = 2; + // the qc gives us 3 axis radius, the longest axis is the capsule + // axis, since ODE doesn't like this idea we have to create a + // capsule which uses the standard orientation, and apply a + // transform to it + if (axisindex == 0) + { + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 90, 1); + radius = min(geomsize[1], geomsize[2]) * 0.5f; + } + else if (axisindex == 1) + { + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 90, 0, 0, 1); + radius = min(geomsize[0], geomsize[2]) * 0.5f; } else { - ed->priv.server->ode_geom = (void *)dCreateCylinder((dSpaceID)world->physics.ode_space, radius, length); - dMassSetCylinderTotal(&mass, massval, axisindex+1, radius, length); + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 0, 1); + radius = min(geomsize[0], geomsize[1]) * 0.5f; + } + length = geomsize[axisindex]; + // check if length is not enough, reduce radius then + if (length <= 0) + { + radius -= (1 - length)*0.5; + length = 1; } + ed->priv.server->ode_geom = (void *)dCreateCylinder((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCylinderTotal(&mass, massval, axisindex+1, radius, length); + break; + case GEOMTYPE_CYLINDER_X: + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 90, 1); + radius = min(geomsize[1], geomsize[2]) * 0.5f; + length = geomsize[0]; + ed->priv.server->ode_geom = (void *)dCreateCylinder((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCylinderTotal(&mass, massval, 1, radius, length); + break; + case GEOMTYPE_CYLINDER_Y: + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 90, 0, 0, 1); + radius = min(geomsize[0], geomsize[2]) * 0.5f; + length = geomsize[1]; + ed->priv.server->ode_geom = (void *)dCreateCylinder((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCylinderTotal(&mass, massval, 2, radius, length); + break; + case GEOMTYPE_CYLINDER_Z: + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 0, 1); + radius = min(geomsize[0], geomsize[1]) * 0.5f; + length = geomsize[2]; + ed->priv.server->ode_geom = (void *)dCreateCylinder((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCylinderTotal(&mass, massval, 3, radius, length); break; default: - Sys_Error("World_Physics_BodyFromEntity: unrecognized solid value %i was accepted by filter\n", solid); + Sys_Error("World_Physics_BodyFromEntity: unrecognized geomtype value %i was accepted by filter\n", solid); // this goto only exists to prevent warnings from the compiler // about uninitialized variables (mass), while allowing it to // catch legitimate uninitialized variable warnings goto treatasbox; } + ed->priv.server->ode_mass = massval; + ed->priv.server->ode_modelindex = modelindex; + VectorCopy(entmins, ed->priv.server->ode_mins); + VectorCopy(entmaxs, ed->priv.server->ode_maxs); + VectorCopy(scale, ed->priv.server->ode_scale); + ed->priv.server->ode_movelimit = min(geomsize[0], min(geomsize[1], geomsize[2])); Matrix4x4_Invert_Simple(&ed->priv.server->ode_offsetimatrix, &ed->priv.server->ode_offsetmatrix); ed->priv.server->ode_massbuf = Mem_Alloc(mempool, sizeof(mass)); memcpy(ed->priv.server->ode_massbuf, &mass, sizeof(dMass)); @@ -2280,6 +2638,7 @@ treatasbox: dGeomSetData((dGeomID)ed->priv.server->ode_geom, (void*)ed); if (movetype == MOVETYPE_PHYSICS && ed->priv.server->ode_geom) { + // entity is dynamic if (ed->priv.server->ode_body == NULL) { ed->priv.server->ode_body = (void *)(body = dBodyCreate((dWorldID)world->physics.ode_world)); @@ -2291,6 +2650,7 @@ treatasbox: } else { + // entity is deactivated if (ed->priv.server->ode_body != NULL) { if(ed->priv.server->ode_geom) @@ -2443,9 +2803,9 @@ treatasbox: r[0][2] = up[0]; r[1][2] = up[1]; r[2][2] = up[2]; - if(body) + if (body) { - if(movetype == MOVETYPE_PHYSICS) + if (movetype == MOVETYPE_PHYSICS) { dGeomSetBody((dGeomID)ed->priv.server->ode_geom, body); dBodySetPosition(body, origin[0], origin[1], origin[2]); @@ -2474,7 +2834,7 @@ treatasbox: } } - if(body) + if (body) { // limit movement speed to prevent missed collisions at high speed @@ -2512,14 +2872,14 @@ treatasbox: } } -#define MAX_CONTACTS 16 +#define MAX_CONTACTS 32 static void nearCallback (void *data, dGeomID o1, dGeomID o2) { world_t *world = (world_t *)data; prvm_prog_t *prog = world->prog; dContact contact[MAX_CONTACTS]; // max contacts per collision pair - dBodyID b1; - dBodyID b2; + int b1enabled = 0, b2enabled = 0; + dBodyID b1, b2; dJointID c; int i; int numcontacts; @@ -2527,6 +2887,7 @@ static void nearCallback (void *data, dGeomID o1, dGeomID o2) float bouncestop1 = 60.0f / 800.0f; float bouncefactor2 = 0.0f; float bouncestop2 = 60.0f / 800.0f; + float erp; dVector3 grav; prvm_edict_t *ed1, *ed2; @@ -2542,12 +2903,16 @@ static void nearCallback (void *data, dGeomID o1, dGeomID o2) } b1 = dGeomGetBody(o1); + if (b1) + b1enabled = dBodyIsEnabled(b1); b2 = dGeomGetBody(o2); + if (b2) + b2enabled = dBodyIsEnabled(b2); - // at least one object has to be using MOVETYPE_PHYSICS or we just don't care - if (!b1 && !b2) + // at least one object has to be using MOVETYPE_PHYSICS and should be enabled or we just don't care + if (!b1enabled && !b2enabled) return; - + // exit without doing anything if the two bodies are connected by a joint if (b1 && b2 && dAreConnectedExcluding(b1, b2, dJointTypeContact)) return; @@ -2606,14 +2971,27 @@ static void nearCallback (void *data, dGeomID o1, dGeomID o2) dWorldGetGravity((dWorldID)world->physics.ode_world, grav); bouncestop1 *= fabs(grav[2]); + // get erp + // select object that moves faster ang get it's erp + erp = (VectorLength2(PRVM_gameedictvector(ed1, velocity)) > VectorLength2(PRVM_gameedictvector(ed2, velocity))) ? PRVM_gameedictfloat(ed1, erp) : PRVM_gameedictfloat(ed2, erp); + + // get max contact points for this collision + numcontacts = (int)PRVM_gameedictfloat(ed1, maxcontacts); + if (!numcontacts) + numcontacts = physics_ode_contact_maxpoints.integer; + if (PRVM_gameedictfloat(ed2, maxcontacts)) + numcontacts = max(numcontacts, (int)PRVM_gameedictfloat(ed2, maxcontacts)); + else + numcontacts = max(numcontacts, physics_ode_contact_maxpoints.integer); + // generate contact points between the two non-space geoms - numcontacts = dCollide(o1, o2, MAX_CONTACTS, &(contact[0].geom), sizeof(contact[0])); + numcontacts = dCollide(o1, o2, min(MAX_CONTACTS, numcontacts), &(contact[0].geom), sizeof(contact[0])); // add these contact points to the simulation for (i = 0;i < numcontacts;i++) { contact[i].surface.mode = (physics_ode_contact_mu.value != -1 ? dContactApprox1 : 0) | (physics_ode_contact_erp.value != -1 ? dContactSoftERP : 0) | (physics_ode_contact_cfm.value != -1 ? dContactSoftCFM : 0) | (bouncefactor1 > 0 ? dContactBounce : 0); contact[i].surface.mu = physics_ode_contact_mu.value * ed1->priv.server->ode_friction * ed2->priv.server->ode_friction; - contact[i].surface.soft_erp = physics_ode_contact_erp.value; + contact[i].surface.soft_erp = physics_ode_contact_erp.value + erp; contact[i].surface.soft_cfm = physics_ode_contact_cfm.value; contact[i].surface.bounce = bouncefactor1; contact[i].surface.bounce_vel = bouncestop1; @@ -2635,13 +3013,29 @@ void World_Physics_Frame(world_t *world, double frametime, double gravity) int i; prvm_edict_t *ed; - world->physics.ode_iterations = bound(1, physics_ode_iterationsperframe.integer, 1000); - if (physics_ode_constantstep.integer > 0 && physics_ode_constantstep.integer < 1) - world->physics.ode_step = physics_ode_constantstep.integer / world->physics.ode_iterations; - else if (physics_ode_constantstep.integer) - world->physics.ode_step = sys_ticrate.integer / world->physics.ode_iterations; - else + if (!physics_ode_constantstep.value) + { + world->physics.ode_iterations = bound(1, physics_ode_iterationsperframe.integer, 1000); world->physics.ode_step = frametime / world->physics.ode_iterations; + } + else + { + world->physics.ode_time += frametime; + // step size + if (physics_ode_constantstep.value > 0 && physics_ode_constantstep.value < 1) + world->physics.ode_step = physics_ode_constantstep.value; + else + world->physics.ode_step = sys_ticrate.value; + if (world->physics.ode_time > 0.2f) + world->physics.ode_time = world->physics.ode_step; + // set number of iterations to process + world->physics.ode_iterations = 0; + while(world->physics.ode_time >= world->physics.ode_step) + { + world->physics.ode_iterations++; + world->physics.ode_time -= world->physics.ode_step; + } + } world->physics.ode_movelimit = physics_ode_movelimit.value / world->physics.ode_step; World_Physics_UpdateODE(world); @@ -2665,18 +3059,23 @@ void World_Physics_Frame(world_t *world, double frametime, double gravity) dWorldSetGravity((dWorldID)world->physics.ode_world, 0, 0, -gravity * physics_ode_world_gravitymod.value); // set the tolerance for closeness of objects dWorldSetContactSurfaceLayer((dWorldID)world->physics.ode_world, max(0, physics_ode_contactsurfacelayer.value)); - // run collisions for the current world state, creating JointGroup tdelta3 = Sys_DirtyTime(); dSpaceCollide((dSpaceID)world->physics.ode_space, (void *)world, nearCallback); collisiontime += (Sys_DirtyTime() - tdelta3)*10000; - + // apply forces + if (prog) + { + int j; + for (j = 0, ed = prog->edicts + j;j < prog->num_edicts;j++, ed++) + if (!prog->edicts[j].priv.required->free) + World_Physics_Frame_ForceFromEntity(world, ed); + } // run physics (move objects, calculate new velocities) // be sure not to pass 0 as step time because that causes an ODE error dWorldSetQuickStepNumIterations((dWorldID)world->physics.ode_world, bound(1, physics_ode_worldstep_iterations.integer, 200)); if (world->physics.ode_step > 0) dWorldQuickStep((dWorldID)world->physics.ode_world, world->physics.ode_step); - // clear the JointGroup now that we're done with it dJointGroupEmpty((dJointGroupID)world->physics.ode_contactgroup); } @@ -2707,7 +3106,7 @@ void World_Physics_Frame(world_t *world, double frametime, double gravity) if (dBodyIsEnabled(body)) world->physics.ode_activeovjects++; } - Con_Printf("ODE Stats(%s): %3.01f (%3.01f collision) %3.01f total : %i objects %i active %i disabled\n", prog->name, simulationtime, collisiontime, (Sys_DirtyTime() - tdelta)*10000, world->physics.ode_numobjects, world->physics.ode_activeovjects, (world->physics.ode_numobjects - world->physics.ode_activeovjects)); + Con_Printf("ODE Stats(%s): %i iterations, %3.01f (%3.01f collision) %3.01f total : %i objects %i active %i disabled\n", prog->name, world->physics.ode_iterations, simulationtime, collisiontime, (Sys_DirtyTime() - tdelta)*10000, world->physics.ode_numobjects, world->physics.ode_activeovjects, (world->physics.ode_numobjects - world->physics.ode_activeovjects)); } } } diff --git a/misc/source/darkplaces-src/world.h b/misc/source/darkplaces-src/world.h index 122b9c70..18e9b001 100644 --- a/misc/source/darkplaces-src/world.h +++ b/misc/source/darkplaces-src/world.h @@ -50,6 +50,8 @@ typedef struct world_physics_s int ode_iterations; // actual step (server frametime / ode_iterations) vec_t ode_step; + // time we need to simulate, for constantstep + vec_t ode_time; // stats int ode_numobjects; // total objects cound int ode_activeovjects; // active objects count @@ -117,6 +119,15 @@ int World_EntitiesInBox(world_t *world, const vec3_t mins, const vec3_t maxs, in void World_Start(world_t *world); void World_End(world_t *world); +// physics macros +#ifndef ODE_STATIC +# define ODE_DYNAMIC 1 +#endif + +#if defined(ODE_STATIC) || defined(ODE_DYNAMIC) +# define USEODE 1 +#endif + // update physics // this is called by SV_Physics void World_Physics_Frame(world_t *world, double frametime, double gravity); diff --git a/misc/source/darkplaces-src/zone.c b/misc/source/darkplaces-src/zone.c index 02920535..2f756d0e 100644 --- a/misc/source/darkplaces-src/zone.c +++ b/misc/source/darkplaces-src/zone.c @@ -40,15 +40,26 @@ unsigned int sentinel_seed; qboolean mem_bigendian = false; void *mem_mutex = NULL; +// divVerent: enables file backed malloc using mmap to conserve swap space (instead of malloc) +#ifndef FILE_BACKED_MALLOC +# define FILE_BACKED_MALLOC 0 +#endif + // LordHavoc: enables our own low-level allocator (instead of malloc) -#define MEMCLUMPING 0 -#define MEMCLUMPING_FREECLUMPS 0 +#ifndef MEMCLUMPING +# define MEMCLUMPING 0 +#endif +#ifndef MEMCLUMPING_FREECLUMPS +# define MEMCLUMPING_FREECLUMPS 0 +#endif #if MEMCLUMPING // smallest unit we care about is this many bytes #define MEMUNIT 128 // try to do 32MB clumps, but overhead eats into this -#define MEMWANTCLUMPSIZE (1<<27) +#ifndef MEMWANTCLUMPSIZE +# define MEMWANTCLUMPSIZE (1<<27) +#endif // give malloc padding so we can't waste most of a page at the end #define MEMCLUMPSIZE (MEMWANTCLUMPSIZE - MEMWANTCLUMPSIZE/MEMUNIT/32 - 128) #define MEMBITS (MEMCLUMPSIZE / MEMUNIT) @@ -92,6 +103,46 @@ static mempool_t *poolchain = NULL; void Mem_PrintStats(void); void Mem_PrintList(size_t minallocationsize); +#if FILE_BACKED_MALLOC +#include +#include +typedef struct mmap_data_s +{ + size_t len; +} +mmap_data_t; +static void *mmap_malloc(size_t size) +{ + char vabuf[MAX_OSPATH + 1]; + char *tmpdir = getenv("TEMP"); + mmap_data_t *data; + int fd; + size += sizeof(mmap_data_t); // waste block + dpsnprintf(vabuf, sizeof(vabuf), "%s/darkplaces.XXXXXX", tmpdir ? tmpdir : "/tmp"); + fd = mkstemp(vabuf); + if(fd < 0) + return NULL; + ftruncate(fd, size); + data = (unsigned char *) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd, 0); + close(fd); + unlink(vabuf); + if(!data) + return NULL; + data->len = size; + return (void *) (data + 1); +} +static void mmap_free(void *mem) +{ + mmap_data_t *data; + if(!mem) + return; + data = ((mmap_data_t *) mem) - 1; + munmap(data, data->len); +} +#define malloc mmap_malloc +#define free mmap_free +#endif + #if MEMCLUMPING != 2 // some platforms have a malloc that returns NULL but succeeds later // (Windows growing its swapfile for example)