networked entity editing now kinda working. still needs much more work before its usable.

try to use microsoft's poor-man's eax stuff with directsound. snd_eax is disabled by default still thankfully.
some hlmdl fixes

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5029 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2016-12-07 18:45:25 +00:00
parent 4925e5f842
commit 5ded3710b4
39 changed files with 1532 additions and 803 deletions

View File

@ -1164,7 +1164,7 @@ float CL_FilterTime (double time, float wantfps, qboolean ignoreserver) //now re
{
if (!wantfps)
return -1;
fps = max (30.0, wantfps);
fps = max (1.0, wantfps);
}
else
{

View File

@ -1341,24 +1341,25 @@ char *CG_GetConfigString(int num);
//
#ifdef CSQC_DAT
qboolean CSQC_Inited(void);
void CSQC_RendererRestarted(void);
void CSQC_RendererRestarted(void);
qboolean CSQC_UnconnectedOkay(qboolean inprinciple);
qboolean CSQC_UnconnectedInit(void);
qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checksum);
qboolean CSQC_ConsoleLink(char *text, char *info);
void CSQC_RegisterCvarsAndThings(void);
void CSQC_RegisterCvarsAndThings(void);
qboolean CSQC_SetupToRenderPortal(int entnum);
qboolean CSQC_DrawView(void);
qboolean CSQC_UseGamecodeLoadingScreen(void);
void CSQC_Shutdown(void);
void CSQC_Shutdown(void);
qboolean CSQC_StuffCmd(int lplayernum, char *cmd, char *cmdend);
void CSQC_MapEntityEdited(int idx, const char *newe);
qboolean CSQC_LoadResource(char *resname, char *restype);
qboolean CSQC_ParsePrint(char *message, int printlevel);
qboolean CSQC_ParseGamePacket(void);
qboolean CSQC_CenterPrint(int lplayernum, char *cmd);
qboolean CSQC_Parse_Damage(float save, float take, vec3_t source);
void CSQC_Input_Frame(int lplayernum, usercmd_t *cmd);
void CSQC_WorldLoaded(void);
void CSQC_Input_Frame(int lplayernum, usercmd_t *cmd);
void CSQC_WorldLoaded(void);
qboolean CSQC_ParseTempEntity(void);
qboolean CSQC_ConsoleCommand(char *cmd);
qboolean CSQC_KeyPress(int key, int unicode, qboolean down, unsigned int devid);
@ -1367,16 +1368,16 @@ qboolean CSQC_MousePosition(float xabs, float yabs, unsigned int devid);
qboolean CSQC_JoystickAxis(int axis, float value, unsigned int devid);
qboolean CSQC_Accelerometer(float x, float y, float z);
qboolean CSQC_Gyroscope(float x, float y, float z);
int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float vol, float attenuation, float pitchmod, float timeofs, unsigned int flags);
void CSQC_ParseEntities(void);
void CSQC_ResetTrails(void);
int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float vol, float attenuation, float pitchmod, float timeofs, unsigned int flags);
void CSQC_ParseEntities(void);
void CSQC_ResetTrails(void);
qboolean CSQC_DeltaPlayer(int playernum, player_state_t *state);
void CSQC_DeltaStart(float time);
void CSQC_DeltaStart(float time);
qboolean CSQC_DeltaUpdate(entity_state_t *src);
void CSQC_DeltaEnd(void);
void CSQC_DeltaEnd(void);
void CSQC_CvarChanged(cvar_t *var);
void CSQC_CvarChanged(cvar_t *var);
#else
#define CSQC_UnconnectedOkay(inprinciple) false
#define CSQC_UnconnectedInit() false

View File

@ -73,6 +73,7 @@ cvar_t con_separatechat = CVAR("con_separatechat", "0");
cvar_t con_timestamps = CVAR("con_timestamps", "0");
cvar_t con_timeformat = CVAR("con_timeformat", "(%H:%M:%S) ");
cvar_t con_textsize = CVARD("con_textsize", "8", "Resize the console text to be a different height, scaled separately from the hud. The value is the height in (virtual) pixels.");
extern cvar_t log_developer;
#define NUM_CON_TIMES 24
@ -1064,9 +1065,9 @@ void VARGS Con_SafeTPrintf (translation_t text, ...)
static void Con_DPrintFromThread (void *ctx, void *data, size_t a, size_t b)
{
if (!developer.value)
if (log_developer.ival)
Con_Log(data);
else
if (developer.ival)
{
Sys_Printf ("%s", (const char*)data); // also echo to debugging console
Con_PrintCon(&con_main, data, con_main.parseflags);
@ -1092,8 +1093,7 @@ void VARGS Con_DPrintf (const char *fmt, ...)
Sys_Printf("%s", msg);
return;
#else
extern cvar_t log_developer;
if (!developer.value && !log_developer.value)
if (!developer.ival && !log_developer.ival)
return; // early exit
#endif
@ -1103,14 +1103,13 @@ void VARGS Con_DPrintf (const char *fmt, ...)
if (!Sys_IsMainThread())
{
if (developer.ival)
COM_AddWork(WG_MAIN, Con_DPrintFromThread, NULL, Z_StrDup(msg), 0, 0);
COM_AddWork(WG_MAIN, Con_DPrintFromThread, NULL, Z_StrDup(msg), 0, 0);
return;
}
if (!developer.value)
if (log_developer.ival)
Con_Log(msg);
else
if (developer.ival)
{
Sys_Printf ("%s", msg); // also echo to debugging console
if (con_initialized)

View File

@ -1798,7 +1798,7 @@ static char *PM_GetTempName(package_t *p)
return Z_StrDup(destname);
}
static void PM_AddDownloadedPackage(const char *filename)
/*static void PM_AddDownloadedPackage(const char *filename)
{
char pathname[1024];
package_t *p;
@ -1822,7 +1822,7 @@ static void PM_AddDownloadedPackage(const char *filename)
p->license = NULL;
p->author = NULL;
p->previewimage = NULL;
}
}*/
int PM_IsApplying(void)
{
@ -2041,6 +2041,8 @@ static void PM_ApplyChanges(void)
PM_StartADownload(); //and try to do those downloads.
}
//names packages that were listed from the manifest.
//if 'mark' is true, then this is an initial install.
void PM_ManifestPackage(const char *metaname, qboolean mark)
{
domanifestinstall = mark;
@ -2298,6 +2300,9 @@ void Menu_Download_Update(void)
void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri)
{
}
void PM_ManifestPackage(const char *metaname, qboolean mark)
{
}
void PM_Shutdown(void)
{
}

View File

@ -2832,6 +2832,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
const char *fname;
shader_t *shader;
vec2_t fs = {8,8};
float bones[12*MAX_BONES];
modelview_t *mods = c->dptr;
@ -2887,9 +2888,19 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
ent.shaderTime = 0;//realtime;
ent.framestate.g[FS_REG].lerpweight[0] = 1;
ent.framestate.g[FS_REG].frame[0] = mods->framegroup;
ent.framestate.g[FS_REG].frametime[0] = realtime - mods->framechangetime;
ent.framestate.g[FS_REG].frametime[1] = realtime - mods->framechangetime;
ent.framestate.g[FS_REG].frametime[0] = ent.framestate.g[FS_REG].frametime[1] = realtime - mods->framechangetime;
ent.customskin = Mod_RegisterSkinFile(va("%s_0.skin", mods->modelname));
// ent.framestate.bonecount = Mod_GetNumBones(ent.model, false);
ent.framestate.bonestate = bones;
ent.framestate.bonecount = Mod_GetBoneRelations(ent.model, 0, MAX_BONES, &ent.framestate, ent.framestate.bonestate);
ent.framestate.skeltype = SKEL_RELATIVE;
ent.light_avg[0] = ent.light_avg[1] = ent.light_avg[2] = 0.66;
ent.light_range[0] = ent.light_range[1] = ent.light_range[2] = 0.33;
ent.light_dir[0] = 0; ent.light_dir[1] = 1; ent.light_dir[2] = 0;
ent.light_known = 2;
V_AddEntity(&ent);
V_ApplyRefdef();

View File

@ -161,6 +161,7 @@ enum mlverbosity_e
const char *Mod_GetEntitiesString(struct model_s *mod);
void Mod_SetEntitiesStringLen(struct model_s *mod, const char *str, size_t strsize);
void Mod_SetEntitiesString(struct model_s *mod, const char *str, qboolean docopy);
void Mod_ParseEntities(struct model_s *mod);
extern void Mod_ClearAll (void);
extern void Mod_Purge (enum mod_purge_e type);
extern struct model_s *Mod_FindName (const char *name); //find without loading. needload should be set.

View File

@ -126,6 +126,8 @@ extern sfx_t *cl_sfx_r_exp3;
globalfunction(loadresource, "CSQC_LoadResource");/*EXT_CSQC_1*/ \
globalfunction(parse_tempentity, "CSQC_Parse_TempEntity");/*EXT_CSQC_ABSOLUTLY_VILE*/ \
\
globalfunction(mapentityedited, "CSQC_MapEntityEdited");\
\
/*These are pointers to the csqc's globals.*/ \
globalfloat(simtime, "time"); /*float The simulation(aka: smoothed server) time, speed drifts based upon latency*/ \
globalfloat(frametime, "frametime"); /*float Client render frame interval*/ \
@ -1504,14 +1506,13 @@ void QCBUILTIN PF_R_AddTrisoup(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
unsigned int vertsptr = G_INT(OFS_PARM2);
unsigned int indexesptr = G_INT(OFS_PARM3);
unsigned int numindexes = G_INT(OFS_PARM4);
qboolean twod = qcflags & 4;
qboolean twod = qcflags & DRAWFLAG_2D;
unsigned int beflags;
unsigned int numverts;
qcvertex_t *vert;
unsigned int *idx;
unsigned int i, j, first;
if ((qcflags & 3) == DRAWFLAG_ADD)
beflags = BEF_NOSHADOWS|BEF_FORCEADDITIVE;
else if ((qcflags & 3) == DRAWFLAG_MODULATE)
@ -1536,9 +1537,7 @@ void QCBUILTIN PF_R_AddTrisoup(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
//validates the pointer.
numverts = (prinst->stringtablesize - vertsptr) / sizeof(qcvertex_t);
if (numverts < 1)
numverts = 1;
if (vertsptr <= 0 || vertsptr+numverts*sizeof(qcvertex_t) >= prinst->stringtablesize)
if (numverts < 1 || vertsptr <= 0 || vertsptr+numverts*sizeof(qcvertex_t) >= prinst->stringtablesize)
{
PR_BIError(prinst, "PF_R_AddTrisoup: invalid vertexes pointer\n");
return;
@ -7611,6 +7610,18 @@ qboolean CSQC_ParseGamePacket(void)
return true;
}
void CSQC_MapEntityEdited(int idx, const char *newe)
{
void *pr_globals;
if (!csqcprogs || !csqcg.mapentityedited)
return;
pr_globals = PR_globals(csqcprogs, PR_CURRENT);
G_INT(OFS_PARM0) = idx;
(((string_t *)pr_globals)[OFS_PARM1] = PR_TempString(csqcprogs, newe));
PR_ExecuteProgram (csqcprogs, csqcg.mapentityedited);
}
qboolean CSQC_LoadResource(char *resname, char *restype)
{
void *pr_globals;

View File

@ -4,13 +4,13 @@
#ifndef SERVERONLY
#include "shader.h"
#endif
#include "com_mesh.h"
//FIXME: shadowmaps should build a cache of the nearby area surfaces and flag those models as RF_NOSHADOW or something
//fixme: merge areas and static ents too somehow.
void Mod_SetParent (mnode_t *node, mnode_t *parent);
static int D3_ClusterForPoint (struct model_s *model, vec3_t point);
void R_Generate_Mesh_ST_Vectors(mesh_t *mesh);
#ifndef SERVERONLY
void ModD3_GenAreaVBO(void *ctx, void *data, size_t a, size_t b)

View File

@ -2347,6 +2347,7 @@ void Surf_SetupFrame(void)
{
mleaf_t *leaf;
vec3_t temp, pvsorg;
int viewcontents;
if (!cl.worldmodel || (!cl.worldmodel->nodes && cl.worldmodel->type != mod_heightmap))
r_refdef.flags |= RDF_NOWORLDMODEL;
@ -2364,7 +2365,7 @@ void Surf_SetupFrame(void)
R_UpdateHDR(r_refdef.vieworg);
}
r_viewcontents = 0;
viewcontents = 0;
if (r_refdef.flags & RDF_NOWORLDMODEL)
{
}
@ -2385,7 +2386,7 @@ void Surf_SetupFrame(void)
r_viewleaf2 = NULL;
leaf = Mod_PointInLeaf (cl.worldmodel, pvsorg);
r_viewcontents = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, pvsorg);
viewcontents = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, pvsorg);
r_viewcluster = r_viewcluster2 = leaf->cluster;
// check above and below so crossing solid water doesn't draw wrong
@ -2449,22 +2450,22 @@ void Surf_SetupFrame(void)
switch(r_viewleaf->contents)
{
case Q1CONTENTS_WATER:
r_viewcontents |= FTECONTENTS_WATER;
viewcontents |= FTECONTENTS_WATER;
break;
case Q1CONTENTS_LAVA:
r_viewcontents |= FTECONTENTS_LAVA;
viewcontents |= FTECONTENTS_LAVA;
break;
case Q1CONTENTS_SLIME:
r_viewcontents |= FTECONTENTS_SLIME;
viewcontents |= FTECONTENTS_SLIME;
break;
case Q1CONTENTS_SKY:
r_viewcontents |= FTECONTENTS_SKY;
viewcontents |= FTECONTENTS_SKY;
break;
case Q1CONTENTS_SOLID:
r_viewcontents |= FTECONTENTS_SOLID;
viewcontents |= FTECONTENTS_SOLID;
break;
case Q1CONTENTS_LADDER:
r_viewcontents |= FTECONTENTS_LADDER;
viewcontents |= FTECONTENTS_LADDER;
break;
}
}
@ -2473,7 +2474,7 @@ void Surf_SetupFrame(void)
#ifdef TERRAIN
if (!(r_refdef.flags & RDF_NOWORLDMODEL) && cl.worldmodel && cl.worldmodel->terrain)
{
r_viewcontents |= Heightmap_PointContents(cl.worldmodel, NULL, pvsorg);
viewcontents |= Heightmap_PointContents(cl.worldmodel, NULL, pvsorg);
}
#endif
@ -2484,12 +2485,16 @@ void Surf_SetupFrame(void)
VectorCopy(pmove.player_maxs, t2);
VectorClear(pmove.player_maxs);
VectorClear(pmove.player_mins);
r_viewcontents |= PM_ExtraBoxContents(pvsorg);
viewcontents |= PM_ExtraBoxContents(pvsorg);
VectorCopy(t1, pmove.player_mins);
VectorCopy(t2, pmove.player_maxs);
}
if (!r_secondaryview)
V_SetContentsColor (r_viewcontents);
if (!r_refdef.recurse)
{
r_viewcontents = viewcontents;
if (!r_secondaryview)
V_SetContentsColor (viewcontents);
}
if (r_refdef.playerview->audio.defaulted)

View File

@ -101,6 +101,7 @@ cvar_t r_wireframe = CVARFD ("r_wireframe", "0",
CVAR_CHEAT, "Developer feature where everything is drawn with wireframe over the top. Only active where cheats are permitted.");
cvar_t r_wireframe_smooth = CVAR ("r_wireframe_smooth", "0");
cvar_t r_refract_fbo = CVARD ("r_refract_fbo", "1", "Use an fbo for refraction. If 0, just renders as a portal and uses a copy of the current framebuffer.");
cvar_t r_refractreflect_scale = CVARD ("r_refractreflect_scale", "0.5", "Use a different scale for refraction and reflection. Because $reasons.");
cvar_t gl_miptexLevel = CVAR ("gl_miptexLevel", "0");
cvar_t r_drawviewmodel = CVARF ("r_drawviewmodel", "1", CVAR_ARCHIVE);
cvar_t r_drawviewmodelinvis = CVAR ("r_drawviewmodelinvis", "0");
@ -278,7 +279,7 @@ extern cvar_t r_drawentities;
extern cvar_t r_drawviewmodel;
extern cvar_t r_drawworld;
extern cvar_t r_fullbright;
cvar_t r_mirroralpha = CVARFD("r_mirroralpha","1", CVAR_CHEAT|CVAR_SHADERSYSTEM, "Specifies how the default shader is generated for the 'window02_1' texture. Values less than 1 will turn it into a mirror.");
cvar_t r_mirroralpha = CVARFD("r_mirroralpha","1", CVAR_CHEAT|CVAR_SHADERSYSTEM|CVAR_RENDERERLATCH, "Specifies how the default shader is generated for the 'window02_1' texture. Values less than 1 will turn it into a mirror.");
extern cvar_t r_netgraph;
cvar_t r_norefresh = CVAR("r_norefresh","0");
extern cvar_t r_novis;
@ -798,6 +799,7 @@ void Renderer_Init(void)
Cvar_Register (&r_wireframe, GRAPHICALNICETIES);
Cvar_Register (&r_wireframe_smooth, GRAPHICALNICETIES);
Cvar_Register (&r_refract_fbo, GRAPHICALNICETIES);
Cvar_Register (&r_refractreflect_scale, GRAPHICALNICETIES);
Cvar_Register (&r_postprocshader, GRAPHICALNICETIES);
Cvar_Register (&r_fxaa, GRAPHICALNICETIES);
Cvar_Register (&r_renderscale, GRAPHICALNICETIES);

View File

@ -20,27 +20,68 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "quakedef.h"
#include "winquake.h"
#include <dsound.h>
#ifndef DECLSPEC_SELECTANY
#define DECLSPEC_SELECTANY
#endif
#define FORCE_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
EXTERN_C const GUID DECLSPEC_SELECTANY name \
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
#if _MSC_VER <= 1200
DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93);
DEFINE_GUID(IID_IDirectSound, 0x279AFA83, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60);
#else
FORCE_DEFINE_GUID(IID_IDirectSound, 0x279AFA83, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60);
FORCE_DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93);
#endif
#ifdef AVAIL_DSOUND
#define iDirectSoundCreate(a,b,c) pDirectSoundCreate(a,b,c)
#define iDirectSoundEnumerate(a,b,c) pDirectSoundEnumerate(a,b)
//#define DIRECTSOUND_VERSION 0x800 //either < 0x800 (eax-only) or 0x800 (microsoft's fx stuff).
#include <dsound.h>
#if !defined(IDirectSoundFXI3DL2Reverb_SetAllParameters) && DIRECTSOUND_VERSION>=0x800
//mingw defines version as 0x900, but doesn't provide all the extra interfaces (only the core stuff).
//which makes it kinda pointless, so lets provide the crap that its missing.
typedef struct {
LONG lRoom;
LONG lRoomHF;
FLOAT flRoomRolloffFactor;
FLOAT flDecayTime;
FLOAT flDecayHFRatio;
LONG lReflections;
FLOAT flReflectionsDelay;
LONG lReverb;
FLOAT flReverbDelay;
FLOAT flDiffusion;
FLOAT flDensity;
FLOAT flHFReference;
} DSFXI3DL2Reverb;
typedef struct IDirectSoundFXI3DL2Reverb
{
struct
{
STDMETHOD(QueryInterface)(struct IDirectSoundFXI3DL2Reverb *this_, REFIID riid, LPVOID * ppvObj);
STDMETHOD_(ULONG,AddRef)(struct IDirectSoundFXI3DL2Reverb *this_);
STDMETHOD_(ULONG,Release)(struct IDirectSoundFXI3DL2Reverb *this_);
STDMETHOD(SetAllParameters)(struct IDirectSoundFXI3DL2Reverb *this_, const DSFXI3DL2Reverb *pcDsFxI3DL2Reverb);
//INCOMPLETE
} *lpVtbl;
} IDirectSoundFXI3DL2Reverb;
#define IDirectSoundFXI3DL2Reverb8 IDirectSoundFXI3DL2Reverb
#define IID_IDirectSoundFXI3DL2Reverb8 IID_IDirectSoundFXI3DL2Reverb
#define IDirectSoundFXI3DL2Reverb_Release(a) (a)->lpVtbl->Release(a)
#define IDirectSoundFXI3DL2Reverb_SetAllParameters(a,b) (a)->lpVtbl->SetAllParameters(a,b)
#endif
#if _MSC_VER <= 1200
#define FORCE_DEFINE_GUID DEFINE_GUID
#else
#ifndef DECLSPEC_SELECTANY
#define DECLSPEC_SELECTANY
#endif
#define FORCE_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
EXTERN_C const GUID DECLSPEC_SELECTANY name \
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
#endif
#if DIRECTSOUND_VERSION >= 0x0800
FORCE_DEFINE_GUID(IID_IDirectSoundBuffer8, 0x6825a449, 0x7524, 0x4d82, 0x92, 0x0f, 0x50, 0xe3, 0x6a, 0xb3, 0xab, 0x1e);
FORCE_DEFINE_GUID(IID_IDirectSound8, 0xC50A7E93, 0xF395, 0x4834, 0x9E, 0xF6, 0x7F, 0xA9, 0x9D, 0xE5, 0x09, 0x66);
FORCE_DEFINE_GUID(IID_IDirectSoundFXI3DL2Reverb, 0x4b166a6a, 0x0d66, 0x43f3, 0x80, 0xe3, 0xee, 0x62, 0x80, 0xde, 0xe1, 0xa4);
FORCE_DEFINE_GUID(GUID_DSFX_STANDARD_I3DL2REVERB, 0xef985e71, 0xd5c7, 0x42d4, 0xba, 0x4d, 0x2d, 0x07, 0x3e, 0x2e, 0x96, 0xf4);
HRESULT (WINAPI *pDirectSoundCreate8)(GUID FAR *lpGUID, LPDIRECTSOUND8 FAR *lplpDS, IUnknown FAR *pUnkOuter);
#endif
FORCE_DEFINE_GUID(IID_IDirectSound, 0x279AFA83, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60);
FORCE_DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93);
HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);
HRESULT (WINAPI *pDirectSoundEnumerate)(LPDSENUMCALLBACKA lpCallback, LPVOID lpContext);
#if defined(VOICECHAT)
@ -59,9 +100,19 @@ typedef struct {
LPDIRECTSOUNDBUFFER pDSBuf;
LPDIRECTSOUNDBUFFER pDSPBuf;
#if DIRECTSOUND_VERSION >= 0x0800
//dsound8 interfaces, for reverb effects
LPDIRECTSOUND8 pDS8;
LPDIRECTSOUNDBUFFER8 pDSBuf8;
IDirectSoundFXI3DL2Reverb8 *pReverb;
#endif
DWORD gSndBufSize;
DWORD mmstarttime;
int curreverb;
int curreverbmodcount; //so it updates if the effect itself is updated
#ifdef _IKsPropertySet_
LPKSPROPERTYSET EaxKsPropertiesSet;
#endif
@ -73,14 +124,14 @@ static void DSOUND_Restore(soundcardinfo_t *sc)
{
DWORD dwStatus;
dshandle_t *dh = sc->handle;
if (dh->pDSBuf->lpVtbl->GetStatus (dh->pDSBuf, &dwStatus) != ERROR_SUCCESS)
if (IDirectSoundBuffer_GetStatus (dh->pDSBuf, &dwStatus) != ERROR_SUCCESS)
Con_Printf ("Couldn't get sound buffer status\n");
if (dwStatus & DSBSTATUS_BUFFERLOST)
dh->pDSBuf->lpVtbl->Restore (dh->pDSBuf);
IDirectSoundBuffer_Restore (dh->pDSBuf);
if (!(dwStatus & DSBSTATUS_PLAYING))
dh->pDSBuf->lpVtbl->Play(dh->pDSBuf, 0, 0, DSBPLAY_LOOPING);
IDirectSoundBuffer_Play(dh->pDSBuf, 0, 0, DSBPLAY_LOOPING);
}
static DWORD dsound_locksize;
@ -97,7 +148,7 @@ static void *DSOUND_Lock(soundcardinfo_t *sc, unsigned int *sampidx)
reps = 0;
while ((hresult = dh->pDSBuf->lpVtbl->Lock(dh->pDSBuf, 0, dh->gSndBufSize, (void**)&ret, &dsound_locksize,
while ((hresult = IDirectSoundBuffer_Lock(dh->pDSBuf, 0, dh->gSndBufSize, (void**)&ret, &dsound_locksize,
(void**)&pbuf2, &dwSize2, 0)) != DS_OK)
{
if (hresult != DSERR_BUFFERLOST)
@ -122,7 +173,7 @@ static void *DSOUND_Lock(soundcardinfo_t *sc, unsigned int *sampidx)
static void DSOUND_Unlock(soundcardinfo_t *sc, void *buffer)
{
dshandle_t *dh = sc->handle;
dh->pDSBuf->lpVtbl->Unlock(dh->pDSBuf, buffer, dsound_locksize, NULL, 0);
IDirectSoundBuffer_Unlock(dh->pDSBuf, buffer, dsound_locksize, NULL, 0);
}
/*
@ -140,34 +191,39 @@ static void DSOUND_Shutdown_Internal (soundcardinfo_t *sc)
sc->handle = NULL;
#ifdef _IKsPropertySet_
if (dh->EaxKsPropertiesSet)
{
IKsPropertySet_Release(dh->EaxKsPropertiesSet);
}
dh->EaxKsPropertiesSet = NULL;
#endif
#if DIRECTSOUND_VERSION >= 0x0800
if (dh->pReverb)
IDirectSoundFXI3DL2Reverb_Release(dh->pReverb);
dh->pReverb = NULL;
if (dh->pDSBuf8)
IDirectSoundBuffer8_Release(dh->pDSBuf8);
dh->pDSBuf8 = NULL;
#endif
if (dh->pDSBuf)
{
dh->pDSBuf->lpVtbl->Stop(dh->pDSBuf);
dh->pDSBuf->lpVtbl->Release(dh->pDSBuf);
IDirectSoundBuffer_Stop(dh->pDSBuf);
IDirectSoundBuffer_Release(dh->pDSBuf);
if (dh->pDSBuf == dh->pDSPBuf)
dh->pDSPBuf = NULL;
dh->pDSBuf = NULL;
}
// only release primary buffer if it's not also the mixing buffer we just released
if (dh->pDSPBuf && (dh->pDSBuf != dh->pDSPBuf))
{
dh->pDSPBuf->lpVtbl->Release(dh->pDSPBuf);
}
if (dh->pDSPBuf)
IDirectSoundBuffer_Release(dh->pDSPBuf);
dh->pDSPBuf = NULL;
if (dh->pDS)
{
dh->pDS->lpVtbl->SetCooperativeLevel (dh->pDS, mainwindow, DSSCL_NORMAL);
dh->pDS->lpVtbl->Release(dh->pDS);
IDirectSound_SetCooperativeLevel (dh->pDS, mainwindow, DSSCL_NORMAL);
IDirectSound_Release(dh->pDS);
}
dh->pDS = NULL;
dh->pDSBuf = NULL;
dh->pDSPBuf = NULL;
#ifdef _IKsPropertySet_
dh->EaxKsPropertiesSet = NULL;
#endif
Z_Free(dh);
}
@ -225,7 +281,9 @@ static void DSOUND_Shutdown (soundcardinfo_t *sc)
# define SPEAKER_TOP_BACK_RIGHT 0x20000
/* Bit mask locations reserved for future use*/
#ifndef SPEAKER_RESERVED
# define SPEAKER_RESERVED 0x7FFC0000
#endif
/* Used to specify that any possible permutation of speaker configurations*/
# define SPEAKER_ALL 0x80000000
@ -391,11 +449,24 @@ typedef enum
} DSPROPERTY_EAX_BUFFERPROPERTY;
#endif
static void DSOUND_SetReverb(soundcardinfo_t *sc, size_t reverb)
static long GainToMillibels(float gain)
{
return 100*20*(0.43429*log(gain));
}
static void DSOUND_SetReverb(soundcardinfo_t *sc, size_t reverbidx)
{
#ifdef _IKsPropertySet_
dshandle_t *dh = sc->handle;
struct reverbproperties_s *prop;
if (reverbidx >= numreverbproperties)
return; //invalid
if (dh->curreverb == reverbidx && dh->curreverbmodcount == reverbproperties[reverbidx].modificationcount)
return; //nothing changed.
dh->curreverb = reverbidx;
dh->curreverbmodcount = reverbproperties[reverbidx].modificationcount;
prop = &reverbproperties[dh->curreverb].props;
#ifdef _IKsPropertySet_
//attempt at eax support.
//EAX is a global thing. Get it going in a game and your media player will be doing it too.
@ -403,64 +474,20 @@ static void DSOUND_SetReverb(soundcardinfo_t *sc, size_t reverb)
{
EAXLISTENERPROPERTIES ListenerProperties = {0};
/* DWORD p;
IKsPropertySet_Get(dh->EaxKsPropertiesSet, &DSPROPSETID_EAX20_LISTENERPROPERTIES,
DSPROPERTY_EAXLISTENER_ALLPARAMETERS, 0, 0, &ListenerProperties,
sizeof(ListenerProperties), &p);
*/
if (reverb)
{
#if 1 //phycotic.
ListenerProperties.flEnvironmentSize = 2.8;
ListenerProperties.flEnvironmentDiffusion = 0.240;
ListenerProperties.lRoom = -374;
ListenerProperties.lRoomHF = -150;
ListenerProperties.flRoomRolloffFactor = 0;
ListenerProperties.flAirAbsorptionHF = -5;
ListenerProperties.lReflections = -10000;
ListenerProperties.flReflectionsDelay = 0.053;
ListenerProperties.lReverb = 625;
ListenerProperties.flReverbDelay = 0.08;
ListenerProperties.flDecayTime = 5.096;
ListenerProperties.flDecayHFRatio = 0.910;
ListenerProperties.dwFlags = 0x3f;
ListenerProperties.dwEnvironment = EAX_ENVIRONMENT_PSYCHOTIC;
#else
ListenerProperties.flEnvironmentSize = 5.8;
ListenerProperties.flEnvironmentDiffusion = 0;
ListenerProperties.lRoom = -374;
ListenerProperties.lRoomHF = -2860;
ListenerProperties.flRoomRolloffFactor = 0;
ListenerProperties.flAirAbsorptionHF = -5;
ListenerProperties.lReflections = -889;
ListenerProperties.flReflectionsDelay = 0.024;
ListenerProperties.lReverb = 797;
ListenerProperties.flReverbDelay = 0.035;
ListenerProperties.flDecayTime = 5.568;
ListenerProperties.flDecayHFRatio = 0.100;
ListenerProperties.dwFlags = 0x3f;
ListenerProperties.dwEnvironment = EAX_ENVIRONMENT_UNDERWATER;
#endif
}
else
{
ListenerProperties.flEnvironmentSize = 1;
ListenerProperties.flEnvironmentDiffusion = 0;
ListenerProperties.lRoom = 0;
ListenerProperties.lRoomHF = 0;
ListenerProperties.flRoomRolloffFactor = 0;
ListenerProperties.flAirAbsorptionHF = 0;
ListenerProperties.lReflections = 1000;
ListenerProperties.flReflectionsDelay = 0;
ListenerProperties.lReverb = 813;
ListenerProperties.flReverbDelay = 0.00;
ListenerProperties.flDecayTime = 0.1;
ListenerProperties.flDecayHFRatio = 0.1;
ListenerProperties.dwFlags = 0x3f;
ListenerProperties.dwEnvironment = EAX_ENVIRONMENT_GENERIC;
}
// env = EAX_ENVIRONMENT_UNDERWATER;
ListenerProperties.flEnvironmentSize = prop->flEchoTime;
ListenerProperties.flEnvironmentDiffusion = prop->flDiffusion;
ListenerProperties.lRoom = GainToMillibels(prop->flGain);
ListenerProperties.lRoomHF = GainToMillibels(prop->flGainHF);
ListenerProperties.flRoomRolloffFactor = prop->flRoomRolloffFactor;
ListenerProperties.flAirAbsorptionHF = prop->flAirAbsorptionGainHF;
ListenerProperties.lReflections = GainToMillibels(prop->flReflectionsGain);
ListenerProperties.flReflectionsDelay = prop->flReflectionsDelay;
ListenerProperties.lReverb = GainToMillibels(prop->flLateReverbGain);
ListenerProperties.flReverbDelay = prop->flLateReverbDelay;
ListenerProperties.flDecayTime = prop->flDecayTime;
ListenerProperties.flDecayHFRatio = prop->flDecayHFRatio;
ListenerProperties.dwFlags = 0x3f;
ListenerProperties.dwEnvironment = reverbidx?EAX_ENVIRONMENT_UNDERWATER:0;
if (FAILED(IKsPropertySet_Set(dh->EaxKsPropertiesSet, &DSPROPSETID_EAX20_LISTENERPROPERTIES,
DSPROPERTY_EAXLISTENER_ALLPARAMETERS, 0, 0, &ListenerProperties,
@ -468,6 +495,27 @@ static void DSOUND_SetReverb(soundcardinfo_t *sc, size_t reverb)
Con_SafePrintf ("EAX set failed\n");
}
#endif
#if DIRECTSOUND_VERSION >= 0x0800
if (dh->pReverb)
{
DSFXI3DL2Reverb reverb;
reverb.lRoom = bound(-10000, GainToMillibels(prop->flGain), 0); // [-10000, 0] default: -1000 mB
reverb.lRoomHF = bound(-10000, GainToMillibels(prop->flGainHF), 0); // [-10000, 0] default: 0 mB
reverb.flRoomRolloffFactor = bound(0.0, prop->flRoomRolloffFactor, 10.0); // [0.0, 10.0] default: 0.0
reverb.flDecayTime = bound(0.1, prop->flDecayTime, 20.0); // [0.1, 20.0] default: 1.49s
reverb.flDecayHFRatio = bound(0.1, prop->flDecayHFRatio, 2.0); // [0.1, 2.0] default: 0.83
reverb.lReflections = bound(-10000, GainToMillibels(prop->flReflectionsGain), 1000); // [-10000, 1000] default: -2602 mB
reverb.flReflectionsDelay = bound(0.0, prop->flReflectionsDelay, 0.3); // [0.0, 0.3] default: 0.007 s
reverb.lReverb = bound(-10000, GainToMillibels(prop->flLateReverbGain), 2000); // [-10000, 2000] default: 200 mB
reverb.flReverbDelay = bound(0.0, prop->flLateReverbDelay, 0.1); // [0.0, 0.1] default: 0.011 s
reverb.flDiffusion = bound(0.0, prop->flDiffusion*100, 100.0); // [0.0, 100.0] default: 100.0 %
reverb.flDensity = bound(0.0, prop->flDensity*100, 100.0); // [0.0, 100.0] default: 100.0 %
reverb.flHFReference = bound(20.0, prop->flHFReference, 20000.0); // [20.0, 20000.0] default: 5000.0 Hz
IDirectSoundFXI3DL2Reverb_SetAllParameters(dh->pReverb, &reverb);
}
#endif
}
/*
@ -487,7 +535,7 @@ static unsigned int DSOUND_GetDMAPos(soundcardinfo_t *sc)
dshandle_t *dh = sc->handle;
dh->pDSBuf->lpVtbl->GetCurrentPosition(dh->pDSBuf, &mmtime, &dwWrite);
IDirectSoundBuffer_GetCurrentPosition(dh->pDSBuf, &mmtime, &dwWrite);
s = mmtime - dh->mmstarttime;
@ -520,10 +568,17 @@ static qboolean DSOUND_InitOutputLibrary(void)
}
if (!pDirectSoundCreate)
pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate");
if (!pDirectSoundCreate)
#if DIRECTSOUND_VERSION >= 0x0800
if (!pDirectSoundCreate8)
pDirectSoundCreate8 = (void *)GetProcAddress(hInstDS,"DirectSoundCreate8"); //xp+
if (!pDirectSoundCreate8)
#endif
{
Con_SafePrintf ("Couldn't get DS proc addr\n");
return false;
if (!pDirectSoundCreate)
{
Con_SafePrintf ("Couldn't get DS proc addr\n");
return false;
}
}
if (!pDirectSoundEnumerate)
pDirectSoundEnumerate = (void *)GetProcAddress(hInstDS,"DirectSoundEnumerateA");
@ -539,11 +594,8 @@ Direct-Sound support
static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
{
extern cvar_t snd_inactive;
#if _MSC_VER > 1200 //fixme err
#ifdef _IKsPropertySet_
extern cvar_t snd_eax;
#endif
#endif
int usereverb; //2=eax, 1=ds8
DSBUFFERDESC dsbuf;
DSBCAPS dsbcaps;
DWORD dwSize, dwWrite;
@ -613,23 +665,23 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
}
format.Format.nChannels = sc->sn.numchannels;
format.Format.wBitsPerSample = sc->sn.samplebits;
format.Format.nSamplesPerSec = sc->sn.speed;
format.Format.nBlockAlign = format.Format.nChannels
*format.Format.wBitsPerSample / 8;
format.Format.nAvgBytesPerSec = format.Format.nSamplesPerSec
*format.Format.nBlockAlign;
format.Format.wBitsPerSample = sc->sn.samplebits;
format.Format.nSamplesPerSec = sc->sn.speed;
format.Format.nBlockAlign = format.Format.nChannels * format.Format.wBitsPerSample / 8;
format.Format.nAvgBytesPerSec = format.Format.nSamplesPerSec * format.Format.nBlockAlign;
if (!DSOUND_InitOutputLibrary())
return false;
sc->handle = Z_Malloc(sizeof(dshandle_t));
dh = sc->handle;
usereverb = !!snd_eax.ival;
//EAX attempt
#if _MSC_VER > 1200
#ifdef _IKsPropertySet_
dh->pDS = NULL;
if (snd_eax.ival)
if (usereverb)
{
CoInitialize(NULL);
if (FAILED(CoCreateInstance( &CLSID_EAXDirectSound, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectSound, (void **)&dh->pDS )))
@ -637,6 +689,7 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
else
{
IDirectSound_Initialize(dh->pDS, dsguid);
usereverb = 2;
}
}
@ -644,8 +697,22 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
#endif
#endif
{
while ((hresult = iDirectSoundCreate(dsguid, &dh->pDS, NULL)) != DS_OK)
for(;;)
{
dh->pDS = NULL;
#if DIRECTSOUND_VERSION >= 0x0800
dh->pDS8 = NULL;
if (pDirectSoundCreate8)
{
hresult = pDirectSoundCreate8(dsguid, &dh->pDS8, NULL);
dh->pDS = (void*)dh->pDS8; //evil cast
}
else
#endif
hresult = pDirectSoundCreate(dsguid, &dh->pDS, NULL);
if (hresult == DS_OK)
break;
if (hresult != DSERR_ALLOCATED)
{
Con_SafePrintf (": create failed\n");
@ -669,7 +736,7 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
#ifdef FTE_SDL
#define mainwindow GetDesktopWindow()
#endif
if (DS_OK != dh->pDS->lpVtbl->SetCooperativeLevel (dh->pDS, mainwindow, DSSCL_EXCLUSIVE))
if (DS_OK != IDirectSound_SetCooperativeLevel (dh->pDS, mainwindow, DSSCL_EXCLUSIVE))
{
Con_SafePrintf ("Set coop level failed\n");
DSOUND_Shutdown_Internal (sc);
@ -678,7 +745,7 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
dscaps.dwSize = sizeof(dscaps);
if (DS_OK != dh->pDS->lpVtbl->GetCaps (dh->pDS, &dscaps))
if (DS_OK != IDirectSound_GetCaps (dh->pDS, &dscaps))
{
Con_SafePrintf ("Couldn't get DS caps\n");
}
@ -716,11 +783,11 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
if (!COM_CheckParm ("-snoforceformat"))
{
if (DS_OK == dh->pDS->lpVtbl->CreateSoundBuffer(dh->pDS, &dsbuf, &dh->pDSPBuf, NULL))
if (DS_OK == IDirectSound_CreateSoundBuffer(dh->pDS, &dsbuf, &dh->pDSPBuf, NULL))
{
pformat = format;
if (DS_OK != dh->pDSPBuf->lpVtbl->SetFormat (dh->pDSPBuf, (WAVEFORMATEX *)&pformat))
if (DS_OK != IDirectSoundBuffer_SetFormat (dh->pDSPBuf, (WAVEFORMATEX *)&pformat))
{
// if (snd_firsttime)
// Con_SafePrintf ("Set primary sound buffer format: no\n");
@ -741,6 +808,12 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
memset (&dsbuf, 0, sizeof(dsbuf));
dsbuf.dwSize = sizeof(DSBUFFERDESC);
dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY|DSBCAPS_LOCSOFTWARE; //dmw 29 may, 2003 removed locsoftware
#if DIRECTSOUND_VERSION >= 0x0800
if (usereverb == 1)
dsbuf.dwFlags |= DSBCAPS_CTRLFX;
#endif
#ifdef DSBCAPS_GLOBALFOCUS
if (snd_inactive.ival)
{
@ -761,7 +834,7 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
memset(&dsbcaps, 0, sizeof(dsbcaps));
dsbcaps.dwSize = sizeof(dsbcaps);
if (DS_OK != dh->pDS->lpVtbl->CreateSoundBuffer(dh->pDS, &dsbuf, &dh->pDSBuf, NULL))
if (DS_OK != IDirectSound_CreateSoundBuffer(dh->pDS, &dsbuf, &dh->pDSBuf, NULL))
{
Con_SafePrintf ("DS:CreateSoundBuffer Failed");
DSOUND_Shutdown_Internal (sc);
@ -772,7 +845,7 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
sc->sn.samplebits = format.Format.wBitsPerSample;
sc->sn.speed = format.Format.nSamplesPerSec;
if (DS_OK != dh->pDSBuf->lpVtbl->GetCaps (dh->pDSBuf, &dsbcaps))
if (DS_OK != IDirectSoundBuffer_GetCaps (dh->pDSBuf, &dsbcaps))
{
Con_SafePrintf ("DS:GetCaps failed\n");
DSOUND_Shutdown_Internal (sc);
@ -784,14 +857,14 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
}
else
{
if (DS_OK != dh->pDS->lpVtbl->SetCooperativeLevel (dh->pDS, mainwindow, DSSCL_WRITEPRIMARY))
if (DS_OK != IDirectSound_SetCooperativeLevel (dh->pDS, mainwindow, DSSCL_WRITEPRIMARY))
{
Con_SafePrintf ("Set coop level failed\n");
DSOUND_Shutdown_Internal (sc);
return false;
}
if (DS_OK != dh->pDSPBuf->lpVtbl->GetCaps (dh->pDSPBuf, &dsbcaps))
if (DS_OK != IDirectSoundBuffer_GetCaps (dh->pDSPBuf, &dsbcaps))
{
Con_Printf ("DS:GetCaps failed\n");
DSOUND_Shutdown_Internal (sc);
@ -804,21 +877,38 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
dh->gSndBufSize = dsbcaps.dwBufferBytes;
#if DIRECTSOUND_VERSION >= 0x0800
if (usereverb == 1)
{
if (SUCCEEDED(IDirectSoundBuffer_QueryInterface(dh->pDSBuf, &IID_IDirectSoundBuffer8, (void*)&dh->pDSBuf8)))
{
DSEFFECTDESC effects[1];
DWORD results[1];
memset(effects, 0, sizeof(effects));
effects[0].dwSize = sizeof(effects[0]);
effects[0].dwFlags = 0;
effects[0].guidDSFXClass = GUID_DSFX_STANDARD_I3DL2REVERB;
if (SUCCEEDED(IDirectSoundBuffer8_SetFX(dh->pDSBuf8, 1, effects, results)))
if (SUCCEEDED(IDirectSoundBuffer8_GetObjectInPath(dh->pDSBuf8, &GUID_DSFX_STANDARD_I3DL2REVERB, 0, &IID_IDirectSoundFXI3DL2Reverb8, (void*)&dh->pReverb)))
usereverb = 0;
}
}
#endif
#if 1
// Make sure mixer is active
dh->pDSBuf->lpVtbl->Play(dh->pDSBuf, 0, 0, DSBPLAY_LOOPING);
IDirectSoundBuffer_Play(dh->pDSBuf, 0, 0, DSBPLAY_LOOPING);
/* if (snd_firsttime)
Con_SafePrintf(" %d channel(s)\n"
" %d bits/sample\n"
" %d bytes/sec\n",
shm->channels, shm->samplebits, shm->speed);*/
Con_DPrintf(" %d channel(s)\n"
" %d bits/sample\n"
" %d bytes/sec\n",
sc->sn.numchannels, sc->sn.samplebits, sc->sn.speed);
// initialize the buffer
reps = 0;
while ((hresult = dh->pDSBuf->lpVtbl->Lock(dh->pDSBuf, 0, dh->gSndBufSize, (void**)&buffer, &dwSize, NULL, NULL, 0)) != DS_OK)
while ((hresult = IDirectSoundBuffer_Lock(dh->pDSBuf, 0, dh->gSndBufSize, (void**)&buffer, &dwSize, NULL, NULL, 0)) != DS_OK)
{
if (hresult != DSERR_BUFFERLOST)
{
@ -840,18 +930,21 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
// Sleep(500);
dh->pDSBuf->lpVtbl->Unlock(dh->pDSBuf, buffer, dwSize, NULL, 0);
IDirectSoundBuffer_Unlock(dh->pDSBuf, buffer, dwSize, NULL, 0);
dh->pDSBuf->lpVtbl->Stop(dh->pDSBuf);
IDirectSoundBuffer_Stop(dh->pDSBuf);
#endif
dh->pDSBuf->lpVtbl->GetCurrentPosition(dh->pDSBuf, &dh->mmstarttime, &dwWrite);
dh->pDSBuf->lpVtbl->Play(dh->pDSBuf, 0, 0, DSBPLAY_LOOPING);
IDirectSoundBuffer_GetCurrentPosition(dh->pDSBuf, &dh->mmstarttime, &dwWrite);
IDirectSoundBuffer_Play(dh->pDSBuf, 0, 0, DSBPLAY_LOOPING);
sc->sn.samples = dh->gSndBufSize/(sc->sn.samplebits/8);
sc->sn.samplepos = 0;
sc->sn.buffer = NULL;
dh->curreverb = ~0;
dh->curreverbmodcount = ~0;
sc->Lock = DSOUND_Lock;
sc->Unlock = DSOUND_Unlock;
@ -864,7 +957,7 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
#if _MSC_VER > 1200
#ifdef _IKsPropertySet_
//attempt at eax support
if (snd_eax.ival)
if (usereverb == 2)
{
int r;
DWORD support;
@ -878,20 +971,23 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
IKsPropertySet_Release(dh->EaxKsPropertiesSet);
dh->EaxKsPropertiesSet = NULL;
Con_SafePrintf ("EAX 2 not supported\n");
return true;//otherwise successful. It can be used for normal sound anyway.
//otherwise successful. It can be used for normal sound anyway.
}
//worked. EAX is supported.
else
usereverb = 0; //worked. EAX is fully inited.
}
else
{
Con_SafePrintf ("Couldn't get extended properties\n");
Con_DPrintf ("Couldn't get extended properties\n");
dh->EaxKsPropertiesSet = NULL;
}
}
#endif
#endif
if (usereverb)
Con_SafePrintf ("Couldn't enable environmental reverb effects\n");
return true;
}

View File

@ -2373,7 +2373,7 @@ static void SND_AccumulateSpacialization(soundcardinfo_t *sc, channel_t *ch, vec
dist = VectorNormalize(world_vec) * ch->dist_mult;
if (ch->flags & CF_NOSPACIALISE)
if ((ch->flags & CF_NOSPACIALISE) || !ch->dist_mult)
{
scale = 1;
scale = (1.0 - dist) * scale;
@ -2501,7 +2501,7 @@ static void SND_Spatialize(soundcardinfo_t *sc, channel_t *ch)
dist = VectorNormalize(world_vec) * ch->dist_mult;
if (ch->flags & CF_NOSPACIALISE)
if ((ch->flags & CF_NOSPACIALISE) || !ch->dist_mult)
{
scale = 1;
scale = (1.0 - dist) * scale;

View File

@ -2,7 +2,9 @@
//frankly, xaudio2 gives nothing over directsound, unless we're getting it to do all the mixing instead. which gets really messy and far too involved.
//I suppose it has a use with WINRT... although that doesn't apply to any actual users.
//we're lazy and don't do any special threading, this makes it inferior to the directsound implementation - potentially, the callback feature could allow for slightly lower latencies.
//also no reverb (fixme: XAUDIO2FX_REVERB_PARAMETERS).
//dxsdk = 2.7 = win7+
//w8sdk = 2.8 = win8+

View File

@ -237,7 +237,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define ZYMOTICMODELS //zymotic skeletal models.
#define DPMMODELS //darkplaces model format (which I've never seen anyone use)
#define PSKMODELS //PSK model format (ActorX stuff from UT, though not the format the game itself uses)
// #define HALFLIFEMODELS //halflife model support (experimental)
#define HALFLIFEMODELS //halflife model support (experimental)
#define INTERQUAKEMODELS
#define RAGDOLL

View File

@ -885,6 +885,7 @@ struct
vec3_t *anorm;
vec3_t *anorms;
vec3_t *anormt;
float lerp;
vbo_t vbo;
vbo_t *vbop;
@ -1671,6 +1672,8 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
{
if (meshcache.vertgroup == inf->shares_verts && meshcache.ent == e && usebones == meshcache.usebones)
{
mesh->xyz_blendw[0] = meshcache.lerp;
mesh->xyz_blendw[1] = 1-meshcache.lerp;
mesh->xyz_array = meshcache.acoords1;
mesh->xyz2_array = meshcache.acoords2;
mesh->normals_array = meshcache.anorm;
@ -1976,6 +1979,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
meshcache.anorm = mesh->normals_array;
meshcache.anorms = mesh->snormals_array;
meshcache.anormt = mesh->tnormals_array;
meshcache.lerp = mesh->xyz_blendw[0];
if (vbop)
meshcache.vbop = *vbop;
@ -3987,36 +3991,35 @@ qboolean QDECL Mod_LoadQ2Model (model_t *mod, void *buffer, size_t fsize)
int Mod_GetNumBones(model_t *model, qboolean allowtags)
{
galiasinfo_t *inf;
if (!model || model->type != mod_alias)
return 0;
inf = Mod_Extradata(model);
if (model && model->type == mod_alias)
{
galiasinfo_t *inf = Mod_Extradata(model);
#ifdef SKELETALMODELS
if (inf->numbones)
return inf->numbones;
else
if (inf->numbones)
return inf->numbones;
else
#endif
if (allowtags)
return inf->numtags;
else
if (allowtags)
return inf->numtags;
return 0;
}
#ifdef HALFLIFEMODELS
if (model && model->type == mod_halflife)
return HLMDL_GetNumBones(model);
#endif
return 0;
}
int Mod_GetBoneRelations(model_t *model, int firstbone, int lastbone, framestate_t *fstate, float *result)
{
#ifdef SKELETALMODELS
galiasinfo_t *inf;
if (!model || model->type != mod_alias)
return false;
inf = Mod_Extradata(model);
return Alias_BlendBoneData(inf, fstate, result, SKEL_RELATIVE, firstbone, lastbone);
if (model && model->type == mod_alias)
return Alias_BlendBoneData(Mod_Extradata(model), fstate, result, SKEL_RELATIVE, firstbone, lastbone);
#endif
#ifdef HALFLIFEMODELS
if (model && model->type == mod_halflife)
return HLMDL_GetBoneData(model, firstbone, lastbone, fstate, result);
#endif
return 0;
}
@ -4272,7 +4275,7 @@ int Mod_TagNumForName(model_t *model, const char *name)
return 0;
#ifdef HALFLIFEMODELS
if (model->type == mod_halflife)
return HLMod_BoneForName(model, name);
return HLMDL_BoneForName(model, name);
#endif
if (model->type != mod_alias)
return 0;
@ -4310,7 +4313,7 @@ int Mod_FrameNumForName(model_t *model, int surfaceidx, const char *name)
return -1;
#ifdef HALFLIFEMODELS
if (model->type == mod_halflife)
return HLMod_FrameForName(model, name);
return HLMDL_FrameForName(model, name);
#endif
if (model->type != mod_alias)
return 0;
@ -4364,18 +4367,23 @@ const char *Mod_FrameNameForNum(model_t *model, int surfaceidx, int num)
if (!model)
return NULL;
if (model->type != mod_alias)
return NULL;
if (model->type == mod_alias)
{
inf = Mod_Extradata(model);
inf = Mod_Extradata(model);
while(surfaceidx-->0 && inf)
inf = inf->nextsurf;
while(surfaceidx-->0 && inf)
inf = inf->nextsurf;
if (!inf || num >= inf->numanimations)
return NULL;
group = inf->ofsanimations;
return group[num].name;
if (!inf || num >= inf->numanimations)
return NULL;
group = inf->ofsanimations;
return group[num].name;
}
#ifdef HALFLIFEMODELS
if (model->type == mod_halflife)
return HLMDL_FrameNameForNum(model, surfaceidx, num);
#endif
return NULL;
}
qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop)
@ -4385,23 +4393,28 @@ qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **nam
if (!model)
return false;
if (model->type != mod_alias)
return false;
if (model->type == mod_alias)
{
inf = Mod_Extradata(model);
inf = Mod_Extradata(model);
while(surfaceidx-->0 && inf)
inf = inf->nextsurf;
while(surfaceidx-->0 && inf)
inf = inf->nextsurf;
if (!inf || num >= inf->numanimations)
return false;
group = inf->ofsanimations;
if (!inf || num >= inf->numanimations)
return false;
group = inf->ofsanimations;
*name = group[num].name;
*numframes = group[num].numposes;
*loop = group[num].loop;
*duration = group->numposes/group->rate;
return true;
*name = group[num].name;
*numframes = group[num].numposes;
*loop = group[num].loop;
*duration = group->numposes/group->rate;
return true;
}
#ifdef HALFLIFEMODELS
if (model->type == mod_halflife)
return HLMDL_FrameInfoForNum(model, surfaceidx, num, name, numframes, duration, loop);
#endif
return false;
}
#ifndef SERVERONLY

View File

@ -9,8 +9,9 @@ extern "C" {
#include <stdlib.h>
#endif
int HLMod_BoneForName(model_t *mod, const char *name);
int HLMod_FrameForName(model_t *mod, const char *name);
#ifdef HALFLIFEMODELS
#include "model_hl.h"
#endif
//a single pose within an animation (note: always refered to via a framegroup, even if there's only one frame in that group).
typedef struct
@ -223,14 +224,10 @@ qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **nam
void Mod_DoCRC(model_t *mod, char *buffer, int buffersize);
qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize);
#ifdef MAP_PROC
qboolean Mod_LoadMap_Proc(model_t *mode, void *buffer);
#endif
void Mod_AccumulateTextureVectors(vecV_t *vc, vec2_t *tc, vec3_t *nv, vec3_t *sv, vec3_t *tv, index_t *idx, int numidx);
void Mod_AccumulateMeshTextureVectors(mesh_t *mesh);
void Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v);
void R_Generate_Mesh_ST_Vectors(mesh_t *mesh);
#ifdef __cplusplus
};

View File

@ -17,7 +17,7 @@ cvar_t log_name[LOG_TYPES] = { CVARFC("log_name", "", CVAR_NOTFROMSERVER, Log_N
CVARFC("log_name_rcon", "rcon", CVAR_NOTFROMSERVER, Log_Name_Callback)};
cvar_t log_dir = CVARFC("log_dir", "", CVAR_NOTFROMSERVER, Log_Dir_Callback);
cvar_t log_readable = CVARFD("log_readable", "7", CVAR_NOTFROMSERVER, "Bitfield describing what to convert/strip. If 0, exact byte representation will be used.\n&1: Dequakify text.\n&2: Strip special markup.\n&4: Strip ansi control codes.");
cvar_t log_developer = CVARF("log_developer", "0", CVAR_NOTFROMSERVER);
cvar_t log_developer = CVARFD("log_developer", "0", CVAR_NOTFROMSERVER, "Enables logging of console prints when set to 1. Otherwise unimportant messages will not fill up your log files.");
cvar_t log_rotate_files = CVARF("log_rotate_files", "0", CVAR_NOTFROMSERVER);
cvar_t log_rotate_size = CVARF("log_rotate_size", "131072", CVAR_NOTFROMSERVER);
cvar_t log_timestamps = CVARF("log_timestamps", "1", CVAR_NOTFROMSERVER);

View File

@ -1708,6 +1708,29 @@ void QCBUILTIN PF_hash_destroytab (pubprogfuncs_t *prinst, struct globalvars_s *
Z_Free(tab->bucketmem);
}
}
void PF_Hash_DestroyAll(pubprogfuncs_t *prinst)
{
qboolean freed = true;
size_t idx;
for (idx = 0; idx < pf_hash_maxtables; idx++)
{
if (pf_hashtab[idx].prinst == prinst)
{
pf_hashtab[idx].prinst = NULL;
Hash_Enumerate(&pf_hashtab[idx].tab, PF_hash_destroytab_enum, NULL);
Z_Free(pf_hashtab[idx].bucketmem);
}
else if (pf_hashtab[idx].prinst)
freed = false;
}
if (freed && pf_hashtab)
{
pf_hash_maxtables = 0;
Z_Free(pf_hashtab);
pf_hashtab = NULL;
}
}
void QCBUILTIN PF_hash_createtab (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
//FIXME: these need to be managed by the qcvm for garbage collection
@ -2567,6 +2590,7 @@ void PR_fclose_progs (pubprogfuncs_t *prinst)
{
PF_fcloseall(prinst);
search_close_progs(prinst, true);
PF_Hash_DestroyAll(prinst);
}
//File access

View File

@ -159,6 +159,8 @@ typedef struct
vec3_t e_light_dir; float pad2;
vec3_t e_light_mul; float pad3;
vec4_t e_lmscale[4];
vec4_t e_uppercolour;
vec4_t e_lowercolour;
} cbuf_entity_t;
//vertex attributes
@ -2781,6 +2783,34 @@ void D3D11BE_SetupLightCBuffer(dlight_t *l, vec3_t colour)
ID3D11DeviceContext_Unmap(d3ddevctx, (ID3D11Resource*)shaderstate.lcbuffer, 0);
}
static void R_FetchPlayerColour(unsigned int cv, vec4_t rgba)
{
int i;
if (cv >= 16)
{
rgba[0] = (((cv&0xff0000)>>16)**((unsigned char*)&d_8to24rgbtable[15]+0)) / (256.0*256);
rgba[1] = (((cv&0x00ff00)>>8)**((unsigned char*)&d_8to24rgbtable[15]+1)) / (256.0*256);
rgba[2] = (((cv&0x0000ff)>>0)**((unsigned char*)&d_8to24rgbtable[15]+2)) / (256.0*256);
rgba[3] = 1.0;
return;
}
i = cv;
if (i >= 8)
{
i<<=4;
}
else
{
i<<=4;
i+=15;
}
i*=3;
rgba[0] = host_basepal[i+0] / 255.0;
rgba[1] = host_basepal[i+1] / 255.0;
rgba[2] = host_basepal[i+2] / 255.0;
rgba[3] = 1.0;
}
//also updates the entity constant buffer
static void BE_RotateForEntity (const entity_t *e, const model_t *mod)
@ -2968,6 +2998,9 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod)
VectorCopy(e->light_dir, cbe->e_light_dir);
VectorCopy(e->light_range, cbe->e_light_mul);
R_FetchPlayerColour(e->topcolour, cbe->e_uppercolour);
R_FetchPlayerColour(e->bottomcolour, cbe->e_lowercolour);
//various stuff in modelspace
Matrix4x4_CM_Transform3(modelinv, r_origin, cbe->e_eyepos);

View File

@ -153,6 +153,8 @@ HRESULT STDMETHODCALLTYPE d3dinclude_Open(ID3DInclude *this, D3D_INCLUDE_TYPE In
"float3 e_light_dir; float pad2;\n"
"float3 e_light_mul; float pad3;\n"
"float4 e_lmscale[4];\n"
"float4 e_uppercolour;\n"
"float4 e_lowercolour;\n"
"};\n"
"cbuffer fteviewdefs : register(b1)\n"
"{\n"
@ -473,12 +475,31 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
for (; *precompilerconstants; precompilerconstants++)
{
const char *t = *precompilerconstants;
t = COM_Parse(t);
t = COM_Parse(t);
defines[consts].Name = Z_StrDup(com_token);
defines[consts].Definition = t?Z_StrDup(t):NULL;
consts++;
const char *t, *nl;
char *v;
for (t = *precompilerconstants; *t; t++)
{
t = COM_Parse(t);
t = COM_Parse(t);
defines[consts].Name = Z_StrDup(com_token);
while (*t == ' ' || *t == '\t')
t++;
nl = strchr(t, '\n');
if (!nl)
nl = nl+strlen(nl);
if (nl && nl != t)
{
v = BZ_Malloc(nl-t+1);
memcpy(v, t, nl-t);
v[nl-t] = 0;
defines[consts].Definition = v;
}
else
defines[consts].Definition = t?Z_StrDup(t):NULL;
consts++;
t = nl;
}
}
defines[consts].Name = NULL;

View File

@ -178,10 +178,29 @@ static qboolean D3D9Shader_CreateProgram (program_t *prog, const char *sname, un
for (defbufe = defbuf; *precompilerconstants; precompilerconstants++)
{
defines[consts].Definition = COM_ParseOut(*precompilerconstants+7, defbufe, defbuf+sizeof(defbuf) - defbufe-1);
defines[consts].Name = defbufe;
defbufe += strlen(defbufe)+1;
consts++;
const char *l, *nl;
for(l = *precompilerconstants; *l; l = nl)
{
l += 7; //skip over the assumed #define
l = COM_ParseOut(l, defbufe, defbuf+sizeof(defbuf) - defbufe-1);
defines[consts].Name = defbufe;
defbufe += strlen(defbufe)+1;
while (*l == ' ' || *l == '\t')
l++;
nl = strchr(l, '\n');
if (nl && *nl)
{
defines[consts++].Definition = defbufe;
memcpy(defbufe, l, nl-l);
defbufe[nl-l] = 0;
defbufe += nl++-l+1;
}
else
defines[consts++].Definition = l;
}
}
defines[consts].Name = NULL;

View File

@ -29,6 +29,7 @@ extern cvar_t gl_overbright;
extern cvar_t gl_ati_truform;
extern cvar_t r_wireframe;
extern cvar_t r_refract_fbo;
extern cvar_t r_refractreflect_scale;
extern texid_t missing_texture;
extern texid_t missing_texture_gloss;
@ -103,12 +104,12 @@ struct {
texid_t tex_sourcedepth;
texid_t tex_reflectcube;/*used where $reflectcube was invalid or failed*/
fbostate_t fbo_2dfbo;
fbostate_t fbo_reflectrefrac;
fbostate_t fbo_reflectrefrac[R_MAX_RECURSE];
fbostate_t fbo_lprepass;
texid_t tex_reflection; /*basically a portal rendered to texture*/
texid_t tex_refraction; /*the (culled) underwater view*/
texid_t tex_refractiondepth; /*the (culled) underwater view*/
texid_t tex_ripplemap; /*temp image for waves and things.*/
texid_t tex_reflection[R_MAX_RECURSE]; /*basically a portal rendered to texture*/
texid_t tex_refraction[R_MAX_RECURSE]; /*the (culled) underwater view*/
texid_t tex_refractiondepth[R_MAX_RECURSE]; /*the (culled) underwater view*/
texid_t tex_ripplemap[R_MAX_RECURSE]; /*temp image for waves and things.*/
int curpatchverts;
qboolean force2d;
@ -1239,7 +1240,7 @@ static void Shader_BindTextureForPass(int tmu, const shaderpass_t *pass)
t = shaderstate.tex_sourcedepth;
break;
case T_GEN_REFLECTION:
t = shaderstate.tex_reflection;
t = shaderstate.tex_reflection[r_refdef.recurse];
break;
case T_GEN_REFRACTION:
if (!r_refract_fboival)
@ -1247,13 +1248,13 @@ static void Shader_BindTextureForPass(int tmu, const shaderpass_t *pass)
T_Gen_CurrentRender(tmu);
return;
}
t = shaderstate.tex_refraction;
t = shaderstate.tex_refraction[r_refdef.recurse];
break;
case T_GEN_REFRACTIONDEPTH:
t = shaderstate.tex_refractiondepth;
t = shaderstate.tex_refractiondepth[r_refdef.recurse];
break;
case T_GEN_RIPPLEMAP:
t = shaderstate.tex_ripplemap;
t = shaderstate.tex_ripplemap[r_refdef.recurse];
break;
}
GL_LazyBind(tmu, GL_TEXTURE_2D, t);
@ -1383,24 +1384,28 @@ void GenerateFogTexture(texid_t *tex, float density, float zscale)
void GLBE_DestroyFBOs(void)
{
size_t i;
GLBE_FBO_Destroy(&shaderstate.fbo_2dfbo);
GLBE_FBO_Destroy(&shaderstate.fbo_reflectrefrac);
GLBE_FBO_Destroy(&shaderstate.fbo_lprepass);
if (shaderstate.tex_reflection)
for (i = 0; i < R_MAX_RECURSE; i++)
{
Image_DestroyTexture(shaderstate.tex_reflection);
shaderstate.tex_reflection = r_nulltex;
}
if (shaderstate.tex_refraction)
{
Image_DestroyTexture(shaderstate.tex_refraction);
shaderstate.tex_refraction = r_nulltex;
}
if (shaderstate.tex_refractiondepth)
{
Image_DestroyTexture(shaderstate.tex_refractiondepth);
shaderstate.tex_refractiondepth = r_nulltex;
GLBE_FBO_Destroy(&shaderstate.fbo_reflectrefrac[i]);
if (shaderstate.tex_reflection[i])
{
Image_DestroyTexture(shaderstate.tex_reflection[i]);
shaderstate.tex_reflection[i] = r_nulltex;
}
if (shaderstate.tex_refraction[i])
{
Image_DestroyTexture(shaderstate.tex_refraction[i]);
shaderstate.tex_refraction[i] = r_nulltex;
}
if (shaderstate.tex_refractiondepth[i])
{
Image_DestroyTexture(shaderstate.tex_refractiondepth[i]);
shaderstate.tex_refractiondepth[i] = r_nulltex;
}
}
if (shaderstate.temptexture)
{
@ -4643,6 +4648,10 @@ static void GLBE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist)
{
batch_t *batch, *masklists[2];
int i;
if (!dynamiclist && !worldlist[SHADER_SORT_PORTAL])
return; //no portals to draw
/*attempt to draw portal shaders*/
if (shaderstate.mode == BEM_STANDARD)
{
@ -4668,19 +4677,19 @@ static void GLBE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist)
//make sure the current scene doesn't draw over the portal where its not meant to. clamp depth so the near clip plane doesn't cause problems.
if (gl_config.arb_depth_clamp)
qglEnable(GL_DEPTH_CLAMP_ARB);
/*draw depth only, to mask it off*/
GLBE_SelectMode(BEM_DEPTHONLY);
for (i = 0; i < 2; i++)
{
for (batch = i?dynamiclist:worldlist[SHADER_SORT_PORTAL]; batch; batch = batch->next)
{
if (batch->meshes == batch->firstmesh)
continue;
// if (batch->meshes == batch->firstmesh)
// continue;
/*draw depth only, to mask it off*/
GLBE_SelectMode(BEM_DEPTHONLY);
GLBE_SubmitBatch(batch);
GLBE_SelectMode(BEM_STANDARD);
}
}
GLBE_SelectMode(BEM_STANDARD);
if (gl_config.arb_depth_clamp)
qglDisable(GL_DEPTH_CLAMP_ARB);
}
@ -4749,9 +4758,9 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
int oldfbo;
float oldil;
int oldbem;
//these flags require rendering some view as an fbo
if (r_refdef.recurse)
if (r_refdef.recurse == r_portalrecursion.ival || r_refdef.recurse == R_MAX_RECURSE)
continue;
//these flags require rendering some view as an fbo
if (shaderstate.mode != BEM_STANDARD && shaderstate.mode != BEM_DEPTHDARK)
continue;
oldbem = shaderstate.mode;
@ -4759,36 +4768,37 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
if ((bs->flags & SHADER_HASREFLECT) && gl_config.ext_framebuffer_objects)
{
float renderscale = r_refractreflect_scale.value;
vrect_t orect = r_refdef.vrect;
pxrect_t oprect = r_refdef.pxrect;
if (!shaderstate.tex_reflection)
if (!shaderstate.tex_reflection[r_refdef.recurse])
{
shaderstate.tex_reflection = Image_CreateTexture("***tex_reflection***", NULL, 0);
if (!shaderstate.tex_reflection->num)
qglGenTextures(1, &shaderstate.tex_reflection->num);
shaderstate.tex_reflection[r_refdef.recurse] = Image_CreateTexture("***tex_reflection***", NULL, 0);
if (!shaderstate.tex_reflection[r_refdef.recurse]->num)
qglGenTextures(1, &shaderstate.tex_reflection[r_refdef.recurse]->num);
}
r_refdef.vrect.x = 0;
r_refdef.vrect.y = 0;
r_refdef.vrect.width = vid.fbvwidth/2;
r_refdef.vrect.height = vid.fbvheight/2;
r_refdef.vrect.width = max(1, vid.fbvwidth * renderscale);
r_refdef.vrect.height = max(1, vid.fbvheight * renderscale);
r_refdef.pxrect.x = 0;
r_refdef.pxrect.y = 0;
r_refdef.pxrect.width = vid.fbpwidth/2;
r_refdef.pxrect.height = vid.fbpheight/2;
if (shaderstate.tex_reflection->width!=r_refdef.pxrect.width || shaderstate.tex_reflection->height!=r_refdef.pxrect.height)
r_refdef.pxrect.width = max(1, vid.fbpwidth * renderscale);
r_refdef.pxrect.height = max(1, vid.fbpheight * renderscale);
if (shaderstate.tex_reflection[r_refdef.recurse]->width!=r_refdef.pxrect.width || shaderstate.tex_reflection[r_refdef.recurse]->height!=r_refdef.pxrect.height)
{
shaderstate.tex_reflection->width = r_refdef.pxrect.width;
shaderstate.tex_reflection->height = r_refdef.pxrect.height;
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_reflection);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shaderstate.tex_reflection->width, shaderstate.tex_reflection->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
shaderstate.tex_reflection[r_refdef.recurse]->width = r_refdef.pxrect.width;
shaderstate.tex_reflection[r_refdef.recurse]->height = r_refdef.pxrect.height;
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_reflection[r_refdef.recurse]);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac, FBO_RB_DEPTH, &shaderstate.tex_reflection, 1, r_nulltex, shaderstate.tex_reflection->width, shaderstate.tex_reflection->height, 0);
r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac.rb_size[1];
oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac[r_refdef.recurse], FBO_RB_DEPTH, &shaderstate.tex_reflection[r_refdef.recurse], 1, r_nulltex, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0);
r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac[r_refdef.recurse].rb_size[1];
GL_ViewportUpdate();
GL_ForceDepthWritable();
qglClearColor(0, 0, 0, 1);
@ -4803,28 +4813,29 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
{
if (r_refract_fboival)
{
float renderscale = min(1, r_refractreflect_scale.value);
vrect_t ovrect = r_refdef.vrect;
pxrect_t oprect = r_refdef.pxrect;
r_refdef.vrect.x = 0;
r_refdef.vrect.y = 0;
r_refdef.vrect.width = vid.fbvwidth/2;
r_refdef.vrect.height = vid.fbvheight/2;
r_refdef.vrect.width = max(1, vid.fbvwidth * renderscale);
r_refdef.vrect.height = max(1, vid.fbvheight * renderscale);
r_refdef.pxrect.x = 0;
r_refdef.pxrect.y = 0;
r_refdef.pxrect.width = vid.fbpwidth/2;
r_refdef.pxrect.height = vid.fbpheight/2;
r_refdef.pxrect.width = max(1, vid.fbpwidth * renderscale);
r_refdef.pxrect.height = max(1, vid.fbpheight * renderscale);
if (!shaderstate.tex_refraction)
if (!shaderstate.tex_refraction[r_refdef.recurse])
{
shaderstate.tex_refraction = Image_CreateTexture("***tex_refraction***", NULL, 0);
if (!shaderstate.tex_refraction->num)
qglGenTextures(1, &shaderstate.tex_refraction->num);
shaderstate.tex_refraction[r_refdef.recurse] = Image_CreateTexture("***tex_refraction***", NULL, 0);
if (!shaderstate.tex_refraction[r_refdef.recurse]->num)
qglGenTextures(1, &shaderstate.tex_refraction[r_refdef.recurse]->num);
}
if (shaderstate.tex_refraction->width != r_refdef.pxrect.width || shaderstate.tex_refraction->height != r_refdef.pxrect.height)
if (shaderstate.tex_refraction[r_refdef.recurse]->width != r_refdef.pxrect.width || shaderstate.tex_refraction[r_refdef.recurse]->height != r_refdef.pxrect.height)
{
shaderstate.tex_refraction->width = r_refdef.pxrect.width;
shaderstate.tex_refraction->height = r_refdef.pxrect.height;
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_refraction);
shaderstate.tex_refraction[r_refdef.recurse]->width = r_refdef.pxrect.width;
shaderstate.tex_refraction[r_refdef.recurse]->height = r_refdef.pxrect.height;
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_refraction[r_refdef.recurse]);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@ -4833,30 +4844,30 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
}
if (bs->flags & SHADER_HASREFRACTDEPTH)
{
if (!shaderstate.tex_refractiondepth)
if (!shaderstate.tex_refractiondepth[r_refdef.recurse])
{
shaderstate.tex_refractiondepth = Image_CreateTexture("***tex_refractiondepth***", NULL, 0);
if (!shaderstate.tex_refractiondepth->num)
qglGenTextures(1, &shaderstate.tex_refractiondepth->num);
shaderstate.tex_refractiondepth[r_refdef.recurse] = Image_CreateTexture("***tex_refractiondepth***", NULL, 0);
if (!shaderstate.tex_refractiondepth[r_refdef.recurse]->num)
qglGenTextures(1, &shaderstate.tex_refractiondepth[r_refdef.recurse]->num);
}
if (shaderstate.tex_refractiondepth->width != r_refdef.pxrect.width || shaderstate.tex_refractiondepth->height != r_refdef.pxrect.height)
if (shaderstate.tex_refractiondepth[r_refdef.recurse]->width != r_refdef.pxrect.width || shaderstate.tex_refractiondepth[r_refdef.recurse]->height != r_refdef.pxrect.height)
{
shaderstate.tex_refractiondepth->width = r_refdef.pxrect.width;
shaderstate.tex_refractiondepth->height = r_refdef.pxrect.height;
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_refractiondepth);
shaderstate.tex_refractiondepth[r_refdef.recurse]->width = r_refdef.pxrect.width;
shaderstate.tex_refractiondepth[r_refdef.recurse]->height = r_refdef.pxrect.height;
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_refractiondepth[r_refdef.recurse]);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24_ARB, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac, FBO_TEX_DEPTH, &shaderstate.tex_refraction, 1, shaderstate.tex_refractiondepth, r_refdef.pxrect.width, r_refdef.pxrect.height, 0);
oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac[r_refdef.recurse], FBO_TEX_DEPTH, &shaderstate.tex_refraction[r_refdef.recurse], 1, shaderstate.tex_refractiondepth[r_refdef.recurse], r_refdef.pxrect.width, r_refdef.pxrect.height, 0);
}
else
{
oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac, FBO_RB_DEPTH, &shaderstate.tex_refraction, 1, r_nulltex, r_refdef.pxrect.width, r_refdef.pxrect.height, 0);
oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac[r_refdef.recurse], FBO_RB_DEPTH, &shaderstate.tex_refraction[r_refdef.recurse], 1, r_nulltex, r_refdef.pxrect.width, r_refdef.pxrect.height, 0);
}
r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac.rb_size[1];
r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac[r_refdef.recurse].rb_size[1];
GL_ViewportUpdate();
GL_ForceDepthWritable();
@ -4874,37 +4885,38 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
}
if ((bs->flags & SHADER_HASRIPPLEMAP) && gl_config.ext_framebuffer_objects)
{
float renderscale = r_refractreflect_scale.value;
vrect_t orect = r_refdef.vrect;
pxrect_t oprect = r_refdef.pxrect;
r_refdef.vrect.x = 0;
r_refdef.vrect.y = 0;
r_refdef.vrect.width = vid.fbvwidth/2;
r_refdef.vrect.height = vid.fbvheight/2;
r_refdef.vrect.width = max(1, vid.fbvwidth * renderscale);
r_refdef.vrect.height = max(1, vid.fbvheight * renderscale);
r_refdef.pxrect.x = 0;
r_refdef.pxrect.y = 0;
r_refdef.pxrect.width = vid.fbpwidth/2;
r_refdef.pxrect.height = vid.fbpheight/2;
r_refdef.pxrect.width = max(1, vid.fbpwidth * renderscale);
r_refdef.pxrect.height = max(1, vid.fbpheight * renderscale);
if (!shaderstate.tex_ripplemap)
if (!shaderstate.tex_ripplemap[r_refdef.recurse])
{
//FIXME: can we use RGB8 instead?
shaderstate.tex_ripplemap = Image_CreateTexture("***tex_ripplemap***", NULL, 0);
if (!shaderstate.tex_ripplemap->num)
qglGenTextures(1, &shaderstate.tex_ripplemap->num);
shaderstate.tex_ripplemap[r_refdef.recurse] = Image_CreateTexture("***tex_ripplemap***", NULL, 0);
if (!shaderstate.tex_ripplemap[r_refdef.recurse]->num)
qglGenTextures(1, &shaderstate.tex_ripplemap[r_refdef.recurse]->num);
}
if (shaderstate.tex_ripplemap->width != r_refdef.pxrect.width || shaderstate.tex_ripplemap->height != r_refdef.pxrect.height)
if (shaderstate.tex_ripplemap[r_refdef.recurse]->width != r_refdef.pxrect.width || shaderstate.tex_ripplemap[r_refdef.recurse]->height != r_refdef.pxrect.height)
{
shaderstate.tex_ripplemap->width = r_refdef.pxrect.width;
shaderstate.tex_ripplemap->height = r_refdef.pxrect.height;
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_ripplemap);
shaderstate.tex_ripplemap[r_refdef.recurse]->width = r_refdef.pxrect.width;
shaderstate.tex_ripplemap[r_refdef.recurse]->height = r_refdef.pxrect.height;
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_ripplemap[r_refdef.recurse]);
qglTexImage2D(GL_TEXTURE_2D, 0, /*(gl_config.glversion>3.1)?GL_RGBA8_SNORM:*/GL_RGBA16F_ARB, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac, 0, &shaderstate.tex_ripplemap, 1, r_nulltex, r_refdef.pxrect.width, r_refdef.pxrect.height, 0);
r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac.rb_size[1];
oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac[r_refdef.recurse], 0, &shaderstate.tex_ripplemap[r_refdef.recurse], 1, r_nulltex, r_refdef.pxrect.width, r_refdef.pxrect.height, 0);
r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac[r_refdef.recurse].rb_size[1];
GL_ViewportUpdate();
qglClearColor(0, 0, 0, 1);
@ -5058,7 +5070,7 @@ void GLBE_RenderToTextureUpdate2d(qboolean destchanged)
else
GLBE_FBO_Push(NULL);
GL_Set2D(false);
GL_Set2D(false);
}
else
{

View File

@ -18,6 +18,18 @@ cvar_t mod_terrain_networked = CVARD("mod_terrain_networked", "0", "Terrain edit
cvar_t mod_terrain_defaulttexture = CVARD("mod_terrain_defaulttexture", "", "Newly created terrain tiles will use this texture. This should generally be updated by the terrain editor.");
cvar_t mod_terrain_savever = CVARD("mod_terrain_savever", "", "Which terrain section version to write if terrain was edited.");
enum
{
hmcmd_brush_delete,
hmcmd_brush_insert,
hmcmd_prespawning, //sent before initial inserts
hmcmd_prespawned, //sent just after initial inserts
hmcmd_ent_edit = 0x40,
hmcmd_ent_remove
};
void validatelinks(link_t *firstnode)
{
/* link_t *node;
@ -4808,8 +4820,9 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
vec3_t pos;// G_VECTOR(OFS_PARM1);
float radius = G_FLOAT(OFS_PARM2);
float quant = G_FLOAT(OFS_PARM3);
int modelindex = ((wedict_t*)PROG_TO_EDICT(prinst, *vmw->g.self))->v->modelindex;
// G_FLOAT(OFS_RETURN) = Heightmap_Edit(w->worldmodel, action, pos, radius, quant);
model_t *mod = vmw->Get_CModel(vmw, ((wedict_t*)PROG_TO_EDICT(prinst, *vmw->g.self))->v->modelindex);
model_t *mod = vmw->Get_CModel(vmw, modelindex);
heightmap_t *hm;
vec4_t tally;
@ -4828,16 +4841,86 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
case ter_ent_get:
{
int idx = G_INT(OFS_PARM1);
G_INT(OFS_RETURN) = 0;
if (!mod->numentityinfo)
Mod_ParseEntities(mod);
if (idx >= mod->numentityinfo || !mod->entityinfo[idx].keyvals)
G_INT(OFS_RETURN) = 0;
else
G_INT(OFS_RETURN) = PR_TempString(prinst, mod->entityinfo[idx].keyvals);
}
return;
case ter_ent_set:
{
int idx = G_INT(OFS_PARM1);
const char *news = PR_GetStringOfs(prinst, OFS_PARM2);
const char *newvals;
if (!mod->numentityinfo)
Mod_ParseEntities(mod);
if (idx < mod->numentityinfo)
{
Z_Free(mod->entityinfo[idx].keyvals);
mod->entityinfo[idx].keyvals = NULL;
}
if (G_INT(OFS_PARM2))
{
newvals = PR_GetStringOfs(prinst, OFS_PARM2);
if (idx >= mod->numentityinfo)
Z_ReallocElements(&mod->entityinfo, &mod->numentityinfo, idx+64, sizeof(*mod->entityinfo));
mod->entityinfo[idx].keyvals = Z_StrDup(newvals);
}
else
newvals = NULL;
G_INT(OFS_RETURN) = 0;
#ifndef CLIENTONLY
if (sv.state && modelindex > 0)
{
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
MSG_WriteShort(&sv.multicast, modelindex);
MSG_WriteByte(&sv.multicast, newvals?hmcmd_ent_edit:hmcmd_ent_remove);
MSG_WriteLong(&sv.multicast, idx);
if (newvals)
MSG_WriteString(&sv.multicast, newvals);
SV_MulticastProtExt(vec3_origin, MULTICAST_ALL_R, ~0, 0, 0);
//tell ssqc, csqc will be told by the server
}
else
#endif
#ifndef SERVERONLY
if (cls.state && modelindex > 0)
{
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
MSG_WriteShort(&cls.netchan.message, modelindex);
MSG_WriteByte(&cls.netchan.message, newvals?hmcmd_ent_edit:hmcmd_ent_remove);
MSG_WriteLong(&cls.netchan.message, idx);
if (newvals)
MSG_WriteString(&cls.netchan.message, newvals);
#ifdef CSQC_DAT
CSQC_MapEntityEdited(idx, newvals);
#endif
}
else
#endif
{
#ifdef CSQC_DAT
CSQC_MapEntityEdited(idx, newvals);
#endif
}
}
return;
case ter_ent_add:
{
int idx = G_INT(OFS_PARM1);
const char *news = PR_GetStringOfs(prinst, OFS_PARM2);
G_INT(OFS_RETURN) = mod->numentityinfo;
}
return;
case ter_ent_count:
if (!mod->numentityinfo)
Mod_ParseEntities(mod);
G_INT(OFS_RETURN) = mod->numentityinfo;
return;
case ter_ents_wipe:
G_INT(OFS_RETURN) = PR_TempString(prinst, Mod_GetEntitiesString(mod));
Mod_SetEntitiesString(mod, "", true);
@ -6018,6 +6101,7 @@ static qboolean Brush_Deserialise(heightmap_t *hm, brushes_t *br)
}
return true;
}
#ifndef SERVERONLY
heightmap_t *CL_BrushEdit_ForceContext(model_t *mod)
{
@ -6050,14 +6134,20 @@ void CL_Parse_BrushEdit(void)
model_t *mod = (modelindex<countof(cl.model_precache))?cl.model_precache[modelindex]:NULL;
heightmap_t *hm = mod?mod->terrain:NULL;
if (cmd == 0)
#ifdef CLIENTONLY
const qboolean ignore = false;
#else
const qboolean ignore = (sv.state>=ss_loading); //if we're the server then we already have this info. don't break anything (this info is present for demos).
#endif
if (cmd == hmcmd_brush_delete)
{
int id = MSG_ReadLong();
if (sv.state >= ss_loading)
if (ignore)
return; //ignore if we're the server, we should already have it anyway.
Terr_Brush_DeleteId(hm, id);
}
else if (cmd == 1)
else if (cmd == hmcmd_brush_insert) //1=create/replace
{
brushes_t brush;
@ -6069,7 +6159,7 @@ void CL_Parse_BrushEdit(void)
brush.faces = alloca(sizeof(*brush.faces) * brush.numplanes);
if (!Brush_Deserialise(hm, &brush))
Host_EndGame("CL_Parse_BrushEdit: unparsable brush\n");
if (sv.state >= ss_loading)
if (ignore)
return; //ignore if we're the server, we should already have it anyway (but might need it for demos, hence why its still sent).
if (brush.id)
{
@ -6088,9 +6178,9 @@ void CL_Parse_BrushEdit(void)
}
Terr_Brush_Insert(mod, hm, &brush);
}
else if (cmd == 2)
{
if (sv.state >= ss_loading)
else if (cmd == hmcmd_prespawning)
{ //delete all
if (ignore)
return; //ignore if we're the server, we should already have it anyway.
hm = CL_BrushEdit_ForceContext(mod); //make sure we don't end up with any loaded brushes.
@ -6100,9 +6190,37 @@ void CL_Parse_BrushEdit(void)
Terr_Brush_DeleteIdx(hm, hm->numbrushes-1);
}
}
else if (cmd == 3)
else if (cmd == hmcmd_prespawned)
{
//follows edits after a 2
}
else if (cmd == hmcmd_ent_edit)
{ //ent edit
int id = MSG_ReadLong();
const char *data = MSG_ReadString();
if (id > 0xffff)
return;
if (id >= mod->numentityinfo)
Z_ReallocElements(&mod->entityinfo, &mod->numentityinfo, id+64, sizeof(*mod->entityinfo));
if (id < mod->numentityinfo)
{
if (!ignore)
{
Z_Free(mod->entityinfo[id].keyvals);
mod->entityinfo[id].keyvals = Z_StrDup(data);
}
CSQC_MapEntityEdited(id, data);
}
}
else if (cmd == hmcmd_ent_remove)
{
int id = MSG_ReadLong();
if (sv.state >= ss_loading)
return; //if we're the server then this will already have been done. don't clobber from internal latency
if (id < mod->numentityinfo)
{
Z_Free(mod->entityinfo[id].keyvals);
mod->entityinfo[id].keyvals = NULL;
}
}
else
Host_EndGame("CL_Parse_BrushEdit: unknown command %i\n", cmd);
@ -6140,7 +6258,7 @@ qboolean SV_Prespawn_Brushes(sizebuf_t *msg, unsigned int *modelindex, unsigned
{ //make sure the client starts with a clean slate.
MSG_WriteByte(msg, svcfte_brushedit);
MSG_WriteShort(msg, *modelindex);
MSG_WriteByte(msg, 2);
MSG_WriteByte(msg, hmcmd_prespawning);
}
//weird loop to try to ensure we never miss any brushes.
@ -6161,7 +6279,7 @@ qboolean SV_Prespawn_Brushes(sizebuf_t *msg, unsigned int *modelindex, unsigned
{
MSG_WriteByte(msg, svcfte_brushedit);
MSG_WriteShort(msg, *modelindex);
MSG_WriteByte(msg, 1);
MSG_WriteByte(msg, hmcmd_brush_insert);
Brush_Serialise(msg, best);
*lastid = bestid;
return true;
@ -6178,8 +6296,8 @@ qboolean SV_Parse_BrushEdit(void)
int cmd = MSG_ReadByte();
model_t *mod = (modelindex<countof(sv.models))?sv.models[modelindex]:NULL;
heightmap_t *hm = mod?mod->terrain:NULL;
if (cmd == 0)
{
if (cmd == hmcmd_brush_delete)
{ //delete
unsigned int brushid = MSG_ReadLong();
if (!authorise)
{
@ -6190,12 +6308,12 @@ qboolean SV_Parse_BrushEdit(void)
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
MSG_WriteShort(&sv.multicast, modelindex);
MSG_WriteByte(&sv.multicast, 0);
MSG_WriteByte(&sv.multicast, hmcmd_brush_delete);
MSG_WriteLong(&sv.multicast, brushid);
SV_MulticastProtExt(vec3_origin, MULTICAST_ALL_R, ~0, 0, 0);
return true;
}
else if (cmd == 1)
else if (cmd == hmcmd_brush_insert)
{
brushes_t brush;
memset(&brush, 0, sizeof(brush));
@ -6221,11 +6339,31 @@ qboolean SV_Parse_BrushEdit(void)
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
MSG_WriteShort(&sv.multicast, modelindex);
MSG_WriteByte(&sv.multicast, 1);
MSG_WriteByte(&sv.multicast, hmcmd_brush_insert);
Brush_Serialise(&sv.multicast, &brush);
SV_MulticastProtExt(vec3_origin, MULTICAST_ALL_R, ~0, 0, 0);
return true;
}
else if (cmd == hmcmd_ent_edit || cmd == hmcmd_ent_remove)
{
size_t entid = MSG_ReadLong();
char *keyvals = (cmd == hmcmd_ent_edit)?MSG_ReadString():NULL;
if (mod->submodelof != mod)
return true;
if (!authorise)
{
SV_PrintToClient(host_client, PRINT_MEDIUM, "Entity editing ignored: you are not a mapper\n");
return true;
}
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
MSG_WriteShort(&sv.multicast, modelindex);
MSG_WriteByte(&sv.multicast, keyvals?hmcmd_ent_edit:hmcmd_ent_remove);
MSG_WriteLong(&sv.multicast, entid);
if (keyvals)
MSG_WriteString(&sv.multicast, keyvals);
SV_MulticastProtExt(vec3_origin, MULTICAST_ALL_R, ~0, 0, 0);
}
else
{
Con_Printf("SV_Parse_BrushEdit: %s sent an unknown command: %i\n", host_client->name, cmd);
@ -6366,7 +6504,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
{
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
MSG_WriteShort(&sv.multicast, modelindex);
MSG_WriteByte(&sv.multicast, 0);
MSG_WriteByte(&sv.multicast, hmcmd_brush_delete);
MSG_WriteLong(&sv.multicast, brushid);
SV_MulticastProtExt(vec3_origin, MULTICAST_ALL_R, ~0, 0, 0);
}
@ -6377,7 +6515,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
{
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
MSG_WriteShort(&cls.netchan.message, modelindex);
MSG_WriteByte(&cls.netchan.message, 0);
MSG_WriteByte(&cls.netchan.message, hmcmd_brush_delete);
MSG_WriteLong(&cls.netchan.message, brushid);
}
#else
@ -6418,7 +6556,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
{
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
MSG_WriteShort(&sv.multicast, modelindex);
MSG_WriteByte(&sv.multicast, 1);
MSG_WriteByte(&sv.multicast, hmcmd_brush_insert);
Brush_Serialise(&sv.multicast, nb);
SV_MulticastProtExt(vec3_origin, MULTICAST_ALL_R, ~0, 0, 0);
return;
@ -6429,7 +6567,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
{
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
MSG_WriteShort(&cls.netchan.message, modelindex);
MSG_WriteByte(&cls.netchan.message, 1);
MSG_WriteByte(&cls.netchan.message, hmcmd_brush_insert);
Brush_Serialise(&cls.netchan.message, nb);
return;
}
@ -6456,7 +6594,7 @@ void QCBUILTIN PF_brush_delete(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
{
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
MSG_WriteShort(&sv.multicast, modelindex);
MSG_WriteByte(&sv.multicast, 0);
MSG_WriteByte(&sv.multicast, hmcmd_brush_delete);
MSG_WriteLong(&sv.multicast, brushid);
SV_MulticastProtExt(vec3_origin, MULTICAST_ALL_R, ~0, 0, 0);
return;
@ -6467,7 +6605,7 @@ void QCBUILTIN PF_brush_delete(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
{
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
MSG_WriteShort(&cls.netchan.message, modelindex);
MSG_WriteByte(&cls.netchan.message, 0);
MSG_WriteByte(&cls.netchan.message, hmcmd_brush_delete);
MSG_WriteLong(&cls.netchan.message, brushid);
return;
}

View File

@ -3,6 +3,7 @@
#ifdef HALFLIFEMODELS
#include "shader.h"
#include "com_mesh.h"
/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Half-Life Model Renderer (Experimental) Copyright (C) 2001 James 'Ender' Brown [ender@quakesrc.org] This program is
@ -22,7 +23,6 @@
Also, please note that it won't do all hl models....
Nor will it work 100%
*/
#include "model_hl.h"
void QuaternionGLMatrix(float x, float y, float z, float w, vec4_t *GLM)
{
@ -66,6 +66,140 @@ matrix3x4 transform_matrix[MAX_BONES]; /* Vertex transformation matrix */
void GL_Draw_HL_AliasFrame(short *order, vec3_t *transformed, float tex_w, float tex_h);
struct hlvremaps
{
unsigned short vertidx;
unsigned short normalidx;
unsigned short scoord;
unsigned short tcoord;
};
static index_t HLMDL_DeDupe(unsigned short *order, struct hlvremaps *rem, size_t *count)
{
size_t i;
for (i = *count; i-- > 0;)
{
if (rem[i].vertidx == order[0] && rem[i].normalidx == order[1] && rem[i].scoord == order[2] && rem[i].tcoord == order[3])
return i;
}
i = *count;
rem[i].vertidx = order[0];
rem[i].normalidx = order[1];
rem[i].scoord = order[2];
rem[i].tcoord = order[3];
*count += 1;
return i;
}
//parse the vertex info, pull out what we can
static void HLMDL_PrepareVerticies (hlmodel_t *model, hlmdl_submodel_t *amodel, struct hlalternative_s *submodel)
{
struct hlvremaps *uvert;
size_t uvertcount;
unsigned short count;
int i;
size_t idx = 0, v, m;
mesh_t *mesh = &submodel->mesh;
index_t *index;
vec3_t *verts = (vec3_t *) ((qbyte *) model->header + amodel->vertindex);
qbyte *bone = ((qbyte *) model->header + amodel->vertinfoindex);
vec3_t *norms = (vec3_t *) ((qbyte *) model->header + amodel->normindex);
uvertcount = 0;
uvert = malloc(sizeof(*uvert)*2048);
index = mesh->indexes = ZG_Malloc(model->memgroup, sizeof(*mesh->colors4b_array)*65536);
for(m = 0; m < amodel->nummesh; m++)
{
hlmdl_mesh_t *inmesh = (hlmdl_mesh_t *) ((qbyte *) model->header + amodel->meshindex) + m;
unsigned short *order = (unsigned short *) ((qbyte *) model->header + inmesh->index);
submodel->submesh[m].firstindex = mesh->numindexes;
submodel->submesh[m].numindexes = 0;
for(;;)
{
count = *order++; /* get the vertex count and primitive type */
if(!count) break; /* done */
if(count & 0x8000)
{ //fan
int first = HLMDL_DeDupe(order+0*4, uvert, &uvertcount);
int prev = HLMDL_DeDupe(order+1*4, uvert, &uvertcount);
for (i = min(2,count); i < -(short)count; i++)
{
index[idx++] = first;
index[idx++] = prev;
index[idx++] = prev = HLMDL_DeDupe(order+i*4, uvert, &uvertcount);
}
}
else
{
int v0 = HLMDL_DeDupe(order+0*4, uvert, &uvertcount);
int v1 = HLMDL_DeDupe(order+1*4, uvert, &uvertcount);
//emit (count-2)*3 indicies as a strip
//012 213, etc
for (i = min(2,count); i < count; i++)
{
if (i & 1)
{
index[idx++] = v1;
index[idx++] = v0;
}
else
{
index[idx++] = v0;
index[idx++] = v1;
}
v0 = v1;
index[idx++] = v1 = HLMDL_DeDupe(order+i*4, uvert, &uvertcount);
}
}
order += i*4;
}
submodel->submesh[m].numindexes = idx - submodel->submesh[m].firstindex;
}
mesh->numindexes = idx;
mesh->numvertexes = uvertcount;
mesh->colors4b_array = ZG_Malloc(model->memgroup, sizeof(*mesh->colors4b_array)*uvertcount);
mesh->st_array = ZG_Malloc(model->memgroup, sizeof(*mesh->st_array)*uvertcount);
mesh->lmst_array[0] = ZG_Malloc(model->memgroup, sizeof(*mesh->lmst_array[0])*uvertcount);
mesh->xyz_array = ZG_Malloc(model->memgroup, sizeof(*mesh->xyz_array)*uvertcount);
mesh->normals_array = ZG_Malloc(model->memgroup, sizeof(*mesh->normals_array)*uvertcount);
mesh->snormals_array = ZG_Malloc(model->memgroup, sizeof(*mesh->snormals_array)*uvertcount);
mesh->tnormals_array = ZG_Malloc(model->memgroup, sizeof(*mesh->tnormals_array)*uvertcount);
mesh->bonenums = ZG_Malloc(model->memgroup, sizeof(*mesh->bonenums)*uvertcount);
mesh->boneweights = ZG_Malloc(model->memgroup, sizeof(*mesh->boneweights)*uvertcount);
//prepare the verticies now that we have the mappings
for(v = 0; v < uvertcount; v++)
{
mesh->bonenums[v][0] = mesh->bonenums[v][1] = mesh->bonenums[v][2] = mesh->bonenums[v][3] = bone[uvert[v].vertidx];
Vector4Set(mesh->boneweights[v], 1, 0, 0, 0);
Vector4Set(mesh->colors4b_array[v], 255, 255, 255, 255); //why bytes? why not?
mesh->lmst_array[0][v][0] = uvert[v].scoord;
mesh->lmst_array[0][v][1] = uvert[v].tcoord;
VectorCopy(verts[uvert[v].vertidx], mesh->xyz_array[v]);
//Warning: these models use different tables for vertex and normals.
//this means they might be transformed by different bones. we ignore that and just assume that the normals will want the same bone.
VectorCopy(norms[uvert[v].normalidx], mesh->normals_array[v]);
}
//don't need that mapping any more
free(uvert);
//treat this as the base pose, and calculate the sdir+tdir for bumpmaps.
R_Generate_Mesh_ST_Vectors(mesh);
}
/*
=======================================================================================================================
Mod_LoadHLModel - read in the model's constituent parts
@ -73,10 +207,9 @@ void GL_Draw_HL_AliasFrame(short *order, vec3_t *transformed, float tex_w, float
*/
qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
{
/*~~*/
int i;
int i;
hlmodelcache_t *model;
hlmodel_t *model;
hlmdl_header_t *header;
hlmdl_header_t *texheader;
hlmdl_tex_t *tex;
@ -84,11 +217,12 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
hlmdl_bonecontroller_t *bonectls;
struct hlmodelshaders_s *shaders;
void *texmem = NULL;
/*~~*/
int body;
//load the model into hunk
model = ZG_Malloc(&mod->memgroup, sizeof(hlmodelcache_t));
model = ZG_Malloc(&mod->memgroup, sizeof(hlmodel_t));
model->memgroup = &mod->memgroup;
header = ZG_Malloc(&mod->memgroup, fsize);
memcpy(header, buffer, fsize);
@ -97,7 +231,7 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
//this is to let bigfoot know when he comes to port it all... And I'm lazy.
#ifdef warningmsg
#pragma warningmsg("-----------------------------------------")
#pragma warningmsg("FIXME: No byteswapping on halflife models")
#pragma warningmsg("FIXME: No byteswapping on halflife models") //hah, yeah, good luck with that, you'll need it.
#pragma warningmsg("-----------------------------------------")
#endif
#endif
@ -141,24 +275,8 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
header->numtextures = texheader->numtextures;
tex = (hlmdl_tex_t *) ((qbyte *) texheader + texheader->textures);
bones = (hlmdl_bone_t *) ((qbyte *) header + header->boneindex);
bonectls = (hlmdl_bonecontroller_t *) ((qbyte *) header + header->controllerindex);
/* won't work - doesn't know exact sizes.
header = Hunk_Alloc(sizeof(hlmdl_header_t));
memcpy(header, (hlmdl_header_t *) buffer, sizeof(hlmdl_header_t));
tex = Hunk_Alloc(sizeof(hlmdl_tex_t)*header->numtextures);
memcpy(tex, (hlmdl_tex_t *) buffer, sizeof(hlmdl_tex_t)*header->numtextures);
bones = Hunk_Alloc(sizeof(hlmdl_bone_t)*header->numtextures);
memcpy(bones, (hlmdl_bone_t *) buffer, sizeof(hlmdl_bone_t)*header->numbones);
bonectls = Hunk_Alloc(sizeof(hlmdl_bonecontroller_t)*header->numcontrollers);
memcpy(bonectls, (hlmdl_bonecontroller_t *) buffer, sizeof(hlmdl_bonecontroller_t)*header->numcontrollers);
*/
bones = (hlmdl_bone_t *) ((qbyte *) header + header->boneindex);
bonectls = (hlmdl_bonecontroller_t *) ((qbyte *) header + header->controllerindex);
model->header = header;
model->bones = bones;
@ -166,18 +284,19 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
shaders = ZG_Malloc(&mod->memgroup, texheader->numtextures*sizeof(shader_t));
model->shaders = shaders;
for(i = 0; i < texheader->numtextures; i++)
{
Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "%s_%i.tga", mod->name, i);
for(i = 0; i < texheader->numtextures; i++)
{
Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "%s/%s", mod->name, COM_SkipPath(tex[i].name));
memset(&shaders[i].defaulttex, 0, sizeof(shaders[i].defaulttex));
shaders[i].defaulttex.base = Image_GetTexture(shaders[i].name, "", IF_NOALPHA, (qbyte *) texheader + tex[i].offset, (qbyte *) texheader + tex[i].w * tex[i].h + tex[i].offset, tex[i].w, tex[i].h, TF_8PAL24);
shaders[i].w = tex[i].w;
shaders[i].h = tex[i].h;
}
}
model->numskins = texheader->numtextures;
model->skins = ZG_Malloc(&mod->memgroup, model->numskins*sizeof(*model->skins));
memcpy(model->skins, (short *) ((qbyte *) texheader + texheader->skins), model->numskins*sizeof(*model->skins));
model->numskinrefs = texheader->skinrefs;
model->numskingroups = texheader->skingroups;
model->skinref = ZG_Malloc(&mod->memgroup, model->numskinrefs*model->numskingroups*sizeof(*model->skinref));
memcpy(model->skinref, (short *) ((qbyte *) texheader + texheader->skins), model->numskinrefs*model->numskingroups*sizeof(*model->skinref));
if (texmem)
@ -185,6 +304,23 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
mod->type = mod_halflife;
mod->meshinfo = model;
model->numgeomsets = model->header->numbodyparts;
model->geomset = ZG_Malloc(&mod->memgroup, sizeof(*model->geomset) * model->numgeomsets);
for (body = 0; body < model->header->numbodyparts; body++)
{
hlmdl_bodypart_t *bodypart = (hlmdl_bodypart_t *) ((qbyte *) model->header + model->header->bodypartindex) + body;
int bodyindex;
model->geomset[body].numalternatives = bodypart->nummodels;
model->geomset[body].alternatives = ZG_Malloc(&mod->memgroup, sizeof(*model->geomset[body].alternatives) * bodypart->nummodels);
for (bodyindex = 0; bodyindex < bodypart->nummodels; bodyindex++)
{
hlmdl_submodel_t *amodel = (hlmdl_submodel_t *) ((qbyte *) model->header + bodypart->modelindex) + bodyindex;
model->geomset[body].alternatives[bodyindex].numsubmeshes = amodel->nummesh;
model->geomset[body].alternatives[bodyindex].submesh = ZG_Malloc(&mod->memgroup, sizeof(*model->geomset[body].alternatives[bodyindex].submesh) * amodel->nummesh);
HLMDL_PrepareVerticies(model, amodel, &model->geomset[body].alternatives[bodyindex]);
}
}
return true;
}
@ -200,12 +336,12 @@ void *Mod_GetHalfLifeModelData(model_t *mod)
}
#endif
int HLMod_FrameForName(model_t *mod, const char *name)
int HLMDL_FrameForName(model_t *mod, const char *name)
{
int i;
hlmdl_header_t *h;
hlmdl_sequencelist_t *seqs;
hlmodelcache_t *mc;
hlmodel_t *mc;
if (!mod || mod->type != mod_halflife)
return -1; //halflife models only, please
@ -222,12 +358,12 @@ int HLMod_FrameForName(model_t *mod, const char *name)
return -1;
}
int HLMod_BoneForName(model_t *mod, char *name)
int HLMDL_BoneForName(model_t *mod, const char *name)
{
int i;
hlmdl_header_t *h;
hlmdl_bone_t *bones;
hlmodelcache_t *mc;
hlmodel_t *mc;
if (!mod || mod->type != mod_halflife)
return -1; //halflife models only, please
@ -315,17 +451,23 @@ void HL_CalcBoneAdj(hlmodel_t *model)
/*~~~~~~~~~~~~~~~~~~~~~*/
if(control[i].type & 0x8000)
{
value = model->controller[j] + control[i].start;
{ //wraps normally
value = model->controller[j];// + control[i].start;
}
else
{
value = (model->controller[j]+1)*0.5; //shifted to give a valid range between -1 and 1, with 0 being mid-range.
if(value < 0)
value = 0;
else if(value > 1.0)
value = 1.0;
value = (1.0 - value) * control[i].start + value * control[i].end;
// value = (model->controller[j]+1)*0.5; //shifted to give a valid range between -1 and 1, with 0 being mid-range.
// if(value < 0)
// value = 0;
// else if(value > 1.0)
// value = 1.0;
// value = (1.0 - value) * control[i].start + value * control[i].end;
value = model->controller[j];
if (value < control[i].start)
value = control[i].start;
if (value > control[i].end)
value = control[i].end;
}
/* Rotational controllers need their values converted */
@ -342,11 +484,10 @@ void HL_CalcBoneAdj(hlmodel_t *model)
=======================================================================================================================
*/
void QuaternionSlerp( const vec4_t p, vec4_t q, float t, vec4_t qt );
void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, float subblendfrac, float frametime)
void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, float subblendfrac, float frametime, float *matrix)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
int i;
float matrix[3][4];
vec3_t organg1[2];
vec3_t organg2[2];
vec3_t organgb[2];
@ -362,6 +503,8 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl
hlmdl_anim_t *animation;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
matrix += firstbone*12;
if (sequencedata->name[32])
{
size_t fz;
@ -460,7 +603,7 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl
subblendfrac = 0;
if (subblendfrac > 1)
subblendfrac = 1;
for(i = firstbone; i < lastbone; i++)
for(i = firstbone; i < lastbone; i++, matrix+=12)
{
//calc first blend (writes organgb+quatb)
HL_CalculateBones(frame1, model->adjust, model->bones + i, animation + i, organgb[0]);
@ -486,26 +629,17 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl
VectorInterpolate(organg1[0], frametime, organg2[0], organg1[0]);
}
//blend the two
//blend the two, figure out a matrix.
QuaternionSlerp(quatb, quat1, subblendfrac, quat1);
FloatInterpolate(organgb[0][0], subblendfrac, organg1[0][0], matrix[0][3]);
FloatInterpolate(organgb[0][0], subblendfrac, organg1[0][1], matrix[1][3]);
FloatInterpolate(organgb[0][0], subblendfrac, organg1[0][2], matrix[2][3]);
/* If we have a parent, take the addition. Otherwise just copy the values */
if(model->bones[i].parent>=0)
{
R_ConcatTransforms(transform_matrix[model->bones[i].parent], matrix, transform_matrix[i]);
}
else
{
memcpy(transform_matrix[i], matrix, 12 * sizeof(float));
}
QuaternionGLMatrix(quat1[0], quat1[1], quat1[2], quat1[3], (vec4_t*)matrix);
FloatInterpolate(organgb[0][0], subblendfrac, organg1[0][0], matrix[0*4+3]);
FloatInterpolate(organgb[0][0], subblendfrac, organg1[0][1], matrix[1*4+3]);
FloatInterpolate(organgb[0][0], subblendfrac, organg1[0][2], matrix[2*4+3]);
}
}
else
{
for(i = firstbone; i < lastbone; i++)
for(i = firstbone; i < lastbone; i++, matrix+=12)
{
HL_CalculateBones(frame1, model->adjust, model->bones + i, animation + i, organg1[0]);
QuaternionGLAngle(organg1[1], quat1); /* A quaternion */
@ -519,147 +653,172 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl
VectorInterpolate(organg1[0], frametime, organg2[0], organg1[0]);
}
//figure out the relative bone matrix.
//we probably ought to keep them as quats or something.
QuaternionGLMatrix(quat1[0], quat1[1], quat1[2], quat1[3], matrix);
matrix[0][3] = organg1[0][0];
matrix[1][3] = organg1[0][1];
matrix[2][3] = organg1[0][2];
/* If we have a parent, take the addition. Otherwise just copy the values */
if(model->bones[i].parent>=0)
{
R_ConcatTransforms(transform_matrix[model->bones[i].parent], matrix, transform_matrix[i]);
}
else
{
memcpy(transform_matrix[i], matrix, 12 * sizeof(float));
}
QuaternionGLMatrix(quat1[0], quat1[1], quat1[2], quat1[3], (vec4_t*)matrix);
matrix[0*4+3] = organg1[0][0];
matrix[1*4+3] = organg1[0][1];
matrix[2*4+3] = organg1[0][2];
}
}
}
void R_HL_BuildFrame(hlmodel_t *model, hlmdl_model_t *amodel, entity_t *curent, short *order, float tex_s, float tex_t, mesh_t *mesh)
int HLMDL_GetNumBones(model_t *mod)
{
static vecV_t xyz[2048];
static vec3_t norm[2048];
static vec2_t st[2048];
static byte_vec4_t vc[2048];
static index_t index[4096];
int count;
int b;
int cbone;
int bgroup;
int lastbone;
int v, i;
vec3_t *verts;
qbyte *bone;
vec3_t transformed[2048];
hlmodel_t *mc;
if (!mod || mod->type != mod_halflife)
return -1; //halflife models only, please
int idx = 0;
int vert = 0;
mc = Mod_Extradata(mod);
return mc->header->numbones;
}
mesh->xyz_array = xyz;
mesh->st_array = st;
mesh->normals_array = norm; //for lighting algos to not crash
mesh->snormals_array = norm; //for rtlighting
mesh->tnormals_array = norm; //for rtlighting
mesh->indexes = index;
mesh->colors4b_array = vc;
int HLMDL_GetBoneData(model_t *mod, int firstbone, int lastbone, framestate_t *fstate, float *result)
{
int b, cbone, bgroup;
hlmodel_t *model = Mod_Extradata(mod);
for (b = 0; b < MAX_BONE_CONTROLLERS; b++)
model->controller[b] = curent->framestate.bonecontrols[b];
// Con_Printf("%s %i\n", sequence->name, sequence->unknown1[0]);
cbone = 0;
for (bgroup = 0; bgroup < FS_COUNT; bgroup++)
model->controller[b] = fstate->bonecontrols[b];
for (cbone = 0, bgroup = 0; bgroup < FS_COUNT; bgroup++)
{
lastbone = curent->framestate.g[bgroup].endbone;
lastbone = fstate->g[bgroup].endbone;
if (bgroup == FS_COUNT-1)
lastbone = model->header->numbones;
if (cbone >= lastbone)
continue;
HL_SetupBones(model, curent->framestate.g[bgroup].frame[0], cbone, lastbone, (curent->framestate.g[bgroup].subblendfrac+1)*0.5, curent->framestate.g[bgroup].frametime[0]); /* Setup the bones */
HL_SetupBones(model, fstate->g[bgroup].frame[0], cbone, lastbone, (fstate->g[bgroup].subblendfrac+1)*0.5, fstate->g[bgroup].frametime[0], result); /* Setup the bones */
cbone = lastbone;
}
return cbone;
}
const char *HLMDL_FrameNameForNum(model_t *mod, int surfaceidx, int seqnum)
{
hlmodel_t *model = Mod_Extradata(mod);
hlmdl_sequencelist_t *sequence = (hlmdl_sequencelist_t *) ((qbyte *) model->header + model->header->seqindex) +
((unsigned int)seqnum>=model->header->numseq?0:seqnum);
return sequence->name;
}
qboolean HLMDL_FrameInfoForNum(model_t *mod, int surfaceidx, int seqnum, char **name, int *numframes, float *duration, qboolean *loop)
{
hlmodel_t *model = Mod_Extradata(mod);
hlmdl_sequencelist_t *sequence = (hlmdl_sequencelist_t *) ((qbyte *) model->header + model->header->seqindex) +
((unsigned int)seqnum>=model->header->numseq?0:seqnum);
verts = (vec3_t *) ((qbyte *) model->header + amodel->vertindex);
bone = ((qbyte *) model->header + amodel->vertinfoindex);
for(v = 0; v < amodel->numverts; v++)
*name = sequence->name;
*numframes = sequence->numframes;
*duration = sequence->numframes/sequence->timing;
*loop = sequence->loop;
return true;
}
void R_HL_BuildFrame(hlmodel_t *model, hlmdl_submodel_t *amodel, entity_t *curent, int bodypart, int bodyidx, int meshidx, float tex_s, float tex_t, mesh_t *mesh, qboolean gpubones)
{
int b;
int cbone;
int bgroup;
int lastbone;
int v;
*mesh = model->geomset[bodypart].alternatives[bodyidx].mesh;
//FIXME: cache this!
if (curent->framestate.bonecount >= model->header->numbones)
{
VectorTransform(verts[v], (void *)transform_matrix[bone[v]], transformed[v]);
}
for(;;)
{
count = *order++; /* get the vertex count and primitive type */
if(!count) break; /* done */
if(count < 0)
if (curent->framestate.skeltype == SKEL_RELATIVE)
{
count = -count;
//emit (count-2)*3 indicies as a fan
for (i = 0; i < count-2; i++)
mesh->numbones = model->header->numbones;
for (b = 0; b < mesh->numbones; b++)
{
index[idx++] = vert + 0;
index[idx++] = vert + i+1;
index[idx++] = vert + i+2;
/* If we have a parent, take the addition. Otherwise just copy the values */
if(model->bones[b].parent>=0)
{
R_ConcatTransforms(transform_matrix[model->bones[b].parent], (void*)(curent->framestate.bonestate+b*12), transform_matrix[b]);
}
else
{
memcpy(transform_matrix[b], curent->framestate.bonestate+b*12, 12 * sizeof(float));
}
}
mesh->bones = transform_matrix[0][0];
}
else
{
//emit (count-2)*3 indicies as a strip
mesh->bones = curent->framestate.bonestate;
mesh->numbones = curent->framestate.bonecount;
}
}
else
{
float relatives[12*MAX_BONES];
mesh->bones = transform_matrix[0][0];
mesh->numbones = model->header->numbones;
for (i = 0; ; )
{
if (i == count-2)
break;
index[idx++] = vert + i;
index[idx++] = vert + i+1;
index[idx++] = vert + i+2;
i++;
if (i == count-2)
break;
index[idx++] = vert + i;
index[idx++] = vert + i+2;
index[idx++] = vert + i+1;
i++;
}
//FIXME: needs caching.
for (b = 0; b < MAX_BONE_CONTROLLERS; b++)
model->controller[b] = curent->framestate.bonecontrols[b];
for (cbone = 0, bgroup = 0; bgroup < FS_COUNT; bgroup++)
{
lastbone = curent->framestate.g[bgroup].endbone;
if (bgroup == FS_COUNT-1)
lastbone = model->header->numbones;
if (cbone >= lastbone)
continue;
HL_SetupBones(model, curent->framestate.g[bgroup].frame[0], cbone, lastbone, (curent->framestate.g[bgroup].subblendfrac+1)*0.5, curent->framestate.g[bgroup].frametime[0], relatives); /* Setup the bones */
cbone = lastbone;
}
do
//convert relative to absolutes
for (b = 0; b < cbone; b++)
{
VectorCopy(transformed[order[0]], xyz[vert]);
//FIXME: what's order[1]?
/* texture coordinates come from the draw list */
st[vert][0] = order[2] * tex_s;
st[vert][1] = order[3] * tex_t;
/*fixme: build vertex normals in the base pose and transform them using the same bone matricies (just discard the origin part)*/
norm[vert][0] = 1;
norm[vert][1] = 1;
norm[vert][2] = 1;
vc[vert][0] = 255;
vc[vert][1] = 255;
vc[vert][2] = 255;
vc[vert][3] = 255;
order += 4;
vert++;
} while(--count);
/* If we have a parent, take the addition. Otherwise just copy the values */
if(model->bones[b].parent>=0)
{
R_ConcatTransforms(transform_matrix[model->bones[b].parent], (void*)(relatives+b*12), transform_matrix[b]);
}
else
{
memcpy(transform_matrix[b], relatives+b*12, 12 * sizeof(float));
}
}
}
mesh->numindexes = idx;
mesh->numvertexes = vert;
mesh->indexes += model->geomset[bodypart].alternatives[bodyidx].submesh[meshidx].firstindex;
mesh->numindexes = model->geomset[bodypart].alternatives[bodyidx].submesh[meshidx].numindexes;
if (gpubones)
{ //get the backend to do the skeletal stuff (read: glsl)
for(v = 0; v < mesh->numvertexes; v++)
{ //should really come up with a better way to deal with this, like rect textures.
mesh->st_array[v][0] = mesh->lmst_array[0][v][0] * tex_s;
mesh->st_array[v][1] = mesh->lmst_array[0][v][1] * tex_t;
}
}
else
{ //backend can't handle it, apparently. do it in software.
static vecV_t nxyz[2048];
static vec3_t nnorm[2048];
for(v = 0; v < mesh->numvertexes; v++)
{ //should really come up with a better way to deal with this, like rect textures.
mesh->st_array[v][0] = mesh->lmst_array[0][v][0] * tex_s;
mesh->st_array[v][1] = mesh->lmst_array[0][v][1] * tex_t;
VectorTransform(mesh->xyz_array[v], (void *)transform_matrix[mesh->bonenums[v][0]], nxyz[v]);
nnorm[v][0] = DotProduct(mesh->normals_array[v], transform_matrix[mesh->bonenums[v][0]][0]);
nnorm[v][1] = DotProduct(mesh->normals_array[v], transform_matrix[mesh->bonenums[v][0]][1]);
nnorm[v][2] = DotProduct(mesh->normals_array[v], transform_matrix[mesh->bonenums[v][0]][2]);
//FIXME: svector, tvector!
}
mesh->xyz_array = nxyz;
mesh->normals_array = nnorm;
mesh->bonenums = NULL;
mesh->boneweights = NULL;
mesh->bones = NULL;
mesh->numbones = 0;
}
}
void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches);
@ -670,26 +829,24 @@ void R_HL_BuildMesh(struct batch_s *b)
void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
{
hlmodelcache_t *modelc = Mod_Extradata(rent->model);
hlmodel_t model;
hlmodel_t *model = Mod_Extradata(rent->model);
int body, m;
int batchid = 0;
static mesh_t bmesh, *mptr = &bmesh;
skinfile_t *sk = NULL;
//general model
model.header = modelc->header;
model.bones = modelc->bones;
model.bonectls = modelc->bonectls;
model.shaders = modelc->shaders;
model.animcache = modelc->animcache;
model.memgroup = &rent->model->memgroup;
unsigned int entity_body = rent->bottomcolour;
for (body = 0; body < model.header->numbodyparts; body++)
if (rent->customskin)
sk = Mod_LookupSkin(rent->customskin);
//entity_body = rent->body; //hey, if its there, lets use it.
for (body = 0; body < model->header->numbodyparts; body++)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
hlmdl_bodypart_t *bodypart = (hlmdl_bodypart_t *) ((qbyte *) model.header + model.header->bodypartindex) + body;
int bodyindex = (0 / bodypart->base) % bodypart->nummodels;
hlmdl_model_t *amodel = (hlmdl_model_t *) ((qbyte *) model.header + bodypart->modelindex) + bodyindex;
hlmdl_bodypart_t *bodypart = (hlmdl_bodypart_t *) ((qbyte *) model->header + model->header->bodypartindex) + body;
int bodyindex = ((sk && body < MAX_GEOMSETS && sk->geomset[body] >= 1)?sk->geomset[body]-1:(entity_body / bodypart->base)) % bodypart->nummodels;
hlmdl_submodel_t *amodel = (hlmdl_submodel_t *) ((qbyte *) model->header + bodypart->modelindex) + bodyindex;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
@ -697,16 +854,18 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
for(m = 0; m < amodel->nummesh; m++)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
hlmdl_mesh_t *mesh = (hlmdl_mesh_t *) ((qbyte *) model.header + amodel->meshindex) + m;
hlmdl_mesh_t *mesh = (hlmdl_mesh_t *) ((qbyte *) model->header + amodel->meshindex) + m;
float tex_w;
float tex_h;
struct hlmodelshaders_s *s;
int skinidx = mesh->skinindex;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if (mesh->skinindex >= modelc->numskins)
continue;
s = &model.shaders[modelc->skins[mesh->skinindex]];
if (skinidx >= model->numskinrefs)
continue; //can happen from bad mesh/skin mixing
if (rent->skinnum < model->numskingroups)
skinidx += rent->skinnum * model->numskinrefs;
s = &model->shaders[model->skinref[skinidx]];
if (batches)
{
@ -716,19 +875,34 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
if (!b)
return;
if (!s->shader)
{
s->shader = R_RegisterSkin(s->name, rent->model->name);
R_BuildDefaultTexnums(&s->defaulttex, s->shader);
}
b->skin = NULL;
b->shader = s->shader;
if (sk)
{
int i;
for (i = 0; i < sk->nummappings; i++)
{
if (!strcmp(sk->mappings[i].surface, s->name))
{
b->skin = &sk->mappings[i].texnums;
b->shader = sk->mappings[i].shader;
break;
}
}
}
b->buildmeshes = R_HL_BuildMesh;
b->ent = rent;
b->mesh = NULL;
b->firstmesh = 0;
b->meshes = 1;
b->skin = NULL;
b->texture = NULL;
b->shader = s->shader;
for (j = 0; j < MAXRLIGHTMAPS; j++)
b->lightmap[j] = -1;
b->surf_first = batchid;
@ -761,7 +935,7 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
b->next = batches[sort];
batches[sort] = b;
}
else
else
{
if (batchid == b->surf_first)
{
@ -769,7 +943,7 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
tex_h = 1.0f / s->h;
b->mesh = &mptr;
R_HL_BuildFrame(&model, amodel, b->ent, (short *) ((qbyte *) model.header + mesh->index), tex_w, tex_h, b->mesh[0]);
R_HL_BuildFrame(model, amodel, b->ent, body, bodyindex, m, tex_w, tex_h, b->mesh[0], b->shader->prog && (b->shader->prog->supportedpermutations & PERMUTATION_SKELETAL));
return;
}
}

View File

@ -452,13 +452,48 @@ void Mod_ResortShaders(void)
const char *Mod_GetEntitiesString(model_t *mod)
{
size_t vl;
size_t e;
size_t sz;
char *o;
if (!mod)
return NULL;
if (mod->entities_raw) //still cached/correct
return mod->entities_raw;
if (!mod->numentityinfo)
return NULL;
//reform the entities back into a full string now that we apparently need it
//find needed buffer size
for (e = 0, sz = 0; e < mod->numentityinfo; e++)
{
if (!mod->entityinfo[e].keyvals)
continue;
sz += 2;
sz += strlen(mod->entityinfo[e].keyvals);
sz += 2;
}
sz+=1;
o = BZ_Malloc(sz);
//splurge it out
for (e = 0, sz = 0; e < mod->numentityinfo; e++)
{
if (!mod->entityinfo[e].keyvals)
continue;
o[sz+0] = '{';
o[sz+1] = '\n';
sz += 2;
vl = strlen(mod->entityinfo[e].keyvals);
memcpy(&o[sz], mod->entityinfo[e].keyvals, vl);
sz += vl;
o[sz+0] = '}';
o[sz+1] = '\n';
sz += 2;
}
o[sz+0] = 0;
mod->entities_raw = o;
return mod->entities_raw;
}
void Mod_SetEntitiesString(model_t *mod, const char *str, qboolean docopy)
@ -493,6 +528,64 @@ void Mod_SetEntitiesStringLen(model_t *mod, const char *str, size_t strsize)
Mod_SetEntitiesString(mod, str, false);
}
void Mod_ParseEntities(model_t *mod)
{
char key[1024];
char value[4096];
const char *entstart;
const char *entend;
const char *entdata;
size_t c, m;
c = 0; m = 0;
while (mod->numentityinfo > 0)
Z_Free(mod->entityinfo[--mod->numentityinfo].keyvals);
Z_Free(mod->entityinfo);
mod->entityinfo = NULL;
entdata = mod->entities_raw;
while(1)
{
if (!(entdata=COM_ParseOut(entdata, key, sizeof(key))))
break;
if (strcmp(key, "{"))
break;
//skip whitespace to save space.
while (*entdata == ' ' || *entdata == '\r' || *entdata == '\n' || *entdata == '\t')
entdata++;
entstart = entdata;
while(1)
{
entend = entdata;
entdata=COM_ParseOut(entdata, key, sizeof(key));
if (!strcmp(key, "}"))
break;
entdata=COM_ParseOut(entdata, value, sizeof(value));
}
if (!entdata)
break; //erk. eof
if (c == m)
{
if (!m)
m = 64;
else
m *= 2;
mod->entityinfo = BZ_Realloc(mod->entityinfo, sizeof(*mod->entityinfo) * m);
}
mod->entityinfo[c].keyvals = BZ_Malloc(entend-entstart + 1);
memcpy(mod->entityinfo[c].keyvals, entstart, entend-entstart);
mod->entityinfo[c].keyvals[entend-entstart] = 0;
c++;
}
mod->numentityinfo = c;
}
/*
===================
Mod_ClearAll

View File

@ -899,9 +899,6 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2],
qbyte newvis[(MAX_MAP_LEAFS+7)/8];
float ivmat[16], trmat[16];
if (r_refdef.recurse >= R_MAX_RECURSE-1)
return;
if (!mesh->xyz_array)
return;
@ -947,6 +944,15 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2],
if (DotProduct(r_refdef.vieworg, plane.normal)-plane.dist < -r_refdef.mindist)
return;
if (r_refdef.recurse >= R_MAX_RECURSE-1)
{
GLBE_SelectMode(BEM_DEPTHDARK);
GLBE_SubmitBatch(batch);
GLBE_SelectMode(BEM_STANDARD);
return;
}
TRACE(("GLR_DrawPortal: portal type %i\n", portaltype));
oldrefdef = r_refdef;
@ -1156,9 +1162,7 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2],
fp.dist += 0.01;
r_refdef.frustum[r_refdef.frustum_numplanes++] = fp;
}
//force culling to update to match the new front face.
// memcpy(r_refdef.m_view, vmat, sizeof(float)*16);
#if 1
if (depthmasklist)
{
/*draw already-drawn portals as depth-only, to ensure that their contents are not harmed*/
@ -1172,7 +1176,6 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2],
qglMatrixMode(GL_MODELVIEW);
}
//portals to mask are relative to the old view still.
GLBE_SelectEntity(&r_worldentity);
currententity = NULL;
if (gl_config.arb_depth_clamp)
qglEnable(GL_DEPTH_CLAMP_ARB); //ignore the near clip plane(ish), this means nearer portals can still mask further ones.
@ -1184,8 +1187,8 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2],
{
if (dmask == batch)
continue;
if (dmask->meshes == dmask->firstmesh)
continue;
// if (dmask->meshes == dmask->firstmesh)
// continue;
GLBE_SubmitBatch(dmask);
}
}
@ -1195,6 +1198,9 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2],
currententity = NULL;
}
#endif
// r_refdef = oldrefdef;
// return;
//now determine the stuff the backend will use.
memcpy(r_refdef.m_view, vmat, sizeof(float)*16);

View File

@ -221,9 +221,11 @@ enum shaderparsemode_e
static struct
{
enum shaderparsemode_e mode;
qboolean droppass;
qboolean forceprogramify;
//for dpwater compat, used to generate a program
int dpwatertype;
float reflectmin;
float reflectmax;
float reflectfactor;
@ -231,7 +233,6 @@ static struct
vec3_t refractcolour;
vec3_t reflectcolour;
float wateralpha;
qboolean droppass;
} parsestate;
typedef struct shaderkey_s
@ -2281,6 +2282,7 @@ static void Shader_DP_Water(shader_t *shader, shaderpass_t *pass, char **ptr)
{
parsestate.forceprogramify = true;
parsestate.dpwatertype |= 3;
parsestate.reflectmin = Shader_ParseFloat(shader, ptr, 0);
parsestate.reflectmax = Shader_ParseFloat(shader, ptr, 0);
parsestate.refractfactor = Shader_ParseFloat(shader, ptr, 0);
@ -2293,6 +2295,9 @@ static void Shader_DP_Reflect(shader_t *shader, shaderpass_t *pass, char **ptr)
{
parsestate.forceprogramify = true;
parsestate.dpwatertype |= 1;
parsestate.reflectmin = 1;
parsestate.reflectmax = 1;
parsestate.reflectfactor = Shader_ParseFloat(shader, ptr, 0);
Shader_ParseVector(shader, ptr, parsestate.reflectcolour);
}
@ -2300,6 +2305,7 @@ static void Shader_DP_Refract(shader_t *shader, shaderpass_t *pass, char **ptr)
{
parsestate.forceprogramify = true;
parsestate.dpwatertype |= 2;
parsestate.refractfactor = Shader_ParseFloat(shader, ptr, 0);
Shader_ParseVector(shader, ptr, parsestate.refractcolour);
}
@ -4257,9 +4263,9 @@ void Shader_Programify (shader_t *s)
return;*/
}
if (parsestate.refractfactor || parsestate.reflectfactor)
if (parsestate.dpwatertype)
{
prog = va("altwater#REFLECT#USEMODS#FRESNEL_EXP=2.0"
prog = va("altwater%s#USEMODS#FRESNEL_EXP=2.0"
//variable parts
"#STRENGTH_REFR=%g#STRENGTH_REFL=%g"
"#TINT_REFR=%g,%g,%g"
@ -4267,6 +4273,7 @@ void Shader_Programify (shader_t *s)
"#FRESNEL_MIN=%g#FRESNEL_RANGE=%g"
"#ALPHA=%g",
//those args
(parsestate.dpwatertype&1)?"#REFLECT":"",
parsestate.refractfactor*0.01, parsestate.reflectfactor*0.01,
parsestate.refractcolour[0],parsestate.refractcolour[1],parsestate.refractcolour[2],
parsestate.reflectcolour[0],parsestate.reflectcolour[1],parsestate.reflectcolour[2],
@ -5633,7 +5640,7 @@ void Shader_DefaultBSPQ2(const char *shortname, shader_t *s, const void *args)
void Shader_DefaultBSPQ1(const char *shortname, shader_t *s, const void *args)
{
char *builtin = NULL;
if (r_mirroralpha.value < 1 && !strcmp(shortname, "window02_1"))
if (r_mirroralpha.value < 1 && (!strcmp(shortname, "window02_1") || !strncmp(shortname, "mirror", 6)))
{
if (r_mirroralpha.value < 0)
{

View File

@ -21,28 +21,30 @@
*/
typedef struct
{
int filetypeid; //IDSP
int filetypeid; //IDSP
int version; //10
char name[64];
int filesize;
vec3_t unknown3[5];
int unknown4;
int numbones;
int boneindex;
int numcontrollers;
int controllerindex;
int unknown5[2];
int numseq;
int seqindex;
int unknown6;
int seqgroups;
int numtextures;
int textures;
int unknown7[3];
int skins;
int numbodyparts;
int bodypartindex;
int unknown9[8];
char name[64];
int filesize;
vec3_t unknown3[5];
int unknown4; //flags
int numbones;
int boneindex;
int numcontrollers;
int controllerindex;
int unknown5[2]; //hitboxes
int numseq;
int seqindex;
int unknown6; //external sequences
int seqgroups;
int numtextures;
int textures;
int unknown7; //something to do with external textures
int skinrefs;
int skingroups;
int skins;
int numbodyparts;
int bodypartindex;
int unknown9[8]; //attachments, sounds, transitions
} hlmdl_header_t;
/*
@ -52,11 +54,11 @@ typedef struct
*/
typedef struct
{
char name[64];
int flags;
int w; /* width */
int h; /* height */
int offset; /* index */
char name[64];
int flags; /*flat, chrome, fullbright*/
int w; /* width */
int h; /* height */
int offset; /* index */
} hlmdl_tex_t;
/*
@ -66,10 +68,10 @@ typedef struct
*/
typedef struct
{
char name[64];
int nummodels;
int base;
int modelindex;
char name[64];
int nummodels;
int base;
int modelindex;
} hlmdl_bodypart_t;
/*
@ -79,11 +81,11 @@ typedef struct
*/
typedef struct
{
int numtris;
int index;
int skinindex;
int unknown2;
int unknown3;
int numtris;
int index;
int skinindex;
int unknown2;
int unknown3;
} hlmdl_mesh_t;
/*
@ -93,12 +95,12 @@ typedef struct
*/
typedef struct
{
char name[32];
int parent;
int unknown1;
int bonecontroller[6];
float value[6];
float scale[6];
char name[32];
int parent;
int unknown1;
int bonecontroller[6];
float value[6];
float scale[6];
} hlmdl_bone_t;
/*
@ -108,31 +110,33 @@ typedef struct
*/
typedef struct
{
int name;
int type;
float start;
float end;
int unknown1;
int index;
int name;
int type;
float start;
float end;
int unknown1;
int index;
} hlmdl_bonecontroller_t;
/*
-----------------------------------------------------------------------------------------------------------------------
halflife model descriptor
halflife submodel descriptor
-----------------------------------------------------------------------------------------------------------------------
*/
typedef struct
{
char name[64];
int unknown1;
float unknown2;
int nummesh;
int meshindex;
int numverts;
int vertinfoindex;
int vertindex;
int unknown3[5];
} hlmdl_model_t;
char name[64];
int unknown1;
float unknown2;
int nummesh;
int meshindex;
int numverts;
int vertinfoindex;
int vertindex;
int unknown3[2];
int normindex;
int unknown4[2];
} hlmdl_submodel_t;
/*
-----------------------------------------------------------------------------------------------------------------------
@ -141,7 +145,7 @@ typedef struct
*/
typedef struct
{
unsigned short offset[6];
unsigned short offset[6];
} hlmdl_anim_t;
/*
@ -151,11 +155,11 @@ typedef struct
*/
typedef union
{
struct {
qbyte valid;
qbyte total;
} num;
short value;
struct {
qbyte valid;
qbyte total;
} num;
short value;
} hlmdl_animvalue_t;
/*
@ -165,24 +169,24 @@ typedef union
*/
typedef struct
{
char name[32];
float timing;
char name[32];
float timing;
int loop;
int unknown1[4];
int numframes;
int unknown2[2];
int motiontype;
int motionbone;
vec3_t unknown3;
int unknown4[2];
vec3_t bbox[2];
int hasblendseq;
int index;
int unknown7[2];
float unknown[4];
int unknown8;
unsigned int seqindex;
int unknown9[4];
int unknown1[4];
int numframes;
int unknown2[2];
int motiontype;
int motionbone;
vec3_t unknown3;
int unknown4[2];
vec3_t bbox[2];
int hasblendseq;
int index;
int unknown7[2];
float unknown[4];
int unknown8;
unsigned int seqindex;
int unknown9[4];
} hlmdl_sequencelist_t;
/*
@ -192,9 +196,9 @@ typedef struct
*/
typedef struct
{
char name[96]; /* should be split label[32] and name[64] */
unsigned int cache;
int data;
char name[96]; /* should be split label[32] and name[64] */
unsigned int cache;
int data;
} hlmdl_sequencedata_t;
typedef struct
@ -209,27 +213,19 @@ typedef struct
halflife model internal structure
-----------------------------------------------------------------------------------------------------------------------
*/
typedef struct
{
float controller[5]; /* Position of bone controllers */
float adjust[5];
/* Static pointers */
hlmdl_header_t *header;
hlmdl_bone_t *bones;
hlmdl_bonecontroller_t *bonectls;
struct hlmodelshaders_s *shaders;
hlmdl_sequencefile_t **animcache;
zonegroup_t *memgroup;
} hlmodel_t;
#define MAX_ANIM_GROUPS 16 //submodel files containing anim data.
typedef struct //this is stored as the cache. an hlmodel_t is generated when drawing
{
hlmdl_header_t *header;
hlmdl_bone_t *bones;
hlmdl_bonecontroller_t *bonectls;
//updated while rendering...
float controller[5]; /* Position of bone controllers */
float adjust[5];
hlmdl_header_t *header;
hlmdl_bone_t *bones;
hlmdl_bonecontroller_t *bonectls;
hlmdl_sequencefile_t *animcache[MAX_ANIM_GROUPS];
zonegroup_t *memgroup;
struct hlmodelshaders_s
{
char name[MAX_QPATH];
@ -237,9 +233,26 @@ typedef struct //this is stored as the cache. an hlmodel_t is generated when dra
shader_t *shader;
int w, h;
} *shaders;
short *skins;
int numskins;
} hlmodelcache_t;
short *skinref;
int numskinrefs;
int numskingroups;
int numgeomsets;
struct
{
int numalternatives;
struct hlalternative_s
{
mesh_t mesh;
int numsubmeshes;
struct
{
int firstindex;
int numindexes;
} *submesh;
} *alternatives;
} *geomset;
} hlmodel_t;
/* HL mathlib prototypes: */
void QuaternionGLAngle(const vec3_t angles, vec4_t quaternion);
@ -252,3 +265,11 @@ void R_DrawHLModel(entity_t *curent);
/* physics stuff */
void *Mod_GetHalfLifeModelData(model_t *mod);
//reflectioney things, including bone data
int HLMDL_BoneForName(model_t *mod, const char *name);
int HLMDL_FrameForName(model_t *mod, const char *name);
const char *HLMDL_FrameNameForNum(model_t *model, int surfaceidx, int num);
qboolean HLMDL_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop);
int HLMDL_GetNumBones(model_t *mod);
int HLMDL_GetBoneData(model_t *model, int firstbone, int lastbone, framestate_t *fstate, float *result);

View File

@ -3121,6 +3121,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#endif
#ifdef D3D11QUAKE
{QR_DIRECT3D11, 11, "defaultskin",
"!!permu UPPERLOWER\n"
"!!samps diffuse upper lower fullbright\n"
"struct a2v\n"
@ -3183,11 +3184,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#ifdef UPPER\n"
"float4 uc = t_upper.Sample(SampleType, inp.tc);\n"
"col.rgb = lerp(col.rgb, uc.rgb*e_uppercolour, uc.a);\n"
"col.rgb += uc.rgb*e_uppercolour.rgb*uc.a;\n"
"#endif\n"
"#ifdef LOWER\n"
"float4 lc = t_lower.Sample(SampleType, inp.tc);\n"
"col.rgb = lerp(col.rgb, lc.rgb*e_lowercolour, lc.a);\n"
"col.rgb += lc.rgb*e_lowercolour.rgb*lc.a;\n"
"#endif\n"
"col.rgb *= inp.light;\n"
//#ifdef FULLBRIGHT
@ -4482,7 +4483,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "defaultwall",
"!!ver 110 130\n"
"!!ver 110 // 130\n"
"!!permu DELUXE\n"
"!!permu FULLBRIGHT\n"
"!!permu FOG\n"

View File

@ -11939,8 +11939,12 @@ void PR_DumpPlatform_f(void)
{"TEREDIT_RESET_SECT", "const float", CS, NULL, ter_reset},
{"TEREDIT_RELOAD_SECT", "const float", CS, NULL, ter_reloadsect},
{"TEREDIT_ENTS_WIPE", "const float", CS, NULL, ter_ents_wipe},
{"TEREDIT_ENTS_CONCAT", "const float", CS, NULL, ter_ents_concat},
{"TEREDIT_ENTS_GET", "const float", CS, NULL, ter_ents_get},
// {"TEREDIT_ENTS_CONCAT", "const float", CS, NULL, ter_ents_concat},
// {"TEREDIT_ENTS_GET", "const float", CS, NULL, ter_ents_get},
{"TEREDIT_ENT_GET", "const float", CS, NULL, ter_ent_get},
{"TEREDIT_ENT_SET", "const float", CS, NULL, ter_ent_set},
{"TEREDIT_ENT_ADD", "const float", CS, NULL, ter_ent_add},
{"TEREDIT_ENT_COUNT", "const float", CS, NULL, ter_ent_count},
#endif
{"SLIST_HOSTCACHEVIEWCOUNT", "const float", CS|MENU, NULL, SLIST_HOSTCACHEVIEWCOUNT},

View File

@ -6398,7 +6398,7 @@ int SV_PMTypeForClient (client_t *cl, edict_t *ent)
case MOVETYPE_WALK:
default:
#ifndef NOLEGACY
if (ent->v->health <= 0)
if (cl && ent->v->health <= 0)
return PM_DEAD;
#endif
return PM_NORMAL;

View File

@ -1,4 +1,4 @@
!!ver 110 130
!!ver 110 // 130
!!permu DELUXE
!!permu FULLBRIGHT
!!permu FOG

View File

@ -1,3 +1,4 @@
!!permu UPPERLOWER
!!samps diffuse upper lower fullbright
struct a2v
@ -60,11 +61,11 @@ struct v2f
#ifdef UPPER
float4 uc = t_upper.Sample(SampleType, inp.tc);
col.rgb = lerp(col.rgb, uc.rgb*e_uppercolour, uc.a);
col.rgb += uc.rgb*e_uppercolour.rgb*uc.a;
#endif
#ifdef LOWER
float4 lc = t_lower.Sample(SampleType, inp.tc);
col.rgb = lerp(col.rgb, lc.rgb*e_lowercolour, lc.a);
col.rgb += lc.rgb*e_lowercolour.rgb*lc.a;
#endif
col.rgb *= inp.light;
//#ifdef FULLBRIGHT

View File

@ -6051,10 +6051,9 @@ void VKBE_DrawWorld (batch_t **worldbatches)
//fixme: figure out some way to safely orphan this data so that we can throw the rest to a worker.
BE_GenModelBatches(batches, shaderstate.curdlight, BEM_STANDARD);
BE_UploadLightmaps(false);
if (r_refdef.scenevis)
{
BE_UploadLightmaps(false);
//make sure the world draws correctly
r_worldentity.shaderRGBAf[0] = 1;
r_worldentity.shaderRGBAf[1] = 1;

View File

@ -1352,7 +1352,7 @@ static qboolean VK_R_RenderScene_Cubemap(struct vk_rendertarg *fb)
shader_t *shader;
int facemask;
extern cvar_t r_projection;
int osm = r_refdef.stereomethod;
int osm;
struct vk_rendertarg_cube *rtc = &vk_rt_cubemap;
if (!*ffov.string || !strcmp(ffov.string, "0"))
@ -1497,6 +1497,7 @@ static qboolean VK_R_RenderScene_Cubemap(struct vk_rendertarg *fb)
VectorCopy(r_refdef.viewangles, saveang);
saveang[2] = 0;
osm = r_refdef.stereomethod;
r_refdef.stereomethod = STEREO_OFF;
VKBE_RT_Gen_Cube(rtc, cmapsize, r_clear.ival?true:false);

View File

@ -1,6 +1,10 @@
../csaddon.dat
//pr_dumpplatform -FFTE -Fdefines -TCS -O csplat
opts.qc
//#pragma flag enable assumeint
//#pragma flag enable typeexplicit
#define CSQC
csplat.qc
csfixups.qc

View File

@ -67,6 +67,7 @@ Available options:
#define DP_EF_RED
#define DP_ENT_CUSTOMCOLORMAP
#define DP_ENT_EXTERIORMODELTOCLIENT
#define DP_ENT_SCALE
#define DP_ENT_TRAILEFFECTNUM /* self.traileffectnum=particleeffectnum("myeffectname"); can be used to attach a particle trail to the given server entity. This is equivelent to calling trailparticles each frame. */
#define DP_ENT_VIEWMODEL
#define DP_GECKO_SUPPORT
@ -148,6 +149,8 @@ Available options:
#define DP_TE_CUSTOMFLASH
#define DP_TE_EXPLOSIONRGB
#define DP_TE_PARTICLECUBE
#define DP_TE_PARTICLERAIN
#define DP_TE_PARTICLESNOW
#define DP_TE_SMALLFLASH
#define DP_TE_SPARK
#define DP_TE_STANDARDEFFECTBUILTINS
@ -160,10 +163,12 @@ Available options:
#define FTE_CALLTIMEOFDAY /* Replication of mvdsv functionality (call calltimeofday to cause 'timeofday' to be called, with arguments that can be saved off to a global). Generally strftime is simpler to use. */
#define FTE_CSQC_ALTCONSOLES /* The engine tracks multiple consoles. These may or may not be directly visible to the user. */
#define FTE_CSQC_BASEFRAME /* Specifies that .basebone, .baseframe2, .baselerpfrac, baseframe1time, etc exist in csqc. These fields affect all bones in the entity's model with a lower index than the .basebone field, allowing you to give separate control to the legs of a skeletal model, without affecting the torso animations. */
#define FTE_QC_BASEFRAME /* Specifies that .basebone and .baseframe exist in ssqc. These fields affect all bones in the entity's model with a lower index than the .basebone field, allowing you to give separate control to the legs of a skeletal model, without affecting the torso animations, from ssqc. */
#define FTE_CSQC_SERVERBROWSER
#define FTE_CSQC_SKELETONOBJECTS /* Provides container objects for skeletal bone data, which can be modified on a per bone basis if needed. This allows you to dynamically generate animations (or just blend them with greater customisation) instead of being limited to a single animation or two. */
#define FTE_CSQC_RAWIMAGES /* Provides raw rgba image access to csqc. With this, the csprogs can read textures into qc-accessible memory, modify it, and then upload it to the renderer. */
#define FTE_CSQC_RENDERTARGETS /* VF_RT_DESTCOLOUR exists and can be used to redirect any rendering to a texture instead of the screen. */
#define FTE_CSQC_REVERB /* Specifies that the mod can create custom reverb effects. Whether they will actually be used or not depends upon the sound driver. */
#define FTE_CSQC_WINDOWCAPTION /* Provides csqc with the ability to change the window caption as displayed when running windowed or in the task bar when switched out. */
#define FTE_ENT_SKIN_CONTENTS /* self.skin = CONTENTS_WATER; makes a brush entity into water. use -16 for a ladder. */
#define FTE_ENT_UNIQUESPAWNID
#define FTE_EXTENDEDTEXTCODES
@ -183,9 +188,14 @@ Available options:
#define FTE_PART_SCRIPT /* Specifies that the r_particledesc cvar can be used to select a list of particle effects to load from particles/*.cfg, the format of which is documented elsewhere. */
#define FTE_PART_NAMESPACES /* Specifies that the engine can use foo.bar to load effect foo from particle description bar. When used via ssqc, this should cause the client to download whatever effects as needed. */
#define FTE_PART_NAMESPACE_EFFECTINFO /* Specifies that effectinfo.bar can load effects from effectinfo.txt for DP compatibility. */
#define FTE_QC_BASEFRAME /* Specifies that .basebone and .baseframe exist in ssqc. These fields affect all bones in the entity's model with a lower index than the .basebone field, allowing you to give separate control to the legs of a skeletal model, without affecting the torso animations, from ssqc. */
#define FTE_QC_FILE_BINARY /* Extends FRIK_FILE with binary read+write, as well as allowing seeking. Requires pointers. */
#define FTE_QC_CHANGELEVEL_HUB /* Adds an extra argument to changelevel which is carried over to the next map in the 'spawnspot' global. Maps will be saved+reloaded until the extra argument is omitted again, purging all saved maps. Saved games will contain a copy of each preserved map. parm1-parm64 globals can be used, giving more space to transfer more player data. */
#define FTE_QC_CHECKCOMMAND /* Provides a way to test if a console command exists, and whether its a command/alias/cvar. Does not say anything about the expected meanings of any arguments or values. */
#define FTE_QC_CHECKPVS
#define FTE_QC_HARDWARECURSORS /* setcursormode exists in both csqc+menuqc, and accepts additional arguments to specify a cursor image to use when this module has focus. If the image exceeds hardware limits, it will be emulated using regular draws - this at least still avoids conflicting cursors. */
#define FTE_QC_CROSSPRODUCT
#define FTE_QC_FS_SEARCH_SIZEMTIME
#define FTE_QC_HARDWARECURSORS /* setcursormode exists in both csqc+menuqc, and accepts additional arguments to specify a cursor image to use when this module has focus. If the image exceeds hardware limits (or hardware cursors are unsupported), it will be emulated using regular draws - this at least still avoids conflicting cursors as only one will ever be used, even if console+menu+csqc are all overlayed. */
#define FTE_QC_HASHTABLES /* Provides efficient string-based lookups. */
#define FTE_QC_INTCONV /* Provides string<>int conversions, including hex representations. */
#define FTE_QC_MATCHCLIENTNAME
@ -193,6 +203,7 @@ Available options:
#define FTE_QC_PERSISTENTTEMPSTRINGS /* Supersedes DP_QC_MULTIPLETEMPSTRINGS. Temp strings are garbage collected automatically, and do not expire while they're still in use. This makes strzone redundant. */
#define FTE_QC_RAGDOLL_WIP
#define FTE_QC_SENDPACKET /* Allows the use of out-of-band udp packets to/from other hosts. Includes the SV_ParseConnectionlessPacket event. */
#define FTE_QC_STUFFCMDFLAGS /* Variation on regular stuffcmd that gives control over how spectators/mvds should be treated. */
#define FTE_QC_TRACETRIGGER
#define FTE_QUAKE2_CLIENT /* This engine is able to act as a quake2 client */
#define FTE_QUAKE2_SERVER /* This engine is able to act as a quake2 server */
@ -500,6 +511,13 @@ const int CONTENTBIT_SKY = 0x80000000i;
const int CONTENTBITS_POINTSOLID = CONTENTBIT_SOLID|0x00000002|CONTENTBIT_BODY; /* Bits that traceline would normally consider solid */
const int CONTENTBITS_BOXSOLID = CONTENTBIT_SOLID|0x00000002|CONTENTBIT_BODY|CONTENTBIT_PLAYERCLIP; /* Bits that tracebox would normally consider solid */
const int CONTENTBITS_FLUID = CONTENTBIT_WATER|CONTENTBIT_SLIME|CONTENTBIT_LAVA|CONTENTBIT_SKY;
const int SPA_POSITION; /* These SPA_* constants are to specify which attribute is returned by the getsurfacepointattribute builtin */
const int SPA_S_AXIS = 1;
const int SPA_T_AXIS = 2;
const int SPA_R_AXIS = 3; /* aka: SPA_NORMAL */
const int SPA_TEXCOORDS0 = 4;
const int SPA_LIGHTMAP0_TEXCOORDS = 5;
const int SPA_LIGHTMAP0_COLOR = 6;
#define CHAN_AUTO 0 /* The automatic channel, play as many sounds on this channel as you want, and they'll all play, however the other channels will replace each other. */
#define CHAN_WEAPON 1
#define CHAN_VOICE 2
@ -737,10 +755,12 @@ Note that any rendertarget textures may be destroyed on video mode changes or so
#define TEREDIT_MESH_KILL 16
#define TEREDIT_TINT 17
#define TEREDIT_RESET_SECT 20
#define TEREDIT_RELOAD_SECT 21
#define TEREDIT_RELOAD_SECT 21
#define TEREDIT_ENTS_WIPE 22
#define TEREDIT_ENTS_CONCAT 23
#define TEREDIT_ENTS_GET 24
#define TEREDIT_ENT_GET 26
#define TEREDIT_ENT_SET 27
#define TEREDIT_ENT_ADD 28
#define TEREDIT_ENT_COUNT 29
#define SLIST_HOSTCACHEVIEWCOUNT 0
#define SLIST_HOSTCACHETOTALCOUNT 1
#define SLIST_MASTERQUERYCOUNT 2
@ -804,7 +824,7 @@ void(entity e) remove = #15; /*
Destroys the given entity and clears some limited fields (including model, modelindex, solid, classname). Any references to the entity following the call are an error. After two seconds, the entity will be reused, in the interim you can unfortunatly still read its fields to see if the reference is no longer valid. */
void(vector v1, vector v2, float flags, entity ent) traceline = #16; /*
Traces an infinitely thin line through the world from v1 towards v2.
Traces a thin line through the world from v1 towards v2.
Will not collide with ent, ent.owner, or any entity who's owner field refers to ent.
The passed entity will also be used to determine whether to use a capsule trace, the contents that the trace should impact, and a couple of other extra fields that define the trace.
There are no side effects beyond the trace_* globals being written.
@ -926,6 +946,9 @@ void (vector pos, string samp, float vol, float atten) ambientsound = #74;
string(string str) precache_model2 = #75;
string(string str) precache_sound2 = #76;
string(string str) precache_file2 = #77;
string(entity e, string key) infokey = #80; /* Part of QW_ENGINE
If e is world, returns the field 'key' from either the serverinfo or the localinfo. If e is a player, returns the value of 'key' from the player's userinfo string. There are a few special exceptions, like 'ip' which is not technically part of the userinfo. */
float(string) stof = #81; /* Part of FRIK_FILE, FTE_STRINGS, QW_ENGINE, ZQ_QC_STRINGS*/
void(vector start, vector mins, vector maxs, vector end, float nomonsters, entity ent) tracebox = #90; /* Part of DP_QC_TRACEBOX
Exactly like traceline, but a box instead of a uselessly thin point. Acceptable sizes are limited by bsp format, q1bsp has strict acceptable size values. */
@ -962,7 +985,7 @@ float(string extname) checkextension = #99; /*
Use cvar("pr_checkextension") to see if this builtin exists. */
float(__variant funcref) checkbuiltin = #0:checkbuiltin; /*
Checks to see if the specified builtin is supported/mapped. This is intended as a way to check for #0 functions, allowing for simple single-builtin functions. */
Checks to see if the specified builtin is supported/mapped. This is intended as a way to check for #0 functions, allowing for simple single-builtin functions. Warning, if two different engines map different builtins to the same number, then this function will not tell you which will be called, only that it won't crash (the exception being #0, which are remapped as available). */
float(float value) anglemod = #102;
filestream(string filename, float mode, optional float mmapminsize) fopen = #110; /* Part of FRIK_FILE
@ -975,17 +998,17 @@ string(filestream fhandle) fgets = #112; /* Part of FRIK_FILE
void(filestream fhandle, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7) fputs = #113; /* Part of FRIK_FILE
Writes the given string(s) into the file. For compatibility with fgets, you should ensure that the string is terminated with a \n - this will not otherwise be done for you. It is up to the engine whether dos or unix line endings are actually written. */
int(filestream fhandle, void *ptr, int size) fread = #0:fread; /*
int(filestream fhandle, void *ptr, int size) fread = #0:fread; /* Part of FTE_QC_FILE_BINARY
Reads binary data out of the file. Returns truncated lengths if the read exceeds the length of the file. */
int(filestream fhandle, void *ptr, int size) fwrite = #0:fwrite; /*
int(filestream fhandle, void *ptr, int size) fwrite = #0:fwrite; /* Part of FTE_QC_FILE_BINARY
Writes binary data out of the file. */
#define ftell fseek //c compat
int(filestream fhandle, optional int newoffset) fseek = #0:fseek; /*
int(filestream fhandle, optional int newoffset) fseek = #0:fseek; /* Part of FTE_QC_FILE_BINARY
Changes the current position of the file, if specified. Returns prior position, in bytes. */
int(filestream fhandle, optional int newsize) fsize = #0:fsize; /*
int(filestream fhandle, optional int newsize) fsize = #0:fsize; /* Part of FTE_QC_FILE_BINARY
Reports the total size of the file, in bytes. Can also be used to truncate/extend the file */
float(string s) strlen = #114; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/
@ -1116,10 +1139,10 @@ int(string) stoh = #261; /* Part of FTE_QC_INTCONV
string(int) htos = #262; /* Part of FTE_QC_INTCONV
Formats an integer as a base16 string, with leading 0s and no prefix. Always returns 8 characters. */
int(float) ftoi = #0:ftoi; /*
int(float) ftoi = #0:ftoi; /* Part of FTE_QC_INTCONV
Converts the given float into a true integer without depending on extended qcvm instructions. */
float(int) itof = #0:itof; /*
float(int) itof = #0:itof; /* Part of FTE_QC_INTCONV
Converts the given true integer into a float without depending on extended qcvm instructions. */
float(float modlindex, optional float useabstransforms) skel_create = #263; /* Part of FTE_CSQC_SKELETONOBJECTS
@ -1171,10 +1194,10 @@ float(float modidx, float framenum) frameduration = #277; /* Part of FTE_CSQC_SK
Retrieves the duration (in seconds) of the specified framegroup. */
#define dotproduct(v1,v2) ((vector)(v1)*(vector)(v2))
vector(vector v1, vector v2) crossproduct = #0:crossproduct; /*
vector(vector v1, vector v2) crossproduct = #0:crossproduct; /* Part of FTE_QC_CROSSPRODUCT
Small helper function to calculate the crossproduct of two vectors. */
void(float action, optional vector pos, optional float radius, optional float quant, ...) terrain_edit = #278; /*
void(float action, optional vector pos, optional float radius, optional float quant, ...) terrain_edit = #278; /* Part of FTE_TERRAIN_MAP
Realtime terrain editing. Actions are the TEREDIT_ constants. */
typedef struct
@ -1187,25 +1210,25 @@ typedef struct
vector tdir;
float tbias;
} brushface_t;
int(float modelidx, int brushid, brushface_t *out_faces, int maxfaces, int *out_contents) brush_get = #0:brush_get; /*
int(float modelidx, int brushid, brushface_t *out_faces, int maxfaces, int *out_contents) brush_get = #0:brush_get; /* Part of FTE_RAW_MAP
Queries a brush's information. You must pre-allocate the face array for the builtin to write to. Return value is the number of faces retrieved, 0 on error. */
int(float modelidx, brushface_t *in_faces, int numfaces, int contents, optional int brushid) brush_create = #0:brush_create; /*
int(float modelidx, brushface_t *in_faces, int numfaces, int contents, optional int brushid) brush_create = #0:brush_create; /* Part of FTE_RAW_MAP
Inserts a new brush into the model. Return value is the new brush's id. */
void(float modelidx, int brushid) brush_delete = #0:brush_delete; /*
void(float modelidx, int brushid) brush_delete = #0:brush_delete; /* Part of FTE_RAW_MAP
Destroys the specified brush. */
float(float modelid, int brushid, int faceid, float selectedstate) brush_selected = #0:brush_selected; /*
float(float modelid, int brushid, int faceid, float selectedstate) brush_selected = #0:brush_selected; /* Part of FTE_RAW_MAP
Allows you to easily set transient visual properties of a brush. returns old value. selectedstate=-1 changes nothing (called for its return value). */
int(float modelid, int brushid, int faceid, vector *points, int maxpoints) brush_getfacepoints = #0:brush_getfacepoints; /*
int(float modelid, int brushid, int faceid, vector *points, int maxpoints) brush_getfacepoints = #0:brush_getfacepoints; /* Part of FTE_RAW_MAP
Returns the list of verticies surrounding the given face. If face is 0, returns the center of the brush (if space for 1 point) or the mins+maxs (if space for 2 points). */
int(int faceid, brushface_t *in_faces, int numfaces, vector *points, int maxpoints) brush_calcfacepoints = #0:brush_calcfacepoints; /*
int(int faceid, brushface_t *in_faces, int numfaces, vector *points, int maxpoints) brush_calcfacepoints = #0:brush_calcfacepoints; /* Part of FTE_RAW_MAP
Determines the points of the specified face, if the specified brush were to actually be created. */
int(float modelid, vector *planes, float *dists, int numplanes, int *out_brushes, int *out_faces, int maxresults) brush_findinvolume = #0:brush_findinvolume; /*
int(float modelid, vector *planes, float *dists, int numplanes, int *out_brushes, int *out_faces, int maxresults) brush_findinvolume = #0:brush_findinvolume; /* Part of FTE_RAW_MAP
Allows you to easily obtain a list of brushes+faces within the given bounding region. If out_faces is not null, the same brush might be listed twice. */
void(optional entity ent, optional vector neworigin) touchtriggers = #279; /*
@ -1320,10 +1343,10 @@ float(string name) iscachedpic = #316; /*
string(string name, optional float trywad) precache_pic = #317; /*
Forces the engine to load the named image. If trywad is specified, the specified name must any lack path and extension. */
void(string imagename, int width, int height, int *pixeldata) r_uploadimage = #0:r_uploadimage; /*
void(string imagename, int width, int height, int *pixeldata) r_uploadimage = #0:r_uploadimage; /* Part of FTE_CSQC_RAWIMAGES
Updates a texture with the specified rgba data. Will be created if needed. */
int*(string filename, __out int width, __out int height) r_readimage = #0:r_readimage; /*
int*(string filename, __out int width, __out int height) r_readimage = #0:r_readimage; /* Part of FTE_CSQC_RAWIMAGES
Reads and decodes an image from disk, providing raw pixel data. Returns __NULL__ if the image could not be read for any reason. Use memfree to free the data once you're done with it. */
#define draw_getimagesize drawgetimagesize
@ -1480,7 +1503,7 @@ typedef struct {
float flRoomRolloffFactor;
int iDecayHFLimit;
} reverbinfo_t;
void(float reverbslot, reverbinfo_t *reverbinfo, int sizeofreverinfo_t) setup_reverb = #0:setup_reverb; /*
void(float reverbslot, reverbinfo_t *reverbinfo, int sizeofreverinfo_t) setup_reverb = #0:setup_reverb; /* Part of FTE_CSQC_REVERB
Reconfigures a reverb slot for weird effects. Slot 0 is reserved for no effects. Slot 1 is reserved for underwater effects. Reserved slots will be reinitialised on snd_restart, but can otherwise be changed. These reverb slots can be activated with SetListener. Note that reverb will currently only work when using OpenAL. */
void(string cmdname) registercommand = #352; /*
@ -1581,7 +1604,7 @@ void(string conname, vector pos, vector size, float fontsize) con_draw = #393; /
float(string conname, float inevtype, float parama, float paramb, float paramc) con_input = #394; /* Part of FTE_CSQC_ALTCONSOLES
Forwards input events to the named console. Mouse updates should be absolute only. */
void(string newcaption) setwindowcaption = #0:setwindowcaption; /*
void(string newcaption) setwindowcaption = #0:setwindowcaption; /* Part of FTE_CSQC_WINDOWCAPTION
Replaces the title of the game window, as seen when task switching or just running in windowed mode. */
float() cvars_haveunsaved = #0:cvars_haveunsaved; /*
@ -1602,8 +1625,8 @@ void(vector org, vector dir, float count) te_blood = #405; /* Part of DP_TE_BLOO
void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower = #406; /* Part of _DP_TE_BLOODSHOWER*/
void(vector org, vector color) te_explosionrgb = #407; /* Part of DP_TE_EXPLOSIONRGB*/
void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube = #408; /* Part of DP_TE_PARTICLECUBE*/
void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain = #409; /* Part of _DP_TE_PARTICLERAIN*/
void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow = #410; /* Part of _DP_TE_PARTICLESNOW*/
void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain = #409; /* Part of DP_TE_PARTICLERAIN*/
void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow = #410; /* Part of DP_TE_PARTICLESNOW*/
void(vector org, vector vel, float howmany) te_spark = #411; /* Part of DP_TE_SPARK*/
void(vector org) te_gunshotquad = #412; /* Part of _DP_TE_QUADEFFECTS1*/
void(vector org) te_spikequad = #413; /* Part of _DP_TE_QUADEFFECTS1*/
@ -1646,10 +1669,10 @@ float(searchhandle handle) search_getsize = #446; /* Part of DP_QC_FS_SEARCH
string(searchhandle handle, float num) search_getfilename = #447; /* Part of DP_QC_FS_SEARCH
Retrieves name of one of the files that was found by the initial search. */
float(searchhandle handle, float num) search_getfilesize = #0:search_getfilesize; /*
float(searchhandle handle, float num) search_getfilesize = #0:search_getfilesize; /* Part of FTE_QC_FS_SEARCH_SIZEMTIME
Retrieves the size of one of the files that was found by the initial search. */
string(searchhandle handle, float num) search_getfilemtime = #0:search_getfilemtime; /*
string(searchhandle handle, float num) search_getfilemtime = #0:search_getfilemtime; /* Part of FTE_QC_FS_SEARCH_SIZEMTIME
Retrieves modification time of one of the files. */
string(string cvarname) cvar_string = #448; /* Part of DP_QC_CVAR_STRING*/

View File

@ -151,14 +151,16 @@ entedit_t*() editor_ents_new =
{
local int nent;
local entedit_t *newents;
nent = numents;
numents += 1i;
//extend the list
newents = memalloc(sizeof(entedit_t)*numents);
memcpy((__variant*)newents, (__variant*)editents, sizeof(entedit_t)*nent);
memfree((__variant*)editents);
editents = newents;
nent = terrain_edit(TEREDIT_ENT_ADD, "");
if (nent >= numents)
{
//extend the list
newents = memalloc(sizeof(entedit_t)*(nent+1));
memcpy((__variant*)newents, (__variant*)editents, sizeof(entedit_t)*numents);
memfree((__variant*)editents);
editents = newents;
numents = nent+1;
}
editents[nent].fields = hash_createtab(12, EV_STRING);
@ -170,11 +172,35 @@ void(float num) editor_ents_delete =
if (num >= 0 && num < numents)
{
hash_destroytab(editents[num].fields);
numents--;
memcpy(&editents[num], &editents[num+1], sizeof(entedit_t) * (numents-num));
editents[num].fields = 0;
terrain_edit(TEREDIT_ENT_SET, num, __NULL__);
}
};
string(entedit_t *ent) reforment =
{
string n = "";
for (int i = 0; ; i++)
{
string key, value;
key = hash_getkey(ent->fields, i);
if isnull(key)
break;
if (key == "{")
continue;
value = ent->fields[key];
//inject markup into the value so that it doesn't get too corrupted
value = strreplace("\\", "\\\\", value);
value = strreplace("\"", "\\\"", value);
value = strreplace("\n", "\\n", value);
//these are more optional
value = strreplace("\t", "\\t", value);
value = strreplace("\r", "\\r", value);
n = strcat(n, key, " \"", value, "\"\n");
}
return n;
};
void() updatemodelents =
{
entsdirty = FALSE;
@ -183,47 +209,18 @@ void() updatemodelents =
for (int e = 0; e < numents; e++)
{
local entedit_t *ent = &editents[e];
string n;
n = "{\n";
for (int i = 0; ; i++)
{
string key, value;
key = hash_getkey(ent->fields, i);
if isnull(key)
break;
value = ent->fields[key];
//inject markup into the value so that it doesn't get too corrupted
value = strreplace("\\", "\\\\", value);
value = strreplace("\"", "\\\"", value);
value = strreplace("\n", "\\n", value);
//these are more optional
value = strreplace("\t", "\\t", value);
value = strreplace("\r", "\\r", value);
n = strcat(n, key, " \"", value, "\"\n");
}
n = strcat(n, "}\n");
terrain_edit(TEREDIT_ENTS_CONCAT, n);
string n = reforment(ent);
terrain_edit(TEREDIT_ENT_SET, e, n);
}
};
float(float mode) editor_ents_poll =
void(entedit_t *ent) editor_ents_edited =
{
if (mode != MODE_ENTSEDIT)
{
updatemodelents();
localcmd("mod_terrain_save\n"); //saves a .ent if its a bsp, a .map if it has brushes, and a .hmp if otherwise. or something.
ca_checksave = __NULL__;
return TRUE;
}
return FALSE;
}
void() editor_ents_edited =
{
ca_checksave = editor_ents_poll;
entsdirty = TRUE;
entsapplytime = cltime+2;
string n = reforment(ent);
terrain_edit(TEREDIT_ENT_SET, ent-editents, n);
}
inline float(string model) modelindexforname =
@ -265,7 +262,7 @@ void(entedit_t *nent) editor_ents_updated =
{
if (classn == entclasses[i].classn)
{
nent->modelindex = modelindexforname(entclasses[i].model);
nent->modelindex = 0;//modelindexforname(entclasses[i].model);
nent->alpha = 0.3;
nent->colourmod = entclasses[i].colour;
nent->mins = entclasses[i].mins;
@ -285,7 +282,6 @@ entedit_t*(entedit_t *o) editor_ents_clone =
{
int i;
entedit_t *n = editor_ents_new();
for (i = 0; ; i++)
{
@ -301,52 +297,62 @@ entedit_t*(entedit_t *o) editor_ents_clone =
return n;
};
void() editor_ents_reload =
{
local entedit_t *nent;
local string field, value;
//reset ent state
getentitytoken(__NULL__);
int id;
int f, fcount;
for(;;)
numents = terrain_edit(TEREDIT_ENT_COUNT);
editents = memalloc(sizeof(entedit_t)*numents);
for (id = 0; id < numents; id++)
{
field = getentitytoken();
if isnull(field)
field = terrain_edit(TEREDIT_ENT_GET, id);
nent = &editents[id];
if (nent->fields)
hash_destroytab(nent->fields);
nent->fields = 0;
if (field == __NULL__)
continue;
nent->fields = hash_createtab(12, EV_STRING);
fcount = tokenize(field);
for (f = 0; f < fcount; f+=2)
{
break;
}
if (field == "{")
{
local entedit_t *nent;
nent = editor_ents_new();
for(;;)
{
field = getentitytoken();
if isnull(field)
{
print("Truncated ent lump\n");
return;
}
if (field == "}")
break;
value = getentitytoken();
nent.fields[field] = value;
// print(sprintf("%s: %s\n", field, value));
}
editor_ents_updated(nent);
}
else
{
print(sprintf("Corrupt ent lump, found \"%s\"\n", field));
return;
field = argv(f);
value = argv(f+1);
nent->fields[field] = value;
}
editor_ents_updated(nent);
}
};
//called when another client has edited an entity.
void(int idx, string new) CSQC_MapEntityEdited =
{
if (idx >= numents)
{
if not (new)
return; //deleting an ent that doesn't already exist? :o
}
local entedit_t *ent = &editents[idx];
if (ent->fields)
hash_destroytab(ent->fields);
ent->fields = hash_createtab(12, EV_STRING);
int fcount = tokenize(new);
for (int f = 0; f < fcount; f+=2)
{
string field = argv(f);
string value = argv(f+1);
ent->fields[field] = value;
}
editor_ents_updated(ent);
// editor_ents_edited(ent);
};
void(string shadername, vector min, vector max, vector col) editor_ents_drawbbox =
{
if (min == max)
@ -520,7 +526,8 @@ float(float key, float unic, vector mousepos) editor_ents_key =
{
if (selectedent >= numents)
return FALSE;
string value = editents[selectedent].fields[editkey];
ent = &editents[selectedent];
string value = ent->fields[editkey];
if (key == K_ESCAPE)
{
@ -531,7 +538,7 @@ float(float key, float unic, vector mousepos) editor_ents_key =
{
if (!value)
{
hash_delete(editents[selectedent].fields, editkey);
hash_delete(ent->fields, editkey);
editfieldtype = 0;
}
else
@ -548,8 +555,9 @@ float(float key, float unic, vector mousepos) editor_ents_key =
if (editfieldtype)
{
editents[selectedent].fields[editkey] = value;
editor_ents_updated(&editents[selectedent]);
ent->fields[editkey] = value;
editor_ents_edited(ent);
editor_ents_updated(ent);
}
}
else if (key == K_ESCAPE && selectedent)
@ -566,18 +574,18 @@ float(float key, float unic, vector mousepos) editor_ents_key =
//figure out how far along the plane normal to push the entity in order to ensure that its mins/maxs is on the floor/slope/ceiling/wall/etc
//yay dotproducts
float ext = [
float ext = trace_plane_normal * [
(trace_plane_normal[0] < 0)?ent->mins[0]:ent->maxs[0],
(trace_plane_normal[1] < 0)?ent->mins[1]:ent->maxs[1],
(trace_plane_normal[2] < 0)?ent->mins[2]:ent->maxs[2]
] * trace_plane_normal;
];
//update the all important origin
string str = sprintf("%v", trace_endpos + trace_plane_normal * ext);
ent->fields["origin"] = str;
//and fix up the quick-access stuff
ent->org = stov(ent->fields["origin"]);
editor_ents_edited();
editor_ents_edited(ent);
}
else
return FALSE;
@ -612,7 +620,7 @@ void(vector mousepos) editor_ents_overlay =
break;
value = ent->fields[key];
col = '1 1 1';
if (pickedit && mousepos_y >= pos_y && mousepos_y < pos_y + 8)
if (pickedit && mousepos_y >= pos_y && mousepos_y < pos_y + 8 && mousepos_x < 128)
{
col_y = 0;
editkey = key;

View File

@ -1,3 +0,0 @@
//this file must contain only definitions+pragmas. if it contains variables it will break the defs+crc.
//#pragma flag enable assumeint
//#pragma flag enable typeexplicit