1
0
Fork 0
forked from fte/fteqw

Add ortho lights (still has serious issues that make them unusable on regular maps).

First real attempt at lit water.
Parsing rtlights is now aware of spotlights.
Default cl_yieldcpu to 1, to save cpu for anyone who sets cl_maxfps lower. Added to menus.
presets now include view angle clamping - maps made for quakespasm REQUIRE full pitch angles despite it otherwise being considered a cheat or glitchy (on servers that try to block the cheat).
fix r_fullbrightSkins>=1 issue.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5274 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2018-07-22 11:49:37 +00:00
parent 1da1414e48
commit 0fee3a4aea
59 changed files with 1576 additions and 943 deletions

View file

@ -832,6 +832,7 @@ endif
ifeq (1,$(USE_OPUS))
LIBOPUS_STATIC=-DOPUS_STATIC
LIBOPUS_LDFLAGS=-lopus
ALL_CFLAGS+=-I/usr/include/opus
endif
ifeq (1,$(USE_SPEEX))
LIBSPEEX_STATIC=-DSPEEX_STATIC

View file

@ -1765,9 +1765,9 @@ static void CL_SendUserinfoUpdate(void)
else if (cls.fteprotocolextensions2 & PEXT2_INFOBLOBS)
{ //only flood servers that actually support it.
if (final)
s = va("%ssetinfo \"%s\" \"%s\" %u", pl, enckey, encval, bloboffset);
s = va("%ssetinfo \"%s\" \"%s\" %u", pl, enckey, encval, (unsigned int)bloboffset);
else
s = va("%ssetinfo \"%s\" \"%s\" %u+", pl, enckey, encval, bloboffset);
s = va("%ssetinfo \"%s\" \"%s\" %u+", pl, enckey, encval, (unsigned int)bloboffset);
}
else
{ //server doesn't support it, just ignore the key

View file

@ -57,9 +57,9 @@ cvar_t cl_shownet = CVARD("cl_shownet","0", "Debugging var. 0 shows nothing. 1 s
cvar_t cl_pure = CVARD("cl_pure", "0", "0=standard quake rules.\n1=clients should prefer files within packages present on the server.\n2=clients should use *only* files within packages present on the server.\nDue to quake 1.01/1.06 differences, a setting of 2 is only reliable with total conversions.\nIf sv_pure is set, the client will prefer the highest value set.");
cvar_t cl_sbar = CVARFC("cl_sbar", "0", CVAR_ARCHIVE, CL_Sbar_Callback);
cvar_t cl_hudswap = CVARF("cl_hudswap", "0", CVAR_ARCHIVE);
cvar_t cl_maxfps = CVARF("cl_maxfps", "500", CVAR_ARCHIVE);
cvar_t cl_maxfps = CVARFD("cl_maxfps", "500", CVAR_ARCHIVE, "Sets the maximum allowed framerate. If you're using vsync or want to uncap framerates entirely then you should probably set this to 0. Set cl_yieldcpu 0 if you're trying to benchmark.");
cvar_t cl_idlefps = CVARFD("cl_idlefps", "30", CVAR_ARCHIVE, "This is the maximum framerate to attain while idle/paused/unfocused.");
cvar_t cl_yieldcpu = CVARFD("cl_yieldcpu", "0", CVAR_ARCHIVE, "Attempt to yield between frames. This can resolve issues with certain drivers and background software, but can mean less consistant frame times. Will reduce power consumption/heat generation so should be set on laptops or similar (over-hot/battery powered) devices.");
cvar_t cl_yieldcpu = CVARFD("cl_yieldcpu", "1", CVAR_ARCHIVE, "Attempt to yield between frames. This can resolve issues with certain drivers and background software, but can mean less consistant frame times. Will reduce power consumption/heat generation so should be set on laptops or similar (over-hot/battery powered) devices.");
cvar_t cl_nopext = CVARF("cl_nopext", "0", CVAR_ARCHIVE);
cvar_t cl_pext_mask = CVAR("cl_pext_mask", "0xffffffff");
cvar_t cl_nolerp = CVARD("cl_nolerp", "0", "Disables interpolation. If set, missiles/monsters will be show exactly what was last received, which will be jerky. Does not affect players. A value of 2 means 'interpolate only in single-player/coop'.");
@ -1634,6 +1634,9 @@ void CL_ClearState (void)
InfoBuf_Clear(&cl.serverinfo, true);
for (i = 0; i < MAX_CLIENTS; i++)
InfoBuf_Clear(&cl.players[i].userinfo, true);
// wipe the entire cl structure
memset (&cl, 0, sizeof(cl));
@ -5567,7 +5570,7 @@ double Host_Frame (double time)
{
while(COM_DoWork(0, false))
;
return (cl_yieldcpu.ival || vid.isminimized)? (1.0 / maxfps - (realtime - oldrealtime)) : 0;
return (cl_yieldcpu.ival || vid.isminimized || idle)? (1.0 / maxfps - (realtime - oldrealtime)) : 0;
}
if (spare < 0 || cls.state < ca_onserver)
spare = 0; //uncapped.

View file

@ -305,7 +305,7 @@ typedef struct
#define LFLAG_NOSHADOWS (1<<8)
#define LFLAG_SHADOWMAP (1<<9)
#define LFLAG_CREPUSCULAR (1<<10) //weird type of sun light that gives god rays
//#define LFLAG_ORTHO (1<<11) //sun-style -light
#define LFLAG_ORTHO (1<<11) //sun-style -light
#define LFLAG_INTERNAL (LFLAG_LIGHTMAP|LFLAG_FLASHBLEND) //these are internal to FTE, and never written to disk (ie: .rtlights files shouldn't contain these)
#define LFLAG_DYNAMIC (LFLAG_LIGHTMAP | LFLAG_FLASHBLEND | LFLAG_NORMALMODE | LFLAG_REALTIMEMODE)

View file

@ -369,10 +369,10 @@ void PM_ValidatePackage(package_t *p)
}
else if (p->qhash)
{
char buf[8];
searchpathfuncs_t *archive;
#ifdef PACKAGE_Q1PAK
char buf[8];
if (!Q_strcasecmp(COM_FileExtension(n, buf, sizeof(buf)), "pak"))
archive = FSPAK_LoadArchive(pf, NULL, n, n, NULL);
else
@ -2852,6 +2852,10 @@ qboolean PM_FindUpdatedEngine(char *syspath, size_t syspathsize)
}
#else
qboolean PM_CanInstall(const char *packagename)
{
return false;
}
void PM_Command_f (void)
{
Con_Printf("Package Manager is not implemented in this build\n");

View file

@ -341,6 +341,7 @@ void Media_WriteCurrentTrack(sizebuf_t *buf)
qboolean Media_NamedTrack(const char *track, const char *looptrack)
{
unsigned int tracknum;
//FIXME: for q2, gog uses ../music/Track%02i.ogg, with various remapping requirements for the mission packs.
static char *path[] =
{
"music/",

View file

@ -793,6 +793,7 @@ const char *presetexec[] =
"seta cl_gibfilter 1;"
"if cl_deadbodyfilter == 0 then seta cl_deadbodyfilter 1;" //as useful as 2 is, some mods use death frames for crouching etc.
"seta gl_simpleitems 1;"
"seta cl_fullpitch 1;seta maxpitch \"\";seta minpitch \"\";" //mimic quakespasm where possible.
, // fast options
"gl_texturemode ln;"
@ -838,8 +839,10 @@ const char *presetexec[] =
//"d_mipcap \"0 3\";" //logically correct, but will fuck up on ATI drivers if increased mid-map, because ATI will just ignore any levels that are not currently enabled.
"cl_gibfilter 0;"
"seta cl_deadbodyfilter 0;"
"cl_fullpitch 1;maxpitch 90;seta minpitch -90;" //QS has cheaty viewpitch range. some maps require it.
, //vanilla-esque options.
"cl_fullpitch 0;maxpitch \"\";seta minpitch \"\";" //quakespasm is not vanilla
"gl_texturemode nll;" //yup, we went there.
"gl_texturemode2d n.l;" //yeah, 2d too.
"r_nolerp 1;"
@ -876,6 +879,7 @@ const char *presetexec[] =
"r_loadlit 1;"
"r_nolerp 0;"
"r_noframegrouplerp 0;"
"cl_fullpitch 1;maxpitch 90;seta minpitch -90;"
, // nice options
// "r_stains 0.75;"
@ -1112,7 +1116,7 @@ void M_Menu_FPS_f (void)
menu_t *menu;
fpsmenuinfo_t *info;
extern cvar_t v_contentblend, show_fps, cl_r2g, cl_gibfilter, cl_expsprite, cl_deadbodyfilter, cl_lerp_players, cl_nolerp;
extern cvar_t v_contentblend, show_fps, cl_r2g, cl_gibfilter, cl_expsprite, cl_deadbodyfilter, cl_lerp_players, cl_nolerp, cl_maxfps, cl_yieldcpu;
static menuresel_t resel;
int y;
menu = M_Options_Title(&y, sizeof(fpsmenuinfo_t));
@ -1129,6 +1133,8 @@ void M_Menu_FPS_f (void)
MB_CMD("Apply", M_PresetApply, "Applies selected preset."),
MB_SPACING(4),
MB_COMBOCVAR("Show FPS", show_fps, fpsopts, fpsvalues, "Display FPS or frame millisecond values on screen. Settings except immediate are for values across 1 second."),
MB_EDITCVARSLIM("Framerate Limiter", cl_maxfps.name, "Limits the maximum framerate. Set to 0 for none."),
MB_CHECKBOXCVARTIP("Yield CPU", cl_yieldcpu, 1, "Reduce CPU usage between frames.\nShould probably be off when using vsync."),
MB_COMBOCVAR("Player lerping", cl_lerp_players, playerlerpopts, values_0_1, "Smooth movement of other players, but will increase effective latency. Does not affect all network protocols."),
MB_COMBOCVAR("Entity lerping", cl_nolerp, entlerpopts, values_0_1_2, "Smooth movement of entities, but will increase effective latency."),
MB_CHECKBOXCVAR("Content Blend", v_contentblend, 0),
@ -2782,6 +2788,18 @@ void M_Menu_Video_f (void)
};
static const char *scalevalues[] = { "1", "1.5", "2", "2.5", "3", "4", "5", "6", NULL};
static const char *vsyncopts[] =
{
"Off",
"Strict",
"Lax",
"Alternate Frames",
NULL
};
static const char *vsyncvalues[] = { "0", "1", "-1", "2", NULL};
extern cvar_t vid_vsync;
extern cvar_t cl_maxfps;
extern cvar_t cl_yieldcpu;
/*
static const char *vsyncoptions[] =
@ -2849,6 +2867,7 @@ void M_Menu_Video_f (void)
MB_EDITCVARSLIMRETURN("Height", "vid_height", info->height),
MB_EDITCVARSLIMRETURN("Color Depth", "vid_bpp", info->bpp),
MB_EDITCVARSLIMRETURN("Refresh Rate", "vid_displayfrequency", info->hz),
MB_SPACING(4),
MB_COMBORETURN("2D Mode", res2dmodeopts, res2dmodechoice, info->res2dmode, "Select method for determining or configuring 2D resolution and scaling. The default option matches the current display resolution, and the scale option scales by a factor of the display resolution."),
// scale entry
@ -2874,6 +2893,11 @@ void M_Menu_Video_f (void)
MB_SLIDER("Gamma", v_gamma, 1.5, 0.25, -0.05, NULL),
MB_COMBOCVAR("Gamma Mode", vid_srgb, srgbopts, srgbvalues, "Controls the colour space to try to use."),
MB_SLIDER("Contrast", v_contrast, 0.8, 3, 0.05, NULL),
MB_COMBOCVAR("VSync", vid_vsync, vsyncopts, vsyncvalues, "Controls whether to wait for rendering to finish."),
MB_EDITCVARSLIM("Framerate Limiter", cl_maxfps.name, "Limits the maximum framerate. Set to 0 for none."),
MB_CHECKBOXCVARTIP("Yield CPU", cl_yieldcpu, 1, "Reduce CPU usage between frames.\nShould probably be off when using vsync."),
MB_END()
};
MC_AddBulk(menu, &resel, bulk, 16, 200, y);

View file

@ -1,4 +1,6 @@
#ifdef VKQUAKE
//we need some types available elsewhere, but don't really want to have to include the entire vulkan api everywhere.
//unfortunately, vulkan's handle types are not well defined.
#if defined(__LP64__) || defined(_WIN64)
#define VulkanAPIRandomness void*
#elif defined(_MSC_VER) && _MSC_VER < 1300
@ -6,12 +8,12 @@
#else
#define VulkanAPIRandomness long long
#endif
#define VkRetardedDescriptorSet VulkanAPIRandomness
#define VkRetardedShaderModule VulkanAPIRandomness
#define VkRetardedPipelineLayout VulkanAPIRandomness
#define VkRetardedDescriptorSetLayout VulkanAPIRandomness
#define VkRetardedBuffer VulkanAPIRandomness
#define VkRetardedDeviceMemory VulkanAPIRandomness
#define qVkDescriptorSet VulkanAPIRandomness
#define qVkShaderModule VulkanAPIRandomness
#define qVkPipelineLayout VulkanAPIRandomness
#define qVkDescriptorSetLayout VulkanAPIRandomness
#define qVkBuffer VulkanAPIRandomness
#define qVkDeviceMemory VulkanAPIRandomness
#endif
//These are defined later in the source tree. This file should probably be moved to a later spot.
@ -248,7 +250,7 @@ typedef struct image_s
#ifdef VKQUAKE
struct
{
VkRetardedDescriptorSet vkdescriptor;
qVkDescriptorSet vkdescriptor;
struct vk_image_s *vkimage;
};
#endif
@ -334,7 +336,7 @@ typedef union vboarray_s
#ifdef VKQUAKE
struct
{
VkRetardedBuffer buff;
qVkBuffer buff;
unsigned int offs;
} vk;
#endif

View file

@ -940,7 +940,7 @@ static int PClassic_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
if (dir)
VectorCopy(dir, dl->axis[0]);
else
VectorSet(dir, 0, 0, 1);
VectorSet(dl->axis[0], 0, 0, 1);
VectorVectors(dl->axis[0], dl->axis[1], dl->axis[2]);
VectorInverse(dl->axis[1]);
if (dir)

View file

@ -975,4 +975,24 @@ void QCBUILTIN PF_cl_getgamedirinfo(pubprogfuncs_t *prinst, struct globalvars_s
G_INT(OFS_RETURN) = 0;
}
//This is consistent with vanilla quakeworld's 'packet' console command.
void QCBUILTIN PF_cl_SendPacket(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
netadr_t to;
const char *address = PR_GetStringOfs(prinst, OFS_PARM0);
const char *contents = PF_VarString(prinst, 1, pr_globals);
G_FLOAT(OFS_RETURN) = NETERR_NOROUTE;
if (NET_StringToAdr(address, 0, &to))
{
char *send = Z_Malloc(4+strlen(contents));
send[0] = send[1] = send[2] = send[3] = 0xff;
memcpy(send+4, contents, strlen(contents));
//FIXME: NS_CLIENT is likely to change its port randomly...
G_FLOAT(OFS_RETURN) = NET_SendPacket(NS_CLIENT, 4+strlen(contents), send, &to);
Z_Free(send);
}
}
#endif

View file

@ -522,7 +522,7 @@ typedef struct csqcedict_s
int lastruntime;
int solidsize;
#ifdef USERBE
entityode_t ode;
entityrbe_t rbe;
#endif
/*the above is shared with ssqc*/
@ -6207,7 +6207,7 @@ static struct {
{"checkpvs", PF_checkpvs, 240},
// {"matchclientname", PF_matchclient, 241},
{"sendpacket", PF_NoCSQC, 242}, //void(string dest, string content) sendpacket = #242; (FTE_QC_SENDPACKET)
{"sendpacket", PF_cl_SendPacket, 242}, //void(string dest, string content) sendpacket = #242; (FTE_QC_SENDPACKET)
// {"bulleten", PF_bulleten, 243}, (removed builtin)
{"rotatevectorsbytag", PF_rotatevectorsbytag, 244},

View file

@ -292,6 +292,7 @@ void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
G_FLOAT(OFS_RETURN) = slotnum;
}
#ifndef NOLEGACY
void CL_LoadFont_f(void)
{
//console command for compat with dp/debug.
@ -405,6 +406,7 @@ void CL_LoadFont_f(void)
Cvar_Set(&gl_font, facename);
}
}
#endif
//scrolling could be done with scissoring.
//selection could be done with some substrings
@ -585,7 +587,7 @@ void QCBUILTIN PF_CL_drawrotpic (pubprogfuncs_t *prinst, struct globalvars_s *pr
r2d_be_flags = PF_SelectDPDrawFlag(flag);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
R2D_Image2dQuad(points, tcoords, p);
R2D_Image2dQuad((const vec2_t*)points, (const vec2_t*)tcoords, p);
r2d_be_flags = 0;
G_FLOAT(OFS_RETURN) = 1;
@ -657,7 +659,7 @@ void QCBUILTIN PF_CL_drawrotsubpic (pubprogfuncs_t *prinst, struct globalvars_s
r2d_be_flags = PF_SelectDPDrawFlag(flag);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
R2D_Image2dQuad(points, tcoords, p);
R2D_Image2dQuad((const vec2_t*)points, (const vec2_t*)tcoords, p);
r2d_be_flags = 0;
G_FLOAT(OFS_RETURN) = 1;
@ -2148,6 +2150,7 @@ static struct {
{"strtrim", PF_strtrim, 0},
//gap
{"shaderforname", PF_shaderforname, 238},
{"sendpacket", PF_cl_SendPacket, 242},
//gap
{"hash_createtab", PF_hash_createtab, 287},
{"hash_destroytab", PF_hash_destroytab, 288},
@ -2765,7 +2768,9 @@ void MP_RegisterCvarsAndCmds(void)
Cmd_AddCommand("coredump_menuqc", MP_CoreDump_f);
Cmd_AddCommand("menu_cmd", MP_GameCommand_f);
Cmd_AddCommand("breakpoint_menu", MP_Breakpoint_f);
#ifndef NOLEGACY
Cmd_AddCommand("loadfont", CL_LoadFont_f);
#endif
Cmd_AddCommand("poke_menuqc", MP_Poke_f);

View file

@ -1115,6 +1115,39 @@ void skel_lookup(world_t *world, int skelidx, framestate_t *out)
}
}
void skel_updateentbounds(world_t *w, wedict_t *ent)
{/*
float radius[MAX_BONES];
float maxr = 0;
size_t i, numbones;
skelobject_t *skel = skel_get(w, ent->xv->skeletonindex);
galiasbone_t *bones;
if (!skel)
return;
bones = Mod_GetBoneInfo(skel->model, &numbones);
if (!skel || numbones != skel->numbones)
return;
if (skel->type == SKEL_RELATIVE)
{
for (i = 0; i < skel->numbones; i++)
{
radius[i] = skel->bonematrix[i*12+3]*skel->bonematrix[i*12+3]+skel->bonematrix[i*12+7]*skel->bonematrix[i*12+7]+skel->bonematrix[i*12+11]*skel->bonematrix[i*12+11];
if (bones[i].parent >= 0)
radius[i] += radius[bones[i].parent];
if (maxr < radius[i] + bones[i].radius)
maxr = radius[i] + bones[i].radius;
}
for (i = 0; i < 3; i++)
{
if (ent->v->absmin[i] > env->v->origin-maxr)
ent->v->absmin[i] = env->v->origin-maxr;
if (ent->v->absmax[i] < env->v->origin+maxr)
ent->v->absmax[i] = env->v->origin+maxr;
}
}*/
}
void QCBUILTIN PF_skel_mmap(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
world_t *world = prinst->parms->user;

View file

@ -301,7 +301,9 @@ extern cvar_t com_protocolname;
extern cvar_t com_protocolversion;
extern cvar_t com_nogamedirnativecode;
extern cvar_t com_parseutf8;
#ifndef NOLEGACY
extern cvar_t com_parseezquake;
#endif
extern cvar_t sys_ticrate;
extern cvar_t sys_nostdout;
extern cvar_t developer;

View file

@ -3600,6 +3600,8 @@ void Surf_DeInit(void)
Z_Free(surf_frustumvis[i].buffer);
memset(surf_frustumvis, 0, sizeof(surf_frustumvis));
CL_FreeDlights();
lightmap=NULL;
numlightmaps=0;
@ -4286,6 +4288,7 @@ TRACE(("dbg: Surf_NewMap: tp\n"));
cl_static_entities[i].emit = NULL;
}
CL_InitDlights();
#ifdef RTLIGHTS
Sh_PreGenerateLights();
#endif

View file

@ -101,6 +101,9 @@ cvar_t gl_shadeq1_name = CVARD ("gl_shadeq1_name", "*", "Rename all surfac
extern cvar_t r_vertexlight;
extern cvar_t r_forceprogramify;
extern cvar_t dpcompat_nopremulpics;
#ifdef PSKMODELS
cvar_t dpcompat_psa_ungroup = CVAR ("dpcompat_psa_ungroup", "0");
#endif
cvar_t mod_md3flags = CVARD ("mod_md3flags", "1", "The flags field of md3s was never officially defined. If this is set to 1, the flags will be treated identically to mdl files. Otherwise they will be ignored. Naturally, this is required to provide rotating pickups in quake.");
@ -418,7 +421,6 @@ cvar_t vid_triplebuffer = CVARAFD ("vid_triplebuffer", "1", "gl_triplebuffe
cvar_t r_portalrecursion = CVARD ("r_portalrecursion", "1", "The number of portals the camera is allowed to recurse through.");
cvar_t r_portaldrawplanes = CVARD ("r_portaldrawplanes", "0", "Draw front and back planes in portals. Debug feature.");
cvar_t r_portalonly = CVARD ("r_portalonly", "0", "Don't draw things which are not portals. Debug feature.");
cvar_t dpcompat_psa_ungroup = CVAR ("dpcompat_psa_ungroup", "0");
cvar_t r_noaliasshadows = CVARF ("r_noaliasshadows", "0", CVAR_ARCHIVE);
cvar_t r_shadows = CVARFD ("r_shadows", "0", CVAR_ARCHIVE, "Draw basic blob shadows underneath entities without using realtime lighting.");
cvar_t r_showbboxes = CVARD("r_showbboxes", "0", "Debugging. Shows bounding boxes. 1=ssqc, 2=csqc. Red=solid, Green=stepping/toss/bounce, Blue=onground.");
@ -516,7 +518,9 @@ void GLRenderer_Init(void)
Cvar_Register (&gl_lateswap, GLRENDEREROPTIONS);
Cvar_Register (&gl_lerpimages, GLRENDEREROPTIONS);
#ifdef PSKMODELS
Cvar_Register (&dpcompat_psa_ungroup, GLRENDEREROPTIONS);
#endif
Cvar_Register (&r_lerpmuzzlehack, GLRENDEREROPTIONS);
Cvar_Register (&r_noframegrouplerp, GLRENDEREROPTIONS);
Cvar_Register (&r_portalrecursion, GLRENDEREROPTIONS);
@ -1004,7 +1008,9 @@ void Renderer_Init(void)
Cvar_Register (&r_polygonoffset_stencil_offset, GLRENDEREROPTIONS);
Cvar_Register (&r_forceprogramify, GLRENDEREROPTIONS);
#ifndef NOLEGACY
Cvar_Register (&dpcompat_nopremulpics, GLRENDEREROPTIONS);
#endif
#ifdef VKQUAKE
Cvar_Register (&vk_stagingbuffers, VKRENDEREROPTIONS);
Cvar_Register (&vk_submissionthread, VKRENDEREROPTIONS);
@ -1792,12 +1798,16 @@ TRACE(("dbg: R_ApplyRenderer: efrags\n"));
void R_ReloadRenderer_f (void)
{
#ifndef CLIENTONLY
void *portalblob = NULL;
size_t portalsize = 0;
#endif
float time = Sys_DoubleTime();
if (qrenderer == QR_NONE || qrenderer == QR_HEADLESS)
return; //don't bother reloading the renderer if its not actually rendering anything anyway.
#ifndef CLIENTONLY
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
{
void *t;
@ -1805,6 +1815,7 @@ void R_ReloadRenderer_f (void)
if (portalsize && (portalblob = BZ_Malloc(portalsize)))
memcpy(portalblob, t, portalsize);
}
#endif
Cvar_ApplyLatches(CVAR_VIDEOLATCH|CVAR_RENDERERLATCH);
R_ShutdownRenderer(false);
@ -1813,13 +1824,14 @@ void R_ReloadRenderer_f (void)
R_ApplyRenderer_Load(NULL);
Cvar_ApplyCallbacks(CVAR_RENDERERCALLBACK);
#ifndef CLIENTONLY
if (portalblob)
{
if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
CM_ReadPortalState(sv.world.worldmodel, portalblob, portalsize);
BZ_Free(portalblob);
}
#endif
}
//use Cvar_ApplyLatches(CVAR_RENDERERLATCH) beforehand.
@ -2036,8 +2048,10 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring)
void R_RestartRenderer (rendererstate_t *newr)
{
#ifndef CLIENTONLY
void *portalblob = NULL;
size_t portalsize = 0;
#endif
rendererstate_t oldr;
if (r_blockvidrestart)
{
@ -2045,6 +2059,7 @@ void R_RestartRenderer (rendererstate_t *newr)
return;
}
#ifndef CLIENTONLY
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
{
void *t;
@ -2052,6 +2067,7 @@ void R_RestartRenderer (rendererstate_t *newr)
if (portalsize && (portalblob = BZ_Malloc(portalsize)))
memcpy(portalblob, t, portalsize);
}
#endif
TRACE(("dbg: R_RestartRenderer_f renderer %p\n", newr->renderer));
@ -2127,12 +2143,14 @@ void R_RestartRenderer (rendererstate_t *newr)
}
}
#ifndef CLIENTONLY
if (portalblob)
{
if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
CM_ReadPortalState(sv.world.worldmodel, portalblob, portalsize);
BZ_Free(portalblob);
}
#endif
Cvar_ApplyCallbacks(CVAR_RENDERERCALLBACK);
SCR_EndLoadingPlaque();

View file

@ -2829,18 +2829,20 @@ static void S_UpdateSoundCard(soundcardinfo_t *sc, qboolean updateonly, channel_
target_chan->entchannel = entchannel;
SND_Spatialize(sc, target_chan);
if (!updateonly && !target_chan->vol[0] && !target_chan->vol[1] && !target_chan->vol[2] && !target_chan->vol[3] && !target_chan->vol[4] && !target_chan->vol[5] && sc->ChannelUpdate)
{
target_chan->sfx = NULL;
return; // not audible at all
}
if (!S_LoadSound (sfx))
{
target_chan->sfx = NULL;
return; // couldn't load the sound's data
}
//FIXME: why does this only filter for openal devices? its weird.
if (!updateonly && !target_chan->vol[0] && !target_chan->vol[1] && !target_chan->vol[2] && !target_chan->vol[3] && !target_chan->vol[4] && !target_chan->vol[5] && sc->ChannelUpdate)
if (sfx->loopstart == -1 && !(flags&CF_FORCELOOP)) //only skip if its not looping.
{
target_chan->sfx = NULL;
return; // not audible at all
}
target_chan->sfx = sfx;
if (updateonly && sc->ChannelUpdate)

View file

@ -26,8 +26,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
cvar_t ruleset_allow_in = CVAR("ruleset_allow_in", "1");
cvar_t rcon_level = CVAR("rcon_level", "20");
cvar_t cmd_maxbuffersize = CVAR("cmd_maxbuffersize", "65536");
#ifndef NOLEGACY
cvar_t dpcompat_set = CVAR("dpcompat_set", "0");
cvar_t dpcompat_console = CVARD("dpcompat_console", "0", "Enables hacks to emulate DP's console.");
#else
static const cvar_t dpcompat_set = {0};
static const cvar_t dpcompat_console = {0};
#endif
int Cmd_ExecLevel;
qboolean cmd_didwait;
qboolean cmd_blockwait;
@ -857,7 +862,11 @@ void Cmd_Echo_f (void)
Con_Printf ("%s", t);
#else
t = TP_ParseFunChars(t);
#ifndef NOLEGACY
Con_PrintFlags (t, (com_parseezquake.ival?PFS_EZQUAKEMARKUP:0), 0);
#else
Con_PrintFlags (t, 0, 0);
#endif
#endif
}
@ -4222,12 +4231,12 @@ void Cmd_Init (void)
Cmd_AddCommand ("cmdlist", Cmd_List_f);
Cmd_AddCommand ("aliaslist", Cmd_AliasList_f);
Cmd_AddCommand ("macrolist", Cmd_MacroList_f);
Cmd_AddCommand ("cvarlist", Cvar_List_f);
Cmd_AddCommand ("cvarreset", Cvar_Reset_f);
Cmd_AddCommandD ("macrolist", Cmd_MacroList_f, "Lists all available $macro expansions.");
Cmd_AddCommandD ("cvarlist", Cvar_List_f, "Lists all cvars. eg, 'cvarlist -cvd *' can be used to list all cvars with a value other than the mod's default.");
Cmd_AddCommandD ("cvarreset", Cvar_Reset_f, "Resets the named cvar to its default value.");
Cmd_AddCommandD ("cvarwatch", Cvar_Watch_f, "Prints a notification when the named cvar is changed. Also displays the start/end of configs. Alternatively, use '-watch foo' on the commandline.");
Cmd_AddCommand ("cvar_lockdefaults", Cvar_LockDefaults_f);
Cmd_AddCommand ("cvar_purgedefaults", Cvar_PurgeDefaults_f);
Cmd_AddCommandD ("cvar_purgedefaults", Cvar_PurgeDefaults_f, "Resets all cvar defaults to back to the engine's default. Does not change their active value.");
Cmd_AddCommandD ("apropos", Cmd_Apropos_f, "Lists all cvars or commands with the specified substring somewhere in their name or descrition.");
Cmd_AddCommandD ("find", Cmd_Apropos_f, "Lists all cvars or commands with the specified substring somewhere in their name or descrition.");
@ -4237,7 +4246,6 @@ void Cmd_Init (void)
Cmd_AddMacro("ukdate", Macro_UKDate, false);
Cmd_AddMacro("usdate", Macro_USDate, false);
Cmd_AddMacro("date", Macro_ProperDate, false);
Cmd_AddMacro("properdate", Macro_ProperDate, false);
Cmd_AddMacro("version", Macro_Version, false);
Cmd_AddMacro("qt", Macro_Quote, false);
Cmd_AddMacro("dedicated", Macro_Dedicated, false);
@ -4247,8 +4255,10 @@ void Cmd_Init (void)
Cvar_Register(&ruleset_allow_in, "Console");
Cmd_AddCommandD ("in", Cmd_In_f, "Issues the given command after a time delay. Disabled if ruleset_allow_in is 0.");
#ifndef NOLEGACY
Cvar_Register(&dpcompat_set, "Darkplaces compatibility");
Cvar_Register(&dpcompat_console, "Darkplaces compatibility");
#endif
Cvar_Register (&cl_warncmd, "Warnings");
Cvar_Register (&cfg_save_all, "client operation options");
Cvar_Register (&cfg_save_auto, "client operation options");

View file

@ -16,7 +16,6 @@
#endif
qboolean r_loadbumpmapping;
extern cvar_t dpcompat_psa_ungroup;
extern cvar_t r_noframegrouplerp;
cvar_t r_lerpmuzzlehack = CVARF ("r_lerpmuzzlehack", "1", CVAR_ARCHIVE);
static void QDECL r_meshpitch_callback(cvar_t *var, char *oldvalue)
@ -2029,9 +2028,11 @@ void Mod_AddSingleSurface(entity_t *ent, int surfaceidx, shader_t *shader)
#else
if (!mod->numanimations)
{
#ifdef SKELETALMODELS
if (mod->ofs_skel_xyz)
posedata = mod->ofs_skel_xyz;
else
#endif
continue;
}
else
@ -5551,6 +5552,7 @@ qboolean QDECL Mod_LoadZymoticModel(model_t *mod, void *buffer, size_t fsize)
//psk
#ifdef PSKMODELS
/*Typedefs copied from DarkPlaces*/
extern cvar_t dpcompat_psa_ungroup;
typedef struct pskchunk_s
{
@ -6061,6 +6063,7 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
}
num_animinfo = numgroups;
}
#ifdef NOLEGACY
else if (dpcompat_psa_ungroup.ival)
{
/*unpack each frame of each animation to be a separate framegroup*/
@ -6086,6 +6089,7 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
}
num_animinfo = iframe;
}
#endif
else
{
/*keep each framegroup as a group*/

View file

@ -66,6 +66,7 @@ struct galiasbone_s
{
char name[32];
int parent;
// float radius;
float inverse[12];
};

View file

@ -1,3 +1,7 @@
#include "quakedef.h"
#ifdef USE_INTERNAL_BULLET
#define FTEENGINE
#undef FTEPLUGIN
#include "../../plugins/bullet/bulletplug.cpp"
#endif

View file

@ -1371,53 +1371,53 @@ static void QDECL World_ODE_End(world_t *world)
static void QDECL World_ODE_RemoveJointFromEntity(world_t *world, wedict_t *ed)
{
ed->ode.ode_joint_type = 0;
if(ed->ode.ode_joint)
dJointDestroy((dJointID)ed->ode.ode_joint);
ed->ode.ode_joint = NULL;
ed->rbe.joint_type = 0;
if(ed->rbe.joint.joint)
dJointDestroy((dJointID)ed->rbe.joint.joint);
ed->rbe.joint.joint = NULL;
}
static void QDECL World_ODE_RemoveFromEntity(world_t *world, wedict_t *ed)
{
if (!ed->ode.ode_physics)
if (!ed->rbe.physics)
return;
// entity is not physics controlled, free any physics data
ed->ode.ode_physics = false;
if (ed->ode.ode_geom)
dGeomDestroy((dGeomID)ed->ode.ode_geom);
ed->ode.ode_geom = NULL;
if (ed->ode.ode_body)
ed->rbe.physics = false;
if (ed->rbe.body.geom)
dGeomDestroy((dGeomID)ed->rbe.body.geom);
ed->rbe.body.geom = NULL;
if (ed->rbe.body.body)
{
dJointID j;
dBodyID b1, b2;
wedict_t *ed2;
while(dBodyGetNumJoints((dBodyID)ed->ode.ode_body))
while(dBodyGetNumJoints((dBodyID)ed->rbe.body.body))
{
j = dBodyGetJoint((dBodyID)ed->ode.ode_body, 0);
j = dBodyGetJoint((dBodyID)ed->rbe.body.body, 0);
ed2 = (wedict_t *) dJointGetData(j);
b1 = dJointGetBody(j, 0);
b2 = dJointGetBody(j, 1);
if(b1 == (dBodyID)ed->ode.ode_body)
if(b1 == (dBodyID)ed->rbe.body.body)
{
b1 = 0;
ed2->ode.ode_joint_enemy = 0;
ed2->rbe.joint_enemy = 0;
}
if(b2 == (dBodyID)ed->ode.ode_body)
if(b2 == (dBodyID)ed->rbe.body.body)
{
b2 = 0;
ed2->ode.ode_joint_aiment = 0;
ed2->rbe.joint_aiment = 0;
}
dJointAttach(j, b1, b2);
}
dBodyDestroy((dBodyID)ed->ode.ode_body);
dBodyDestroy((dBodyID)ed->rbe.body.body);
}
ed->ode.ode_body = NULL;
ed->rbe.body.body = NULL;
rbefuncs->ReleaseCollisionMesh(ed);
if(ed->ode.ode_massbuf)
BZ_Free(ed->ode.ode_massbuf);
ed->ode.ode_massbuf = NULL;
if(ed->rbe.massbuf)
BZ_Free(ed->rbe.massbuf);
ed->rbe.massbuf = NULL;
}
static void World_ODE_Frame_BodyToEntity(world_t *world, wedict_t *ed)
@ -1427,7 +1427,7 @@ static void World_ODE_Frame_BodyToEntity(world_t *world, wedict_t *ed)
const dReal *o;
const dReal *r; // for some reason dBodyGetRotation returns a [3][4] matrix
const dReal *vel;
dBodyID body = (dBodyID)ed->ode.ode_body;
dBodyID body = (dBodyID)ed->rbe.body.body;
int movetype;
float bodymatrix[16];
float entitymatrix[16];
@ -1479,7 +1479,7 @@ static void World_ODE_Frame_BodyToEntity(world_t *world, wedict_t *ed)
VectorCopy(vel, velocity);
VectorCopy(avel, spinvelocity);
Matrix4x4_RM_FromVectors(bodymatrix, forward, left, up, origin);
Matrix4_Multiply(ed->ode.ode_offsetimatrix, bodymatrix, entitymatrix);
Matrix4_Multiply(ed->rbe.offsetimatrix, bodymatrix, entitymatrix);
Matrix3x4_RM_ToVectors(entitymatrix, forward, left, up, origin);
VectorAngles(forward, up, angles, false);
@ -1507,11 +1507,11 @@ static void World_ODE_Frame_BodyToEntity(world_t *world, wedict_t *ed)
VectorCopy(avelocity, ed->v->avelocity);
// values for BodyFromEntity to check if the qc modified anything later
VectorCopy(origin, ed->ode.ode_origin);
VectorCopy(velocity, ed->ode.ode_velocity);
VectorCopy(angles, ed->ode.ode_angles);
VectorCopy(avelocity, ed->ode.ode_avelocity);
ed->ode.ode_gravity = dBodyGetGravityMode(body);
VectorCopy(origin, ed->rbe.origin);
VectorCopy(velocity, ed->rbe.velocity);
VectorCopy(angles, ed->rbe.angles);
VectorCopy(avelocity, ed->rbe.avelocity);
ed->rbe.gravity = dBodyGetGravityMode(body);
rbefuncs->LinkEdict(world, ed, true);
}
@ -1544,10 +1544,10 @@ static void World_ODE_Frame_JointFromEntity(world_t *world, wedict_t *ed)
jointtype = 0; // can't have both
o = (wedict_t*)PROG_TO_EDICT(world->progs, enemy);
if(ED_ISFREE(o) || o->ode.ode_body == 0)
if(ED_ISFREE(o) || o->rbe.body.body == 0)
enemy = 0;
o = (wedict_t*)PROG_TO_EDICT(world->progs, aiment);
if(ED_ISFREE(o) || o->ode.ode_body == 0)
if(ED_ISFREE(o) || o->rbe.body.body == 0)
aiment = 0;
// see http://www.ode.org/old_list_archives/2006-January/017614.html
// we want to set ERP? make it fps independent and work like a spring constant
@ -1579,7 +1579,7 @@ static void World_ODE_Frame_JointFromEntity(world_t *world, wedict_t *ed)
FMax = 0;
Stop = dInfinity;
}
if(jointtype == ed->ode.ode_joint_type && VectorCompare(origin, ed->ode.ode_joint_origin) && VectorCompare(velocity, ed->ode.ode_joint_velocity) && VectorCompare(angles, ed->ode.ode_joint_angles) && enemy == ed->ode.ode_joint_enemy && aiment == ed->ode.ode_joint_aiment && VectorCompare(movedir, ed->ode.ode_joint_movedir))
if(jointtype == ed->rbe.joint_type && VectorCompare(origin, ed->rbe.joint_origin) && VectorCompare(velocity, ed->rbe.joint_velocity) && VectorCompare(angles, ed->rbe.joint_angles) && enemy == ed->rbe.joint_enemy && aiment == ed->rbe.joint_aiment && VectorCompare(movedir, ed->rbe.joint_movedir))
return; // nothing to do
AngleVectorsFLU(angles, forward, left, up);
switch(jointtype)
@ -1608,28 +1608,28 @@ static void World_ODE_Frame_JointFromEntity(world_t *world, wedict_t *ed)
j = 0;
break;
}
if(ed->ode.ode_joint)
if(ed->rbe.joint.joint)
{
//Con_Printf("deleted old joint %i\n", (int) (ed - prog->edicts));
dJointAttach(ed->ode.ode_joint, 0, 0);
dJointDestroy(ed->ode.ode_joint);
dJointAttach(ed->rbe.joint.joint, 0, 0);
dJointDestroy(ed->rbe.joint.joint);
}
ed->ode.ode_joint = (void *) j;
ed->ode.ode_joint_type = jointtype;
ed->ode.ode_joint_enemy = enemy;
ed->ode.ode_joint_aiment = aiment;
VectorCopy(origin, ed->ode.ode_joint_origin);
VectorCopy(velocity, ed->ode.ode_joint_velocity);
VectorCopy(angles, ed->ode.ode_joint_angles);
VectorCopy(movedir, ed->ode.ode_joint_movedir);
ed->rbe.joint.joint = (void *) j;
ed->rbe.joint_type = jointtype;
ed->rbe.joint_enemy = enemy;
ed->rbe.joint_aiment = aiment;
VectorCopy(origin, ed->rbe.joint_origin);
VectorCopy(velocity, ed->rbe.joint_velocity);
VectorCopy(angles, ed->rbe.joint_angles);
VectorCopy(movedir, ed->rbe.joint_movedir);
if(j)
{
//Con_Printf("made new joint %i\n", (int) (ed - prog->edicts));
dJointSetData(j, (void *) ed);
if(enemy)
b1 = (dBodyID)((WEDICT_NUM_UB(world->progs, enemy))->ode.ode_body);
b1 = (dBodyID)((WEDICT_NUM_UB(world->progs, enemy))->rbe.body.body);
if(aiment)
b2 = (dBodyID)((WEDICT_NUM_UB(world->progs, aiment))->ode.ode_body);
b2 = (dBodyID)((WEDICT_NUM_UB(world->progs, aiment))->rbe.body.body);
dJointAttach(j, b1, b2);
switch(jointtype)
@ -1995,7 +1995,7 @@ static void QDECL World_ODE_RagDestroyJoint(world_t *world, rbejoint_t *joint)
static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
{
struct odectx_s *ctx = (struct odectx_s*)world->rbe;
dBodyID body = (dBodyID)ed->ode.ode_body;
dBodyID body = (dBodyID)ed->rbe.body.body;
dMass mass;
float test;
void *dataID;
@ -2090,7 +2090,7 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
break;
default:
// case GEOMTYPE_NONE:
if (ed->ode.ode_physics)
if (ed->rbe.physics)
World_ODE_RemoveFromEntity(world, ed);
return;
}
@ -2099,7 +2099,7 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
if (DotProduct(geomsize,geomsize) == 0)
{
// we don't allow point-size physics objects...
if (ed->ode.ode_physics)
if (ed->rbe.physics)
World_ODE_RemoveFromEntity(world, ed);
return;
}
@ -2108,21 +2108,21 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
massval = 1.0f;
// check if we need to create or replace the geom
if (!ed->ode.ode_physics
|| !VectorCompare(ed->ode.ode_mins, entmins)
|| !VectorCompare(ed->ode.ode_maxs, entmaxs)
|| ed->ode.ode_mass != massval
|| ed->ode.ode_modelindex != modelindex)
if (!ed->rbe.physics
|| !VectorCompare(ed->rbe.mins, entmins)
|| !VectorCompare(ed->rbe.maxs, entmaxs)
|| ed->rbe.mass != massval
|| ed->rbe.modelindex != modelindex)
{
modified = true;
World_ODE_RemoveFromEntity(world, ed);
ed->ode.ode_physics = true;
VectorCopy(entmins, ed->ode.ode_mins);
VectorCopy(entmaxs, ed->ode.ode_maxs);
ed->ode.ode_mass = massval;
ed->ode.ode_modelindex = modelindex;
ed->rbe.physics = true;
VectorCopy(entmins, ed->rbe.mins);
VectorCopy(entmaxs, ed->rbe.maxs);
ed->rbe.mass = massval;
ed->rbe.modelindex = modelindex;
VectorAvg(entmins, entmaxs, geomcenter);
ed->ode.ode_movelimit = min(geomsize[0], min(geomsize[1], geomsize[2]));
ed->rbe.movelimit = min(geomsize[0], min(geomsize[1], geomsize[2]));
if (massval * geomsize[0] * geomsize[1] * geomsize[2] == 0)
{
@ -2135,37 +2135,37 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
switch(geomtype)
{
case GEOMTYPE_TRIMESH:
Matrix4x4_Identity(ed->ode.ode_offsetmatrix);
ed->ode.ode_geom = NULL;
Matrix4x4_Identity(ed->rbe.offsetmatrix);
ed->rbe.body.geom = NULL;
if (!model)
{
Con_Printf("entity %i (classname %s) has no model\n", NUM_FOR_EDICT(world->progs, (edict_t*)ed), PR_GetString(world->progs, ed->v->classname));
if (ed->ode.ode_physics)
if (ed->rbe.physics)
World_ODE_RemoveFromEntity(world, ed);
return;
}
if (!rbefuncs->GenerateCollisionMesh(world, model, ed, geomcenter))
{
if (ed->ode.ode_physics)
if (ed->rbe.physics)
World_ODE_RemoveFromEntity(world, ed);
return;
}
Matrix4x4_RM_CreateTranslate(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
Matrix4x4_RM_CreateTranslate(ed->rbe.offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
// now create the geom
dataID = dGeomTriMeshDataCreate();
dGeomTriMeshDataBuildSingle(dataID, (void*)ed->ode.ode_vertex3f, sizeof(float[3]), ed->ode.ode_numvertices, ed->ode.ode_element3i, ed->ode.ode_numtriangles*3, sizeof(int[3]));
ed->ode.ode_geom = (void *)dCreateTriMesh(ctx->space, dataID, NULL, NULL, NULL);
dGeomTriMeshDataBuildSingle(dataID, (void*)ed->rbe.vertex3f, sizeof(float[3]), ed->rbe.numvertices, ed->rbe.element3i, ed->rbe.numtriangles*3, sizeof(int[3]));
ed->rbe.body.geom = (void *)dCreateTriMesh(ctx->space, dataID, NULL, NULL, NULL);
dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]);
break;
case GEOMTYPE_BOX:
Matrix4x4_RM_CreateTranslate(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
ed->ode.ode_geom = (void *)dCreateBox(ctx->space, geomsize[0], geomsize[1], geomsize[2]);
Matrix4x4_RM_CreateTranslate(ed->rbe.offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
ed->rbe.body.geom = (void *)dCreateBox(ctx->space, geomsize[0], geomsize[1], geomsize[2]);
dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]);
break;
case GEOMTYPE_SPHERE:
Matrix4x4_RM_CreateTranslate(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
ed->ode.ode_geom = (void *)dCreateSphere(ctx->space, geomsize[0] * 0.5f);
Matrix4x4_RM_CreateTranslate(ed->rbe.offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
ed->rbe.body.geom = (void *)dCreateSphere(ctx->space, geomsize[0] * 0.5f);
dMassSetSphereTotal(&mass, massval, geomsize[0] * 0.5f);
break;
case GEOMTYPE_CAPSULE:
@ -2188,17 +2188,17 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
// transform to it
if (axisindex == 0)
{
Matrix4x4_CM_ModelMatrix(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 90, 1);
Matrix4x4_CM_ModelMatrix(ed->rbe.offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 90, 1);
radius = min(geomsize[1], geomsize[2]) * 0.5f;
}
else if (axisindex == 1)
{
Matrix4x4_CM_ModelMatrix(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 90, 0, 0, 1);
Matrix4x4_CM_ModelMatrix(ed->rbe.offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 90, 0, 0, 1);
radius = min(geomsize[0], geomsize[2]) * 0.5f;
}
else
{
Matrix4x4_CM_ModelMatrix(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 0, 1);
Matrix4x4_CM_ModelMatrix(ed->rbe.offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 0, 1);
radius = min(geomsize[0], geomsize[1]) * 0.5f;
}
length = geomsize[axisindex] - radius*2;
@ -2210,7 +2210,7 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
// because we want to support more than one axisindex, we have to
// create a transform, and turn on its cleanup setting (which will
// cause the child to be destroyed when it is destroyed)
ed->ode.ode_geom = (void *)dCreateCapsule(ctx->space, radius, length);
ed->rbe.body.geom = (void *)dCreateCapsule(ctx->space, radius, length);
dMassSetCapsuleTotal(&mass, massval, axisindex+1, radius, length);
break;
case GEOMTYPE_CYLINDER:
@ -2233,17 +2233,17 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
// transform to it
if (axisindex == 0)
{
Matrix4x4_CM_ModelMatrix(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 90, 1);
Matrix4x4_CM_ModelMatrix(ed->rbe.offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 90, 1);
radius = min(geomsize[1], geomsize[2]) * 0.5f;
}
else if (axisindex == 1)
{
Matrix4x4_CM_ModelMatrix(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 90, 0, 0, 1);
Matrix4x4_CM_ModelMatrix(ed->rbe.offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 90, 0, 0, 1);
radius = min(geomsize[0], geomsize[2]) * 0.5f;
}
else
{
Matrix4x4_CM_ModelMatrix(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 0, 1);
Matrix4x4_CM_ModelMatrix(ed->rbe.offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 0, 1);
radius = min(geomsize[0], geomsize[1]) * 0.5f;
}
length = geomsize[axisindex] - radius*2;
@ -2255,38 +2255,38 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
// because we want to support more than one axisindex, we have to
// create a transform, and turn on its cleanup setting (which will
// cause the child to be destroyed when it is destroyed)
ed->ode.ode_geom = (void *)dCreateCylinder(ctx->space, radius, length);
ed->rbe.body.geom = (void *)dCreateCylinder(ctx->space, radius, length);
dMassSetCylinderTotal(&mass, massval, axisindex+1, radius, length);
break;
default:
Sys_Errorf("World_ODE_BodyFromEntity: unrecognized solid value %i was accepted by filter\n", solid);
}
Matrix3x4_InvertTo4x4_Simple(ed->ode.ode_offsetmatrix, ed->ode.ode_offsetimatrix);
ed->ode.ode_massbuf = BZ_Malloc(sizeof(dMass));
memcpy(ed->ode.ode_massbuf, &mass, sizeof(dMass));
Matrix3x4_InvertTo4x4_Simple(ed->rbe.offsetmatrix, ed->rbe.offsetimatrix);
ed->rbe.massbuf = BZ_Malloc(sizeof(dMass));
memcpy(ed->rbe.massbuf, &mass, sizeof(dMass));
}
if(ed->ode.ode_geom)
dGeomSetData(ed->ode.ode_geom, (void*)ed);
if (movetype == MOVETYPE_PHYSICS && ed->ode.ode_geom)
if(ed->rbe.body.geom)
dGeomSetData(ed->rbe.body.geom, (void*)ed);
if (movetype == MOVETYPE_PHYSICS && ed->rbe.body.geom)
{
if (ed->ode.ode_body == NULL)
if (ed->rbe.body.body == NULL)
{
ed->ode.ode_body = (void *)(body = dBodyCreate(ctx->dworld));
dGeomSetBody(ed->ode.ode_geom, body);
ed->rbe.body.body = (void *)(body = dBodyCreate(ctx->dworld));
dGeomSetBody(ed->rbe.body.geom, body);
dBodySetData(body, (void*)ed);
dBodySetMass(body, (dMass *) ed->ode.ode_massbuf);
dBodySetMass(body, (dMass *) ed->rbe.massbuf);
modified = true;
}
}
else
{
if (ed->ode.ode_body != NULL)
if (ed->rbe.body.body != NULL)
{
if(ed->ode.ode_geom)
dGeomSetBody(ed->ode.ode_geom, 0);
dBodyDestroy((dBodyID) ed->ode.ode_body);
ed->ode.ode_body = NULL;
if(ed->rbe.body.geom)
dGeomSetBody(ed->rbe.body.geom, 0);
dBodyDestroy((dBodyID) ed->rbe.body.body);
ed->rbe.body.body = NULL;
modified = true;
}
}
@ -2371,16 +2371,16 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
}
// check if the qc edited any position data
if (!VectorCompare(origin, ed->ode.ode_origin)
|| !VectorCompare(velocity, ed->ode.ode_velocity)
|| !VectorCompare(angles, ed->ode.ode_angles)
|| !VectorCompare(avelocity, ed->ode.ode_avelocity)
|| gravity != ed->ode.ode_gravity)
if (!VectorCompare(origin, ed->rbe.origin)
|| !VectorCompare(velocity, ed->rbe.velocity)
|| !VectorCompare(angles, ed->rbe.angles)
|| !VectorCompare(avelocity, ed->rbe.avelocity)
|| gravity != ed->rbe.gravity)
modified = true;
// store the qc values into the physics engine
body = ed->ode.ode_body;
if (modified && ed->ode.ode_geom)
body = ed->rbe.body.body;
if (modified && ed->rbe.body.geom)
{
dVector3 r[3];
float entitymatrix[16];
@ -2388,27 +2388,27 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
#if 0
Con_Printf("entity %i got changed by QC\n", (int) (ed - prog->edicts));
if(!VectorCompare(origin, ed->ode.ode_origin))
Con_Printf(" origin: %f %f %f -> %f %f %f\n", ed->ode.ode_origin[0], ed->ode.ode_origin[1], ed->ode.ode_origin[2], origin[0], origin[1], origin[2]);
if(!VectorCompare(velocity, ed->ode.ode_velocity))
Con_Printf(" velocity: %f %f %f -> %f %f %f\n", ed->ode.ode_velocity[0], ed->ode.ode_velocity[1], ed->ode.ode_velocity[2], velocity[0], velocity[1], velocity[2]);
if(!VectorCompare(angles, ed->ode.ode_angles))
Con_Printf(" angles: %f %f %f -> %f %f %f\n", ed->ode.ode_angles[0], ed->ode.ode_angles[1], ed->ode.ode_angles[2], angles[0], angles[1], angles[2]);
if(!VectorCompare(avelocity, ed->ode.ode_avelocity))
Con_Printf(" avelocity: %f %f %f -> %f %f %f\n", ed->ode.ode_avelocity[0], ed->ode.ode_avelocity[1], ed->ode.ode_avelocity[2], avelocity[0], avelocity[1], avelocity[2]);
if(gravity != ed->ode.ode_gravity)
if(!VectorCompare(origin, ed->rbe.origin))
Con_Printf(" origin: %f %f %f -> %f %f %f\n", ed->rbe.origin[0], ed->rbe.origin[1], ed->rbe.origin[2], origin[0], origin[1], origin[2]);
if(!VectorCompare(velocity, ed->rbe.velocity))
Con_Printf(" velocity: %f %f %f -> %f %f %f\n", ed->rbe.velocity[0], ed->rbe.velocity[1], ed->rbe.velocity[2], velocity[0], velocity[1], velocity[2]);
if(!VectorCompare(angles, ed->rbe.angles))
Con_Printf(" angles: %f %f %f -> %f %f %f\n", ed->rbe.angles[0], ed->rbe.angles[1], ed->rbe.angles[2], angles[0], angles[1], angles[2]);
if(!VectorCompare(avelocity, ed->rbe.avelocity))
Con_Printf(" avelocity: %f %f %f -> %f %f %f\n", ed->rbe.avelocity[0], ed->rbe.avelocity[1], ed->rbe.avelocity[2], avelocity[0], avelocity[1], avelocity[2]);
if(gravity != ed->rbe.gravity)
Con_Printf(" gravity: %i -> %i\n", ed->ide.ode_gravity, gravity);
#endif
// values for BodyFromEntity to check if the qc modified anything later
VectorCopy(origin, ed->ode.ode_origin);
VectorCopy(velocity, ed->ode.ode_velocity);
VectorCopy(angles, ed->ode.ode_angles);
VectorCopy(avelocity, ed->ode.ode_avelocity);
ed->ode.ode_gravity = gravity;
VectorCopy(origin, ed->rbe.origin);
VectorCopy(velocity, ed->rbe.velocity);
VectorCopy(angles, ed->rbe.angles);
VectorCopy(avelocity, ed->rbe.avelocity);
ed->rbe.gravity = gravity;
Matrix4x4_RM_FromVectors(entitymatrix, forward, left, up, origin);
Matrix4_Multiply(ed->ode.ode_offsetmatrix, entitymatrix, bodymatrix);
Matrix4_Multiply(ed->rbe.offsetmatrix, entitymatrix, bodymatrix);
Matrix3x4_RM_ToVectors(bodymatrix, forward, left, up, origin);
r[0][0] = forward[0];
r[1][0] = forward[1];
@ -2423,7 +2423,7 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
{
if(movetype == MOVETYPE_PHYSICS)
{
dGeomSetBody(ed->ode.ode_geom, body);
dGeomSetBody(ed->rbe.body.geom, body);
dBodySetPosition(body, origin[0], origin[1], origin[2]);
dBodySetRotation(body, r[0]);
dBodySetLinearVel(body, velocity[0], velocity[1], velocity[2]);
@ -2432,21 +2432,21 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
}
else
{
dGeomSetBody(ed->ode.ode_geom, body);
dGeomSetBody(ed->rbe.body.geom, body);
dBodySetPosition(body, origin[0], origin[1], origin[2]);
dBodySetRotation(body, r[0]);
dBodySetLinearVel(body, velocity[0], velocity[1], velocity[2]);
dBodySetAngularVel(body, spinvelocity[0], spinvelocity[1], spinvelocity[2]);
dBodySetGravityMode(body, gravity);
dGeomSetBody(ed->ode.ode_geom, 0);
dGeomSetBody(ed->rbe.body.geom, 0);
}
}
else
{
// no body... then let's adjust the parameters of the geom directly
dGeomSetBody(ed->ode.ode_geom, 0); // just in case we previously HAD a body (which should never happen)
dGeomSetPosition(ed->ode.ode_geom, origin[0], origin[1], origin[2]);
dGeomSetRotation(ed->ode.ode_geom, r[0]);
dGeomSetBody(ed->rbe.body.geom, 0); // just in case we previously HAD a body (which should never happen)
dGeomSetPosition(ed->rbe.body.geom, origin[0], origin[1], origin[2]);
dGeomSetRotation(ed->rbe.body.geom, r[0]);
}
}
@ -2527,7 +2527,7 @@ static void VARGS nearCallback (void *data, dGeomID o1, dGeomID o2)
//ragdolls don't make contact with the bbox of the doll entity
//the origional entity should probably not be solid anyway.
//these bodies should probably not collide against bboxes of other entities with ragdolls either, but meh.
if (ed1->ode.ode_body == b1 || ed2->ode.ode_body == b2)
if (ed1->rbe.body.body == b1 || ed2->rbe.body.body == b2)
return;
}
if(!ed1 || ED_ISFREE(ed1))
@ -2791,25 +2791,25 @@ static void World_ODE_RunCmd(world_t *world, rbecommandqueue_t *cmd)
switch(cmd->command)
{
case RBECMD_ENABLE:
if (cmd->edict->ode.ode_body)
dBodyEnable(cmd->edict->ode.ode_body);
if (cmd->edict->rbe.body.body)
dBodyEnable(cmd->edict->rbe.body.body);
break;
case RBECMD_DISABLE:
if (cmd->edict->ode.ode_body)
dBodyDisable(cmd->edict->ode.ode_body);
if (cmd->edict->rbe.body.body)
dBodyDisable(cmd->edict->rbe.body.body);
break;
case RBECMD_FORCE:
if (cmd->edict->ode.ode_body)
if (cmd->edict->rbe.body.body)
{
dBodyEnable(cmd->edict->ode.ode_body);
dBodyAddForceAtPos(cmd->edict->ode.ode_body, cmd->v1[0], cmd->v1[1], cmd->v1[2], cmd->v2[0], cmd->v2[1], cmd->v2[2]);
dBodyEnable(cmd->edict->rbe.body.body);
dBodyAddForceAtPos(cmd->edict->rbe.body.body, cmd->v1[0], cmd->v1[1], cmd->v1[2], cmd->v2[0], cmd->v2[1], cmd->v2[2]);
}
break;
case RBECMD_TORQUE:
if (cmd->edict->ode.ode_body)
if (cmd->edict->rbe.body.body)
{
dBodyEnable(cmd->edict->ode.ode_body);
dBodyAddTorque(cmd->edict->ode.ode_body, cmd->v1[0], cmd->v1[1], cmd->v1[2]);
dBodyEnable(cmd->edict->rbe.body.body);
dBodyAddTorque(cmd->edict->rbe.body.body, cmd->v1[0], cmd->v1[1], cmd->v1[2]);
}
break;
}

View file

@ -111,7 +111,9 @@ cvar_t fs_gamename = CVARAFD("com_fullgamename", NULL, "fs_gamename", CVAR_NOSET
cvar_t com_protocolname = CVARAD("com_protocolname", NULL, "com_gamename", "The protocol game name used for dpmaster queries. For compatibility with DP, you can set this to 'DarkPlaces-Quake' in order to be listed in DP's master server, and to list DP servers.");
cvar_t com_protocolversion = CVARAD("com_protocolversion", "3", NULL, "The protocol version used for dpmaster queries."); //3 by default, for compat with DP/NQ, even if our QW protocol uses different versions entirely. really it only matters for master servers.
cvar_t com_parseutf8 = CVARD("com_parseutf8", "1", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed.
#ifndef NOLEGACY
cvar_t com_parseezquake = CVARD("com_parseezquake", "0", "Treat chevron chars from configs as a per-character flag. You should use this only for compat with nquake's configs.");
#endif
cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "ANSI colour to be used for highlighted text, used when com_parseutf8 is active.");
cvar_t com_nogamedirnativecode = CVARFD("com_nogamedirnativecode", "1", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger delayed eremote exploits in any engine (including "DISTRIBUTION") which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 0, as well as ensure that you don't run unsafe clients.\n");
cvar_t sys_platform = CVAR("sys_platform", PLATFORM);
@ -135,7 +137,9 @@ void COM_Locate_f (void);
#define PAK0_COUNT 339
#define PAK0_CRC 52883
qboolean standard_quake = true, rogue, hipnotic;
#ifdef NQPROT
qboolean standard_quake = true; //unfortunately, the vanilla NQ protocol(and 666) subtly changes when -rogue or -hipnotic are used (and by extension -quoth). QW/FTE protocols don't not need to care, but compat...
#endif
/*
@ -3239,13 +3243,13 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t
conchar_t *oldout = out;
#ifndef NOLEGACY
extern cvar_t dpcompat_console;
#endif
if (flags & PFS_EZQUAKEMARKUP)
{
ezquakemess = true;
utf8 = 0;
}
#endif
if (flags & PFS_FORCEUTF8)
utf8 = 2;
@ -3970,7 +3974,9 @@ skipwhite:
//same as COM_Parse, but parses two quotes next to each other as a single quote as part of the string
char *COM_StringParse (const char *data, char *token, unsigned int tokenlen, qboolean expandmacros, qboolean qctokenize)
{
#ifndef NOLEGACY
extern cvar_t dpcompat_console;
#endif
int c;
int len;
char *s;
@ -4038,6 +4044,7 @@ skipwhite:
if (c == '\"')
{
data++;
#ifndef NOLEGACY
if (dpcompat_console.ival)
{
while (1)
@ -4066,6 +4073,7 @@ skipwhite:
}
}
else
#endif
{
while (1)
{
@ -4330,7 +4338,11 @@ skipwhite:
const char *COM_QuotedString(const char *string, char *buf, int buflen, qboolean omitquotes)
{
#ifndef NOLEGACY
extern cvar_t dpcompat_console;
#else
static const cvar_t dpcompat_console = {0};
#endif
const char *result = buf;
if (strchr(string, '\r') || strchr(string, '\n') || (!dpcompat_console.ival && strchr(string, '\"')))
{
@ -5713,7 +5725,9 @@ void COM_Init (void)
Cvar_Register (&gameversion_max, "Gamecode");
Cvar_Register (&com_nogamedirnativecode, "Gamecode");
Cvar_Register (&com_parseutf8, "Internationalisation");
#ifndef NOLEGACY
Cvar_Register (&com_parseezquake, NULL);
#endif
Cvar_Register (&com_highlightcolor, "Internationalisation");
com_parseutf8.ival = 1;

View file

@ -397,7 +397,9 @@ char *COM_DeFunString(conchar_t *str, conchar_t *stop, char *out, int outsize, q
#define PFS_KEEPMARKUP 1 //leave markup in the final string (but do parse it)
#define PFS_FORCEUTF8 2 //force utf-8 decoding
#define PFS_NOMARKUP 4 //strip markup completely
#ifndef NOLEGACY
#define PFS_EZQUAKEMARKUP 8 //aim for compat with ezquake instead of q3 compat
#endif
#define PFS_CENTERED 16 //flag used by console prints (text should remain centered)
#define PFS_NONOTIFY 32 //flag used by console prints (text won't be visible other than by looking at the console)
conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, int keepmarkup); //ext is usually CON_WHITEMASK, returns its null terminator

View file

@ -175,6 +175,7 @@ char *Cvar_FlagToName(int flag)
#define CLF_LATCHES 0x20
#define CLF_FLAGS 0x40
#define CLF_FLAGMASK 0x80
#define CLF_CHANGEDONLY 0x100
void Cvar_List_f (void)
{
cvar_group_t *grp;
@ -186,6 +187,7 @@ void Cvar_List_f (void)
static char *cvarlist_help =
"cvarlist list all cvars matching given parameters\n"
"Syntax: cvarlist [-FLdhlrv] [-f flag] [-g group] [cvar]\n"
" -c includes only the cvars that have been changed from their defaults\n"
" -F shows cvar flags\n"
" -L shows latched values\n"
" -a shows cvar alternate names\n"
@ -225,6 +227,9 @@ void Cvar_List_f (void)
gsearch = Cmd_Argv(i);
break;
case 'c':
listflags |= CLF_CHANGEDONLY;
break;
case 'a':
listflags |= CLF_ALTNAME;
break;
@ -358,6 +363,9 @@ showhelp:
if ((listflags & CLF_FLAGMASK) && !(cmd->flags & cvarflags))
continue;
if ((listflags & CLF_CHANGEDONLY) && cmd->defaultstr && !strcmp(cmd->string, cmd->defaultstr))
continue;
// print cvar list header
if (!(listflags & CLF_RAW) && !num)
Con_TPrintf("CVar list:\n");

View file

@ -3683,6 +3683,9 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
i = COM_CheckNextParm ("-basepack", i);
}
#ifdef NQPROT
standard_quake = true;
#endif
for (i = 0; i < sizeof(fs_manifest->gamepath) / sizeof(fs_manifest->gamepath[0]); i++)
{
char *dir = fs_manifest->gamepath[i].path;
@ -3697,12 +3700,20 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
continue;
}
if (!Q_strncasecmp(dir, "downloads", 9))
//some gamedirs should never be used...
if (!Q_strncasecmp(dir, "downloads", 9) || !Q_strncasecmp(dir, "docs", 4) || !Q_strncasecmp(dir, "help", 4))
{
Con_Printf ("Gamedir should not be \"%s\"\n", dir);
continue;
}
#ifdef NQPROT
//vanilla NQ uses a slightly different protocol when started with -rogue or -hipnotic (and by extension -quoth).
//QW+FTE protocols don't care so we can get away with being a little loose here
if (!strcmp(dir, "rogue") || !strcmp(dir, "hipnotic") || !strcmp(dir, "quoth"))
standard_quake = false;
#endif
//paths equal to '*' actually result in loading packages without an actual gamedir. note that this does not imply that we can write anything.
if (!strcmp(dir, "*"))
{

View file

@ -2555,6 +2555,28 @@ static qboolean CModQ3_LoadFogs (model_t *mod, qbyte *mod_base, lump_t *l)
return true;
}
texid_t *Mod_CubemapForOrigin(model_t *wmodel, vec3_t org)
{
int i;
menvmap_t *e;
float bestdist = FLT_MAX, dist;
texid_t *ret = NULL;
vec3_t move;
if (!wmodel || wmodel->loadstate != MLS_LOADED)
return NULL;
for ( i=0 , e=wmodel->envmaps ; i<wmodel->numenvmaps ; i++, e++)
{
VectorSubtract(org, e->origin, move);
dist = DotProduct(move,move);
if (bestdist > dist)
{
bestdist = dist;
ret = e->image;
}
}
return ret;
}
mfog_t *Mod_FogForOrigin(model_t *wmodel, vec3_t org)
{
int i, j;

View file

@ -34,7 +34,7 @@ struct wedict_s
int solidsize;
#ifdef USERBE
entityode_t ode;
entityrbe_t rbe;
#endif
/*the above is shared with ssqc*/
};
@ -289,6 +289,7 @@ void QCBUILTIN PF_setattachment(pubprogfuncs_t *prinst, struct globalvars_s *pr_
void skel_dodelete(world_t *world);
void skel_reset(world_t *world);
void skel_reload(void);
void skel_updateentbounds();
#endif
void QCBUILTIN PF_physics_supported(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_physics_enable(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -458,6 +459,7 @@ void QCBUILTIN PF_cl_sprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
void QCBUILTIN PF_cl_bprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cl_clientcount (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cl_localsound(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cl_SendPacket(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void search_close_progs(pubprogfuncs_t *prinst, qboolean complain);

View file

@ -191,6 +191,8 @@ typedef struct
void (QDECL *RagDestroyJoint)(struct world_s *world, rbejoint_t *joint);
void (QDECL *RunFrame)(struct world_s *world, double frametime, double gravity);
void (QDECL *PushCommand)(struct world_s *world, rbecommandqueue_t *cmd);
// void (QDECL *ExpandBodyAABB)(struct world_s *world, rbebody_t *bodyptr, float *mins, float *maxs); //expands an aabb to include the size of the body.
// void (QDECL *Trace) ();
} rigidbodyengine_t;
#endif

View file

@ -1536,6 +1536,10 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
ambientlight[0] = ambientlight[1] = ambientlight[2] = 1;
shadelight[0] = shadelight[1] = shadelight[2] = 1;
VectorSet(e->light_dir, 1, 0, 0);
VectorClear(e->light_range);
VectorScale(shadelight, fb, e->light_avg);
e->light_known = 2;
return e->light_known-1;
}

View file

@ -193,6 +193,7 @@ struct {
int lightmode;
vec3_t lightorg;
vec3_t lightdir;
vec3_t lightcolours;
vec3_t lightcolourscale;
float lightradius;
@ -3669,6 +3670,14 @@ static void BE_Program_Set_Attributes(const program_t *prog, unsigned int perm,
qglUniform3fvARB(ph, 1, t2);
}
break;
case SP_LIGHTDIRECTION:
{
/*light position in model space*/
vec3_t t2;
Matrix4x4_CM_Transform3x3(shaderstate.modelmatrixinv, shaderstate.lightdir, t2);
qglUniform3fvARB(ph, 1, t2);
}
break;
case SP_LIGHTCOLOURSCALE:
qglUniform3fvARB(ph, 1, shaderstate.lightcolourscale);
break;
@ -3742,6 +3751,39 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas
int perm;
perm = 0;
#if 0
if (shaderstate.sourcevbo->numbones)
perm |= PERMUTATION_SKELETAL;
#ifdef NONSKELETALMODELS
if (shaderstate.sourcevbo->coord2.gl.addr)
perm |= PERMUTATION_FRAMEBLEND;
#endif
if (TEXLOADED(shaderstate.curtexnums->bump))
perm |= PERMUTATION_BUMPMAP;
if (TEXLOADED(shaderstate.curtexnums->fullbright))
perm |= PERMUTATION_FULLBRIGHT;
if ((TEXLOADED(shaderstate.curtexnums->loweroverlay) || TEXLOADED(shaderstate.curtexnums->upperoverlay)))
perm |= PERMUTATION_UPPERLOWER;
if (r_refdef.globalfog.density)
perm |= PERMUTATION_FOG;
// if (p->permu[perm|PERMUTATION_DELUXE].handle.glsl.handle && TEXLOADED(shaderstate.curtexnums->bump) && shaderstate.curbatch->lightmap[0] >= 0 && lightmap[shaderstate.curbatch->lightmap[0]]->hasdeluxe)
// perm |= PERMUTATION_DELUXE;
if ((TEXLOADED(shaderstate.curtexnums->reflectcube) || TEXLOADED(shaderstate.curtexnums->reflectmask)))
perm |= PERMUTATION_REFLECTCUBEMASK;
#if MAXRLIGHTMAPS > 1
if (shaderstate.curbatch->lightmap[1] >= 0)
perm |= PERMUTATION_LIGHTSTYLES;
#endif
perm &= p->supportedpermutations;
if (!p->permu[perm].h.loaded)
{
perm = 0;
if (!p->permu[perm].h.loaded)
return;
}
#else
if (shaderstate.sourcevbo->numbones)
{
if (p->permu[perm|PERMUTATION_SKELETAL].h.loaded)
@ -3769,6 +3811,7 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas
#if MAXRLIGHTMAPS > 1
if (shaderstate.curbatch->lightmap[1] >= 0 && p->permu[perm|PERMUTATION_LIGHTSTYLES].h.loaded)
perm |= PERMUTATION_LIGHTSTYLES;
#endif
#endif
GL_SelectProgram(p->permu[perm].h.glsl.handle);
@ -4096,6 +4139,7 @@ qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned
/*simple info*/
shaderstate.lightradius = dl->radius;
VectorCopy(dl->origin, shaderstate.lightorg);
VectorCopy(axis[0], shaderstate.lightdir);
VectorCopy(colour, shaderstate.lightcolours);
#ifdef RTLIGHTS
VectorCopy(dl->lightcolourscales, shaderstate.lightcolourscale);
@ -4113,13 +4157,17 @@ qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned
/*generate light projection information*/
if (shaderstate.lightmode & LSHADER_ORTHO)
{
float view[16];
float proj[16];
float xmin = -dl->radius;
float ymin = -dl->radius;
float znear = -dl->radius;
float xmax = dl->radius;
float ymax = dl->radius;
float zfar = dl->radius;
Matrix4x4_CM_Orthographic(shaderstate.lightprojmatrix, xmin, xmax, ymax, ymin, znear, zfar);
Matrix4x4_CM_Orthographic(proj, xmin, xmax, ymax, ymin, znear, zfar);
Matrix4x4_CM_ModelViewMatrixFromAxis(view, axis[0], axis[2], axis[1], dl->origin);
Matrix4_Multiply(proj, view, shaderstate.lightprojmatrix);
// Matrix4x4_CM_LightMatrixFromAxis(shaderstate.lightprojmatrix, axis[0], axis[1], axis[2], dl->origin);
}
else if (shaderstate.lightmode & LSHADER_SPOT)
@ -5058,74 +5106,17 @@ static void GLBE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist)
}
}
static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
static qboolean GLBE_GenerateBatchTextures(batch_t *batch, shader_t *bs)
{
batch_t *batch;
shader_t *bs;
for (batch = sortlist; batch; batch = batch->next)
{
if (batch->meshes == batch->firstmesh)
continue;
if (batch->flags & BEF_NODLIGHT)
if (shaderstate.mode == BEM_LIGHT)
continue;
if (batch->flags & BEF_NOSHADOWS)
if (shaderstate.mode == BEM_STENCIL || shaderstate.mode == BEM_DEPTHONLY) //fixme: depthonly is not just shadows.
continue;
//buildmeshes updates shaders and generates pose information for sufaces that need it.
//the shader flags checked *after* this call may be a performance issue if it generated lots of new mesh data.
//FIXME: should we assume that the batch's shader will have the same flags?
if (batch->buildmeshes)
{
TRACE(("GLBE_SubmitMeshesSortList: build\n"));
batch->buildmeshes(batch);
}
bs = batch->shader;
TRACE(("GLBE_SubmitMeshesSortList: shader %s\n", bs->name));
//FIXME:!!
if (!bs)
{
Con_Printf("Shader not set...\n");
if (batch->texture)
bs = R_TextureAnimation(0, batch->texture)->shader;
else
continue;
}
if ((bs->flags & SHADER_NODRAW) || !batch->meshes)
continue;
if (bs->flags & SHADER_NODLIGHT)
if (shaderstate.mode == BEM_LIGHT)
continue;
if (bs->flags & SHADER_NOSHADOWS)
if (shaderstate.mode == BEM_STENCIL || shaderstate.mode == BEM_DEPTHONLY) //fixme: depthonly is not just shadows.
continue;
if (bs->flags & SHADER_SKY)
{
if (shaderstate.mode == BEM_STANDARD || shaderstate.mode == BEM_DEPTHDARK)// || shaderstate.mode == BEM_WIREFRAME)
{
if (R_DrawSkyChain(batch))
continue;
}
else if (/*shaderstate.mode != BEM_FOG &&*/ shaderstate.mode != BEM_CREPUSCULAR && shaderstate.mode != BEM_WIREFRAME)
continue;
}
if ((bs->flags & (SHADER_HASREFLECT | SHADER_HASREFRACT | SHADER_HASRIPPLEMAP)) && shaderstate.mode != BEM_WIREFRAME)
{
int oldfbo;
float oldil;
int oldbem;
if (r_refdef.recurse == r_portalrecursion.ival || r_refdef.recurse == R_MAX_RECURSE)
continue;
return false;
//these flags require rendering some view as an fbo
//(BEM_DEPTHDARK is used when lightmap scale is 0, but still shows any emissive stuff)
if (shaderstate.mode != BEM_STANDARD && shaderstate.mode != BEM_DEPTHDARK)
continue;
return false;
oldbem = shaderstate.mode;
oldil = shaderstate.identitylighting;
@ -5312,8 +5303,70 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
}
BE_SelectMode(oldbem);
shaderstate.identitylighting = oldil;
return true;
}
static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
{
batch_t *batch;
shader_t *bs;
for (batch = sortlist; batch; batch = batch->next)
{
if (batch->meshes == batch->firstmesh)
continue;
if (batch->flags & BEF_NODLIGHT)
if (shaderstate.mode == BEM_LIGHT)
continue;
if (batch->flags & BEF_NOSHADOWS)
if (shaderstate.mode == BEM_STENCIL || shaderstate.mode == BEM_DEPTHONLY) //fixme: depthonly is not just shadows.
continue;
//buildmeshes updates shaders and generates pose information for sufaces that need it.
//the shader flags checked *after* this call may be a performance issue if it generated lots of new mesh data.
//FIXME: should we assume that the batch's shader will have the same flags?
if (batch->buildmeshes)
{
TRACE(("GLBE_SubmitMeshesSortList: build\n"));
batch->buildmeshes(batch);
}
bs = batch->shader;
TRACE(("GLBE_SubmitMeshesSortList: shader %s\n", bs->name));
//FIXME:!!
if (!bs)
{
Con_Printf("Shader not set...\n");
if (batch->texture)
bs = R_TextureAnimation(0, batch->texture)->shader;
else
continue;
}
if ((bs->flags & SHADER_NODRAW) || !batch->meshes)
continue;
if (bs->flags & SHADER_NODLIGHT)
if (shaderstate.mode == BEM_LIGHT)
continue;
if (bs->flags & SHADER_NOSHADOWS)
if (shaderstate.mode == BEM_STENCIL || shaderstate.mode == BEM_DEPTHONLY) //fixme: depthonly is not just shadows.
continue;
if (bs->flags & SHADER_SKY)
{
if (shaderstate.mode == BEM_STANDARD || shaderstate.mode == BEM_DEPTHDARK)// || shaderstate.mode == BEM_WIREFRAME)
{
if (R_DrawSkyChain(batch))
continue;
}
else if (/*shaderstate.mode != BEM_FOG &&*/ shaderstate.mode != BEM_CREPUSCULAR && shaderstate.mode != BEM_WIREFRAME)
continue;
}
if ((bs->flags & (SHADER_HASREFLECT | SHADER_HASREFRACT | SHADER_HASRIPPLEMAP)) && shaderstate.mode != BEM_WIREFRAME)
if (!GLBE_GenerateBatchTextures(batch, bs))
continue;
GLBE_SubmitBatch(batch);
}
}

View file

@ -2718,7 +2718,8 @@ static int Mod_Batches_Generate(model_t *mod)
lbatch->lightmap[2] == lmmerge(surf->lightmaptexturenums[2]) &&
lbatch->lightmap[3] == lmmerge(surf->lightmaptexturenums[3]) &&
#endif
lbatch->fog == surf->fog))
lbatch->fog == surf->fog &&
lbatch->envmap == surf->envmap))
batch = lbatch;
else
{
@ -2735,7 +2736,8 @@ static int Mod_Batches_Generate(model_t *mod)
batch->lightmap[2] == lmmerge(surf->lightmaptexturenums[2]) &&
batch->lightmap[3] == lmmerge(surf->lightmaptexturenums[3]) &&
#endif
batch->fog == surf->fog)
batch->fog == surf->fog &&
batch->envmap == surf->envmap)
break;
}
}
@ -2772,6 +2774,7 @@ static int Mod_Batches_Generate(model_t *mod)
batch->next = mod->batches[sortid];
batch->ent = &r_worldentity;
batch->fog = surf->fog;
batch->envmap = surf->envmap;
Vector4Copy(plane, batch->plane);
mod->batches[sortid] = batch;
@ -2938,7 +2941,7 @@ static void Mod_LightmapAllocSurf(lmalloc_t *lmallocator, msurface_t *surf, int
if (isDedicated ||
(surf->texinfo->texture->shader && !(surf->texinfo->texture->shader->flags & SHADER_HASLIGHTMAP)) || //fte
(surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) || //q1
(surf->flags & (SURF_DRAWSKY|SURF_DRAWTILED)) || //q1
(surf->texinfo->flags & TEX_SPECIAL) || //the original 'no lightmap'
(surf->texinfo->flags & (TI_SKY|TI_TRANS33|TI_TRANS66|TI_WARP)) || //q2 surfaces
smax > lmallocator->width || tmax > lmallocator->height || smax < 0 || tmax < 0) //bugs/bounds/etc
@ -3683,8 +3686,18 @@ static qboolean Mod_LoadTexinfo (model_t *loadmodel, qbyte *mod_base, lump_t *l)
out->texture = r_notexture_mip; // texture not found
out->flags = 0;
}
else if (!strncmp(out->texture->name, "scroll", 6) || ((*out->texture->name == '*' || *out->texture->name == '{' || *out->texture->name == '!') && !strncmp(out->texture->name+1, "scroll", 6)))
else
{
if (*out->texture->name == '*' || (*out->texture->name == '!' && loadmodel->fromgame == fg_halflife)) // turbulent
{
if (!(out->flags & TEX_SPECIAL) && !strchr(out->texture->name, '#'))
Q_strncatz(out->texture->name, "#LIT", sizeof(out->texture->name));
}
if (!strncmp(out->texture->name, "scroll", 6) || ((*out->texture->name == '*' || *out->texture->name == '{' || *out->texture->name == '!') && !strncmp(out->texture->name+1, "scroll", 6)))
out->flags |= TI_FLOWING;
}
}
return true;
@ -3896,15 +3909,18 @@ static qboolean Mod_LoadFaces (model_t *loadmodel, qbyte *mod_base, lump_t *l, l
out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED);
continue;
}
if (*out->texinfo->texture->name == '*' || (*out->texinfo->texture->name == '!' && loadmodel->fromgame == fg_halflife)) // turbulent
{
out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED);
out->flags |= SURF_DRAWTURB;
if (out->texinfo->flags & TEX_SPECIAL)
{
out->flags |= SURF_DRAWTILED;
for (i=0 ; i<2 ; i++)
{
out->extents[i] = 16384;
out->texturemins[i] = -8192;
}
}
continue;
}

View file

@ -121,6 +121,7 @@ typedef struct batch_s
struct vbo_s *vbo;
entity_t *ent; /*used for shader properties*/
struct mfog_s *fog;
image_t *envmap;
short lightmap[MAXRLIGHTMAPS]; /*used for shader lightmap textures*/
unsigned char lmlightstyle[MAXRLIGHTMAPS];
@ -390,6 +391,14 @@ typedef struct mfog_s
mplane_t **planes;
} mfog_t;
typedef struct
{
vec3_t origin;
int cubesize; //pixels
texid_t *image;
} menvmap_t;
#define LMSHIFT_DEFAULT 4
typedef struct msurface_s
{
@ -405,6 +414,7 @@ typedef struct msurface_s
unsigned short light_s[MAXRLIGHTMAPS], light_t[MAXRLIGHTMAPS]; // gl lightmap coordinates
image_t *envmap;
mfog_t *fog;
mesh_t *mesh;
@ -972,6 +982,8 @@ typedef struct model_s
q3lightgridinfo_t *lightgrid;
mfog_t *fogs;
int numfogs;
menvmap_t *envmaps;
unsigned numenvmaps;
struct {unsigned int id; char *keyvals;} *entityinfo;
size_t numentityinfo;
const char *entities_raw;

View file

@ -736,15 +736,19 @@ void R_PushDlights (void)
#ifdef RTLIGHTS
qboolean R_ImportRTLights(const char *entlump)
{
typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_INFINITE, LIGHTTYPE_LOCALMIN, LIGHTTYPE_RECIPXX2, LIGHTTYPE_SUN} lighttype_t;
/*I'm using the DP code so I know I'll get the DP results*/
int entnum, style, islight, skin, pflags, n;
lighttype_t type;
float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], colourscales[3], vec[4];
float origin[3], angles[3], mangle[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], colourscales[3], vec[4];
char key[256], value[8192];
char targetname[256], target[256];
int nest;
qboolean okay = false;
infobuf_t targets;
const char *lmp;
memset(&targets, 0, sizeof(targets));
//a quick note about tenebrae:
//by default, tenebrae's rtlights come from the server via static entities, which is all fancy and posh and actually fairly nice... if all servers actually did it.
@ -753,6 +757,7 @@ qboolean R_ImportRTLights(const char *entlump)
//such lights are ONLY created if they're not near some other existing light (like a static entity one).
//this can result in FTE having noticably more and bigger lights than tenebrae. shadowmapping doesn't help performance either.
//handle doom3's header
COM_Parse(entlump);
if (!strcmp(com_token, "Version"))
{
@ -760,6 +765,55 @@ qboolean R_ImportRTLights(const char *entlump)
entlump = COM_Parse(entlump);
}
//find targetnames, and store their origins so that we can deal with spotlights.
for (lmp = entlump; ;)
{
lmp = COM_Parse(lmp);
if (com_token[0] != '{')
break;
*targetname = 0;
VectorClear(origin);
nest = 1;
while (1)
{
lmp = COM_ParseOut(lmp, key, sizeof(key));
if (!lmp)
break; // error
if (key[0] == '{')
{
nest++;
continue;
}
if (key[0] == '}')
{
nest--;
if (!nest)
break; // end of entity
continue;
}
if (nest!=1)
continue;
if (key[0] == '_')
memmove(key, key+1, strlen(key));
while (key[strlen(key)-1] == ' ') // remove trailing spaces
key[strlen(key)-1] = 0;
lmp = COM_ParseOut(lmp, value, sizeof(value));
if (!lmp)
break; // error
// now that we have the key pair worked out...
if (!strcmp("targetname", key))
Q_strncpyz(targetname, value, sizeof(targetname));
else if (!strcmp("origin", key))
sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
}
//if we found an ent with a targetname and an origin, then record where it was.
if (*targetname && (origin[0] || origin[1] || origin[2]))
InfoBuf_SetStarKey(&targets, targetname, va("%f %f %f", origin[0], origin[1], origin[2]));
}
for (entnum = 0; ;entnum++)
{
entlump = COM_Parse(entlump);
@ -770,11 +824,13 @@ qboolean R_ImportRTLights(const char *entlump)
origin[0] = origin[1] = origin[2] = 0;
originhack[0] = originhack[1] = originhack[2] = 0;
angles[0] = angles[1] = angles[2] = 0;
mangle[0] = mangle[1] = mangle[2] = 0;
color[0] = color[1] = color[2] = 1;
light[0] = light[1] = light[2] = 1;light[3] = 300;
overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
fadescale = 1;
lightscale = 1;
*target = 0;
style = 0;
skin = 0;
pflags = 0;
@ -837,14 +893,22 @@ qboolean R_ImportRTLights(const char *entlump)
type = atoi(value);
else if (!strcmp("origin", key))
sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
else if (!strcmp("angle", key))
else if (!strcmp("angle", key)) //orientation for cubemaps (or angle of spot lights)
angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
else if (!strcmp("angles", key))
else if (!strcmp("mangle", key)) //orientation for cubemaps (or angle of spot lights)
{
sscanf(value, "%f %f %f", &mangle[1], &mangle[0], &mangle[2]); //FIXME: order is fucked.
mangle[0] = 360-mangle[0]; //FIXME: pitch is fucked too.
}
//_softangle -- the inner cone angle of a spotlight.
else if (!strcmp("angles", key)) //richer cubemap orientation.
sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
else if (!strcmp("color", key))
sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
else if (!strcmp("wait", key))
fadescale = atof(value);
else if (!strcmp("target", key))
Q_strncpyz(target, value, sizeof(target));
else if (!strcmp("classname", key))
{
if (!strncmp(value, "light", 5))
@ -989,32 +1053,55 @@ qboolean R_ImportRTLights(const char *entlump)
color[0] = color[0] * light[0];
color[1] = color[1] * light[1];
color[2] = color[2] * light[2];
#define CUTOFF (128.0/255)
switch (type)
{
case LIGHTTYPE_MINUSX:
break;
case LIGHTTYPE_RECIPX:
#if 1
radius *= 2;
VectorScale(color, (1.0f / 16.0f), color);
// VectorScale(color, (1.0f / 16.0f), color);
#else
//light util uses something like: cutoff == light/((scaledist*fadescale*radius)/128)
//radius = light/(cutoff*128*scaledist*fadescale)
radius = lightscale*r_editlights_import_radius.value*256/(1*fadescale);
radius = min(radius, 300);
VectorScale(color, 255/light[3], color);
#endif
break;
case LIGHTTYPE_RECIPXX:
case LIGHTTYPE_RECIPXX2:
#if 1
radius *= 2;
VectorScale(color, (1.0f / 16.0f), color);
// VectorScale(color, (1.0f / 16.0f), color);
#else
//light util uses something like: cutoff == light/((scaledist*scaledist*fadescale*fadescale*radius*radius)/(128*128))
radius = lightscale*r_editlights_import_radius.value*sqrt(1/CUTOFF*128*128*1*1*fadescale*fadescale);
radius = min(radius, 300);
VectorScale(color, 255/light[3], color);
#endif
break;
default:
case LIGHTTYPE_NONE:
case LIGHTTYPE_INFINITE:
radius = FLT_MAX; //close enough
break;
case LIGHTTYPE_LOCALMIN: //can't support, treat like LIGHTTYPE_MINUSX
break;
case LIGHTTYPE_SUN:
break;
case LIGHTTYPE_MINUSXX:
break;
}
if (radius < 50) //some mappers insist on many tiny lights. such lights can usually get away with no shadows..
pflags |= PFLAGS_NOSHADOW;
VectorAdd(origin, originhack, origin);
if (radius >= 1 && !(cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, origin) & FTECONTENTS_SOLID))
{
dlight_t *dl = CL_AllocSlight();
if (!dl)
break;
VectorCopy(origin, dl->origin);
AngleVectors(angles, dl->axis[0], dl->axis[1], dl->axis[2]);
VectorInverse(dl->axis[1]);
@ -1026,6 +1113,34 @@ qboolean R_ImportRTLights(const char *entlump)
dl->flags |= (pflags & PFLAGS_NOSHADOW)?LFLAG_NOSHADOWS:0;
dl->style = style+1;
VectorCopy(colourscales, dl->lightcolourscales);
//handle spotlights.
if (mangle[0] || mangle[1] || mangle[2])
{
dl->fov = angles[1];
if (!dl->fov) //default is 40, supposedly
dl->fov = 40;
AngleVectors(mangle, dl->axis[0], dl->axis[1], dl->axis[2]);
VectorInverse(dl->axis[1]);
}
else if (*target)
{
lmp = InfoBuf_ValueForKey(&targets, target);
if (*lmp)
{
dl->fov = angles[1];
if (!dl->fov) //default is 40, supposedly
dl->fov = 40;
sscanf(lmp, "%f %f %f", &angles[0], &angles[1], &angles[2]);
VectorSubtract(angles, origin, dl->axis[0]);
VectorNormalize(dl->axis[0]);
VectorVectors(dl->axis[0], dl->axis[1], dl->axis[2]);
VectorInverse(dl->axis[1]);
//we don't have any control over the inner cone.
}
}
if (skin >= 16)
R_LoadNumberedLightTexture(dl, skin);
@ -1033,6 +1148,8 @@ qboolean R_ImportRTLights(const char *entlump)
}
}
InfoBuf_Clear(&targets, true);
return okay;
}

View file

@ -2045,6 +2045,7 @@ struct shader_field_names_s shader_unif_names[] =
/**/{"l_lightradius", SP_LIGHTRADIUS}, //radius of the current rtlight
/**/{"l_lightcolour", SP_LIGHTCOLOUR}, //rgb values of the current rtlight
/**/{"l_lightposition", SP_LIGHTPOSITION}, //light position in modelspace
{"l_lightdirection", SP_LIGHTDIRECTION}, //light direction in modelspace (ortho lights only, instead of position)
/**/{"l_lightcolourscale", SP_LIGHTCOLOURSCALE},//ambient/diffuse/specular scalers
/**/{"l_cubematrix", SP_LIGHTCUBEMATRIX},//matrix used to control the rtlight's cubemap projection
/**/{"l_shadowmapproj", SP_LIGHTSHADOWMAPPROJ}, //compacted projection matrix for shadowmaps
@ -2181,167 +2182,6 @@ static void Shader_HLSL11ProgramName (shader_t *shader, shaderpass_t *pass, char
Shader_SLProgramName(shader,pass,ptr,QR_DIRECT3D11);
}
static void Shader_ProgramParam ( shader_t *shader, shaderpass_t *pass, char **ptr )
{
#if 1
Con_DPrintf("shader %s: 'param' no longer supported\n", shader->name);
#elif defined(GLQUAKE)
cvar_t *cv = NULL;
enum shaderprogparmtype_e parmtype = SP_BAD;
char *token;
qboolean silent = false;
char *forcename = NULL;
token = Shader_ParseString(ptr);
if (!Q_stricmp(token, "opt"))
{
silent = true;
token = Shader_ParseString(ptr);
}
if (!Q_stricmp(token, "texture"))
{
token = Shader_ParseString(ptr);
specialint = atoi(token);
parmtype = SP_TEXTURE;
}
else if (!Q_stricmp(token, "consti"))
{
token = Shader_ParseSensString(ptr);
specialint = atoi(token);
parmtype = SP_CONSTI;
}
else if (!Q_stricmp(token, "constf"))
{
token = Shader_ParseSensString(ptr);
specialfloat = atof(token);
parmtype = SP_CONSTF;
}
else if (!Q_stricmp(token, "cvari"))
{
token = Shader_ParseSensString(ptr);
cv = Cvar_Get(token, "", 0, "GLSL Shader parameters");
if (!cv)
return;
parmtype = SP_CVARI;
}
else if (!Q_stricmp(token, "cvarf"))
{
token = Shader_ParseSensString(ptr);
cv = Cvar_Get(token, "", 0, "GLSL Shader parameters");
if (!cv)
return;
parmtype = SP_CVARF;
}
else if (!Q_stricmp(token, "cvar3f"))
{
token = Shader_ParseSensString(ptr);
cv = Cvar_Get(token, "", 0, "GLSL Shader parameters");
if (!cv)
return;
parmtype = SP_CVAR3F;
}
else if (!Q_stricmp(token, "time"))
parmtype = SP_E_TIME;
else if (!Q_stricmp(token, "eyepos"))
parmtype = SP_E_EYEPOS;
else if (!Q_stricmp(token, "entmatrix"))
parmtype = SP_M_MODEL;
else if (!Q_stricmp(token, "colours") || !Q_stricmp(token, "colors"))
parmtype = SP_E_COLOURS;
else if (!Q_stricmp(token, "upper"))
parmtype = SP_E_TOPCOLOURS;
else if (!Q_stricmp(token, "lower"))
parmtype = SP_E_BOTTOMCOLOURS;
else if (!Q_stricmp(token, "lightradius"))
parmtype = SP_LIGHTRADIUS;
else if (!Q_stricmp(token, "lightcolour"))
parmtype = SP_LIGHTCOLOUR;
else if (!Q_stricmp(token, "lightpos"))
parmtype = SP_LIGHTPOSITION;
else if (!Q_stricmp(token, "rendertexturescale"))
parmtype = SP_RENDERTEXTURESCALE;
else
Con_Printf("shader %s: parameter type \"%s\" not known\n", shader->name, token);
if (forcename)
token = forcename;
else
token = Shader_ParseSensString(ptr);
if (qrenderer == QR_OPENGL)
{
int specialint = 0;
float specialfloat = 0;
vec3_t specialvec = {0};
int p;
qboolean foundone;
unsigned int uniformloc;
program_t *prog = shader->prog;
if (!prog)
{
Con_Printf("shader %s: param without program set\n", shader->name);
}
else if (prog->numparams == SHADER_PROGPARMS_MAX)
Con_Printf("shader %s: too many parms\n", shader->name);
else
{
if (prog->refs != 1)
Con_Printf("shader %s: parms on shared shader\n", shader->name);
foundone = false;
prog->parm[prog->numparams].type = parmtype;
for (p = 0; p < PERMUTATIONS; p++)
{
if (!prog->permu[p].handle.glsl.handle)
continue;
GLSlang_UseProgram(prog->permu[p].handle.glsl.handle);
uniformloc = qglGetUniformLocationARB(prog->permu[p].handle.glsl.handle, token);
prog->permu[p].parm[prog->numparams] = uniformloc;
if (uniformloc != -1)
{
foundone = true;
switch(parmtype)
{
case SP_BAD:
foundone = false;
break;
case SP_TEXTURE:
case SP_CONSTI:
prog->parm[prog->numparams].ival = specialint;
break;
case SP_CONSTF:
prog->parm[prog->numparams].fval = specialfloat;
break;
case SP_CVARF:
case SP_CVARI:
prog->parm[prog->numparams].pval = cv;
break;
case SP_CVAR3F:
prog->parm[prog->numparams].pval = cv;
qglUniform3fvARB(uniformloc, 1, specialvec);
break;
default:
break;
}
}
}
if (!foundone)
{
if (!silent)
Con_Printf("shader %s: param \"%s\" not found\n", shader->name, token);
}
else
prog->numparams++;
GLSlang_UseProgram(0);
}
}
#endif
}
static void Shader_ReflectCube(shader_t *shader, shaderpass_t *pass, char **ptr)
{
char *token = Shader_ParseString(ptr);
@ -2662,7 +2502,6 @@ static shaderkey_t shaderkeys[] =
{"glslprogram", Shader_GLSLProgramName, "fte"}, //for renderers that accept embedded glsl
{"hlslprogram", Shader_HLSL9ProgramName, "fte"}, //for d3d with embedded hlsl
{"hlsl11program", Shader_HLSL11ProgramName, "fte"}, //for d3d with embedded hlsl
{"param", Shader_ProgramParam, "fte"}, //legacy
{"progblendfunc", Shader_ProgBlendFunc, "fte"}, //specifies the blend mode (actually just overrides the first subpasses' blendmode.
{"progmap", Shader_ProgMap, "fte"}, //avoids needing extra subpasses (actually just inserts an extra pass).

View file

@ -114,6 +114,7 @@ typedef struct shadowmesh_s
{
SMT_STENCILVOLUME, //build edges mesh (and surface list)
SMT_SHADOWMAP, //build front faces mesh (and surface list)
SMT_ORTHO, //bounded by a box and with a single direction rather than an origin.
SMT_SHADOWLESS, //build vis+surface list only
SMT_DEFERRED //build vis without caring about any surfaces at all.
} type;
@ -216,6 +217,46 @@ static void SHM_MeshFrontOnly(int numverts, vecV_t *verts, int numidx, index_t *
vecV_t *outv;
index_t *outi;
/*make sure there's space*/
v = (sh_shmesh->numverts+numverts + inc)&~(inc-1); //and a bit of padding
if (sh_shmesh->maxverts < v)
{
v *= 2;
v += 1024;
sh_shmesh->maxverts = v;
sh_shmesh->verts = BZ_Realloc(sh_shmesh->verts, v * sizeof(*sh_shmesh->verts));
}
outv = sh_shmesh->verts + sh_shmesh->numverts;
for (v = 0; v < numverts; v++)
{
VectorCopy(verts[v], outv[v]);
}
v = (sh_shmesh->numindicies+numidx + inc)&~(inc-1); //and a bit of padding
if (sh_shmesh->maxindicies < v)
{
v *= 2;
v += 1024;
sh_shmesh->maxindicies = v;
sh_shmesh->indicies = BZ_Realloc(sh_shmesh->indicies, v * sizeof(*sh_shmesh->indicies));
}
outi = sh_shmesh->indicies + sh_shmesh->numindicies;
for (i = 0; i < numidx; i++)
{
outi[i] = first + idx[i];
}
sh_shmesh->numverts += numverts;
sh_shmesh->numindicies += numidx;
}
static void SHM_MeshBackOnly(int numverts, vecV_t *verts, int numidx, index_t *idx)
{
int first = sh_shmesh->numverts;
int v, i;
vecV_t *outv;
index_t *outi;
/*make sure there's space*/
v = (sh_shmesh->numverts+numverts + inc)&~(inc-1); //and a bit of padding
if (sh_shmesh->maxverts < v)
@ -239,9 +280,11 @@ static void SHM_MeshFrontOnly(int numverts, vecV_t *verts, int numidx, index_t *
sh_shmesh->indicies = BZ_Realloc(sh_shmesh->indicies, v * sizeof(*sh_shmesh->indicies));
}
outi = sh_shmesh->indicies + sh_shmesh->numindicies;
for (i = 0; i < numidx; i++)
for (i = 0; i < numidx; i+=3)
{
outi[i] = first + idx[i];
outi[i+0] = first + idx[i+2];
outi[i+1] = first + idx[i+1];
outi[i+2] = first + idx[i+0];
}
sh_shmesh->numverts += numverts;
@ -776,6 +819,129 @@ static void SHM_RecursiveWorldNodeQ1_r (dlight_t *dl, mnode_t *node)
SHM_RecursiveWorldNodeQ1_r (dl, node->children[!side]);
}
void CategorizePlane ( mplane_t *plane );
static void SHM_OrthoWorldLeafsQ1 (dlight_t *dl)
{
int c, i;
msurface_t *surf, **mark;
mleaf_t *pleaf, *plastleaf;
float dot;
mplane_t orthoplanes[5];
sh_shadowframe++;
VectorCopy(dl->axis[0], orthoplanes[0].normal);
VectorNegate(dl->axis[0], orthoplanes[1].normal);
VectorCopy(dl->axis[1], orthoplanes[2].normal);
VectorNegate(dl->axis[1], orthoplanes[3].normal);
VectorNegate(dl->axis[0], orthoplanes[4].normal);
for (i = 0; i < countof(orthoplanes); i++)
{
orthoplanes[i].dist = DotProduct(dl->origin, orthoplanes[i].normal) - dl->radius;
CategorizePlane(&orthoplanes[i]);
}
for (pleaf = cl.worldmodel->leafs+1, plastleaf = cl.worldmodel->leafs+cl.worldmodel->submodels[0].visleafs; pleaf <= plastleaf; pleaf++)
{
for (i = 0; i < countof(orthoplanes); i++)
if (BOX_ON_PLANE_SIDE (pleaf->minmaxs, pleaf->minmaxs+3, &orthoplanes[i]) == 2)
goto next;
SHM_Shadow_Cache_Leaf(pleaf);
mark = pleaf->firstmarksurface;
c = pleaf->nummarksurfaces;
while (c --> 0)
{
surf = *mark++;
if (surf->flags & (SURF_DRAWALPHA | SURF_DRAWTILED | SURF_DRAWSKY))
continue;
if (surf->shadowframe != sh_shadowframe)
{
surf->shadowframe = sh_shadowframe;
dot = DotProduct(surf->plane->normal, dl->axis[0]);
if (surf->flags & SURF_PLANEBACK)
dot = -dot;
if (dot < 0)
{
SHM_Shadow_Cache_Surface(surf);
}
// else
// SHM_MeshBackOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
}
}
next:;
}
}
static void SHM_OrthoWorldLeafsQ3 (dlight_t *dl)
{
int c, i;
msurface_t *surf, **mark;
mleaf_t *pleaf, *plastleaf;
mplane_t orthoplanes[5];
sh_shadowframe++;
VectorCopy(dl->axis[0], orthoplanes[0].normal);
VectorNegate(dl->axis[0], orthoplanes[1].normal);
VectorCopy(dl->axis[1], orthoplanes[2].normal);
VectorNegate(dl->axis[1], orthoplanes[3].normal);
VectorNegate(dl->axis[0], orthoplanes[4].normal);
for (i = 0; i < countof(orthoplanes); i++)
{
orthoplanes[i].dist = DotProduct(dl->origin, orthoplanes[i].normal) - dl->radius;
CategorizePlane(&orthoplanes[i]);
}
for (pleaf = cl.worldmodel->leafs+1, plastleaf = cl.worldmodel->leafs+cl.worldmodel->numleafs; pleaf <= plastleaf; pleaf++)
{
for (i = 0; i < countof(orthoplanes); i++)
if (BOX_ON_PLANE_SIDE (pleaf->minmaxs, pleaf->minmaxs+3, &orthoplanes[i]) == 2)
goto next;
SHM_Shadow_Cache_Leaf(pleaf);
mark = pleaf->firstmarksurface;
c = pleaf->nummarksurfaces;
while (c --> 0)
{
surf = *mark++;
if (surf->flags & (SURF_DRAWALPHA | SURF_DRAWTILED | SURF_DRAWSKY))
continue;
if (surf->shadowframe != sh_shadowframe)
{
surf->shadowframe = sh_shadowframe;
// if (dot < 0)
{
SHM_Shadow_Cache_Surface(surf);
}
// else
// SHM_MeshBackOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes);
}
}
next:;
}
}
#ifdef Q2BSPS
static void SHM_RecursiveWorldNodeQ2_r (dlight_t *dl, mnode_t *node)
{
@ -1407,7 +1573,9 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi
if (!lvis)
{
int clus;
if ((type == SMT_SHADOWLESS || dl->lightcolourscales[0]) && cl.worldmodel->funcs.ClustersInSphere)
if (type == SMT_ORTHO)
;
else if ((type == SMT_SHADOWLESS || dl->lightcolourscales[0]) && cl.worldmodel->funcs.ClustersInSphere)
//shadowless lights don't cast shadows, so they're seen through everything - their vis must reflect that.
lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, dl->origin, dl->radius, &lvisb, NULL);
else
@ -1446,9 +1614,14 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi
{
SHM_BeginShadowMesh(dl, type);
if (type == SMT_ORTHO)
SHM_OrthoWorldLeafsQ1(dl);
else
{
SHM_MarkLeavesQ1(dl, lvis);
SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes);
}
}
break;
#ifdef Q2BSPS
case fg_quake2:
@ -1462,8 +1635,13 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi
/*q3 doesn't have edge info*/
SHM_BeginShadowMesh(dl, type);
if (type == SMT_ORTHO)
SHM_OrthoWorldLeafsQ3(dl);
else
{
sh_shadowframe++;
SHM_RecursiveWorldNodeQ3_r(dl, cl.worldmodel->nodes);
}
if (type == SMT_STENCILVOLUME)
SHM_ComposeVolume_BruteForce(dl);
break;
@ -2146,6 +2324,12 @@ static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowm
R_SetFrustum(proj, r_refdef.m_view);
if (lighttype & LSHADER_ORTHO)
{
r_refdef.frustum_numplanes = 4; //kill the near clip plane - we allow ANYTHING nearer through.
qglEnable(GL_DEPTH_CLAMP_ARB);
}
#ifdef SHADOWDBG_COLOURNOTDEPTH
BE_SelectMode(BEM_STANDARD);
#else
@ -2218,6 +2402,9 @@ static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowm
#endif
}
if (lighttype & LSHADER_ORTHO)
qglDisable(GL_DEPTH_CLAMP_ARB);
/*
{
int i;
@ -2310,7 +2497,7 @@ qboolean Sh_GenShadowMap (dlight_t *l, int lighttype, vec3_t axis[3], qbyte *lvi
memcpy(oprojv, r_refdef.m_projection_view, sizeof(oprojv));
memcpy(oview, r_refdef.m_view, sizeof(oview));
oprect = r_refdef.pxrect;
smesh = SHM_BuildShadowMesh(l, lvis, SMT_SHADOWMAP);
smesh = SHM_BuildShadowMesh(l, lvis, (lighttype & LSHADER_ORTHO)?SMT_ORTHO:SMT_SHADOWMAP);
if (lighttype & LSHADER_SPOT)
Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, l->fov, l->fov, r_shadow_shadowmapping_nearclip.value, l->radius, false);
@ -3708,7 +3895,20 @@ void Sh_DrawLights(qbyte *vis)
axis = dl->axis;
drawdlightnum++;
if (dl->flags & LFLAG_CREPUSCULAR)
if (dl->flags & LFLAG_ORTHO)
{
vec3_t saveorg = {dl->origin[0], dl->origin[1], dl->origin[2]}, neworg;
vec3_t saveaxis[3];
memcpy(saveaxis, dl->axis, sizeof(saveaxis));
memcpy(dl->axis, axis, sizeof(saveaxis));
VectorMA(r_origin, dl->radius/3, vpn, neworg);
VectorCopy(neworg, dl->origin);
dl->rebuildcache = true;
Sh_DrawShadowMapLight(dl, colour, axis, NULL);
VectorCopy(saveorg, dl->origin);
memcpy(dl->axis, saveaxis, sizeof(saveaxis));
}
else if (dl->flags & LFLAG_CREPUSCULAR)
Sh_DrawCrepuscularLight(dl, colour);
else if (((i >= RTL_FIRST)?!r_shadow_realtime_world_shadows.ival:!r_shadow_realtime_dlight_shadows.ival) || dl->flags & LFLAG_NOSHADOWS)
{

View file

@ -1473,6 +1473,7 @@ static const char *glsl_hdrs[] =
"uniform float l_lightradius;"
"uniform vec3 l_lightcolour;"
"uniform vec3 l_lightposition;"
"uniform vec3 l_lightdirection;"
"uniform vec3 l_lightcolourscale;"
"uniform mat4 l_cubematrix;"
"uniform vec4 l_shadowmapproj;"
@ -1776,7 +1777,7 @@ static const char *glsl_hdrs[] =
"return ((cubeproj.yxz-vec3(0.0,0.0,0.015))/cubeproj.w + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n"
"#elif defined(ORTHO)\n"
//the light's origin is in the center of the 'cube', projecting from one side to the other, so don't bias the z.
"return ((cubeproj.xyz-vec3(0.0,0.0,0.015))/cubeproj.w + vec3(1.0, 1.0, 0.0)) * vec3(0.5, 0.5, 1.0);\n"
"return ((cubeproj.xyz-vec3(0.0,0.0,0.015))/cubeproj.w + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n"
//"#elif defined(CUBESHADOW)\n"
// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w;
// #define dosamp(x,y) shadowCube(s_t4, shadowcoord + vec2(x,y)*texscale.xy).r

View file

@ -1169,7 +1169,6 @@ void GLVID_SetCaption(const char *text)
SetWindowTextW(mainwindow, wide);
}
static qboolean VID_SetFullDIBMode (rendererstate_t *info)
{
int i;
@ -1265,6 +1264,21 @@ static qboolean VID_SetFullDIBMode (rendererstate_t *info)
if (!dibwindow)
Sys_Error ("Couldn't create DIB window");
{
BOOL fDisable = TRUE;
DWORD qDWMWA_TRANSITIONS_FORCEDISABLED = 3;
HRESULT (WINAPI *pDwmSetWindowAttribute)(HWND hWnd,DWORD dwAttribute,LPCVOID pvAttribute,DWORD cbAttribute);
dllfunction_t dwm[] =
{
{(void*)&pDwmSetWindowAttribute, "DwmSetWindowAttribute"},
{NULL,NULL}
};
if (Sys_LoadLibrary("dwmapi.dll", dwm))
{
pDwmSetWindowAttribute(dibwindow, qDWMWA_TRANSITIONS_FORCEDISABLED, &fDisable, sizeof(fDisable));
}
}
SendMessage (dibwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon);
SendMessage (dibwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon);
@ -2874,7 +2888,7 @@ static LONG WINAPI GLMainWndProc (
GLAppActivate(FALSE, Minimized);//FIXME: thread
ClearAllStates (); //FIXME: thread
#endif
if (modestate == MS_FULLDIB)
if (modestate != MS_WINDOWED)
ShowWindow(mainwindow, SW_SHOWMINNOACTIVE);
break;
case WM_SETFOCUS:

View file

@ -900,6 +900,7 @@ void R_InitSky (shader_t *shader, const char *skyname, qbyte *src, unsigned int
//try to load dual-layer-single-image skies.
//this is always going to be lame special case crap
if (gl_load24bit.ival)
{
size_t filesize = 0;
qbyte *filedata = NULL;

View file

@ -7179,7 +7179,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_OPENGL, 110, "defaultwarp",
"!!permu FOG\n"
"!!cvarf r_wateralpha\n"
"!!samps diffuse\n"
"!!samps diffuse lightmap\n"
"#include \"sys/defs.h\"\n"
@ -7188,6 +7188,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#include \"sys/fog.h\"\n"
"varying vec2 tc;\n"
"#ifdef LIT\n"
"varying vec2 lm0;\n"
"#endif\n"
"#ifdef VERTEX_SHADER\n"
"void main ()\n"
"{\n"
@ -7195,6 +7198,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#ifdef FLOW\n"
"tc.s += e_time * -0.5;\n"
"#endif\n"
"#ifdef LIT\n"
"lm0 = v_lmcoord;\n"
"#endif\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
@ -7211,6 +7217,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"ntc.s = tc.s + sin(tc.t+e_time)*0.125;\n"
"ntc.t = tc.t + sin(tc.s+e_time)*0.125;\n"
"vec3 ts = vec3(texture2D(s_diffuse, ntc));\n"
"#ifdef LIT\n"
"ts *= (texture2D(s_lightmap, lm0) * e_lmscale).rgb;\n"
"#endif\n"
"gl_FragColor = fog4(vec4(ts, USEALPHA));\n"
"}\n"
"#endif\n"
@ -11356,7 +11367,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#ifdef REFLECTCUBEMASK\n"
"varying mat3 invsurface;\n"
"#endif\n"
"#if defined(PCF) || defined(CUBE) || defined(SPOT)\n"
"#if defined(PCF) || defined(CUBE) || defined(SPOT) || defined(ORTHO)\n"
"varying vec4 vtexprojcoord;\n"
"#endif\n"
"#endif\n"
@ -11372,6 +11383,12 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"vec3 n, s, t, w;\n"
"gl_Position = skeletaltransform_wnst(w,n,s,t);\n"
"tcbase = v_texcoord; //pass the texture coords straight through\n"
"#ifdef ORTHO\n"
"vec3 lightminusvertex = -l_lightdirection;\n"
"lightvector.x = dot(lightminusvertex, s.xyz);\n"
"lightvector.y = dot(lightminusvertex, t.xyz);\n"
"lightvector.z = dot(lightminusvertex, n.xyz);\n"
"#else\n"
"vec3 lightminusvertex = l_lightposition - w.xyz;\n"
"#ifdef NOBUMP\n"
//the only important thing is distance
@ -11382,6 +11399,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"lightvector.y = dot(lightminusvertex, t.xyz);\n"
"lightvector.z = dot(lightminusvertex, n.xyz);\n"
"#endif\n"
"#endif\n"
"#if defined(VERTEXCOLOURS)\n"
"vc = v_colour;\n"
"#endif\n"
@ -11396,7 +11414,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"invsurface[1] = v_tvector;\n"
"invsurface[2] = v_normal;\n"
"#endif\n"
"#if defined(PCF) || defined(SPOT) || defined(CUBE)\n"
"#if defined(PCF) || defined(SPOT) || defined(CUBE) || defined(ORTHO)\n"
//for texture projections/shadowmapping on dlights
"vtexprojcoord = (l_cubematrix*vec4(w.xyz, 1.0));\n"
"#endif\n"
@ -11488,7 +11506,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"vec3 t2 = w - dot(w-t_vertex[2],t_normal[2])*t_normal[2];\n"
"w = w*(1.0-factor) + factor*(gl_TessCoord.x*t0+gl_TessCoord.y*t1+gl_TessCoord.z*t2);\n"
"#if defined(PCF) || defined(SPOT) || defined(CUBE)\n"
"#if defined(PCF) || defined(SPOT) || defined(CUBE) || defined(ORTHO)\n"
//for texture projections/shadowmapping on dlights
"vtexprojcoord = (l_cubematrix*vec4(w.xyz, 1.0));\n"
"#endif\n"
@ -11613,8 +11631,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"diff *= vc.rgb * vc.a;\n"
"#endif\n"
"gl_FragColor.rgb = fog3additive(diff*colorscale*l_lightcolour);\n"
"gl_FragColor = vec4(fog3additive(diff*colorscale*l_lightcolour), 1.0);\n"
"}\n"
"#endif\n"

View file

@ -455,6 +455,7 @@ typedef struct {
SP_LIGHTCOLOUR,
SP_LIGHTCOLOURSCALE,
SP_LIGHTPOSITION,
SP_LIGHTDIRECTION,
SP_LIGHTSCREEN,
SP_LIGHTCUBEMATRIX,
SP_LIGHTSHADOWMAPPROJ,
@ -490,10 +491,10 @@ typedef struct programshared_s
#ifdef VKQUAKE
unsigned char *cvardata;
unsigned int cvardatasize;
VkRetardedShaderModule vert; //for slightly faster regeneration
VkRetardedShaderModule frag;
VkRetardedPipelineLayout layout; //all permutations share the same layout. I'm too lazy not to.
VkRetardedDescriptorSetLayout desclayout;
qVkShaderModule vert; //for slightly faster regeneration
qVkShaderModule frag;
qVkPipelineLayout layout; //all permutations share the same layout. I'm too lazy not to.
qVkDescriptorSetLayout desclayout;
struct pipeline_s *pipelines;
#endif
#if defined(GLQUAKE) || defined(D3DQUAKE)

View file

@ -9882,7 +9882,13 @@ static void QCBUILTIN PF_SendPacket(pubprogfuncs_t *prinst, struct globalvars_s
const char *contents = PF_VarString(prinst, 1, pr_globals);
if (NET_StringToAdr(address, 0, &to))
NET_SendPacket(NS_SERVER, strlen(contents), contents, &to);
{
char *send = Z_Malloc(4+strlen(contents));
send[0] = send[1] = send[2] = send[3] = 0xff;
memcpy(send+4, contents, strlen(contents));
G_FLOAT(OFS_RETURN) = NET_SendPacket(NS_SERVER, 4+strlen(contents), send, &to);
Z_Free(send);
}
}
//be careful to not touch the resource unless we're meant to, to avoid stalling
@ -10475,7 +10481,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"checkpvs", PF_checkpvs, 0, 0, 0, 240, "float(vector viewpos, entity entity)"},
{"matchclientname", PF_matchclient, 0, 0, 0, 241, "entity(string match, optional float matchnum)"},
{"sendpacket", PF_SendPacket, 0, 0, 0, 242, "void(string destaddress, string content)"},// (FTE_QC_SENDPACKET)
{"sendpacket", PF_SendPacket, 0, 0, 0, 242, D("void(string destaddress, string content)", "Sends a UDP packet to the specified destination. Note that the payload will be prefixed with four 255 bytes as a sort of security feature.")},// (FTE_QC_SENDPACKET)
// {"bulleten", PF_bulleten, 0, 0, 0, 243}, (removed builtin)
@ -11976,11 +11982,13 @@ void PR_DumpPlatform_f(void)
{"MULTICAST_ALL", "const float", QW|NQ, D("The multicast message is unreliably sent to all players. MULTICAST_ constants are valid arguments for the multicast builtin, which ignores the specified origin when given this constant."), MULTICAST_ALL},
{"MULTICAST_PHS", "const float", QW|NQ, D("The multicast message is unreliably sent to only players that can potentially hear the specified origin. Its quite loose."), MULTICAST_PHS},
{"MULTICAST_PVS", "const float", QW|NQ, D("The multicast message is unreliably sent to only players that can potentially see the specified origin."), MULTICAST_PVS},
{"MULTICAST_ONE", "const float", QW|NQ, D("The multicast message is unreliably sent to the player specified in the msg_entity global. The specified origin is ignored."), MULTICAST_ONE},
{"MULTICAST_ONE", "const float", QW|NQ, D("The multicast message is unreliably sent to the player (AND ALL TRACKING SPECTATORS) specified in the msg_entity global. The specified origin is ignored."), MULTICAST_ONE_SPECS},
{"MULTICAST_ONE_NOSPECS","const float", QW|NQ, D("The multicast message is unreliably sent to the player specified in the msg_entity global. The specified origin is ignored."), MULTICAST_ONE_NOSPECS},
{"MULTICAST_ALL_R", "const float", QW|NQ, D("The multicast message is reliably sent to all players. The specified origin is ignored."), MULTICAST_ALL_R},
{"MULTICAST_PHS_R", "const float", QW|NQ, D("The multicast message is reliably sent to only players that can potentially hear the specified origin. Players might still not receive it if they are out of range."), MULTICAST_PHS_R},
{"MULTICAST_PVS_R", "const float", QW|NQ, D("The multicast message is reliably sent to only players that can potentially see the specified origin. Players might still not receive it if they cannot see the event."), MULTICAST_PVS_R},
{"MULTICAST_ONE_R", "const float", QW|NQ, D("The multicast message is reliably sent to the player specified in the msg_entity global. The specified origin is ignored"), MULTICAST_ONE_R},
{"MULTICAST_ONE_R", "const float", QW|NQ, D("The multicast message is reliably sent to the player (AND ALL TRACKING SPECTATORS) specified in the msg_entity global. The specified origin is ignored"), MULTICAST_ONE_R_SPECS},
{"MULTICAST_ONE_R_NOSPECS","const float", QW|NQ, D("The multicast message is reliably sent to the player specified in the msg_entity global. The specified origin is ignored"), MULTICAST_ONE_R_NOSPECS},
{"PRINT_LOW", "const float", QW, NULL, PRINT_LOW},
{"PRINT_MEDIUM", "const float", QW, NULL, PRINT_MEDIUM},
@ -12091,7 +12099,7 @@ void PR_DumpPlatform_f(void)
{"EF_FLAG1", "const float", QW , NULL, QWEF_FLAG1},
{"EF_FLAG2", "const float", QW , NULL, QWEF_FLAG2},
{"EF_NODRAW", "const float", NQ|CS, NULL, NQEF_NODRAW},
{"EF_ADDITIVE", "const float", NQ|CS, D("The entity will be drawn with an additive blend."), NQEF_ADDITIVE},
{"EF_ADDITIVE", "const float", QW|NQ|CS, D("The entity will be drawn with an additive blend. This is NOT supported on players in any quakeworld engine."), NQEF_ADDITIVE},
{"EF_BLUE", "const float", QW|NQ|CS, D("A blue glow"), EF_BLUE},
{"EF_RED", "const float", QW|NQ|CS, D("A red glow"), EF_RED},
{"EF_GREEN", "const float", QW|NQ|CS, D("A green glow"), EF_GREEN},

View file

@ -448,7 +448,7 @@ typedef struct
qboolean isoffset:1;
int orientpeer;
//ode info
//physics engine info
int geomshape;
float relmatrix[12];
float inverserelmatrix[12];
@ -503,43 +503,32 @@ typedef struct rbecommandqueue_s
typedef struct
{
// physics parameters
qboolean ode_physics;
void *ode_body;
void *ode_geom;
void *ode_joint;
float *ode_vertex3f;
int *ode_element3i;
int ode_numvertices;
int ode_numtriangles;
vec3_t ode_mins;
vec3_t ode_maxs;
vec_t ode_mass;
vec3_t ode_origin;
vec3_t ode_velocity;
vec3_t ode_angles;
vec3_t ode_avelocity;
qboolean ode_gravity;
int ode_modelindex;
vec_t ode_movelimit; // smallest component of (maxs[]-mins[])
float ode_offsetmatrix[16];
float ode_offsetimatrix[16];
int ode_joint_type;
int ode_joint_enemy;
int ode_joint_aiment;
vec3_t ode_joint_origin; // joint anchor
vec3_t ode_joint_angles; // joint axis
vec3_t ode_joint_velocity; // second joint axis
vec3_t ode_joint_movedir; // parameters
void *ode_massbuf;
} entityode_t;
/*
typedef struct
{
void *ode_body;
} skelbodyode_t;
typedef struct
{
int dummy;
} skeljointode_t;
*/
qboolean physics;
rbebody_t body;
rbejoint_t joint;
float *vertex3f;
int *element3i;
int numvertices;
int numtriangles;
vec3_t mins;
vec3_t maxs;
vec_t mass;
vec3_t origin;
vec3_t velocity;
vec3_t angles;
vec3_t avelocity;
qboolean gravity;
int modelindex;
vec_t movelimit; // smallest component of (maxs[]-mins[])
float offsetmatrix[16];
float offsetimatrix[16];
int joint_type;
int joint_enemy;
int joint_aiment;
vec3_t joint_origin; // joint anchor
vec3_t joint_angles; // joint axis
vec3_t joint_velocity; // second joint axis
vec3_t joint_movedir; // parameters
void *massbuf;
} entityrbe_t;
#endif

View file

@ -85,7 +85,7 @@ typedef struct edict_s
int lastruntime;
int solidsize;
#ifdef USERBE
entityode_t ode;
entityrbe_t rbe;
#endif
/*csqc doesn't reference the rest*/

View file

@ -29,9 +29,11 @@ typedef enum multicast_e
MULTICAST_PHS_R,
MULTICAST_PVS_R,
MULTICAST_ONE,
MULTICAST_ONE_R,
MULTICAST_INIT
MULTICAST_ONE_SPECS,
MULTICAST_ONE_R_SPECS,
MULTICAST_INIT,
MULTICAST_ONE_NOSPECS,
MULTICAST_ONE_R_NOSPECS,
} multicast_t;
extern float pm_q2stepheight;

View file

@ -1326,6 +1326,9 @@ qboolean SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizeb
qbyte *oldbonedata;
unsigned int maxbonedatasize;
qboolean overflow = false;
client_t *cl;
float age;
client_frame_t *frame;
if (!client->pendingdeltabits)
return false;
@ -1470,11 +1473,12 @@ qboolean SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizeb
sequence = client->netchan.outgoing_unreliable;
else
sequence = client->netchan.incoming_sequence;
frame = &client->frameunion.frames[sequence & UPDATE_MASK];
/*cache frame info*/
resend = client->frameunion.frames[sequence & UPDATE_MASK].resend;
resend = frame->resend;
outno = 0;
outmax = client->frameunion.frames[sequence & UPDATE_MASK].maxresend;
outmax = frame->maxresend;
/*start writing the packet*/
MSG_WriteByte (msg, svcfte_updateentities);
@ -1557,8 +1561,32 @@ qboolean SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizeb
else
client->nextdeltaindex = j; //we overflowed or something, start going round-robin
client->frameunion.frames[sequence & UPDATE_MASK].numresend = outno;
client->frameunion.frames[sequence & UPDATE_MASK].sequence = sequence;
frame->numresend = outno;
frame->sequence = sequence;
for (i = 0; i < to->num_entities; i++)
{
n = &to->entities[i];
j = n->number-1;
if (j >= sv.allocated_client_slots)
break; //don't track non-player slots.
cl = &svs.clients[j];
//states of other players are actually old.
//by the time we receive the other player's move, this stuff will be outdated and we don't know when that will actually be.
//so (cheaply) guess where they're really meant to be if they're running at a lower framerate.
if (!cl->name[0] || cl->protocol == SCP_BAD) //is bot
age = 0;//= sv.time - sv.world.physicstime; //FIXME
else
age = sv.time - sv.world.physicstime;
age = bound(0, age, 0.1);
VectorMA(n->origin, (sv.time - cl->localtime)/8.0, n->u.q1.velocity, frame->playerpositions[j]);
//FIXME: add framestate_t info.
frame->playerpresent[j] = true;
}
return overflow;
}

View file

@ -5127,6 +5127,9 @@ void SV_InitLocal (void)
Cvar_Register (&sv_resetparms, cvargroup_servercontrol);
if (isDedicated)
sv_public.string = "1";
Cvar_Register (&sv_guidhash, cvargroup_servercontrol);
Cvar_Register (&sv_serverip, cvargroup_servercontrol);
Cvar_Register (&sv_public, cvargroup_servercontrol);
@ -5144,11 +5147,6 @@ void SV_InitLocal (void)
Cvar_Register (&sv_reportheartbeats, cvargroup_servercontrol);
#ifndef SERVERONLY
if (isDedicated)
#endif
Cvar_Set(&sv_public, "1");
Cvar_Register (&sv_showconnectionlessmessages, cvargroup_servercontrol);
Cvar_Register (&sv_banproxies, cvargroup_serverpermissions);
#ifdef SV_MASTER

View file

@ -1082,6 +1082,8 @@ void Route_Calculate(void *ctx, void *data, size_t a, size_t b)
COM_AddWork(WG_MAIN, Route_Calculated, NULL, route, 0, 0);
}
//void route_linkitem(entity item, int ittype) //-1 to unlink
//void route_choosedest(entity ent, int numitemtypes, float *itemweights)
/*
=============
PF_route_calculate
@ -1093,6 +1095,7 @@ the first node in the nodelist is the destination.
typedef struct {
vector dest;
int linkflags;
//float anglehint;
} nodeslist_t;
void(entity ent, vector dest, int denylinkflags, void(entity ent, vector dest, int numnodes, nodeslist_t *nodelist) callback) route_calculate = #0;
=============

View file

@ -706,6 +706,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
qboolean reliable;
client_t *oneclient = NULL, *split;
int seat;
qboolean andspecs = false;
if (!sv.multicast.cursize
#ifdef NQPROT
@ -790,9 +791,11 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
mask = CM_ClusterPVS (sv.world.worldmodel, cluster, NULL, PVM_FAST);
break;
case MULTICAST_ONE_R:
case MULTICAST_ONE_R_NOSPECS:
case MULTICAST_ONE_R_SPECS:
reliable = true;
case MULTICAST_ONE:
case MULTICAST_ONE_NOSPECS:
case MULTICAST_ONE_SPECS:
if (svprogfuncs)
{
edict_t *ent = PROG_TO_EDICT(svprogfuncs, pr_global_struct->msg_entity);
@ -801,6 +804,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
else
oneclient = NULL; //unsupported in this game mode
mask = NULL;
andspecs = (to==MULTICAST_ONE_R_SPECS||to==MULTICAST_ONE_SPECS);
break;
default:
@ -838,7 +842,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
{
if (oneclient != split)
{
if (split->spectator && split->spec_track >= 0 && oneclient == &svs.clients[split->spec_track])
if (andspecs && split->spectator && split->spec_track >= 0 && oneclient == &svs.clients[split->spec_track])
;
else
continue;
@ -975,9 +979,11 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
mask = NULL;
break;
case MULTICAST_ONE_R:
case MULTICAST_ONE_R_NOSPECS:
case MULTICAST_ONE_R_SPECS:
reliable = true;
case MULTICAST_ONE:
case MULTICAST_ONE_NOSPECS:
case MULTICAST_ONE_SPECS:
if (svprogfuncs)
{
edict_t *ent = PROG_TO_EDICT(svprogfuncs, pr_global_struct->msg_entity);
@ -986,6 +992,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
else
oneclient = NULL;
mask = NULL;
andspecs = (to==MULTICAST_ONE_R_SPECS||to==MULTICAST_ONE_SPECS);
break;
default:
@ -1150,9 +1157,15 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
msg = &demo.datagram;
break;
case MULTICAST_ONE_R_NOSPECS:
case MULTICAST_ONE_NOSPECS:
msg = &demo.datagram;
sv.multicast.cursize = 0;
break;
//mvds are all reliables really.
case MULTICAST_ONE_R:
case MULTICAST_ONE:
case MULTICAST_ONE_R_SPECS:
case MULTICAST_ONE_SPECS:
{
int pnum;
if (svprogfuncs)
@ -1190,6 +1203,7 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*ca
int cluster;
int j;
client_t *oneclient = NULL, *split;
qboolean andspecs = false;
switch (to)
{
@ -1224,9 +1238,12 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*ca
mask = NULL;
break;
case MULTICAST_ONE_R:
case MULTICAST_ONE_R_NOSPECS:
case MULTICAST_ONE_R_SPECS:
reliable = true;
case MULTICAST_ONE:
case MULTICAST_ONE_NOSPECS:
case MULTICAST_ONE_SPECS:
if (svprogfuncs)
{
edict_t *ent = PROG_TO_EDICT(svprogfuncs, pr_global_struct->msg_entity);
@ -1235,6 +1252,7 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*ca
else
oneclient = NULL;
mask = NULL;
andspecs = (to == MULTICAST_ONE_R_SPECS || to == MULTICAST_ONE_SPECS);
break;
default:
@ -1262,7 +1280,7 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*ca
{
if (oneclient != split)
{
if (split->spectator && split->spec_track >= 0 && oneclient == &svs.clients[split->spec_track])
if (andspecs && split->spectator && split->spec_track >= 0 && oneclient == &svs.clients[split->spec_track])
;
else
continue;
@ -1340,9 +1358,13 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*ca
msg = &demo.datagram;
break;
case MULTICAST_ONE_R_NOSPECS:
case MULTICAST_ONE_NOSPECS:
return; //demos count as spectators.
//mvds are all reliables really.
case MULTICAST_ONE_R:
case MULTICAST_ONE:
case MULTICAST_ONE_R_SPECS:
case MULTICAST_ONE_SPECS:
{
int pnum = -1;
if (svprogfuncs)
@ -1589,7 +1611,7 @@ void SV_StartSound (int ent, vec3_t origin, float *velocity, int seenmask, int c
if (chflags & CF_UNICAST)
{
SV_MulticastCB(origin, reliable ? MULTICAST_ONE_R : MULTICAST_ONE, seenmask, SV_SoundMulticast, &ctx);
SV_MulticastCB(origin, reliable ? MULTICAST_ONE_R_SPECS : MULTICAST_ONE_SPECS, seenmask, SV_SoundMulticast, &ctx);
}
else
{
@ -1880,13 +1902,10 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
if (client->fteprotocolextensions2 & PEXT2_PREDINFO)
return;
#ifdef NQPROT
if (client->protocol == SCP_DARKPLACES6 || client->protocol == SCP_DARKPLACES7)
nqjunk = false;
else
nqjunk = true;
#endif
bits = 0;
@ -2973,7 +2992,7 @@ static qboolean SV_SyncInfoBuf(client_t *client)
{ //vanilla-compatible info.
if (ISNQCLIENT(client))
{ //except that nq never had any userinfo
const char *s = va("//ui %i \"%s\" \"%s\"\n", (client_t*)info-svs.clients, enckey, encval);
const char *s = va("//ui %i \"%s\" \"%s\"\n", (int)((client_t*)info-svs.clients), enckey, encval);
ClientReliableWrite_Begin(client, svc_stufftext, strlen(s)+2);
ClientReliableWrite_String(client, s);
}

View file

@ -219,7 +219,8 @@ void Sys_Error (const char *error, ...)
exit (1);
}
int ansiremap[8] = {0, 4, 2, 6, 1, 5, 3, 7};
static qboolean useansicolours;
static int ansiremap[8] = {0, 4, 2, 6, 1, 5, 3, 7};
void ApplyColour(unsigned int chr)
{
static int oldchar = CON_WHITEMASK;
@ -229,6 +230,8 @@ void ApplyColour(unsigned int chr)
if (oldchar == chr)
return;
oldchar = chr;
if (!useansicolours) //don't spew weird chars when redirected to a file.
return;
printf("\e[0;"); // reset
@ -713,6 +716,9 @@ static void Friendly_Crash_Handler(int sig, siginfo_t *info, void *vcontext)
#ifdef HAVE_GNUTLS
qboolean SSL_InitGlobal(qboolean isserver);
#endif
#ifdef SQL
#include "sv_sql.h"
#endif
static int Sys_CheckChRoot(void)
{ //also warns if run as root.
int ret = false;
@ -720,7 +726,7 @@ static int Sys_CheckChRoot(void)
//three ways to use this:
//nonroot-with-SUID-root -- chroots+drops to a fixed path when run as a regular user. the homedir mechanism can be used for writing files.
//root -chroot foo -uid bar -- requires root, changes the filesystem and then switches user rights before starting the game itself.
//root -chroot foo -- requires root,changes the filesystem and
//root -chroot foo -- requires root, changes the filesystem and leaves the process with far far too many rights
uid_t ruid, euid, suid;
int arg = COM_CheckParm("-chroot");
@ -735,18 +741,18 @@ static int Sys_CheckChRoot(void)
//this means we can't allow
//FIXME other games. should use the list in fs.c
if (COM_CheckParm("-quake"))
newroot = "/usr/share/quake";
newroot = "/usr/share/games/quake";
else if (COM_CheckParm("-quake2"))
newroot = "/usr/share/quake2";
newroot = "/usr/share/games/quake2";
else if (COM_CheckParm("-quake3"))
newroot = "/usr/share/quake3";
newroot = "/usr/share/games/quake3";
else if (COM_CheckParm("-hexen2") || COM_CheckParm("-portals"))
newroot = "/usr/share/hexen2";
newroot = "/usr/share/games/hexen2";
else
#ifdef GAME_SHORTNAME
newroot = "/usr/share/" GAME_SHORTNAME;
newroot = "/usr/share/games/" GAME_SHORTNAME;
#else
newroot = "/usr/share/quake";
newroot = "/usr/share/games/quake";
#endif
//just read the environment name
@ -765,11 +771,19 @@ static int Sys_CheckChRoot(void)
//make sure there's no suid programs in the new root dir that might get confused by /etc/ being something else.
//this binary MUST NOT be inside the new root.
//make sure we don't crash on any con_printfs.
#ifdef MULTITHREAD
Sys_ThreadsInit();
#endif
//FIXME: should we temporarily try swapping uid+euid so we don't have any more access than a non-suid binary for this initial init stuff?
struct addrinfo *info;
if (getaddrinfo("localhost", NULL, NULL, &info) == 0) //make sure we've loaded /etc/resolv.conf etc, otherwise any dns requests are going to fail.
if (getaddrinfo("master.quakeservers.net", NULL, NULL, &info) == 0) //make sure we've loaded /etc/resolv.conf etc, otherwise any dns requests are going to fail, which would mean no masters.
freeaddrinfo(info);
#ifdef SQL
SQL_Available();
#endif
#ifdef HAVE_GNUTLS
SSL_InitGlobal(false); //we need to load the known CA certs while we still can, as well as any shared objects
//SSL_InitGlobal(true); //make sure we load our public cert from outside the sandbox. an exploit might still be able to find it in memory though. FIXME: disabled in case this reads from somewhere bad - we're still root.
@ -864,6 +878,12 @@ int main(int argc, char *argv[])
parms.manifest = CONFIG_MANIFEST_TEXT;
#endif
//decide if we should be printing colours to the stdout or not.
if (!COM_CheckParm("-nocolour")||!COM_CheckParm("-nocolor"))
useansicolours = false;
else
useansicolours = (isatty(STDOUT_FILENO) || !COM_CheckParm("-colour")||!COM_CheckParm("-color"));
switch(Sys_CheckChRoot())
{
case true:

View file

@ -584,6 +584,16 @@ void QDECL World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers)
VectorAdd (ent->v->origin, ent->v->maxs, ent->v->absmax);
}
//some fancy things can mean the ent's aabb is larger than its collision box.
#ifdef USERBE
// if (ent->rbe.body.body)
// w->rbe->ExpandBodyAABB(w->rbe, &ent->rbe.body, ent->v->absmin, env->v->absmax);
#endif
#ifdef SKELETALOBJECTS
if (ent->xv->skeletonindex)
skel_updateentbounds(ent);
#endif
if (!ent->v->solid)
ent->solidsize = ES_SOLID_BSP;
else// if (1)///*ent->v->modelindex || */ent->v->model)
@ -2793,10 +2803,10 @@ static qboolean GenerateCollisionMesh_BSP(world_t *world, model_t *mod, wedict_t
}
}
ed->ode.ode_element3i = ptr_elements;
ed->ode.ode_vertex3f = ptr_verts;
ed->ode.ode_numvertices = numverts;
ed->ode.ode_numtriangles = numindexes/3;
ed->rbe.element3i = ptr_elements;
ed->rbe.vertex3f = ptr_verts;
ed->rbe.numvertices = numverts;
ed->rbe.numtriangles = numindexes/3;
return true;
}
@ -2859,10 +2869,10 @@ static qboolean GenerateCollisionMesh_Alias(world_t *world, model_t *mod, wedict
Alias_FlushCache(); //it got built using an entity on the stack, make sure other stuff doesn't get hurt.
ed->ode.ode_element3i = ptr_elements;
ed->ode.ode_vertex3f = ptr_verts;
ed->ode.ode_numvertices = numverts;
ed->ode.ode_numtriangles = numindexes/3;
ed->rbe.element3i = ptr_elements;
ed->rbe.vertex3f = ptr_verts;
ed->rbe.numvertices = numverts;
ed->rbe.numtriangles = numindexes/3;
return true;
}
@ -2872,22 +2882,22 @@ static void CollisionMesh_CleanupMesh(wedict_t *ed)
float *v1, *v2, *v3;
vec3_t d1, d2, cr;
int in, out;
for (in = 0, out = 0; in < ed->ode.ode_numtriangles*3; in+=3)
for (in = 0, out = 0; in < ed->rbe.numtriangles*3; in+=3)
{
v1 = &ed->ode.ode_vertex3f[ed->ode.ode_element3i[in+0]*3];
v2 = &ed->ode.ode_vertex3f[ed->ode.ode_element3i[in+1]*3];
v3 = &ed->ode.ode_vertex3f[ed->ode.ode_element3i[in+2]*3];
v1 = &ed->rbe.vertex3f[ed->rbe.element3i[in+0]*3];
v2 = &ed->rbe.vertex3f[ed->rbe.element3i[in+1]*3];
v3 = &ed->rbe.vertex3f[ed->rbe.element3i[in+2]*3];
VectorSubtract(v3, v1, d1);
VectorSubtract(v2, v1, d2);
CrossProduct(d1, d2, cr);
if (DotProduct(cr,cr) == 0)
continue;
ed->ode.ode_element3i[out+0] = ed->ode.ode_element3i[in+0];
ed->ode.ode_element3i[out+1] = ed->ode.ode_element3i[in+1];
ed->ode.ode_element3i[out+2] = ed->ode.ode_element3i[in+2];
ed->rbe.element3i[out+0] = ed->rbe.element3i[in+0];
ed->rbe.element3i[out+1] = ed->rbe.element3i[in+1];
ed->rbe.element3i[out+2] = ed->rbe.element3i[in+2];
out+=3;
}
ed->ode.ode_numtriangles = out/3;
ed->rbe.numtriangles = out/3;
}
qboolean QDECL World_GenerateCollisionMesh(world_t *world, model_t *mod, wedict_t *ed, vec3_t geomcenter)
@ -2912,19 +2922,19 @@ qboolean QDECL World_GenerateCollisionMesh(world_t *world, model_t *mod, wedict_
if (result)
{
CollisionMesh_CleanupMesh(ed);
if (ed->ode.ode_numtriangles > 0)
if (ed->rbe.numtriangles > 0)
return true;
}
return false;
}
void QDECL World_ReleaseCollisionMesh(wedict_t *ed)
{
BZ_Free(ed->ode.ode_element3i);
ed->ode.ode_element3i = NULL;
BZ_Free(ed->ode.ode_vertex3f);
ed->ode.ode_vertex3f = NULL;
ed->ode.ode_numvertices = 0;
ed->ode.ode_numtriangles = 0;
BZ_Free(ed->rbe.element3i);
ed->rbe.element3i = NULL;
BZ_Free(ed->rbe.vertex3f);
ed->rbe.vertex3f = NULL;
ed->rbe.numvertices = 0;
ed->rbe.numtriangles = 0;
}
#endif
#endif

View file

@ -1,6 +1,6 @@
!!permu FOG
!!cvarf r_wateralpha
!!samps diffuse
!!samps diffuse lightmap
#include "sys/defs.h"
@ -9,6 +9,9 @@
#include "sys/fog.h"
varying vec2 tc;
#ifdef LIT
varying vec2 lm0;
#endif
#ifdef VERTEX_SHADER
void main ()
{
@ -16,6 +19,9 @@ void main ()
#ifdef FLOW
tc.s += e_time * -0.5;
#endif
#ifdef LIT
lm0 = v_lmcoord;
#endif
gl_Position = ftetransform();
}
#endif
@ -32,6 +38,11 @@ void main ()
ntc.s = tc.s + sin(tc.t+e_time)*0.125;
ntc.t = tc.t + sin(tc.s+e_time)*0.125;
vec3 ts = vec3(texture2D(s_diffuse, ntc));
#ifdef LIT
ts *= (texture2D(s_lightmap, lm0) * e_lmscale).rgb;
#endif
gl_FragColor = fog4(vec4(ts, USEALPHA));
}
#endif

View file

@ -52,7 +52,7 @@
#ifdef REFLECTCUBEMASK
varying mat3 invsurface;
#endif
#if defined(PCF) || defined(CUBE) || defined(SPOT)
#if defined(PCF) || defined(CUBE) || defined(SPOT) || defined(ORTHO)
varying vec4 vtexprojcoord;
#endif
#endif
@ -68,15 +68,22 @@ void main ()
vec3 n, s, t, w;
gl_Position = skeletaltransform_wnst(w,n,s,t);
tcbase = v_texcoord; //pass the texture coords straight through
#ifdef ORTHO
vec3 lightminusvertex = -l_lightdirection;
lightvector.x = dot(lightminusvertex, s.xyz);
lightvector.y = dot(lightminusvertex, t.xyz);
lightvector.z = dot(lightminusvertex, n.xyz);
#else
vec3 lightminusvertex = l_lightposition - w.xyz;
#ifdef NOBUMP
#ifdef NOBUMP
//the only important thing is distance
lightvector = lightminusvertex;
#else
#else
//the light direction relative to the surface normal, for bumpmapping.
lightvector.x = dot(lightminusvertex, s.xyz);
lightvector.y = dot(lightminusvertex, t.xyz);
lightvector.z = dot(lightminusvertex, n.xyz);
#endif
#endif
#if defined(VERTEXCOLOURS)
vc = v_colour;
@ -92,7 +99,7 @@ void main ()
invsurface[1] = v_tvector;
invsurface[2] = v_normal;
#endif
#if defined(PCF) || defined(SPOT) || defined(CUBE)
#if defined(PCF) || defined(SPOT) || defined(CUBE) || defined(ORTHO)
//for texture projections/shadowmapping on dlights
vtexprojcoord = (l_cubematrix*vec4(w.xyz, 1.0));
#endif
@ -184,7 +191,7 @@ void main()
vec3 t2 = w - dot(w-t_vertex[2],t_normal[2])*t_normal[2];
w = w*(1.0-factor) + factor*(gl_TessCoord.x*t0+gl_TessCoord.y*t1+gl_TessCoord.z*t2);
#if defined(PCF) || defined(SPOT) || defined(CUBE)
#if defined(PCF) || defined(SPOT) || defined(CUBE) || defined(ORTHO)
//for texture projections/shadowmapping on dlights
vtexprojcoord = (l_cubematrix*vec4(w.xyz, 1.0));
#endif
@ -309,8 +316,7 @@ void main ()
diff *= vc.rgb * vc.a;
#endif
gl_FragColor.rgb = fog3additive(diff*colorscale*l_lightcolour);
gl_FragColor = vec4(fog3additive(diff*colorscale*l_lightcolour), 1.0);
}
#endif

View file

@ -257,6 +257,7 @@ enum {
#define PEXT2_MAXPLAYERS 0x00000010 //Client is able to cope with more players than 32. abs max becomes 255, due to colormap issues.
#define PEXT2_PREDINFO 0x00000020 //movevar stats, NQ input sequences+acks.
#define PEXT2_NEWSIZEENCODING 0x00000040 //richer size encoding.
#define PEXT2_INFOBLOBS 0x00000080 //serverinfo+userinfo lengths can be MUCH higher (protocol is unbounded, but expect low sanity limits on userinfo), and contain nulls etc.
//#define PEXT2_PK3DOWNLOADS 0x10000000 //retrieve a list of pk3s/pk3s/paks for downloading (with optional URL and crcs)

View file

@ -19,6 +19,14 @@
#define HAVE_DECOUPLED_API (LIBAVCODEC_VERSION_MAJOR>57 || (LIBAVCODEC_VERSION_MAJOR==57&&LIBAVCODEC_VERSION_MINOR>=36))
//crappy compat crap
#ifndef AV_CODEC_FLAG_GLOBAL_HEADER
#define AV_CODEC_FLAG_GLOBAL_HEADER CODEC_FLAG_GLOBAL_HEADER
#endif
#ifndef AV_ERROR_MAX_STRING_SIZE
#define AV_ERROR_MAX_STRING_SIZE 64
#endif
/*
Most of the logic in here came from here:
http://svn.gnumonks.org/tags/21c3-video/upstream/ffmpeg-0.4.9-pre1/output_example.c

View file

@ -88,7 +88,7 @@ typedef struct bulletcontext_s
{
rigidbodyengine_t funcs;
qboolean hasextraobjs;
bool hasextraobjs;
// void *ode_space;
// void *ode_contactgroup;
// number of constraint solver iterations to use (for dWorldStepFast)
@ -158,10 +158,10 @@ static void QDECL World_Bullet_End(world_t *world)
static void QDECL World_Bullet_RemoveJointFromEntity(world_t *world, wedict_t *ed)
{
ed->ode.ode_joint_type = 0;
// if(ed->ode.ode_joint)
// dJointDestroy((dJointID)ed->ode.ode_joint);
ed->ode.ode_joint = NULL;
ed->rbe.joint_type = 0;
// if(ed->rbe.joint)
// dJointDestroy((dJointID)ed->rbe.joint);
ed->rbe.joint.joint = NULL;
}
static void QDECL World_Bullet_RemoveFromEntity(world_t *world, wedict_t *ed)
@ -169,27 +169,27 @@ static void QDECL World_Bullet_RemoveFromEntity(world_t *world, wedict_t *ed)
struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe;
btRigidBody *body;
btCollisionShape *geom;
if (!ed->ode.ode_physics)
if (!ed->rbe.physics)
return;
// entity is not physics controlled, free any physics data
ed->ode.ode_physics = qfalse;
ed->rbe.physics = qfalse;
body = (btRigidBody*)ed->ode.ode_body;
ed->ode.ode_body = NULL;
body = (btRigidBody*)ed->rbe.body.body;
ed->rbe.body = NULL;
if (body)
ctx->dworld->removeRigidBody (body);
geom = (btCollisionShape*)ed->ode.ode_geom;
ed->ode.ode_geom = NULL;
if (ed->ode.ode_geom)
geom = (btCollisionShape*)ed->rbe.geom;
ed->rbe.geom = NULL;
if (ed->rbe.geom)
delete geom;
//FIXME: joints
rbefuncs->ReleaseCollisionMesh(ed);
if(ed->ode.ode_massbuf)
BZ_Free(ed->ode.ode_massbuf);
ed->ode.ode_massbuf = NULL;
if(ed->rbe.massbuf)
BZ_Free(ed->rbe.massbuf);
ed->rbe.massbuf = NULL;
}
static void World_Bullet_Frame_BodyToEntity(world_t *world, wedict_t *ed)
@ -202,7 +202,7 @@ static void World_Bullet_Frame_BodyToEntity(world_t *world, wedict_t *ed)
const float *o;
const float *r; // for some reason dBodyGetRotation returns a [3][4] matrix
const float *vel;
btRigidBody *body = (btRigidBody*)ed->ode.ode_body;
btRigidBody *body = (btRigidBody*)ed->rbe.body;
int movetype;
float bodymatrix[16];
float entitymatrix[16];
@ -260,7 +260,7 @@ static void World_Bullet_Frame_BodyToEntity(world_t *world, wedict_t *ed)
VectorCopy(avel, spinvelocity);
trans.getBasis().getOpenGLSubMatrix(bodymatrix);
foo Matrix4x4_RM_FromVectors(bodymatrix, forward, left, up, origin);
foo Matrix4_Multiply(ed->ode.ode_offsetimatrix, bodymatrix, entitymatrix);
foo Matrix4_Multiply(ed->rbe.offsetimatrix, bodymatrix, entitymatrix);
foo Matrix3x4_RM_ToVectors(entitymatrix, forward, left, up, origin);
VectorAngles(forward, up, angles);
@ -290,11 +290,11 @@ static void World_Bullet_Frame_BodyToEntity(world_t *world, wedict_t *ed)
VectorCopy(avelocity, ed->v->avelocity);
// values for BodyFromEntity to check if the qc modified anything later
VectorCopy(origin, ed->ode.ode_origin);
VectorCopy(velocity, ed->ode.ode_velocity);
VectorCopy(angles, ed->ode.ode_angles);
VectorCopy(avelocity, ed->ode.ode_avelocity);
// ed->ode.ode_gravity = (qboolean)dBodyGetGravityMode(body);
VectorCopy(origin, ed->rbe.origin);
VectorCopy(velocity, ed->rbe.velocity);
VectorCopy(angles, ed->rbe.angles);
VectorCopy(avelocity, ed->rbe.avelocity);
// ed->rbe.gravity = (qboolean)dBodyGetGravityMode(body);
World_LinkEdict(world, ed, true);
#endif
@ -352,11 +352,11 @@ static void World_Bullet_Frame_JointFromEntity(world_t *world, wedict_t *ed)
jointtype = 0; // can't have both
e1 = (wedict_t*)PROG_TO_EDICT(world->progs, enemy);
b1 = (btRigidBody*)e1->ode.ode_body;
b1 = (btRigidBody*)e1->rbe.body;
if(ED_ISFREE(e1) || !b1)
enemy = 0;
e2 = (wedict_t*)PROG_TO_EDICT(world->progs, aiment);
b2 = (btRigidBody*)e2->ode.ode_body;
b2 = (btRigidBody*)e2->rbe.body;
if(ED_ISFREE(e2) || !b2)
aiment = 0;
// see http://www.ode.org/old_list_archives/2006-January/017614.html
@ -389,14 +389,14 @@ static void World_Bullet_Frame_JointFromEntity(world_t *world, wedict_t *ed)
// FMax = 0;
Stop = BT_INFINITY;
}
if(jointtype == ed->ode.ode_joint_type && VectorCompare(origin, ed->ode.ode_joint_origin) && VectorCompare(velocity, ed->ode.ode_joint_velocity) && VectorCompare(ed->v->angles, ed->ode.ode_joint_angles) && enemy == ed->ode.ode_joint_enemy && aiment == ed->ode.ode_joint_aiment && VectorCompare(movedir, ed->ode.ode_joint_movedir))
if(jointtype == ed->rbe.joint_type && VectorCompare(origin, ed->rbe.joint_origin) && VectorCompare(velocity, ed->rbe.joint_velocity) && VectorCompare(ed->v->angles, ed->rbe.joint_angles) && enemy == ed->rbe.joint_enemy && aiment == ed->rbe.joint_aiment && VectorCompare(movedir, ed->rbe.joint_movedir))
return; // nothing to do
if(ed->ode.ode_joint)
if(ed->rbe.joint)
{
j = (btTypedConstraint*)ed->ode.ode_joint;
j = (btTypedConstraint*)ed->rbe.joint;
rbe->dworld->removeConstraint(j);
ed->ode.ode_joint = NULL;
ed->rbe.joint = NULL;
delete j;
}
if (!jointtype)
@ -408,13 +408,13 @@ static void World_Bullet_Frame_JointFromEntity(world_t *world, wedict_t *ed)
if(aiment)
b2org.setValue(e2->v->origin[0], e2->v->origin[1], e2->v->origin[2]);
ed->ode.ode_joint_type = jointtype;
ed->ode.ode_joint_enemy = enemy;
ed->ode.ode_joint_aiment = aiment;
VectorCopy(origin, ed->ode.ode_joint_origin);
VectorCopy(velocity, ed->ode.ode_joint_velocity);
VectorCopy(ed->v->angles, ed->ode.ode_joint_angles);
VectorCopy(movedir, ed->ode.ode_joint_movedir);
ed->rbe.joint_type = jointtype;
ed->rbe.joint_enemy = enemy;
ed->rbe.joint_aiment = aiment;
VectorCopy(origin, ed->rbe.joint_origin);
VectorCopy(velocity, ed->rbe.joint_velocity);
VectorCopy(ed->v->angles, ed->rbe.joint_angles);
VectorCopy(movedir, ed->rbe.joint_movedir);
rbefuncs->AngleVectors(ed->v->angles, forward, NULL, NULL);
@ -523,7 +523,7 @@ static void World_Bullet_Frame_JointFromEntity(world_t *world, wedict_t *ed)
break;
}
ed->ode.ode_joint = (void *) j;
ed->rbe.joint = (void *) j;
if (j)
{
j->setUserConstraintPtr((void *) ed);
@ -531,76 +531,136 @@ static void World_Bullet_Frame_JointFromEntity(world_t *world, wedict_t *ed)
}
}
static qboolean QDECL World_Bullet_RagMatrixToBody(rbebody_t *bodyptr, float *mat)
static void MatToTransform(const float *mat, btTransform &tr)
{
btRigidBody *body;
/*
dVector3 r[3];
r[0][0] = mat[0];
r[0][1] = mat[1];
r[0][2] = mat[2];
r[1][0] = mat[4];
r[1][1] = mat[5];
r[1][2] = mat[6];
r[2][0] = mat[8];
r[2][1] = mat[9];
r[2][2] = mat[10];
dBodySetPosition(bodyptr->ode_body, mat[3], mat[7], mat[11]);
dBodySetRotation(bodyptr->ode_body, r[0]);
dBodySetLinearVel(bodyptr->ode_body, 0, 0, 0);
dBodySetAngularVel(bodyptr->ode_body, 0, 0, 0);
*/
tr.setBasis(btMatrix3x3(
mat[0], mat[1], mat[2],
mat[3], mat[4], mat[5],
mat[6], mat[7], mat[8]));
tr.setOrigin(btVector3(mat[9], mat[10], mat[11]));
}
static void MatFromTransform(float *mat, const btTransform &tr)
{
const btMatrix3x3 &m = tr.getBasis();
const btVector3 &o = tr.getOrigin();
const btVector3 &r0 = m.getRow(0);
const btVector3 &r1 = m.getRow(1);
const btVector3 &r2 = m.getRow(2);
mat[0] = r0[0];
mat[1] = r0[1];
mat[2] = r0[2];
mat[3] = r1[0];
mat[4] = r1[1];
mat[5] = r1[2];
mat[6] = r2[0];
mat[7] = r2[1];
mat[8] = r2[2];
mat[9] = o[0];
mat[10] = o[1];
mat[11] = o[2];
}
static qboolean QDECL World_Bullet_RagMatrixToBody(rbebody_t *bodyptr, float *mat)
{ //mat is a 4*3 matrix
btTransform tr;
btRigidBody *body = (btRigidBody*)bodyptr->body;
MatToTransform(mat, tr);
body->setWorldTransform(tr);
return qtrue;
}
static qboolean QDECL World_Bullet_RagCreateBody(world_t *world, rbebody_t *bodyptr, rbebodyinfo_t *bodyinfo, float *mat, wedict_t *ent)
{
/*
dMass mass;
float radius;
if (!world->ode.ode_space)
return false;
world->ode.hasodeents = true; //I don't like this, but we need the world etc to be solid.
world->ode.hasextraobjs = true;
btRigidBody *body = NULL;
btCollisionShape *geom = NULL;
float radius, length;
bulletcontext_t *ctx = (bulletcontext_t*)world->rbe;
int axisindex;
ctx->hasextraobjs = true;
switch(bodyinfo->geomshape)
{
case GEOMTYPE_CAPSULE:
radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1]) * 0.5;
bodyptr->ode_geom = (void *)dCreateCapsule(world->ode.ode_space, radius, bodyinfo->dimensions[2]);
dMassSetCapsuleTotal(&mass, bodyinfo->mass, 3, radius, bodyinfo->dimensions[2]);
//aligned along the geom's local z axis
break;
case GEOMTYPE_SPHERE:
//radius
radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1] + bodyinfo->dimensions[2]) / 3;
bodyptr->ode_geom = dCreateSphere(world->ode.ode_space, radius);
dMassSetSphereTotal(&mass, bodyinfo->mass, radius);
//aligned along the geom's local z axis
break;
case GEOMTYPE_CYLINDER:
//radius, length
radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1]) * 0.5;
bodyptr->ode_geom = dCreateCylinder(world->ode.ode_space, radius, bodyinfo->dimensions[2]);
dMassSetCylinderTotal(&mass, bodyinfo->mass, 3, radius, bodyinfo->dimensions[2]);
//alignment is irreleevnt, thouse I suppose it might be scaled wierdly.
/*
case GEOMTYPE_TRIMESH:
// foo Matrix4x4_Identity(ed->rbe.offsetmatrix);
geom = NULL;
if (!model)
{
Con_Printf("entity %i (classname %s) has no model\n", NUM_FOR_EDICT(world->progs, (edict_t*)ed), PR_GetString(world->progs, ed->v->classname));
if (ed->rbe.physics)
World_Bullet_RemoveFromEntity(world, ed);
return;
}
if (!rbefuncs->GenerateCollisionMesh(world, model, ed, geomcenter))
{
if (ed->rbe.physics)
World_Bullet_RemoveFromEntity(world, ed);
return;
}
// foo Matrix4x4_RM_CreateTranslate(ed->rbe.offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
{
btTriangleIndexVertexArray *tiva = new btTriangleIndexVertexArray();
btIndexedMesh mesh;
mesh.m_vertexType = PHY_FLOAT;
mesh.m_indexType = PHY_INTEGER;
mesh.m_numTriangles = ed->rbe.numtriangles;
mesh.m_numVertices = ed->rbe.numvertices;
mesh.m_triangleIndexBase = (const unsigned char*)ed->rbe.element3i;
mesh.m_triangleIndexStride = sizeof(*ed->rbe.element3i)*3;
mesh.m_vertexBase = (const unsigned char*)ed->rbe.vertex3f;
mesh.m_vertexStride = sizeof(*ed->rbe.vertex3f)*3;
tiva->addIndexedMesh(mesh);
geom = new btBvhTriangleMeshShape(tiva, true);
}
break;
*/
default:
Con_DPrintf("World_Bullet_RagCreateBody: unsupported geomshape\n", bodyinfo->geomshape);
case GEOMTYPE_BOX:
//diameter
bodyptr->ode_geom = dCreateBox(world->ode.ode_space, bodyinfo->dimensions[0], bodyinfo->dimensions[1], bodyinfo->dimensions[2]);
dMassSetBoxTotal(&mass, bodyinfo->mass, bodyinfo->dimensions[0], bodyinfo->dimensions[1], bodyinfo->dimensions[2]);
//monkey
geom = new btBoxShape(btVector3(bodyinfo->dimensions[0], bodyinfo->dimensions[1], bodyinfo->dimensions[2]) * 0.5);
break;
case GEOMTYPE_SPHERE:
geom = new btSphereShape(bodyinfo->dimensions[0] * 0.5f);
break;
case GEOMTYPE_CAPSULE:
// case GEOMTYPE_CAPSULE_X:
// case GEOMTYPE_CAPSULE_Y:
case GEOMTYPE_CAPSULE_Z:
radius = (bodyinfo->dimensions[0]+bodyinfo->dimensions[1]) * 0.5f;
geom = new btCapsuleShapeZ(radius, bodyinfo->dimensions[2]);
break;
case GEOMTYPE_CYLINDER:
// case GEOMTYPE_CYLINDER_X:
// case GEOMTYPE_CYLINDER_Y:
case GEOMTYPE_CYLINDER_Z:
radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1]) * 0.5;
geom = new btCylinderShapeZ(btVector3(radius, radius, bodyinfo->dimensions[2])*0.5);
break;
}
bodyptr->ode_body = dBodyCreate(world->ode.ode_world);
dBodySetMass(bodyptr->ode_body, &mass);
dGeomSetBody(bodyptr->ode_geom, bodyptr->ode_body);
dGeomSetData(bodyptr->ode_geom, (void*)ent);
*/
return World_Bullet_RagMatrixToBody(bodyptr, mat);
bodyptr->geom = geom;
//now create the body too
btVector3 fallInertia(0, 0, 0);
((btCollisionShape*)geom)->calculateLocalInertia(bodyinfo->mass, fallInertia);
btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(bodyinfo->mass, NULL, (btCollisionShape*)geom, fallInertia);
MatToTransform(mat, fallRigidBodyCI.m_startWorldTransform);
body = new btRigidBody(fallRigidBodyCI);
body->setUserPointer(ent);
bodyptr->body = (void*)body;
//motion threshhold should be speed/physicsframerate.
//FIXME: recalculate...
body->setCcdMotionThreshold((bodyinfo->dimensions[0]+bodyinfo->dimensions[1]+bodyinfo->dimensions[2])*(4/3));
//radius should be the body's radius
body->setCcdSweptSphereRadius((bodyinfo->dimensions[0]+bodyinfo->dimensions[1]+bodyinfo->dimensions[2])*(0.5/3));
ctx->dworld->addRigidBody(body, ent->xv->dimension_solid, ent->xv->dimension_hit);
return qtrue;
}
static void QDECL World_Bullet_RagMatrixFromJoint(rbejoint_t *joint, rbejointinfo_t *info, float *mat)
@ -694,24 +754,9 @@ static void QDECL World_Bullet_RagMatrixFromJoint(rbejoint_t *joint, rbejointinf
static void QDECL World_Bullet_RagMatrixFromBody(world_t *world, rbebody_t *bodyptr, float *mat)
{
/*
const dReal *o = dBodyGetPosition(bodyptr->ode_body);
const dReal *r = dBodyGetRotation(bodyptr->ode_body);
mat[0] = r[0];
mat[1] = r[1];
mat[2] = r[2];
mat[3] = o[0];
mat[4] = r[4];
mat[5] = r[5];
mat[6] = r[6];
mat[7] = o[1];
mat[8] = r[8];
mat[9] = r[9];
mat[10] = r[10];
mat[11] = o[2];
*/
bulletcontext_t *ctx = (bulletcontext_t*)world->rbe;
btRigidBody *body = (btRigidBody*)bodyptr->body;
MatFromTransform(mat, body->getCenterOfMassTransform());
}
static void QDECL World_Bullet_RagEnableJoint(rbejoint_t *joint, qboolean enabled)
{
@ -728,22 +773,22 @@ static void QDECL World_Bullet_RagCreateJoint(world_t *world, rbejoint_t *joint,
switch(info->type)
{
case JOINTTYPE_POINT:
joint->ode_joint = dJointCreateBall(world->ode.ode_world, 0);
joint->ode_joint = dJointCreateBall(world->rbe.world, 0);
break;
case JOINTTYPE_HINGE:
joint->ode_joint = dJointCreateHinge(world->ode.ode_world, 0);
joint->ode_joint = dJointCreateHinge(world->rbe.world, 0);
break;
case JOINTTYPE_SLIDER:
joint->ode_joint = dJointCreateSlider(world->ode.ode_world, 0);
joint->ode_joint = dJointCreateSlider(world->rbe.world, 0);
break;
case JOINTTYPE_UNIVERSAL:
joint->ode_joint = dJointCreateUniversal(world->ode.ode_world, 0);
joint->ode_joint = dJointCreateUniversal(world->rbe.world, 0);
break;
case JOINTTYPE_HINGE2:
joint->ode_joint = dJointCreateHinge2(world->ode.ode_world, 0);
joint->ode_joint = dJointCreateHinge2(world->rbe.world, 0);
break;
case JOINTTYPE_FIXED:
joint->ode_joint = dJointCreateFixed(world->ode.ode_world, 0);
joint->ode_joint = dJointCreateFixed(world->rbe.world, 0);
break;
default:
joint->ode_joint = NULL;
@ -823,14 +868,20 @@ static void QDECL World_Bullet_RagCreateJoint(world_t *world, rbejoint_t *joint,
static void QDECL World_Bullet_RagDestroyBody(world_t *world, rbebody_t *bodyptr)
{
/*
if (bodyptr->ode_geom)
dGeomDestroy(bodyptr->ode_geom);
bodyptr->ode_geom = NULL;
if (bodyptr->ode_body)
dBodyDestroy(bodyptr->ode_body);
bodyptr->ode_body = NULL;
*/
bulletcontext_t *ctx = (bulletcontext_t*)world->rbe;
btRigidBody *body = (btRigidBody*)bodyptr->body;
btCollisionShape *geom = (btCollisionShape*)bodyptr->geom;
bodyptr->body = NULL;
bodyptr->geom = NULL;
if (body)
{
ctx->dworld->removeRigidBody(body);
delete body;
}
if (geom)
delete geom;
}
static void QDECL World_Bullet_RagDestroyJoint(world_t *world, rbejoint_t *joint)
@ -859,7 +910,7 @@ public:
btVector3 org;
rbefuncs->AngleVectors(edict->v->angles, axis[0], axis[1], axis[2]);
VectorNegate(axis[1], axis[1]);
VectorAvg(edict->ode.ode_mins, edict->ode.ode_maxs, offset);
VectorAvg(edict->rbe.mins, edict->rbe.maxs, offset);
VectorMA(edict->v->origin, offset[0]*1, axis[0], org);
VectorMA(org, offset[1]*1, axis[1], org);
VectorMA(org, offset[2]*1, axis[2], org);
@ -895,30 +946,22 @@ public:
VectorCopy(worldTrans.getBasis().getColumn(0), fwd);
VectorCopy(worldTrans.getBasis().getColumn(1), left);
VectorCopy(worldTrans.getBasis().getColumn(2), up);
VectorAvg(edict->ode.ode_mins, edict->ode.ode_maxs, offset);
VectorAvg(edict->rbe.mins, edict->rbe.maxs, offset);
VectorMA(pos, offset[0]*-1, fwd, pos);
VectorMA(pos, offset[1]*-1, left, pos);
VectorMA(pos, offset[2]*-1, up, edict->v->origin);
rbefuncs->VectorAngles(fwd, up, edict->v->angles, (qboolean)NegativeMeshPitch(world, edict));
const btVector3 &vel = ((btRigidBody*)edict->ode.ode_body)->getLinearVelocity();
const btVector3 &vel = ((btRigidBody*)edict->rbe.body)->getLinearVelocity();
VectorCopy(vel.m_floats, edict->v->velocity);
//so it doesn't get rebuilt
VectorCopy(edict->v->origin, edict->ode.ode_origin);
VectorCopy(edict->v->angles, edict->ode.ode_angles);
VectorCopy(edict->v->velocity, edict->ode.ode_velocity);
VectorCopy(edict->v->origin, edict->rbe.origin);
VectorCopy(edict->v->angles, edict->rbe.angles);
VectorCopy(edict->v->velocity, edict->rbe.velocity);
// World_LinkEdict(world, edict, false);
// if(mSceneNode == nullptr)
// return; // silently return before we set a node
// btQuaternion rot = worldTrans.getRotation();
// mSceneNode ->setOrientation(rot.w(), rot.x(), rot.y(), rot.z());
// btVector3 pos = worldTrans.getOrigin();
// mSceneNode ->setPosition(pos.x(), pos.y(), pos.z());
//FIXME: relink the ent into the areagrid
}
};
@ -1021,7 +1064,7 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
break;
default:
// case GEOMTYPE_NONE:
if (ed->ode.ode_physics)
if (ed->rbe.physics)
World_Bullet_RemoveFromEntity(world, ed);
return;
}
@ -1030,70 +1073,70 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
if (DotProduct(geomsize,geomsize) == 0)
{
// we don't allow point-size physics objects...
if (ed->ode.ode_physics)
if (ed->rbe.physics)
World_Bullet_RemoveFromEntity(world, ed);
return;
}
// check if we need to create or replace the geom
if (!ed->ode.ode_physics
|| !VectorCompare(ed->ode.ode_mins, entmins)
|| !VectorCompare(ed->ode.ode_maxs, entmaxs)
|| ed->ode.ode_modelindex != modelindex)
if (!ed->rbe.physics
|| !VectorCompare(ed->rbe.mins, entmins)
|| !VectorCompare(ed->rbe.maxs, entmaxs)
|| ed->rbe.modelindex != modelindex)
{
btCollisionShape *geom;
modified = qtrue;
World_Bullet_RemoveFromEntity(world, ed);
ed->ode.ode_physics = qtrue;
VectorCopy(entmins, ed->ode.ode_mins);
VectorCopy(entmaxs, ed->ode.ode_maxs);
ed->ode.ode_modelindex = modelindex;
ed->rbe.physics = qtrue;
VectorCopy(entmins, ed->rbe.mins);
VectorCopy(entmaxs, ed->rbe.maxs);
ed->rbe.modelindex = modelindex;
VectorAvg(entmins, entmaxs, geomcenter);
ed->ode.ode_movelimit = min(geomsize[0], min(geomsize[1], geomsize[2]));
ed->rbe.movelimit = min(geomsize[0], min(geomsize[1], geomsize[2]));
/* memset(ed->ode.ode_offsetmatrix, 0, sizeof(ed->ode.ode_offsetmatrix));
ed->ode.ode_offsetmatrix[0] = 1;
ed->ode.ode_offsetmatrix[5] = 1;
ed->ode.ode_offsetmatrix[10] = 1;
ed->ode.ode_offsetmatrix[3] = -geomcenter[0];
ed->ode.ode_offsetmatrix[7] = -geomcenter[1];
ed->ode.ode_offsetmatrix[11] = -geomcenter[2];
/* memset(ed->rbe.offsetmatrix, 0, sizeof(ed->rbe.offsetmatrix));
ed->rbe.offsetmatrix[0] = 1;
ed->rbe.offsetmatrix[5] = 1;
ed->rbe.offsetmatrix[10] = 1;
ed->rbe.offsetmatrix[3] = -geomcenter[0];
ed->rbe.offsetmatrix[7] = -geomcenter[1];
ed->rbe.offsetmatrix[11] = -geomcenter[2];
*/
ed->ode.ode_mass = massval;
ed->rbe.mass = massval;
switch(geomtype)
{
case GEOMTYPE_TRIMESH:
// foo Matrix4x4_Identity(ed->ode.ode_offsetmatrix);
// foo Matrix4x4_Identity(ed->rbe.offsetmatrix);
geom = NULL;
if (!model)
{
Con_Printf("entity %i (classname %s) has no model\n", NUM_FOR_EDICT(world->progs, (edict_t*)ed), PR_GetString(world->progs, ed->v->classname));
if (ed->ode.ode_physics)
if (ed->rbe.physics)
World_Bullet_RemoveFromEntity(world, ed);
return;
}
if (!rbefuncs->GenerateCollisionMesh(world, model, ed, geomcenter))
{
if (ed->ode.ode_physics)
if (ed->rbe.physics)
World_Bullet_RemoveFromEntity(world, ed);
return;
}
// foo Matrix4x4_RM_CreateTranslate(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
// foo Matrix4x4_RM_CreateTranslate(ed->rbe.offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
{
btTriangleIndexVertexArray *tiva = new btTriangleIndexVertexArray();
btIndexedMesh mesh;
mesh.m_vertexType = PHY_FLOAT;
mesh.m_indexType = PHY_INTEGER;
mesh.m_numTriangles = ed->ode.ode_numtriangles;
mesh.m_numVertices = ed->ode.ode_numvertices;
mesh.m_triangleIndexBase = (const unsigned char*)ed->ode.ode_element3i;
mesh.m_triangleIndexStride = sizeof(*ed->ode.ode_element3i)*3;
mesh.m_vertexBase = (const unsigned char*)ed->ode.ode_vertex3f;
mesh.m_vertexStride = sizeof(*ed->ode.ode_vertex3f)*3;
mesh.m_numTriangles = ed->rbe.numtriangles;
mesh.m_numVertices = ed->rbe.numvertices;
mesh.m_triangleIndexBase = (const unsigned char*)ed->rbe.element3i;
mesh.m_triangleIndexStride = sizeof(*ed->rbe.element3i)*3;
mesh.m_vertexBase = (const unsigned char*)ed->rbe.vertex3f;
mesh.m_vertexStride = sizeof(*ed->rbe.vertex3f)*3;
tiva->addIndexedMesh(mesh);
geom = new btBvhTriangleMeshShape(tiva, true);
}
@ -1167,15 +1210,15 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
default:
// Con_Printf("World_Bullet_BodyFromEntity: unrecognized solid value %i was accepted by filter\n", solid);
if (ed->ode.ode_physics)
if (ed->rbe.physics)
World_Bullet_RemoveFromEntity(world, ed);
return;
}
// Matrix3x4_InvertTo4x4_Simple(ed->ode.ode_offsetmatrix, ed->ode.ode_offsetimatrix);
// ed->ode.ode_massbuf = BZ_Malloc(sizeof(dMass));
// memcpy(ed->ode.ode_massbuf, &mass, sizeof(dMass));
// Matrix3x4_InvertTo4x4_Simple(ed->rbe.offsetmatrix, ed->rbe.offsetimatrix);
// ed->rbe.massbuf = BZ_Malloc(sizeof(dMass));
// memcpy(ed->rbe.massbuf, &mass, sizeof(dMass));
ed->ode.ode_geom = (void *)geom;
ed->rbe.geom = (void *)geom;
}
//non-moving objects need to be static objects (and thus need 0 mass)
@ -1183,35 +1226,35 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
massval = 0;
//if the mass changes, we'll need to create a new body (but not the shape, so invalidate the current one)
if (ed->ode.ode_mass != massval)
if (ed->rbe.mass != massval)
{
ed->ode.ode_mass = massval;
body = (btRigidBody*)ed->ode.ode_body;
ed->rbe.mass = massval;
body = (btRigidBody*)ed->rbe.body;
if (body)
ctx->dworld->removeRigidBody(body);
ed->ode.ode_body = NULL;
ed->rbe.body = NULL;
}
// if(ed->ode.ode_geom)
// dGeomSetData(ed->ode.ode_geom, (void*)ed);
if (movetype == MOVETYPE_PHYSICS && ed->ode.ode_mass)
// if(ed->rbe.geom)
// dGeomSetData(ed->rbe.geom, (void*)ed);
if (movetype == MOVETYPE_PHYSICS && ed->rbe.mass)
{
if (ed->ode.ode_body == NULL)
if (ed->rbe.body == NULL)
{
// ed->ode.ode_body = (void *)(body = dBodyCreate(world->ode.ode_world));
// dGeomSetBody(ed->ode.ode_geom, body);
// ed->rbe.body = (void *)(body = dBodyCreate(world->rbe.world));
// dGeomSetBody(ed->rbe.geom, body);
// dBodySetData(body, (void*)ed);
// dBodySetMass(body, (dMass *) ed->ode.ode_massbuf);
// dBodySetMass(body, (dMass *) ed->rbe.massbuf);
btVector3 fallInertia(0, 0, 0);
((btCollisionShape*)ed->ode.ode_geom)->calculateLocalInertia(ed->ode.ode_mass, fallInertia);
btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(ed->ode.ode_mass, new QCMotionState(ed,world), (btCollisionShape*)ed->ode.ode_geom, fallInertia);
((btCollisionShape*)ed->rbe.geom)->calculateLocalInertia(ed->rbe.mass, fallInertia);
btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(ed->rbe.mass, new QCMotionState(ed,world), (btCollisionShape*)ed->rbe.geom, fallInertia);
body = new btRigidBody(fallRigidBodyCI);
body->setUserPointer(ed);
// btTransform trans;
// trans.setFromOpenGLMatrix(ed->ode.ode_offsetmatrix);
// trans.setFromOpenGLMatrix(ed->rbe.offsetmatrix);
// body->setCenterOfMassTransform(trans);
ed->ode.ode_body = (void*)body;
ed->rbe.body = (void*)body;
//motion threshhold should be speed/physicsframerate.
//FIXME: recalculate...
@ -1226,16 +1269,16 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
}
else
{
if (ed->ode.ode_body == NULL)
if (ed->rbe.body == NULL)
{
btRigidBody::btRigidBodyConstructionInfo rbci(ed->ode.ode_mass, new QCMotionState(ed,world), (btCollisionShape*)ed->ode.ode_geom, btVector3(0, 0, 0));
btRigidBody::btRigidBodyConstructionInfo rbci(ed->rbe.mass, new QCMotionState(ed,world), (btCollisionShape*)ed->rbe.geom, btVector3(0, 0, 0));
body = new btRigidBody(rbci);
body->setUserPointer(ed);
// btTransform trans;
// trans.setFromOpenGLMatrix(ed->ode.ode_offsetmatrix);
// trans.setFromOpenGLMatrix(ed->rbe.offsetmatrix);
// body->setCenterOfMassTransform(trans);
ed->ode.ode_body = (void*)body;
if (ed->ode.ode_mass)
ed->rbe.body = (void*)body;
if (ed->rbe.mass)
body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
else
body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT);
@ -1245,7 +1288,7 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
}
}
body = (btRigidBody*)ed->ode.ode_body;
body = (btRigidBody*)ed->rbe.body;
// get current data from entity
gravity = qtrue;
@ -1325,15 +1368,15 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
// check if the qc edited any position data
if (
0//!VectorCompare(origin, ed->ode.ode_origin)
|| !VectorCompare(velocity, ed->ode.ode_velocity)
//|| !VectorCompare(angles, ed->ode.ode_angles)
|| !VectorCompare(avelocity, ed->ode.ode_avelocity)
|| gravity != ed->ode.ode_gravity)
0//!VectorCompare(origin, ed->rbe.origin)
|| !VectorCompare(velocity, ed->rbe.velocity)
//|| !VectorCompare(angles, ed->rbe.angles)
|| !VectorCompare(avelocity, ed->rbe.avelocity)
|| gravity != ed->rbe.gravity)
modified = qtrue;
// store the qc values into the physics engine
body = (btRigidBody*)ed->ode.ode_body;
body = (btRigidBody*)ed->rbe.body;
if (modified && body)
{
// dVector3 r[3];
@ -1342,27 +1385,27 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
#if 0
Con_Printf("entity %i got changed by QC\n", (int) (ed - prog->edicts));
if(!VectorCompare(origin, ed->ode.ode_origin))
Con_Printf(" origin: %f %f %f -> %f %f %f\n", ed->ode.ode_origin[0], ed->ode.ode_origin[1], ed->ode.ode_origin[2], origin[0], origin[1], origin[2]);
if(!VectorCompare(velocity, ed->ode.ode_velocity))
Con_Printf(" velocity: %f %f %f -> %f %f %f\n", ed->ode.ode_velocity[0], ed->ode.ode_velocity[1], ed->ode.ode_velocity[2], velocity[0], velocity[1], velocity[2]);
if(!VectorCompare(angles, ed->ode.ode_angles))
Con_Printf(" angles: %f %f %f -> %f %f %f\n", ed->ode.ode_angles[0], ed->ode.ode_angles[1], ed->ode.ode_angles[2], angles[0], angles[1], angles[2]);
if(!VectorCompare(avelocity, ed->ode.ode_avelocity))
Con_Printf(" avelocity: %f %f %f -> %f %f %f\n", ed->ode.ode_avelocity[0], ed->ode.ode_avelocity[1], ed->ode.ode_avelocity[2], avelocity[0], avelocity[1], avelocity[2]);
if(gravity != ed->ode.ode_gravity)
if(!VectorCompare(origin, ed->rbe.origin))
Con_Printf(" origin: %f %f %f -> %f %f %f\n", ed->rbe.origin[0], ed->rbe.origin[1], ed->rbe.origin[2], origin[0], origin[1], origin[2]);
if(!VectorCompare(velocity, ed->rbe.velocity))
Con_Printf(" velocity: %f %f %f -> %f %f %f\n", ed->rbe.velocity[0], ed->rbe.velocity[1], ed->rbe.velocity[2], velocity[0], velocity[1], velocity[2]);
if(!VectorCompare(angles, ed->rbe.angles))
Con_Printf(" angles: %f %f %f -> %f %f %f\n", ed->rbe.angles[0], ed->rbe.angles[1], ed->rbe.angles[2], angles[0], angles[1], angles[2]);
if(!VectorCompare(avelocity, ed->rbe.avelocity))
Con_Printf(" avelocity: %f %f %f -> %f %f %f\n", ed->rbe.avelocity[0], ed->rbe.avelocity[1], ed->rbe.avelocity[2], avelocity[0], avelocity[1], avelocity[2]);
if(gravity != ed->rbe.gravity)
Con_Printf(" gravity: %i -> %i\n", ed->ide.ode_gravity, gravity);
#endif
// values for BodyFromEntity to check if the qc modified anything later
VectorCopy(origin, ed->ode.ode_origin);
VectorCopy(velocity, ed->ode.ode_velocity);
VectorCopy(angles, ed->ode.ode_angles);
VectorCopy(avelocity, ed->ode.ode_avelocity);
ed->ode.ode_gravity = gravity;
VectorCopy(origin, ed->rbe.origin);
VectorCopy(velocity, ed->rbe.velocity);
VectorCopy(angles, ed->rbe.angles);
VectorCopy(avelocity, ed->rbe.avelocity);
ed->rbe.gravity = gravity;
// foo Matrix4x4_RM_FromVectors(entitymatrix, forward, left, up, origin);
// foo Matrix4_Multiply(ed->ode.ode_offsetmatrix, entitymatrix, bodymatrix);
// foo Matrix4_Multiply(ed->rbe.offsetmatrix, entitymatrix, bodymatrix);
// foo Matrix3x4_RM_ToVectors(bodymatrix, forward, left, up, origin);
// r[0][0] = forward[0];
@ -1392,7 +1435,7 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
// limit movement speed to prevent missed collisions at high speed
btVector3 ovelocity = body->getLinearVelocity();
btVector3 ospinvelocity = body->getAngularVelocity();
movelimit = ed->ode.ode_movelimit * world->ode.ode_movelimit;
movelimit = ed->rbe.movelimit * world->rbe.movelimit;
test = DotProduct(ovelocity,ovelocity);
if (test > movelimit*movelimit)
{
@ -1465,7 +1508,7 @@ static void VARGS nearCallback (void *data, dGeomID o1, dGeomID o2)
//ragdolls don't make contact with the bbox of the doll entity
//the origional entity should probably not be solid anyway.
//these bodies should probably not collide against bboxes of other entities with ragdolls either, but meh.
if (ed1->ode.ode_body == b1 || ed2->ode.ode_body == b2)
if (ed1->rbe.body == b1 || ed2->rbe.body == b2)
return;
}
if(!ed1 || ed1->isfree)
@ -1529,7 +1572,7 @@ static void VARGS nearCallback (void *data, dGeomID o1, dGeomID o2)
bouncefactor1 = bouncefactor2;
}
}
dWorldGetGravity(world->ode.ode_world, grav);
dWorldGetGravity(world->rbe.world, grav);
bouncestop1 *= fabs(grav[2]);
erp = (DotProduct(ed1->v->velocity, ed1->v->velocity) > DotProduct(ed2->v->velocity, ed2->v->velocity)) ? ed1->xv->erp : ed2->xv->erp;
@ -1551,7 +1594,7 @@ static void VARGS nearCallback (void *data, dGeomID o1, dGeomID o2)
contact[i].surface.soft_cfm = physics_bullet_contact_cfm.value;
contact[i].surface.bounce = bouncefactor1;
contact[i].surface.bounce_vel = bouncestop1;
c = dJointCreateContact(world->ode.ode_world, world->ode.ode_contactgroup, contact + i);
c = dJointCreateContact(world->rbe.world, world->rbe.contactgroup, contact + i);
dJointAttach(c, b1, b2);
}
}
@ -1565,9 +1608,9 @@ static void QDECL World_Bullet_Frame(world_t *world, double frametime, double gr
int i;
wedict_t *ed;
// world->ode.ode_iterations = bound(1, physics_bullet_iterationsperframe.ival, 1000);
// world->ode.ode_step = frametime / world->ode.ode_iterations;
// world->ode.ode_movelimit = physics_bullet_movelimit.value / world->ode.ode_step;
// world->rbe.iterations = bound(1, physics_bullet_iterationsperframe.ival, 1000);
// world->rbe.step = frametime / world->rbe.iterations;
// world->rbe.movelimit = physics_bullet_movelimit.value / world->rbe.step;
// copy physics properties from entities to physics engine
@ -1599,22 +1642,22 @@ static void QDECL World_Bullet_Frame(world_t *world, double frametime, double gr
ctx->dworld->stepSimulation(frametime, max(0, physics_bullet_maxiterationsperframe->value), 1/bound(1, physics_bullet_framerate->value, 500));
// set the tolerance for closeness of objects
// dWorldSetContactSurfaceLayer(world->ode.ode_world, max(0, physics_bullet_contactsurfacelayer.value));
// dWorldSetContactSurfaceLayer(world->rbe.world, max(0, physics_bullet_contactsurfacelayer.value));
// run collisions for the current world state, creating JointGroup
// dSpaceCollide(world->ode.ode_space, (void *)world, nearCallback);
// dSpaceCollide(world->rbe.space, (void *)world, nearCallback);
// run physics (move objects, calculate new velocities)
// if (physics_bullet_worldquickstep.ival)
// {
// dWorldSetQuickStepNumIterations(world->ode.ode_world, bound(1, physics_bullet_worldquickstep_iterations.ival, 200));
// dWorldQuickStep(world->ode.ode_world, world->ode.ode_step);
// dWorldSetQuickStepNumIterations(world->rbe.world, bound(1, physics_bullet_worldquickstep_iterations.ival, 200));
// dWorldQuickStep(world->rbe.world, world->rbe.step);
// }
// else
// dWorldStep(world->ode.ode_world, world->ode.ode_step);
// dWorldStep(world->rbe.world, world->rbe.step);
// clear the JointGroup now that we're done with it
// dJointGroupEmpty(world->ode.ode_contactgroup);
// dJointGroupEmpty(world->rbe.contactgroup);
if (world->rbe_hasphysicsents)
{
@ -1631,7 +1674,7 @@ static void QDECL World_Bullet_Frame(world_t *world, double frametime, double gr
static void World_Bullet_RunCmd(world_t *world, rbecommandqueue_t *cmd)
{
btRigidBody *body = (btRigidBody*)(cmd->edict->ode.ode_body);
btRigidBody *body = (btRigidBody*)(cmd->edict->rbe.body);
switch(cmd->command)
{
case RBECMD_ENABLE:
@ -1650,7 +1693,7 @@ static void World_Bullet_RunCmd(world_t *world, rbecommandqueue_t *cmd)
}
break;
case RBECMD_TORQUE:
if (cmd->edict->ode.ode_body)
if (cmd->edict->rbe.body)
{
body->setActivationState(1);
body->applyTorque(btVector3(cmd->v1[0], cmd->v1[1], cmd->v1[2]));
@ -1679,7 +1722,7 @@ static void QDECL World_Bullet_PushCommand(world_t *world, rbecommandqueue_t *va
static void QDECL World_Bullet_TraceEntity(world_t *world, vec3_t start, vec3_t end, wedict_t *ed)
{
struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe;
btCollisionShape *shape = (btCollisionShape*)ed->ode.ode_geom;
btCollisionShape *shape = (btCollisionShape*)ed->rbe.geom;
class myConvexResultCallback : public btCollisionWorld::ConvexResultCallback
{
@ -1738,34 +1781,34 @@ static void QDECL World_Bullet_Start(world_t *world)
/*
if(physics_bullet_world_erp.value >= 0)
dWorldSetERP(world->ode.ode_world, physics_bullet_world_erp.value);
dWorldSetERP(world->rbe.world, physics_bullet_world_erp.value);
if(physics_bullet_world_cfm.value >= 0)
dWorldSetCFM(world->ode.ode_world, physics_bullet_world_cfm.value);
dWorldSetCFM(world->rbe.world, physics_bullet_world_cfm.value);
if (physics_bullet_world_damping.ival)
{
dWorldSetLinearDamping(world->ode.ode_world, (physics_bullet_world_damping_linear.value >= 0) ? (physics_bullet_world_damping_linear.value * physics_bullet_world_damping.value) : 0);
dWorldSetLinearDampingThreshold(world->ode.ode_world, (physics_bullet_world_damping_linear_threshold.value >= 0) ? (physics_bullet_world_damping_linear_threshold.value * physics_bullet_world_damping.value) : 0);
dWorldSetAngularDamping(world->ode.ode_world, (physics_bullet_world_damping_angular.value >= 0) ? (physics_bullet_world_damping_angular.value * physics_bullet_world_damping.value) : 0);
dWorldSetAngularDampingThreshold(world->ode.ode_world, (physics_bullet_world_damping_angular_threshold.value >= 0) ? (physics_bullet_world_damping_angular_threshold.value * physics_bullet_world_damping.value) : 0);
dWorldSetLinearDamping(world->rbe.world, (physics_bullet_world_damping_linear.value >= 0) ? (physics_bullet_world_damping_linear.value * physics_bullet_world_damping.value) : 0);
dWorldSetLinearDampingThreshold(world->rbe.world, (physics_bullet_world_damping_linear_threshold.value >= 0) ? (physics_bullet_world_damping_linear_threshold.value * physics_bullet_world_damping.value) : 0);
dWorldSetAngularDamping(world->rbe.world, (physics_bullet_world_damping_angular.value >= 0) ? (physics_bullet_world_damping_angular.value * physics_bullet_world_damping.value) : 0);
dWorldSetAngularDampingThreshold(world->rbe.world, (physics_bullet_world_damping_angular_threshold.value >= 0) ? (physics_bullet_world_damping_angular_threshold.value * physics_bullet_world_damping.value) : 0);
}
else
{
dWorldSetLinearDamping(world->ode.ode_world, 0);
dWorldSetLinearDampingThreshold(world->ode.ode_world, 0);
dWorldSetAngularDamping(world->ode.ode_world, 0);
dWorldSetAngularDampingThreshold(world->ode.ode_world, 0);
dWorldSetLinearDamping(world->rbe.world, 0);
dWorldSetLinearDampingThreshold(world->rbe.world, 0);
dWorldSetAngularDamping(world->rbe.world, 0);
dWorldSetAngularDampingThreshold(world->rbe.world, 0);
}
if (physics_bullet_autodisable.ival)
{
dWorldSetAutoDisableSteps(world->ode.ode_world, bound(1, physics_bullet_autodisable_steps.ival, 100));
dWorldSetAutoDisableTime(world->ode.ode_world, physics_bullet_autodisable_time.value);
dWorldSetAutoDisableAverageSamplesCount(world->ode.ode_world, bound(1, physics_bullet_autodisable_threshold_samples.ival, 100));
dWorldSetAutoDisableLinearThreshold(world->ode.ode_world, physics_bullet_autodisable_threshold_linear.value);
dWorldSetAutoDisableAngularThreshold(world->ode.ode_world, physics_bullet_autodisable_threshold_angular.value);
dWorldSetAutoDisableFlag (world->ode.ode_world, true);
dWorldSetAutoDisableSteps(world->rbe.world, bound(1, physics_bullet_autodisable_steps.ival, 100));
dWorldSetAutoDisableTime(world->rbe.world, physics_bullet_autodisable_time.value);
dWorldSetAutoDisableAverageSamplesCount(world->rbe.world, bound(1, physics_bullet_autodisable_threshold_samples.ival, 100));
dWorldSetAutoDisableLinearThreshold(world->rbe.world, physics_bullet_autodisable_threshold_linear.value);
dWorldSetAutoDisableAngularThreshold(world->rbe.world, physics_bullet_autodisable_threshold_angular.value);
dWorldSetAutoDisableFlag (world->rbe.world, true);
}
else
dWorldSetAutoDisableFlag (world->ode.ode_world, false);
dWorldSetAutoDisableFlag (world->rbe.world, false);
*/
}

View file

@ -534,7 +534,7 @@ void Plug_InitStandardBuiltins(void)
}
#ifndef Q3_VM
void NATIVEEXPORT dllEntry(qintptr_t (QDECL *funcptr)(qintptr_t,...))
NATIVEEXPORT void QDECL dllEntry(qintptr_t (QDECL *funcptr)(qintptr_t,...))
{
plugin_syscall = funcptr;
}

View file

@ -94,10 +94,14 @@ void BadBuiltin(void);
#endif
#endif
#ifdef _WIN32
#define NATIVEEXPORT __declspec(dllexport) QDECL
#else
#define NATIVEEXPORT __attribute__((visibility("default")))
#ifndef NATIVEEXPORT
#ifdef _WIN32
#define NATIVEEXPORTPROTO __declspec(dllexport)
#define NATIVEEXPORT NATIVEEXPORTPROTO
#else
#define NATIVEEXPORTPROTO
#define NATIVEEXPORT __attribute__((visibility("default")))
#endif
#endif

View file

@ -20,3 +20,13 @@ at the time of writing, r_polygonoffset_* need to be set to 0, or you'll get pur
Cheats: static realtime lighting _used_ to be cheat protected. Which made it useless and unusable. Darkplaces has permitted realtime lights for a while on quakeworld servers without complaint. Thus FTE no longer mandates that the server explicitly allows it.
Having said that, you can tell if static or dynamic lights are enabled in someone else's client via the f_version say request.
todo:
light util that omits direct lighting + engine that forces r_shadow_realtime_world_lightmaps 1
light util that emits e5bgr9 lighting + worldspawn key that forces srgb.
light util that generates complete .rtlights files, with radiuses and colours and falloffs and spotlights etc.
ggx.
screenspace refections.