]> de.git.xonotic.org Git - voretournament/voretournament.git/commitdiff
Update the darkplaces engine source
authorMirceaKitsune <sonichedgehog_hyperblast00@yahoo.com>
Sun, 18 Mar 2012 21:26:27 +0000 (23:26 +0200)
committerMirceaKitsune <sonichedgehog_hyperblast00@yahoo.com>
Sun, 18 Mar 2012 21:26:27 +0000 (23:26 +0200)
91 files changed:
misc/source/darkplaces-src/bspfile.h
misc/source/darkplaces-src/cl_demo.c
misc/source/darkplaces-src/cl_gecko.c [deleted file]
misc/source/darkplaces-src/cl_gecko.h [deleted file]
misc/source/darkplaces-src/cl_input.c
misc/source/darkplaces-src/cl_main.c
misc/source/darkplaces-src/cl_parse.c
misc/source/darkplaces-src/cl_particles.c
misc/source/darkplaces-src/cl_screen.c
misc/source/darkplaces-src/client.h
misc/source/darkplaces-src/clvm_cmds.c
misc/source/darkplaces-src/cmd.c
misc/source/darkplaces-src/common.c
misc/source/darkplaces-src/common.h
misc/source/darkplaces-src/console.c
misc/source/darkplaces-src/crypto.c
misc/source/darkplaces-src/crypto.h
misc/source/darkplaces-src/csprogs.c
misc/source/darkplaces-src/csprogs.h
misc/source/darkplaces-src/dpdefs/csprogsdefs.qc
misc/source/darkplaces-src/dpdefs/dpextensions.qc
misc/source/darkplaces-src/dpdefs/keycodes.qc [new file with mode: 0644]
misc/source/darkplaces-src/dpdefs/menudefs.qc
misc/source/darkplaces-src/dpdefs/progsdefs.qc
misc/source/darkplaces-src/dpsoftrast.c
misc/source/darkplaces-src/dpsoftrast.h
misc/source/darkplaces-src/draw.h
misc/source/darkplaces-src/fs.c
misc/source/darkplaces-src/gl_backend.c
misc/source/darkplaces-src/gl_draw.c
misc/source/darkplaces-src/gl_rmain.c
misc/source/darkplaces-src/gl_rsurf.c
misc/source/darkplaces-src/gl_textures.c
misc/source/darkplaces-src/host.c
misc/source/darkplaces-src/host_cmd.c
misc/source/darkplaces-src/image.c
misc/source/darkplaces-src/image_png.c
misc/source/darkplaces-src/lhnet.c
misc/source/darkplaces-src/libcurl.c
misc/source/darkplaces-src/makefile
misc/source/darkplaces-src/makefile.inc
misc/source/darkplaces-src/mathlib.c
misc/source/darkplaces-src/matrixlib.c
misc/source/darkplaces-src/matrixlib.h
misc/source/darkplaces-src/menu.c
misc/source/darkplaces-src/mod_skeletal_animatevertices_generic.c
misc/source/darkplaces-src/mod_skeletal_animatevertices_sse.c
misc/source/darkplaces-src/model_alias.c
misc/source/darkplaces-src/model_brush.c
misc/source/darkplaces-src/model_brush.h
misc/source/darkplaces-src/model_shared.c
misc/source/darkplaces-src/model_shared.h
misc/source/darkplaces-src/mvm_cmds.c
misc/source/darkplaces-src/netconn.c
misc/source/darkplaces-src/progs.h
misc/source/darkplaces-src/protocol.c
misc/source/darkplaces-src/protocol.h
misc/source/darkplaces-src/prvm_cmds.c
misc/source/darkplaces-src/prvm_edict.c
misc/source/darkplaces-src/prvm_offsets.h
misc/source/darkplaces-src/quakedef.h
misc/source/darkplaces-src/r_shadow.c
misc/source/darkplaces-src/r_textures.h
misc/source/darkplaces-src/render.h
misc/source/darkplaces-src/screen.h
misc/source/darkplaces-src/server.h
misc/source/darkplaces-src/shader_glsl.h
misc/source/darkplaces-src/shader_hlsl.h
misc/source/darkplaces-src/snd_main.c
misc/source/darkplaces-src/snd_wav.c
misc/source/darkplaces-src/sv_main.c
misc/source/darkplaces-src/sv_phys.c
misc/source/darkplaces-src/svn-eol-style-from-gitattributes.sh [new file with mode: 0644]
misc/source/darkplaces-src/svvm_cmds.c
misc/source/darkplaces-src/sys_shared.c
misc/source/darkplaces-src/thread.h
misc/source/darkplaces-src/thread_null.c
misc/source/darkplaces-src/thread_pthread.c
misc/source/darkplaces-src/thread_sdl.c
misc/source/darkplaces-src/thread_win.c
misc/source/darkplaces-src/utf8lib.c
misc/source/darkplaces-src/utf8lib.h
misc/source/darkplaces-src/vid_sdl.c
misc/source/darkplaces-src/vid_shared.c
misc/source/darkplaces-src/vid_wgl.c
misc/source/darkplaces-src/view.c
misc/source/darkplaces-src/wad.c
misc/source/darkplaces-src/wad.h
misc/source/darkplaces-src/world.c
misc/source/darkplaces-src/world.h
misc/source/darkplaces-src/zone.c

index 648b294d4d978abe79a58a7ceb7a87fc4204a81d..e29a9f3946560aa47f0790bfbd059e794d163a01 100644 (file)
@@ -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;
+*/
 
index e60ac367d64fa0760c4a0d10a2c24ff652a0f8b2..1584cb7bf19e59f462b4390be656e0637a5c7a97 100644 (file)
@@ -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 (file)
index e66482d..0000000
+++ /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 <assert.h>
-#include <stdlib.h>
-#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, &paramStr)) 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 <name>\npcreates a browser (full texture path " CLGECKOPREFIX "<name>)\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 <name>\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 <name> <URI>\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 <name> <text>\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 <name> <x> <y>\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 (file)
index c95b410..0000000
+++ /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
-
index af5289f58690c2ae48adebf1a4dba695966224b4..2dd21acd06d6a296af379bc67e10cfd42781b988 100644 (file)
@@ -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
+               // <LordHavoc> 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");
index cb03ffab1d8154ec72a966686125934eb6d30008..94562c275b4e95bed839b2cee5f65f6ed03b8f31 100644 (file)
@@ -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();
 }
-
-
-
index 55e1a79a50410d36793ffaba9c3db78f2838639e..9e414372afeba4ea282a2578d5baec6c2d157c5e 100644 (file)
@@ -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)
        {
index 01e9701c2f44e93f2ae6f7876a421e81fc6a27ae..1e7a909d70a4fdec9875e3ffcf927a0ddbb6bd8a 100644 (file)
@@ -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++;
                                        }
                                }
index 7724b5ce28c0a54a8e62a87a6ee61049062476da..f1ae56690bc8dac6392aac19e08c7f93dfa67e9e 100644 (file)
@@ -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)
index f28e5adb78cdfef974f843555895af22ac927d90..9f86fdab75e63922b2b7a4f4c2c6ab3aeff09b1f 100644 (file)
@@ -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);
 
index f07cf854b2535918929c3508540ee4441f649fa4..d03b632e619d79f715dc7b0b8ea906782c837fd8 100644 (file)
@@ -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);
index 0a42ca4a093d2ad9d59882ea45e6a78d52114efc..beee312d053ec2130607c22c0e916550098b9217 100644 (file)
@@ -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)
 
index ada40e20ca8dbd2dd601e094949cd0e94864185f..3b986194ad7720612a9eeb5b04b91d112f47db9b 100644 (file)
@@ -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;
index e91be28379d9830d08f76523874c35dfb02c63bd..8a6dbd2a62534bfcf4f402ac14793cac3f195c08 100644 (file)
@@ -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
index 14175b07ad4c37cd84ea4e0202c438c43365c098..e21f2cbfb4c88abb54e51b0f49ad3a4d3a6fc390 100644 (file)
@@ -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]));
        }
 }
 
index 09c164e2293240baf404a1138bc3759ae86ea4d6..30b9bd86ab21cb384c5ffce3415d4e0ef8706829 100644 (file)
@@ -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");
index 7edfcd98a389af04ed25559a62de798ebb2fa851..ddc00a92cd24e00455e4a69b30acecd120ca7548 100644 (file)
@@ -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);
index 47573d3cf8cc446661775e2d4d0cb6d4238f8eb7..7faa88772e0f86a74ed9a9de99b4acf2c224e3f4 100644 (file)
@@ -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;
+}
index 2aba12b389140b9ad5de7595b191ebdcf324a677..02fa972aee3dafde0fc7f519fbae610c770e6528 100644 (file)
 #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
index 8fa52e44af7920fca8fb490b381e1f7c9650946a..2d376d4fe41cf0f16832856850e3239cda1b72f5 100644 (file)
@@ -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: <argpos>$ for the argument to format
+//  flags: #0- +
+//  optional: <width>, *, or *<argpos>$ for the field width
+//  optional: .<precision>, .*, or .*<argpos>$ 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;
index 8d2148843e9aa27fb9ab84e579a543482ae75c3c..0acf262b113f212500a08f2e511bb1b81510e569 100644 (file)
@@ -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 (file)
index 0000000..7694573
--- /dev/null
@@ -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;
+
index b23e6baf7af7673bb1d910de57690205253cdbbc..ad8666ed3548786759d2faeb6b9c59dcd5711377 100644 (file)
@@ -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;
index 2904f7db82277257d4ec07833b22a6826d06afc4..912c3ecabe18bee45be837d061a6a388f684376b 100644 (file)
@@ -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;
index a79a9d363aee62cc8b45416277d572eca511b601..4967ef0eb7214422093812fcc5714571fdf153af 100644 (file)
@@ -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);
 }
 
index 9bd1d010b93e04fd2ee1ec236e2efaec433c1074..eb3df2bae40d5c10b60c8dbdbad305e1eba87515 100644 (file)
@@ -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;
 
index 5cb62afa8f84919e53099963aa68b25ac6170be5..1daa5eb0d45b602d7f3358789309a770652ec9b3 100644 (file)
@@ -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
 {
index 93768046d58dbe73e3b2049bb121e55ae920d893..e21a58395b99b6c775903f96bdda2ce20e5f8234 100644 (file)
@@ -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;
                                }
index 8df14f8e1da990268ea13c0e6ca26e9ec5e30ee0..fefedcb37402264b7905d670225ee3d04d9f69e3 100644 (file)
@@ -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++)
index 05d6c92527fefa1c570359d3a4e8e84f51f90981..17213e566db0be1d09e6ca02d42d9e59f1cf59f2 100644 (file)
@@ -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;
index 6c26b8de7040514c4269c65a585f824a9255e8cf..184aa423735a66bf58ad14bf7cd5d503f2b7f41c 100644 (file)
@@ -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 fdd<fd because this follows from fa < r_equalize_entities_minambient.value * fd
-                                                       VectorMA(ent->modellight_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 fdd<fd because this follows from fa < r_equalize_entities_minambient.value * fd
+                                                               VectorMA(ent->modellight_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
index bc37840189571356248e4155bdcc121cbdcca064..2d0f4795316ea88aa4cbbb70e52cd83086a4af13 100644 (file)
@@ -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);
                        }
index 2a81cf50b3e15caca48b98d78733c7b9b1a7bc5b..57c257f27d85d1ecfff4e5909a8e8a426d8c4ef9 100644 (file)
@@ -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)
                {
index a8a8e0de767d63be34b39acf583f824f0e9aea70..2e5030350f4f8a40e2c26189c8cbf7a77cc4eb58 100644 (file)
@@ -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();
        }
 
index e5d477cb3b15bd117d6078e8698baa107f0f50e1..350cef0ddf9336d26a27cdd046683009d981f9bf 100644 (file)
@@ -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;
index 988fbef8e7f27b4a8abcfaf89edb8e92cecea14e..4f85e83e43281148ab1be7af31913e56ce77f888 100644 (file)
@@ -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)
index 9c03f8f3c05be418a2cd97c36a243281e06d6a2e..f71dfdea71eedd45a5597e458cbd403848e87c25 100644 (file)
@@ -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);
index cb87b6d319e2ae866f94ca9bf11d1856120aa9cd..c07866adaaf31cc039f58aac2179914fea24d956 100644 (file)
@@ -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;
index 637a649dcd16269961417d3c18acc27512c65099..3baa91b466f6da44b993a826a2f0cc2078bb1501 100644 (file)
@@ -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)");
 }
index 7a8a4cfb9ca05a986c69e8c5ac4eb15dab907519..35de328396cb28f3f0d9338264f4e9082d901409 100644 (file)
@@ -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
index 409cd2ec22f0486f12c00e1e9f77f1ad06c01a72..d04e5f866d331853f9ce5a90d981ece0cd05608c 100644 (file)
@@ -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
-
index dae0de50ba070a4f144e6830e47e5fa4da125700..b4a1b6a0b1d847032cd783c05b4d5975fb6455fd 100644 (file)
@@ -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
index f84e922d506dce80ac34ed6e69f081b59d1b56eb..78c859cfed39673b9e6f7f6628ca8dae90c91e50 100644 (file)
@@ -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]);
 }
 
index ae83c1d68901cab73bf8642990b7ebb8bde2f7cf..eb926a107ef1451f3dffcd0f3ed2390d0a9276a0 100644 (file)
@@ -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);
index eb741b2a2437a9033bebcd1939d7b01de28e342a..149e8421bed608d309e0851a692ab3a0441fa74d 100644 (file)
@@ -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)
index 00ab435d9661176aeb80ba1baee7a087ffed448a..bc26811701a1184e7e5ed635061a1b83b2d06634 100644 (file)
@@ -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;
index f575d24522db67e7b2d3f604e639905f8d6706c4..648ab31a15460b7f333e6a8686d8df28bbbc554c 100644 (file)
@@ -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);
+                       }       
                }
        }
 
index 7a53d59e4a14051f8db336716db287824559c7f6..6c212aa5339f298ce3a128daa6276e8e50ef4a3c 100644 (file)
@@ -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];
                        }
                }
        }
index eca6546481101dedfd507574e689578fe36e6d35..23fa6d48504e31372ab7e6d607d59acf91380ca6 100644 (file)
@@ -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; i<l->filelen; 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 ; i<count ; i++, in++, out++)
+       for ( i=0 ; i<count ; i++, out++)
        {
-               out->position[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 ; i<count ; i++, in++, out++)
+       for ( i=0 ; i<count ; i++, out++)
        {
-               out->v[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 ; i<count ; i++, in++, out++)
+       for ( i=0 ; i<count ; i++, out++)
        {
-               for (j=0 ; j<3 ; j++)
+               p = MSG_ReadLittleLong(sb);
+               out->plane = 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 ; i<count ; i++, in++, out++)
+       // FIXME: this function could really benefit from some error checking
+       for ( i=0 ; i<count ; i++, out++)
        {
-               for (j=0 ; j<3 ; j++)
-               {
-                       out->mins[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 ; i<count ; i++, out++, in++)
+       for (i=0 ; i<count ; i++, out++)
        {
-               out->planenum = 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;
index f1b60e0e7dc15b79a80eb01f1a99e4259316345b..8020d14ab7990154ef71dc402feebdfc01c616fc 100644 (file)
@@ -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
index 2afe928b13d5daee77c506d932ce7f34550f1ea3..5c000bfa7ba0e53bc4d4433456c80aa9739fafbc 100644 (file)
@@ -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;
index 747bec0cfb32b39b703156937e1b638ff1aba4c9..07e840d3873996c562002f779f3dd1973be71769 100644 (file)
@@ -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;
 
index e90dcdec6e5e38921925775aebc845f4851b39fa..79edacfb2fa365c1c414912d482281f22fb8fac9 100644 (file)
@@ -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
 };
 
index c5858c807155edf82ede94d42a7ec2768bf6e91b..395f6d3303219460de5a8199cc6dd3fc58bb3cb0 100644 (file)
@@ -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);
index 72813bbf4d9a93c540153414729ec826bcf05c4e..ed09789348b875603afea26860077ed1edbae2b7 100644 (file)
@@ -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;
index d63d0918af10111711fda04ef9eafd38248bfa8c..29999302e3b69f7fa170139b43956a10a43d5a2f 100644 (file)
@@ -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");
        }
 }
index 9d694f0f10eb397eb9c2e503a237e9c82ed8018f..3c0c6ce68dbdbc7af78a9a1433ba8dd6ef18f95a 100644 (file)
@@ -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
index 7f1900d9826f6d44d3799b78e01b1803bcd7197a..b7ae1881bac3c13ce0d97cbf1577ddd8937c51a5 100644 (file)
@@ -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);
 }
index 25f9899af9f434cbbf1ee15af061596e5e9c72be..6dc2a6e871d8d9963bdf69ee0104946429a0b5c6 100644 (file)
@@ -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)
index 09ac75edcc95298ae85aba795704ffcc443cfc39..f6c118a0166fd03af75ba942a9f8e0c844cb2af2 100644 (file)
@@ -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)
index 65f241590335bffd34d37b7bbe89ae4193a9872d..66fdfb308c9ccffec4f6be4de38e7b5cece082d5 100644 (file)
@@ -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);
index adec83e15b337ff8a42e49981fdb8679e53a3be1..bdf4f2c5d0b0f9cdd7422f3099c88a1bb28c7325 100644 (file)
@@ -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++)
index 594fcad2a654f7d07fefcbd6740045a21e638f99..e9c9aabae86c5ee0bbcfe7f5e843d0c7b8b3eac1 100644 (file)
@@ -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);
index c869615a2fed6362c19e6e2acbe3ce38253bd4c6..7e60e5048e08878cf69fb38f5744edbb813ee768 100644 (file)
@@ -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
index b88a80d53ca1cf0f15d7ae81b543f6d612eb3ce9..68a2998d78535d730dc3eb4398645f96d63e4bf0 100644 (file)
@@ -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
index 5d399607ca1ea7717ded40dce8dbd944f0e160a3..3be5510ef64b9a0710631889249fdb5d939ecf79 100644 (file)
@@ -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);
index c133ba280471c088e5831bea5c5aae3fea232a1e..41dac64ef0f84762f7ae4d98eddee39658042fd5 100644 (file)
 "#ifdef USESPECULAR\n"
 "dp_varying mediump vec2 TexCoord2;\n"
 "#endif\n"
+"uniform myhalf Alpha;\n"
 "#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
 "      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"
 "\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"
 "      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"
 "      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"
 "\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"
 "      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"
 "      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"
 "      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"
 "{\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"
 "      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"
 "#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"
 "      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"
index f20f8329e7ad7d45a651175e789ad3fb857b84e3..20770d187a3f108f57737ec630042762ffb09831 100644 (file)
 "#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"
 "      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"
 "(\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"
 "#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"
 "      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"
 "      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"
 "(\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"
 "#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"
 "      //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"
 "      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"
 "      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"
 "#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"
 "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"
 "      //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"
index 71f8b4d73e80c6612f7c3c32677ba22a440bf4b0..1fb7cd54d8e7433d84c8645feba33dcdbeb99664 100644 (file)
@@ -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);
 }
 
 
index 258b501c4d7cf08c6e132f7987f481147c6bb5b5..6f861913335007bb2f155a68aa5b672c16cdaaee 100644 (file)
@@ -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;
index 27befbcfcea47edb3f5cf4a20589c50a9a3bee7c..b2e70f3b31b02d779bc8190d4d0d9f932a769956 100644 (file)
@@ -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;
                }
 
index c88ff4c452193c721fa782bb2844169c824ff836..e063526fbcbe26968947ec2c517c6dc634f28221 100644 (file)
@@ -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 (file)
index 0000000..7c1085c
--- /dev/null
@@ -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
index 3bb77ef654990f94c9e224736a778fa5f9b46412..a850abe37024d73716e9b8dbbf1f501a1e9084fe 100644 (file)
@@ -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;
index d033323a9d0f161be28698dea7bf3ef0d0bac411..10f5a60e5d7126a145188698246ddeb23479840c 100644 (file)
@@ -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
 
index 5ba9be8ffa166f49a190f676edabaf3fb02164e5..7f590a47dd62f355e89be3435adb4da0ea33540d 100644 (file)
@@ -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
-
index c7d439c90cf2538b5f533e13a6ab68eeb992dd69..35c4e4b5f4cf319a3d285b8d8a60504c46144d81 100644 (file)
@@ -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)
+{
+}
index 9340403ebb91cbc39a992401004a9de8bb1e7fe6..e86b2c3828fde8c2a5f387290ed38d9e11ca270c 100644 (file)
@@ -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
index 64006dbfb6242fbc1cb05a6c90fce7ac3461552e..d7fd1737358449bb1f587cb76e6a769ca88be847 100644 (file)
@@ -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);
+}
index 893e8306048ede60d060f24efbe3e5c9b8669a23..8564ca195dd64fa416f4557efe3a871fe535c59e 100644 (file)
@@ -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);
+}
index 8994bd7a00a697e124779b86318919aea0d5aaf9..76cc813766d944ed399efdb03f633524ace59187 100644 (file)
@@ -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
index 36c16fe1444d967a255cbe11d87f2904929f6d8b..543fbfc0ed1c886e578d61a65218cdb17cb190dd 100644 (file)
@@ -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
index 97433653fdeb9bfc8409aa6a2f4d1e951ed3c443..88c8e6055f33903233018eb4ca355b2357525041 100644 (file)
@@ -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;
 }
index 9f24869d4cea01848a8ca44551fea8bdd8cdd921..7d8485c336cb7f091acf576d8f02054caf115ea2 100644 (file)
@@ -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;
index 3f7d177dcd1aac21a30ed04e519bd986c5f01a63..cb74dea9357b714510a3a5a70c2f372b09e28fcb 100644 (file)
@@ -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;
index e5bdad5999b59d828bc91164052f1efc2b43ba1f..851c57d14d34ef791224b837587511eb403cb2cb 100644 (file)
@@ -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
        {
index a07f87bb135560c919b9564c038cc8b337b85eaf..4e714b0b2712cfad3b6d9433abf5e8db5a58f929 100644 (file)
@@ -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;
                        }
                }
index b5ab8dbaa2dd7fb1948aa793818ff8f2e7dc3cd9..3c4297d940efd4cc1e41751130b8db3491ef6eaf 100644 (file)
@@ -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
 
index 1225090c626d57c03f04e42ecbfbf65f22495ccd..0becd8a8ddd59645fcda6ae944b38e33c934a235 100644 (file)
@@ -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));
                        }
                }
        }
index 122b9c708a635d959f66780fd8bf6857ad31c612..18e9b00155b1bac6dec53d99449c2de3974c4ae8 100644 (file)
@@ -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);
index 02920535287b75970eaf7f258849f75cd2204748..2f756d0ea803601a9d7d2ce64368f889516068d3 100644 (file)
@@ -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 <stdlib.h>
+#include <sys/mman.h>
+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)