From 0fee3a4aeac13d6e47ecacf6897a12527121a92a Mon Sep 17 00:00:00 2001 From: Spoike Date: Sun, 22 Jul 2018 11:49:37 +0000 Subject: [PATCH] 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 --- engine/Makefile | 1 + engine/client/cl_input.c | 4 +- engine/client/cl_main.c | 9 +- engine/client/client.h | 2 +- engine/client/m_download.c | 6 +- engine/client/m_mp3.c | 1 + engine/client/m_options.c | 26 +- engine/client/merged.h | 18 +- engine/client/p_classic.c | 2 +- engine/client/pr_clcmd.c | 20 + engine/client/pr_csqc.c | 4 +- engine/client/pr_menu.c | 9 +- engine/client/pr_skelobj.c | 33 ++ engine/client/quakedef.h | 2 + engine/client/r_surf.c | 3 + engine/client/renderer.c | 22 +- engine/client/snd_dma.c | 14 +- engine/common/cmd.c | 20 +- engine/common/com_mesh.c | 6 +- engine/common/com_mesh.h | 1 + engine/common/com_phys_bullet.cpp | 4 + engine/common/com_phys_ode.c | 262 ++++++------- engine/common/common.c | 18 +- engine/common/common.h | 2 + engine/common/cvar.c | 8 + engine/common/fs.c | 13 +- engine/common/gl_q2bsp.c | 22 ++ engine/common/pr_common.h | 4 +- engine/common/world.h | 2 + engine/gl/gl_alias.c | 4 + engine/gl/gl_backend.c | 445 ++++++++++++---------- engine/gl/gl_model.c | 36 +- engine/gl/gl_model.h | 12 + engine/gl/gl_rlight.c | 135 ++++++- engine/gl/gl_shader.c | 163 +------- engine/gl/gl_shadow.c | 218 ++++++++++- engine/gl/gl_vidcommon.c | 3 +- engine/gl/gl_vidnt.c | 18 +- engine/gl/gl_warp.c | 1 + engine/gl/r_bishaders.h | 29 +- engine/gl/shader.h | 9 +- engine/server/pr_cmds.c | 18 +- engine/server/progdefs.h | 69 ++-- engine/server/progs.h | 2 +- engine/server/q2game.h | 8 +- engine/server/sv_ents.c | 36 +- engine/server/sv_main.c | 8 +- engine/server/sv_move.c | 3 + engine/server/sv_send.c | 53 ++- engine/server/sv_sys_unix.c | 38 +- engine/server/world.c | 56 +-- engine/shaders/glsl/defaultwarp.glsl | 13 +- engine/shaders/glsl/rtlight.glsl | 28 +- fteqtv/protocol.h | 1 + plugins/avplug/avencode.c | 8 + plugins/bullet/bulletplug.cpp | 541 +++++++++++++++------------ plugins/plugin.c | 2 +- plugins/plugin.h | 12 +- specs/rtlights.txt | 12 +- 59 files changed, 1576 insertions(+), 943 deletions(-) diff --git a/engine/Makefile b/engine/Makefile index 98da5e65d..a182cc20f 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -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 diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 9a3df2f1d..54ff640d3 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -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 diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index e47dbf644..69533e845 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -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. diff --git a/engine/client/client.h b/engine/client/client.h index 3d67fae82..b90902bf8 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -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) diff --git a/engine/client/m_download.c b/engine/client/m_download.c index 59a7e6ee3..b1e13e173 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -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"); diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index c076eee8e..eb91ca8f5 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -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/", diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 7851bb024..9e1a74b70 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -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); diff --git a/engine/client/merged.h b/engine/client/merged.h index 5135bfda2..f9b512111 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -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 diff --git a/engine/client/p_classic.c b/engine/client/p_classic.c index b5844cedd..a2818757a 100644 --- a/engine/client/p_classic.c +++ b/engine/client/p_classic.c @@ -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) diff --git a/engine/client/pr_clcmd.c b/engine/client/pr_clcmd.c index 456746661..c17e0707b 100644 --- a/engine/client/pr_clcmd.c +++ b/engine/client/pr_clcmd.c @@ -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 diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 4c110fc63..79440af16 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -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}, diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index ba659f67a..9d6c899d6 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -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); diff --git a/engine/client/pr_skelobj.c b/engine/client/pr_skelobj.c index e60a484c5..7a58f8db7 100644 --- a/engine/client/pr_skelobj.c +++ b/engine/client/pr_skelobj.c @@ -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; diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index fe6dbad83..ae0df45bd 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -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; diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 6dbc9b4d8..15926bab1 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -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 diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 26ded947f..5e42f3693 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -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(); diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index e46c670ba..2bcd7f4e6 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -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) diff --git a/engine/common/cmd.c b/engine/common/cmd.c index e81f98365..de1d0d5b3 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -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"); diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 51eee857b..62d2d4ea0 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -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*/ diff --git a/engine/common/com_mesh.h b/engine/common/com_mesh.h index 5951d80c5..027fc05c3 100644 --- a/engine/common/com_mesh.h +++ b/engine/common/com_mesh.h @@ -66,6 +66,7 @@ struct galiasbone_s { char name[32]; int parent; +// float radius; float inverse[12]; }; diff --git a/engine/common/com_phys_bullet.cpp b/engine/common/com_phys_bullet.cpp index 3497b82ae..c9c7c9550 100644 --- a/engine/common/com_phys_bullet.cpp +++ b/engine/common/com_phys_bullet.cpp @@ -1,3 +1,7 @@ +#include "quakedef.h" + +#ifdef USE_INTERNAL_BULLET #define FTEENGINE #undef FTEPLUGIN #include "../../plugins/bullet/bulletplug.cpp" +#endif \ No newline at end of file diff --git a/engine/common/com_phys_ode.c b/engine/common/com_phys_ode.c index 041fb3998..a1f52067f 100644 --- a/engine/common/com_phys_ode.c +++ b/engine/common/com_phys_ode.c @@ -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; } diff --git a/engine/common/common.c b/engine/common/common.c index 0b9b6a574..82290e700 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -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; diff --git a/engine/common/common.h b/engine/common/common.h index 815bc7258..42d854061 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -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 diff --git a/engine/common/cvar.c b/engine/common/cvar.c index 08b67f4b8..a044095e4 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -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"); diff --git a/engine/common/fs.c b/engine/common/fs.c index 786a004db..25aaf8766 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -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,11 +3700,19 @@ 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, "*")) diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index e48926e31..7c896c6b3 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -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 ; inumenvmaps ; 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; diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 87b87fb1e..432128008 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -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); diff --git a/engine/common/world.h b/engine/common/world.h index 523b1697c..8c0ad2783 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -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 diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index 7994b059b..ba301014d 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -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; } diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index e3d475851..83330818d 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -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,6 +5106,205 @@ static void GLBE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist) } } +static qboolean GLBE_GenerateBatchTextures(batch_t *batch, shader_t *bs) +{ + int oldfbo; + float oldil; + int oldbem; + if (r_refdef.recurse == r_portalrecursion.ival || r_refdef.recurse == R_MAX_RECURSE) + 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) + return false; + oldbem = shaderstate.mode; + oldil = shaderstate.identitylighting; + + if ((bs->flags & SHADER_HASREFLECT) && gl_config.ext_framebuffer_objects) + { + float renderscale = bs->portalfboscale; + vrect_t orect = r_refdef.vrect; + pxrect_t oprect = r_refdef.pxrect; + if (!shaderstate.tex_reflection[r_refdef.recurse]) + { + shaderstate.tex_reflection[r_refdef.recurse] = Image_CreateTexture("***tex_reflection***", NULL, 0); + if (!shaderstate.tex_reflection[r_refdef.recurse]->num) + qglGenTextures(1, &shaderstate.tex_reflection[r_refdef.recurse]->num); + } + + r_refdef.vrect.x = 0; + r_refdef.vrect.y = 0; + r_refdef.vrect.width = max(1, vid.fbvwidth * renderscale); + r_refdef.vrect.height = max(1, vid.fbvheight * renderscale); + r_refdef.pxrect.x = 0; + r_refdef.pxrect.y = 0; + r_refdef.pxrect.width = max(1, vid.fbpwidth * renderscale); + r_refdef.pxrect.height = max(1, vid.fbpheight * renderscale); + if (shaderstate.tex_reflection[r_refdef.recurse]->width!=r_refdef.pxrect.width || shaderstate.tex_reflection[r_refdef.recurse]->height!=r_refdef.pxrect.height) + { + shaderstate.tex_reflection[r_refdef.recurse]->width = r_refdef.pxrect.width; + shaderstate.tex_reflection[r_refdef.recurse]->height = r_refdef.pxrect.height; + GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_reflection[r_refdef.recurse]); + + if ((vid.flags&VID_FP16) && sh_config.texfmt[PTI_RGBA16F]) + qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + else if ((vid.flags&(VID_SRGBAWARE|VID_FP16)) && sh_config.texfmt[PTI_RGBA8_SRGB]) + qglTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8_EXT, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + else + qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac[r_refdef.recurse], FBO_RB_DEPTH, &shaderstate.tex_reflection[r_refdef.recurse], 1, r_nulltex, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0); + r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac[r_refdef.recurse].rb_size[1]; + GL_ViewportUpdate(); + GL_ForceDepthWritable(); + qglClearColor(0, 0, 0, 1); + qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, 1); + GLBE_FBO_Pop(oldfbo); + r_refdef.vrect = orect; + r_refdef.pxrect = oprect; + GL_ViewportUpdate(); + } + if (bs->flags & (SHADER_HASREFRACT|SHADER_HASREFRACTDEPTH)) + { + if (r_refract_fboival || (bs->flags&SHADER_HASPORTAL)) + { + float renderscale = min(1, bs->portalfboscale); + vrect_t ovrect = r_refdef.vrect; + pxrect_t oprect = r_refdef.pxrect; + r_refdef.vrect.x = 0; + r_refdef.vrect.y = 0; + r_refdef.vrect.width = max(1, vid.fbvwidth * renderscale); + r_refdef.vrect.height = max(1, vid.fbvheight * renderscale); + r_refdef.pxrect.x = 0; + r_refdef.pxrect.y = 0; + r_refdef.pxrect.width = max(1, vid.fbpwidth * renderscale); + r_refdef.pxrect.height = max(1, vid.fbpheight * renderscale); + + if (!shaderstate.tex_refraction[r_refdef.recurse]) + { + shaderstate.tex_refraction[r_refdef.recurse] = Image_CreateTexture("***tex_refraction***", NULL, 0); + if (!shaderstate.tex_refraction[r_refdef.recurse]->num) + qglGenTextures(1, &shaderstate.tex_refraction[r_refdef.recurse]->num); + } + if (shaderstate.tex_refraction[r_refdef.recurse]->width != r_refdef.pxrect.width || shaderstate.tex_refraction[r_refdef.recurse]->height != r_refdef.pxrect.height) + { + shaderstate.tex_refraction[r_refdef.recurse]->width = r_refdef.pxrect.width; + shaderstate.tex_refraction[r_refdef.recurse]->height = r_refdef.pxrect.height; + GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_refraction[r_refdef.recurse]); + if ((vid.flags&VID_FP16) && sh_config.texfmt[PTI_RGBA16F]) + qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + else if ((vid.flags&(VID_SRGBAWARE|VID_FP16)) && sh_config.texfmt[PTI_RGBA16F]) + qglTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8_EXT, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + else + qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + if (bs->flags & SHADER_HASREFRACTDEPTH) + { + if (!shaderstate.tex_refractiondepth[r_refdef.recurse]) + { + shaderstate.tex_refractiondepth[r_refdef.recurse] = Image_CreateTexture("***tex_refractiondepth***", NULL, 0); + if (!shaderstate.tex_refractiondepth[r_refdef.recurse]->num) + qglGenTextures(1, &shaderstate.tex_refractiondepth[r_refdef.recurse]->num); + } + if (shaderstate.tex_refractiondepth[r_refdef.recurse]->width != r_refdef.pxrect.width || shaderstate.tex_refractiondepth[r_refdef.recurse]->height != r_refdef.pxrect.height) + { + shaderstate.tex_refractiondepth[r_refdef.recurse]->width = r_refdef.pxrect.width; + shaderstate.tex_refractiondepth[r_refdef.recurse]->height = r_refdef.pxrect.height; + GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_refractiondepth[r_refdef.recurse]); + qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24_ARB, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac[r_refdef.recurse], FBO_TEX_DEPTH, &shaderstate.tex_refraction[r_refdef.recurse], 1, shaderstate.tex_refractiondepth[r_refdef.recurse], r_refdef.pxrect.width, r_refdef.pxrect.height, 0); + } + else + { + oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac[r_refdef.recurse], FBO_RB_DEPTH, &shaderstate.tex_refraction[r_refdef.recurse], 1, r_nulltex, r_refdef.pxrect.width, r_refdef.pxrect.height, 0); + } + r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac[r_refdef.recurse].rb_size[1]; + GL_ViewportUpdate(); + + GL_ForceDepthWritable(); + qglClearColor(0, 0, 0, 1); + qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (bs->flags&SHADER_HASPORTAL) + GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, 0); + else + GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, ((bs->flags & SHADER_HASREFRACTDEPTH)?3:2)); //fixme + GLBE_FBO_Pop(oldfbo); + + r_refdef.vrect = ovrect; + r_refdef.pxrect = oprect; + GL_ViewportUpdate(); + } + else + GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, 3); + } + if ((bs->flags & SHADER_HASRIPPLEMAP) && gl_config.ext_framebuffer_objects) + { + float renderscale = bs->portalfboscale; + vrect_t orect = r_refdef.vrect; + pxrect_t oprect = r_refdef.pxrect; + r_refdef.vrect.x = 0; + r_refdef.vrect.y = 0; + r_refdef.vrect.width = max(1, vid.fbvwidth * renderscale); + r_refdef.vrect.height = max(1, vid.fbvheight * renderscale); + r_refdef.pxrect.x = 0; + r_refdef.pxrect.y = 0; + r_refdef.pxrect.width = max(1, vid.fbpwidth * renderscale); + r_refdef.pxrect.height = max(1, vid.fbpheight * renderscale); + + if (!shaderstate.tex_ripplemap[r_refdef.recurse]) + { + //FIXME: can we use RGB8 instead? + shaderstate.tex_ripplemap[r_refdef.recurse] = Image_CreateTexture("***tex_ripplemap***", NULL, 0); + if (!shaderstate.tex_ripplemap[r_refdef.recurse]->num) + qglGenTextures(1, &shaderstate.tex_ripplemap[r_refdef.recurse]->num); + } + if (shaderstate.tex_ripplemap[r_refdef.recurse]->width != r_refdef.pxrect.width || shaderstate.tex_ripplemap[r_refdef.recurse]->height != r_refdef.pxrect.height) + { + shaderstate.tex_ripplemap[r_refdef.recurse]->width = r_refdef.pxrect.width; + shaderstate.tex_ripplemap[r_refdef.recurse]->height = r_refdef.pxrect.height; + GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_ripplemap[r_refdef.recurse]); + qglTexImage2D(GL_TEXTURE_2D, 0, /*(gl_config.glversion>3.1)?GL_RGBA8_SNORM:*/GL_RGBA16F_ARB, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_HALF_FLOAT, NULL); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac[r_refdef.recurse], 0, &shaderstate.tex_ripplemap[r_refdef.recurse], 1, r_nulltex, r_refdef.pxrect.width, r_refdef.pxrect.height, 0); + r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac[r_refdef.recurse].rb_size[1]; + GL_ViewportUpdate(); + + qglClearColor(0, 0, 0, 1); + qglClear(GL_COLOR_BUFFER_BIT); + +// r_refdef.waterheight = DotProduct(batch->mesh[0]->xyz_array[0], batch->mesh[0]->normals_array[0]); + + r_refdef.recurse+=1; //paranoid, should stop potential infinite loops + GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_RIPPLE, SHADER_SORT_RIPPLE); + r_refdef.recurse-=1; + GLBE_FBO_Pop(oldfbo); + + r_refdef.vrect = orect; + r_refdef.pxrect = oprect; + GL_ViewportUpdate(); + } + BE_SelectMode(oldbem); + shaderstate.identitylighting = oldil; + return true; +} static void GLBE_SubmitMeshesSortList(batch_t *sortlist) { batch_t *batch; @@ -5117,202 +5364,8 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) } 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) + if (!GLBE_GenerateBatchTextures(batch, bs)) continue; - //these flags require rendering some view as an fbo - if (shaderstate.mode != BEM_STANDARD && shaderstate.mode != BEM_DEPTHDARK) - continue; - oldbem = shaderstate.mode; - oldil = shaderstate.identitylighting; - - if ((bs->flags & SHADER_HASREFLECT) && gl_config.ext_framebuffer_objects) - { - float renderscale = bs->portalfboscale; - vrect_t orect = r_refdef.vrect; - pxrect_t oprect = r_refdef.pxrect; - if (!shaderstate.tex_reflection[r_refdef.recurse]) - { - shaderstate.tex_reflection[r_refdef.recurse] = Image_CreateTexture("***tex_reflection***", NULL, 0); - if (!shaderstate.tex_reflection[r_refdef.recurse]->num) - qglGenTextures(1, &shaderstate.tex_reflection[r_refdef.recurse]->num); - } - - r_refdef.vrect.x = 0; - r_refdef.vrect.y = 0; - r_refdef.vrect.width = max(1, vid.fbvwidth * renderscale); - r_refdef.vrect.height = max(1, vid.fbvheight * renderscale); - r_refdef.pxrect.x = 0; - r_refdef.pxrect.y = 0; - r_refdef.pxrect.width = max(1, vid.fbpwidth * renderscale); - r_refdef.pxrect.height = max(1, vid.fbpheight * renderscale); - if (shaderstate.tex_reflection[r_refdef.recurse]->width!=r_refdef.pxrect.width || shaderstate.tex_reflection[r_refdef.recurse]->height!=r_refdef.pxrect.height) - { - shaderstate.tex_reflection[r_refdef.recurse]->width = r_refdef.pxrect.width; - shaderstate.tex_reflection[r_refdef.recurse]->height = r_refdef.pxrect.height; - GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_reflection[r_refdef.recurse]); - - if ((vid.flags&VID_FP16) && sh_config.texfmt[PTI_RGBA16F]) - qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - else if ((vid.flags&(VID_SRGBAWARE|VID_FP16)) && sh_config.texfmt[PTI_RGBA8_SRGB]) - qglTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8_EXT, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - else - qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac[r_refdef.recurse], FBO_RB_DEPTH, &shaderstate.tex_reflection[r_refdef.recurse], 1, r_nulltex, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0); - r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac[r_refdef.recurse].rb_size[1]; - GL_ViewportUpdate(); - GL_ForceDepthWritable(); - qglClearColor(0, 0, 0, 1); - qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, 1); - GLBE_FBO_Pop(oldfbo); - r_refdef.vrect = orect; - r_refdef.pxrect = oprect; - GL_ViewportUpdate(); - } - if (bs->flags & (SHADER_HASREFRACT|SHADER_HASREFRACTDEPTH)) - { - if (r_refract_fboival || (bs->flags&SHADER_HASPORTAL)) - { - float renderscale = min(1, bs->portalfboscale); - vrect_t ovrect = r_refdef.vrect; - pxrect_t oprect = r_refdef.pxrect; - r_refdef.vrect.x = 0; - r_refdef.vrect.y = 0; - r_refdef.vrect.width = max(1, vid.fbvwidth * renderscale); - r_refdef.vrect.height = max(1, vid.fbvheight * renderscale); - r_refdef.pxrect.x = 0; - r_refdef.pxrect.y = 0; - r_refdef.pxrect.width = max(1, vid.fbpwidth * renderscale); - r_refdef.pxrect.height = max(1, vid.fbpheight * renderscale); - - if (!shaderstate.tex_refraction[r_refdef.recurse]) - { - shaderstate.tex_refraction[r_refdef.recurse] = Image_CreateTexture("***tex_refraction***", NULL, 0); - if (!shaderstate.tex_refraction[r_refdef.recurse]->num) - qglGenTextures(1, &shaderstate.tex_refraction[r_refdef.recurse]->num); - } - if (shaderstate.tex_refraction[r_refdef.recurse]->width != r_refdef.pxrect.width || shaderstate.tex_refraction[r_refdef.recurse]->height != r_refdef.pxrect.height) - { - shaderstate.tex_refraction[r_refdef.recurse]->width = r_refdef.pxrect.width; - shaderstate.tex_refraction[r_refdef.recurse]->height = r_refdef.pxrect.height; - GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_refraction[r_refdef.recurse]); - if ((vid.flags&VID_FP16) && sh_config.texfmt[PTI_RGBA16F]) - qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - else if ((vid.flags&(VID_SRGBAWARE|VID_FP16)) && sh_config.texfmt[PTI_RGBA16F]) - qglTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8_EXT, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - else - qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - if (bs->flags & SHADER_HASREFRACTDEPTH) - { - if (!shaderstate.tex_refractiondepth[r_refdef.recurse]) - { - shaderstate.tex_refractiondepth[r_refdef.recurse] = Image_CreateTexture("***tex_refractiondepth***", NULL, 0); - if (!shaderstate.tex_refractiondepth[r_refdef.recurse]->num) - qglGenTextures(1, &shaderstate.tex_refractiondepth[r_refdef.recurse]->num); - } - if (shaderstate.tex_refractiondepth[r_refdef.recurse]->width != r_refdef.pxrect.width || shaderstate.tex_refractiondepth[r_refdef.recurse]->height != r_refdef.pxrect.height) - { - shaderstate.tex_refractiondepth[r_refdef.recurse]->width = r_refdef.pxrect.width; - shaderstate.tex_refractiondepth[r_refdef.recurse]->height = r_refdef.pxrect.height; - GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_refractiondepth[r_refdef.recurse]); - qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24_ARB, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac[r_refdef.recurse], FBO_TEX_DEPTH, &shaderstate.tex_refraction[r_refdef.recurse], 1, shaderstate.tex_refractiondepth[r_refdef.recurse], r_refdef.pxrect.width, r_refdef.pxrect.height, 0); - } - else - { - oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac[r_refdef.recurse], FBO_RB_DEPTH, &shaderstate.tex_refraction[r_refdef.recurse], 1, r_nulltex, r_refdef.pxrect.width, r_refdef.pxrect.height, 0); - } - r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac[r_refdef.recurse].rb_size[1]; - GL_ViewportUpdate(); - - GL_ForceDepthWritable(); - qglClearColor(0, 0, 0, 1); - qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - if (bs->flags&SHADER_HASPORTAL) - GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, 0); - else - GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, ((bs->flags & SHADER_HASREFRACTDEPTH)?3:2)); //fixme - GLBE_FBO_Pop(oldfbo); - - r_refdef.vrect = ovrect; - r_refdef.pxrect = oprect; - GL_ViewportUpdate(); - } - else - GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, 3); - } - if ((bs->flags & SHADER_HASRIPPLEMAP) && gl_config.ext_framebuffer_objects) - { - float renderscale = bs->portalfboscale; - vrect_t orect = r_refdef.vrect; - pxrect_t oprect = r_refdef.pxrect; - r_refdef.vrect.x = 0; - r_refdef.vrect.y = 0; - r_refdef.vrect.width = max(1, vid.fbvwidth * renderscale); - r_refdef.vrect.height = max(1, vid.fbvheight * renderscale); - r_refdef.pxrect.x = 0; - r_refdef.pxrect.y = 0; - r_refdef.pxrect.width = max(1, vid.fbpwidth * renderscale); - r_refdef.pxrect.height = max(1, vid.fbpheight * renderscale); - - if (!shaderstate.tex_ripplemap[r_refdef.recurse]) - { - //FIXME: can we use RGB8 instead? - shaderstate.tex_ripplemap[r_refdef.recurse] = Image_CreateTexture("***tex_ripplemap***", NULL, 0); - if (!shaderstate.tex_ripplemap[r_refdef.recurse]->num) - qglGenTextures(1, &shaderstate.tex_ripplemap[r_refdef.recurse]->num); - } - if (shaderstate.tex_ripplemap[r_refdef.recurse]->width != r_refdef.pxrect.width || shaderstate.tex_ripplemap[r_refdef.recurse]->height != r_refdef.pxrect.height) - { - shaderstate.tex_ripplemap[r_refdef.recurse]->width = r_refdef.pxrect.width; - shaderstate.tex_ripplemap[r_refdef.recurse]->height = r_refdef.pxrect.height; - GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_ripplemap[r_refdef.recurse]); - qglTexImage2D(GL_TEXTURE_2D, 0, /*(gl_config.glversion>3.1)?GL_RGBA8_SNORM:*/GL_RGBA16F_ARB, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_HALF_FLOAT, NULL); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac[r_refdef.recurse], 0, &shaderstate.tex_ripplemap[r_refdef.recurse], 1, r_nulltex, r_refdef.pxrect.width, r_refdef.pxrect.height, 0); - r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac[r_refdef.recurse].rb_size[1]; - GL_ViewportUpdate(); - - qglClearColor(0, 0, 0, 1); - qglClear(GL_COLOR_BUFFER_BIT); - -// r_refdef.waterheight = DotProduct(batch->mesh[0]->xyz_array[0], batch->mesh[0]->normals_array[0]); - - r_refdef.recurse+=1; //paranoid, should stop potential infinite loops - GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_RIPPLE, SHADER_SORT_RIPPLE); - r_refdef.recurse-=1; - GLBE_FBO_Pop(oldfbo); - - r_refdef.vrect = orect; - r_refdef.pxrect = oprect; - GL_ViewportUpdate(); - } - BE_SelectMode(oldbem); - shaderstate.identitylighting = oldil; - } GLBE_SubmitBatch(batch); } diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 650a96ce1..d1640c0eb 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -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))) - out->flags |= TI_FLOWING; + 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,14 +3909,17 @@ 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); - for (i=0 ; i<2 ; i++) + out->flags |= SURF_DRAWTURB; + if (out->texinfo->flags & TEX_SPECIAL) { - out->extents[i] = 16384; - out->texturemins[i] = -8192; + out->flags |= SURF_DRAWTILED; + for (i=0 ; i<2 ; i++) + { + out->extents[i] = 16384; + out->texturemins[i] = -8192; + } } continue; } diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 9dc32cb7c..ab5332641 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -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; diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index 8b350ce1b..8d7e1b5da 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -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; } diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index f60f3f0a0..aaa547d17 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -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). diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index ac8cd6c8e..4a25433ac 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -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,8 +1614,13 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi { SHM_BeginShadowMesh(dl, type); - SHM_MarkLeavesQ1(dl, lvis); - SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes); + if (type == SMT_ORTHO) + SHM_OrthoWorldLeafsQ1(dl); + else + { + SHM_MarkLeavesQ1(dl, lvis); + SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes); + } } break; #ifdef Q2BSPS @@ -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); - sh_shadowframe++; - SHM_RecursiveWorldNodeQ3_r(dl, cl.worldmodel->nodes); + 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) { diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index eee1dd0bb..12d2d9f7a 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -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 diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 4cf4f8bdf..f49ee7bc1 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -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: diff --git a/engine/gl/gl_warp.c b/engine/gl/gl_warp.c index 4f65ad7b0..c875afee3 100644 --- a/engine/gl/gl_warp.c +++ b/engine/gl/gl_warp.c @@ -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; diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index 31d7c0475..25816aa66 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -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" diff --git a/engine/gl/shader.h b/engine/gl/shader.h index eaf820fba..37fba4941 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -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) diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index b36bd7238..990559bf0 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -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}, diff --git a/engine/server/progdefs.h b/engine/server/progdefs.h index 90bf24606..7dd25209a 100644 --- a/engine/server/progdefs.h +++ b/engine/server/progdefs.h @@ -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 diff --git a/engine/server/progs.h b/engine/server/progs.h index f67adcce2..3dbb52648 100644 --- a/engine/server/progs.h +++ b/engine/server/progs.h @@ -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*/ diff --git a/engine/server/q2game.h b/engine/server/q2game.h index df1dc4b14..5a75be6d9 100644 --- a/engine/server/q2game.h +++ b/engine/server/q2game.h @@ -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; diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index ba8757be2..4456c269a 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -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; } diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 09afc21ee..4ddc2805c 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -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 diff --git a/engine/server/sv_move.c b/engine/server/sv_move.c index e6e83c839..0530afeab 100644 --- a/engine/server/sv_move.c +++ b/engine/server/sv_move.c @@ -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; ============= diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 78c22954a..ec2af0d99 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -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); } diff --git a/engine/server/sv_sys_unix.c b/engine/server/sv_sys_unix.c index 5586fcaad..785138c0b 100644 --- a/engine/server/sv_sys_unix.c +++ b/engine/server/sv_sys_unix.c @@ -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: diff --git a/engine/server/world.c b/engine/server/world.c index 73d5e863d..3deab7fd3 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -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 diff --git a/engine/shaders/glsl/defaultwarp.glsl b/engine/shaders/glsl/defaultwarp.glsl index 7b6c153d1..19bcc43ab 100644 --- a/engine/shaders/glsl/defaultwarp.glsl +++ b/engine/shaders/glsl/defaultwarp.glsl @@ -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 diff --git a/engine/shaders/glsl/rtlight.glsl b/engine/shaders/glsl/rtlight.glsl index f14bba633..ab477d108 100644 --- a/engine/shaders/glsl/rtlight.glsl +++ b/engine/shaders/glsl/rtlight.glsl @@ -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 - vec3 lightminusvertex = l_lightposition - w.xyz; -#ifdef NOBUMP - //the only important thing is distance - lightvector = lightminusvertex; -#else - //the light direction relative to the surface normal, for bumpmapping. +#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 + //the only important thing is distance + lightvector = lightminusvertex; + #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 diff --git a/fteqtv/protocol.h b/fteqtv/protocol.h index d9e1e66c0..482769ec6 100644 --- a/fteqtv/protocol.h +++ b/fteqtv/protocol.h @@ -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) diff --git a/plugins/avplug/avencode.c b/plugins/avplug/avencode.c index 4e75f0cc8..fb06a3c5c 100644 --- a/plugins/avplug/avencode.c +++ b/plugins/avplug/avencode.c @@ -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 diff --git a/plugins/bullet/bulletplug.cpp b/plugins/bullet/bulletplug.cpp index edaf7be5a..6fea115ab 100644 --- a/plugins/bullet/bulletplug.cpp +++ b/plugins/bullet/bulletplug.cpp @@ -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); */ } diff --git a/plugins/plugin.c b/plugins/plugin.c index 2e87cc485..86199f43a 100644 --- a/plugins/plugin.c +++ b/plugins/plugin.c @@ -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; } diff --git a/plugins/plugin.h b/plugins/plugin.h index f451bc15c..9e75a2d49 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -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 diff --git a/specs/rtlights.txt b/specs/rtlights.txt index 6ca864630..2038014d1 100644 --- a/specs/rtlights.txt +++ b/specs/rtlights.txt @@ -19,4 +19,14 @@ gl_specular: makes surfaces shiny. aka: gloss. at the time of writing, r_polygonoffset_* need to be set to 0, or you'll get pure black doors and stuff, doing so will renable z-fighting with co-planer bsp objects. To Be Fixed. 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. \ No newline at end of file +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. \ No newline at end of file