From: divverent Date: Sun, 28 Feb 2010 19:35:36 +0000 (+0000) Subject: WarpZones: X-Git-Tag: xonotic-v0.1.0preview~230^2~434 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=f2467d484c38a13d23bb92f91c19a9d6a71f7bec;p=xonotic%2Fdarkplaces.git WarpZones: - entities with a camera_transform function field arguments: vector origin, vector angles global input: v_forward, v_right, v_up = camera orientation return value: new origin global output: v_forward, v_right, v_up = new camera orientation global output: trace_endpos = origin on "remote side" for culling purposes - on server, only the trace_endpos return value is used, and '0 0 0' angles are passed, and only the trace_endpos is used (this may be subject to change) - a warpzone is an above described entity that contains a surface of a shader that uses the keywords dp_camera AND dp_refract - a camera is an above described entity that contains a surface of a shader that JUST uses the keyword dp_camera - in case of a camera, preferably the camera_transform function shall not use the input values (except for use for certain special effects) - rendering of these warpzones is not recursive (yet) - the warpzones do not have any impact on gameplay - QC support code is needed both on client and server - example support code will be committed to Nexuiz SVN - the interface is not stable yet and may be subject to change git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10035 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/cl_screen.c b/cl_screen.c index 8e727ecf..f561a457 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -1353,8 +1353,8 @@ static void R_Envmap_f (void) r_refdef.view.useperspective = true; r_refdef.view.isoverlay = false; - r_refdef.view.frustum_x = tan(90 * M_PI / 360.0); - r_refdef.view.frustum_y = tan(90 * M_PI / 360.0); + r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0); + r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0); buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3); buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3); diff --git a/csprogs.c b/csprogs.c index 966a12ce..d8a39675 100644 --- a/csprogs.c +++ b/csprogs.c @@ -174,7 +174,7 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum) return false; entrender = cl.csqcrenderentities + edictnum; r_refdef.scene.entities[r_refdef.scene.numentities++] = entrender; - entrender->entitynumber = edictnum; + entrender->entitynumber = edictnum + MAX_EDICTS; //entrender->shadertime = 0; // shadertime was set by spawn() entrender->flags = 0; entrender->alpha = 1; @@ -1045,3 +1045,54 @@ qboolean CL_VM_GetEntitySoundOrigin(int entnum, vec3_t out) return r; } + +qboolean CL_VM_TransformView(int entnum, matrix4x4_t *viewmatrix, mplane_t *clipplane, vec3_t visorigin) +{ + qboolean ret = false; + prvm_edict_t *ed; + prvm_eval_t *val, *valforward, *valright, *valup, *valendpos; + vec3_t forward, left, up, origin, ang; + matrix4x4_t mat, matq; + + CSQC_BEGIN + ed = PRVM_EDICT_NUM(entnum); + // camera: + // camera_transform + if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.camera_transform)) && val->function) + { + ret = true; + if(viewmatrix || clipplane || visorigin) + { + valforward = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_forward); + valright = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_right); + valup = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_up); + valendpos = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_endpos); + if(valforward && valright && valup && valendpos) + { + Matrix4x4_ToVectors(viewmatrix, forward, left, up, origin); + AnglesFromVectors(ang, forward, up, false); + prog->globals.client->time = cl.time; + prog->globals.client->self = entnum; + VectorCopy(origin, PRVM_G_VECTOR(OFS_PARM0)); + VectorCopy(ang, PRVM_G_VECTOR(OFS_PARM1)); + VectorCopy(forward, valforward->vector); + VectorScale(left, -1, valright->vector); + VectorCopy(up, valup->vector); + VectorCopy(origin, valendpos->vector); + PRVM_ExecuteProgram(val->function, "QC function e.camera_transform is missing"); + VectorCopy(PRVM_G_VECTOR(OFS_RETURN), origin); + VectorCopy(valforward->vector, forward); + VectorScale(valright->vector, -1, left); + VectorCopy(valup->vector, up); + VectorCopy(valendpos->vector, visorigin); + Matrix4x4_Invert_Full(&mat, viewmatrix); + Matrix4x4_FromVectors(viewmatrix, forward, left, up, origin); + Matrix4x4_Concat(&matq, viewmatrix, &mat); + Matrix4x4_TransformPositivePlane(&matq, clipplane->normal[0], clipplane->normal[1], clipplane->normal[2], clipplane->dist, &clipplane->normal[0]); + } + } + } + CSQC_END + + return ret; +} diff --git a/csprogs.h b/csprogs.h index 6e2e517c..bb0a3fb8 100644 --- a/csprogs.h +++ b/csprogs.h @@ -64,4 +64,6 @@ qboolean MakeDownloadPacket(const char *filename, unsigned char *data, size_t le qboolean CL_VM_GetEntitySoundOrigin(int entnum, vec3_t out); +qboolean CL_VM_TransformView(int entnum, matrix4x4_t *viewmatrix, mplane_t *clipplane, vec3_t visorigin); + #endif diff --git a/gl_rmain.c b/gl_rmain.c index 23b4035d..ccc6e54d 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "polygon.h" #include "image.h" #include "ft2.h" +#include "csprogs.h" mempool_t *r_main_mempool; rtexturepool_t *r_main_texturepool; @@ -75,6 +76,7 @@ cvar_t r_showdisabledepthtest = {0, "r_showdisabledepthtest", "0", "disables dep cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"}; cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"}; cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"}; +cvar_t r_drawexteriormodel = {0, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"}; cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"}; cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"}; cvar_t r_cullentities_trace_tempentitysamples = {0, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"}; @@ -4481,8 +4483,13 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, // distorted background if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER) mode = SHADERMODE_WATER; - else + else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFRACTION) mode = SHADERMODE_REFRACTION; + else + { + mode = SHADERMODE_GENERIC; + permutation |= SHADERPERMUTATION_DIFFUSE; + } R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset); R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset); @@ -6336,6 +6343,7 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_cullentities_trace_enlarge); Cvar_RegisterVariable(&r_cullentities_trace_delay); Cvar_RegisterVariable(&r_drawviewmodel); + Cvar_RegisterVariable(&r_drawexteriormodel); Cvar_RegisterVariable(&r_speeds); Cvar_RegisterVariable(&r_fullbrights); Cvar_RegisterVariable(&r_wateralpha); @@ -6892,6 +6900,8 @@ static void R_View_UpdateEntityVisible (void) : RENDER_EXTERIORMODEL; if (!r_drawviewmodel.integer) renderimask |= RENDER_VIEWMODEL; + if (!r_drawexteriormodel.integer) + renderimask |= RENDER_EXTERIORMODEL; if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs) { // worldmodel can check visibility @@ -6904,7 +6914,8 @@ static void R_View_UpdateEntityVisible (void) if ((ent->flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL)) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs)) r_refdef.viewcache.entityvisible[i] = true; } - if(r_cullentities_trace.integer && r_refdef.scene.worldmodel->brush.TraceLineOfSight) + if(r_cullentities_trace.integer && r_refdef.scene.worldmodel->brush.TraceLineOfSight && !r_refdef.view.useclipplane) + // sorry, this check doesn't work for portal/reflection/refraction renders as the view origin is not useful for culling { for (i = 0;i < r_refdef.scene.numentities;i++) { @@ -7297,13 +7308,29 @@ void R_ResetViewRendering3D(void) GL_CullFace(r_refdef.view.cullface_back); } +/* +================ +R_RenderView_UpdateViewVectors +================ +*/ +static void R_RenderView_UpdateViewVectors(void) +{ + // break apart the view matrix into vectors for various purposes + // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong + // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc + Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin); + VectorNegate(r_refdef.view.left, r_refdef.view.right); + // make an inverted copy of the view matrix for tracking sprites + Matrix4x4_Invert_Simple(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix); +} + void R_RenderScene(void); void R_RenderWaterPlanes(void); static void R_Water_StartFrame(void) { int i; - int waterwidth, waterheight, texturewidth, textureheight; + int waterwidth, waterheight, texturewidth, textureheight, camerawidth, cameraheight; r_waterstate_waterplane_t *p; if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d) @@ -7327,20 +7354,24 @@ static void R_Water_StartFrame(void) // calculate desired texture sizes // can't use water if the card does not support the texture size if (!r_water.integer || r_showsurfaces.integer) - texturewidth = textureheight = waterwidth = waterheight = 0; + texturewidth = textureheight = waterwidth = waterheight = camerawidth = cameraheight = 0; else if (vid.support.arb_texture_non_power_of_two) { texturewidth = waterwidth; textureheight = waterheight; + camerawidth = waterwidth; + cameraheight = waterheight; } else { for (texturewidth = 1;texturewidth < waterwidth ;texturewidth *= 2); for (textureheight = 1;textureheight < waterheight;textureheight *= 2); + for (camerawidth = 1;camerawidth <= waterwidth; camerawidth *= 2); camerawidth /= 2; + for (cameraheight = 1;cameraheight <= waterheight;cameraheight *= 2); cameraheight /= 2; } // allocate textures as needed - if (r_waterstate.texturewidth != texturewidth || r_waterstate.textureheight != textureheight) + if (r_waterstate.texturewidth != texturewidth || r_waterstate.textureheight != textureheight || r_waterstate.camerawidth != camerawidth || r_waterstate.cameraheight != cameraheight) { r_waterstate.maxwaterplanes = MAX_WATERPLANES; for (i = 0, p = r_waterstate.waterplanes;i < r_waterstate.maxwaterplanes;i++, p++) @@ -7351,10 +7382,15 @@ static void R_Water_StartFrame(void) if (p->texture_reflection) R_FreeTexture(p->texture_reflection); p->texture_reflection = NULL; + if (p->texture_camera) + R_FreeTexture(p->texture_camera); + p->texture_camera = NULL; } memset(&r_waterstate, 0, sizeof(r_waterstate)); r_waterstate.texturewidth = texturewidth; r_waterstate.textureheight = textureheight; + r_waterstate.camerawidth = camerawidth; + r_waterstate.cameraheight = cameraheight; } if (r_waterstate.texturewidth) @@ -7384,8 +7420,13 @@ void R_Water_AddWaterPlane(msurface_t *surface) vec3_t normal; vec3_t center; mplane_t plane; + int cam_ent; r_waterstate_waterplane_t *p; texture_t *t = R_GetCurrentTexture(surface->texture); + cam_ent = t->camera_entity; + if(!(t->currentmaterialflags & MATERIALFLAG_CAMERA)) + cam_ent = 0; + // just use the first triangle with a valid normal for any decisions VectorClear(normal); for (triangleindex = 0, e = rsurface.modelelement3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3) @@ -7415,8 +7456,9 @@ void R_Water_AddWaterPlane(msurface_t *surface) // find a matching plane if there is one for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++) - if (fabs(PlaneDiff(vert[0], &p->plane)) < 1 && fabs(PlaneDiff(vert[1], &p->plane)) < 1 && fabs(PlaneDiff(vert[2], &p->plane)) < 1) - break; + if(p->camera_entity == t->camera_entity) + if (fabs(PlaneDiff(vert[0], &p->plane)) < 1 && fabs(PlaneDiff(vert[1], &p->plane)) < 1 && fabs(PlaneDiff(vert[2], &p->plane)) < 1) + break; if (planeindex >= r_waterstate.maxwaterplanes) return; // nothing we can do, out of planes @@ -7429,16 +7471,20 @@ void R_Water_AddWaterPlane(msurface_t *surface) // clear materialflags and pvs p->materialflags = 0; p->pvsvalid = false; + p->camera_entity = t->camera_entity; } // merge this surface's materialflags into the waterplane p->materialflags |= t->currentmaterialflags; - // merge this surface's PVS into the waterplane - VectorMAM(0.5f, surface->mins, 0.5f, surface->maxs, center); - if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS - && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0) + if(!(p->materialflags & MATERIALFLAG_CAMERA)) { - r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid); - p->pvsvalid = true; + // merge this surface's PVS into the waterplane + VectorMAM(0.5f, surface->mins, 0.5f, surface->maxs, center); + if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS + && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0) + { + r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid); + p->pvsvalid = true; + } } } @@ -7448,6 +7494,7 @@ static void R_Water_ProcessPlanes(void) r_refdef_view_t myview; int planeindex; r_waterstate_waterplane_t *p; + vec3_t visorigin; originalview = r_refdef.view; @@ -7461,6 +7508,13 @@ static void R_Water_ProcessPlanes(void) if (!p->texture_refraction) goto error; } + else if (p->materialflags & MATERIALFLAG_CAMERA) + { + if (!p->texture_camera) + p->texture_camera = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_camera", planeindex), r_waterstate.camerawidth, r_waterstate.cameraheight, NULL, TEXTYPE_COLORBUFFER, TEXF_FORCELINEAR, NULL); + if (!p->texture_camera) + goto error; + } if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)) { @@ -7515,9 +7569,20 @@ static void R_Water_ProcessPlanes(void) { r_waterstate.renderingrefraction = true; r_refdef.view = myview; + r_refdef.view.clipplane = p->plane; VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal); r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist; + + if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity) + { + // we need to perform a matrix transform to render the view... so let's get the transformation matrix + r_waterstate.renderingrefraction = false; // we don't want to hide the player model from these ones + CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin); + R_RenderView_UpdateViewVectors(); + r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false); + } + PlaneClassify(&r_refdef.view.clipplane); R_ResetViewRendering3D(); @@ -7528,6 +7593,47 @@ static void R_Water_ProcessPlanes(void) R_Mesh_CopyToTexture(p->texture_refraction, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); r_waterstate.renderingrefraction = false; } + else if (p->materialflags & MATERIALFLAG_CAMERA) + { + r_refdef.view = myview; + + r_refdef.view.clipplane = p->plane; + VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal); + r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist; + + r_refdef.view.width = r_waterstate.camerawidth; + r_refdef.view.height = r_waterstate.cameraheight; + r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0); + r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0); + + if(p->camera_entity) + { + // we need to perform a matrix transform to render the view... so let's get the transformation matrix + CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin); + } + + // reverse the cullface settings for this render + r_refdef.view.cullface_front = GL_FRONT; + r_refdef.view.cullface_back = GL_BACK; + // also reverse the view matrix + Matrix4x4_ConcatScale3(&r_refdef.view.matrix, 1, -1, 1); + R_RenderView_UpdateViewVectors(); + if(p->camera_entity) + r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false); + + // camera needs no clipplane + r_refdef.view.useclipplane = false; + + PlaneClassify(&r_refdef.view.clipplane); + + R_ResetViewRendering3D(); + R_ClearScreen(r_refdef.fogenabled); + R_View_Update(); + R_RenderScene(); + + R_Mesh_CopyToTexture(p->texture_camera, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_waterstate.renderingrefraction = false; + } } r_waterstate.renderingscene = false; @@ -8243,13 +8349,7 @@ void R_RenderView(void) r_refdef.view.colorscale = r_hdr_scenebrightness.value; - // break apart the view matrix into vectors for various purposes - // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong - // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc - Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin); - VectorNegate(r_refdef.view.left, r_refdef.view.right); - // make an inverted copy of the view matrix for tracking sprites - Matrix4x4_Invert_Simple(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix); + R_RenderView_UpdateViewVectors(); R_Shadow_UpdateWorldLightSelection(); @@ -9074,6 +9174,11 @@ texture_t *R_GetCurrentTexture(texture_t *t) t->update_lastrenderframe = r_textureframe; t->update_lastrenderentity = (void *)ent; + if(ent && ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS) + t->camera_entity = ent->entitynumber; + else + t->camera_entity = 0; + // switch to an alternate material if this is a q1bsp animated material { texture_t *texture = t; @@ -9130,7 +9235,7 @@ texture_t *R_GetCurrentTexture(texture_t *t) if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_waterstate.enabled && !r_refdef.view.isoverlay) t->currentalpha *= t->r_water_wateralpha; if(!r_waterstate.enabled || r_refdef.view.isoverlay) - t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION); + t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA); if (!(rsurface.ent_flags & RENDER_LIGHT)) t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT; else if (rsurface.modeltexcoordlightmap2f == NULL && !(t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) @@ -9153,11 +9258,11 @@ texture_t *R_GetCurrentTexture(texture_t *t) t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND; if (t->currentmaterialflags & MATERIALFLAG_BLENDED) { - if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER)) + if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA)) t->currentmaterialflags &= ~MATERIALFLAG_BLENDED; } else - t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER); + t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA); if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED)) t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH; @@ -10259,6 +10364,8 @@ static void RSurf_BindReflectionForSurface(const msurface_t *surface) bestp = NULL; for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++) { + if(p->camera_entity != rsurface.texture->camera_entity) + continue; d = 0; for (vertexindex = 0, v = rsurface.modelvertex3f + surface->num_firstvertex * 3;vertexindex < surface->num_vertices;vertexindex++, v += 3) { @@ -10276,11 +10383,13 @@ static void RSurf_BindReflectionForSurface(const msurface_t *surface) case RENDERPATH_CGGL: #ifdef SUPPORTCG if (r_cg_permutation->fp_Texture_Refraction) CG_BindTexture(r_cg_permutation->fp_Texture_Refraction, bestp ? bestp->texture_refraction : r_texture_black);CHECKCGERROR + else if (r_cg_permutation->fp_Texture_First) CG_BindTexture(r_cg_permutation->fp_Texture_First, bestp ? bestp->texture_camera : r_texture_black);CHECKCGERROR if (r_cg_permutation->fp_Texture_Reflection) CG_BindTexture(r_cg_permutation->fp_Texture_Reflection, bestp ? bestp->texture_reflection : r_texture_black);CHECKCGERROR #endif break; case RENDERPATH_GL20: if (r_glsl_permutation->loc_Texture_Refraction >= 0) R_Mesh_TexBind(GL20TU_REFRACTION, bestp ? bestp->texture_refraction : r_texture_black); + else if (r_glsl_permutation->loc_Texture_First >= 0) R_Mesh_TexBind(GL20TU_FIRST, bestp ? bestp->texture_camera : r_texture_black); if (r_glsl_permutation->loc_Texture_Reflection >= 0) R_Mesh_TexBind(GL20TU_REFLECTION, bestp ? bestp->texture_reflection : r_texture_black); break; case RENDERPATH_GL13: @@ -10788,7 +10897,7 @@ extern rtexture_t *r_shadow_prepasslightingdiffusetexture; extern rtexture_t *r_shadow_prepasslightingspeculartexture; static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass) { - if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION))) + if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))) return; RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist); if (prepass) @@ -10798,7 +10907,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_DEFERREDGEOMETRY); RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); } - else if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) && !r_waterstate.renderingscene) + else if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)) && !r_waterstate.renderingscene) { // render water or distortion background, then blend surface on top GL_DepthMask(true); diff --git a/gl_rsurf.c b/gl_rsurf.c index acd76992..554fb0fa 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" #include "r_shadow.h" #include "portals.h" +#include "csprogs.h" cvar_t r_ambient = {0, "r_ambient", "0", "brightens map, value is 0-128"}; cvar_t r_lockpvs = {0, "r_lockpvs", "0", "disables pvs switching, allows you to walk around and inspect what is visible from a given location in the map (anything not visible from your current location will not be drawn)"}; @@ -544,10 +545,10 @@ void R_Q1BSP_DrawSky(entity_render_t *ent) R_DrawModelSurfaces(ent, true, true, false, false, false); } -extern void R_Water_AddWaterPlane(msurface_t *surface); +extern void R_Water_AddWaterPlane(msurface_t *surface, int entno); void R_Q1BSP_DrawAddWaterPlanes(entity_render_t *ent) { - int i, j, flagsmask; + int i, j, n, flagsmask; dp_model_t *model = ent->model; msurface_t *surfaces; if (model == NULL) @@ -559,7 +560,7 @@ void R_Q1BSP_DrawAddWaterPlanes(entity_render_t *ent) RSurf_ActiveModelEntity(ent, false, false, false); surfaces = model->data_surfaces; - flagsmask = MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION; + flagsmask = MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA; // add visible surfaces to draw list if (ent == r_refdef.scene.worldentity) @@ -569,16 +570,20 @@ void R_Q1BSP_DrawAddWaterPlanes(entity_render_t *ent) j = model->sortedmodelsurfaces[i]; if (r_refdef.viewcache.world_surfacevisible[j]) if (surfaces[j].texture->basematerialflags & flagsmask) - R_Water_AddWaterPlane(surfaces + j); + R_Water_AddWaterPlane(surfaces + j, 0); } } else { + if(ent->entitynumber >= MAX_EDICTS) // && CL_VM_TransformView(ent->entitynumber - MAX_EDICTS, NULL, NULL, NULL)) + n = ent->entitynumber; + else + n = 0; for (i = 0;i < model->nummodelsurfaces;i++) { j = model->sortedmodelsurfaces[i]; if (surfaces[j].texture->basematerialflags & flagsmask) - R_Water_AddWaterPlane(surfaces + j); + R_Water_AddWaterPlane(surfaces + j, n); } } rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity @@ -1233,7 +1238,7 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface // now figure out what to do with this particular range of surfaces if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL)) continue; - if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION))) + if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))) continue; if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) { diff --git a/model_brush.c b/model_brush.c index e6203723..a5bf318b 100644 --- a/model_brush.c +++ b/model_brush.c @@ -3686,7 +3686,7 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->DrawSky = R_Q1BSP_DrawSky; for (j = 0, surface = &mod->data_surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surface++) - if (surface->texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)) + if (surface->texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) break; if (j < mod->nummodelsurfaces) mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; @@ -7040,7 +7040,7 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->DrawSky = R_Q1BSP_DrawSky; for (j = 0;j < mod->nummodelsurfaces;j++) - if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)) + if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) break; if (j < mod->nummodelsurfaces) mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; diff --git a/model_brush.h b/model_brush.h index 34519383..ab2a5121 100644 --- a/model_brush.h +++ b/model_brush.h @@ -114,6 +114,8 @@ mplane_t; #define MATERIALFLAG_CUSTOMSURFACE 16777216 // causes MATERIALFLAG_BLENDED to render a depth pass before rendering, hiding backfaces and other hidden geometry #define MATERIALFLAG_TRANSDEPTH 33554432 +// like refraction, but doesn't distort etc. +#define MATERIALFLAG_CAMERA 67108864 // combined mask of all attributes that require depth sorted rendering #define MATERIALFLAGMASK_DEPTHSORTED (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST) // combined mask of all attributes that cause some sort of transparency diff --git a/model_shared.c b/model_shared.c index 3d2b877c..0674e723 100644 --- a/model_shared.c +++ b/model_shared.c @@ -1984,6 +1984,10 @@ void Mod_LoadQ3Shaders(void) shader.reflectfactor = atof(parameter[1]); Vector4Set(shader.reflectcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), atof(parameter[5])); } + else if (!strcasecmp(parameter[0], "dpcamera")) + { + shader.textureflags |= Q3TEXTUREFLAG_CAMERA; + } else if (!strcasecmp(parameter[0], "dpwater") && numparameters >= 12) { shader.textureflags |= Q3TEXTUREFLAG_WATERSHADER; @@ -2081,7 +2085,7 @@ void Mod_LoadQ3Shaders(void) } // fix up multiple reflection types if(shader.textureflags & Q3TEXTUREFLAG_WATERSHADER) - shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION); + shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION | Q3TEXTUREFLAG_CAMERA); Q3Shader_AddToHash (&shader); } @@ -2167,6 +2171,8 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool texture->basematerialflags |= MATERIALFLAG_REFLECTION; if (shader->textureflags & Q3TEXTUREFLAG_WATERSHADER) texture->basematerialflags |= MATERIALFLAG_WATERSHADER; + if (shader->textureflags & Q3TEXTUREFLAG_CAMERA) + texture->basematerialflags |= MATERIALFLAG_CAMERA; texture->customblendfunc[0] = GL_ONE; texture->customblendfunc[1] = GL_ZERO; if (shader->numlayers > 0) diff --git a/model_shared.h b/model_shared.h index 40dc7e31..d19c71bf 100644 --- a/model_shared.h +++ b/model_shared.h @@ -207,6 +207,7 @@ shadowmesh_t; #define Q3TEXTUREFLAG_REFRACTION 256 #define Q3TEXTUREFLAG_REFLECTION 512 #define Q3TEXTUREFLAG_WATERSHADER 1024 +#define Q3TEXTUREFLAG_CAMERA 2048 #define Q3PATHLENGTH 64 #define TEXTURE_MAXFRAMES 64 @@ -551,6 +552,7 @@ typedef struct texture_s float reflectfactor; // amount of reflection distort (1.0 = like the cvar specifies) vec4_t reflectcolor4f; // color tint of reflection (including alpha factor) float r_water_wateralpha; // additional wateralpha to apply when r_water is active + int camera_entity; // entity number for use by cameras // offsetmapping dpoffsetmapping_technique_t offsetmapping; diff --git a/progsvm.h b/progsvm.h index 938f29ea..dc7f192a 100644 --- a/progsvm.h +++ b/progsvm.h @@ -266,6 +266,8 @@ typedef struct prvm_prog_fieldoffsets_s int enemy; // ssqc / csqc (physics) int aiment; // ssqc / csqc (physics) int movedir; // ssqc / csqc (physics) + + int camera_transform; // csqc (warpzones) } prvm_prog_fieldoffsets_t; diff --git a/prvm_edict.c b/prvm_edict.c index 1959bc6d..0b8072c5 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -1654,6 +1654,8 @@ void PRVM_FindOffsets(void) prog->fieldoffsets.jointtype = PRVM_ED_FindFieldOffset("jointtype"); prog->fieldoffsets.movedir = PRVM_ED_FindFieldOffset("movedir"); + prog->fieldoffsets.camera_transform = PRVM_ED_FindFieldOffset("camera_transform"); + prog->funcoffsets.CSQC_ConsoleCommand = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand"); prog->funcoffsets.CSQC_Ent_Remove = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove"); prog->funcoffsets.CSQC_Ent_Spawn = PRVM_ED_FindFunctionOffset("CSQC_Ent_Spawn"); diff --git a/quakedef.h b/quakedef.h index c680ccd5..b308f60e 100644 --- a/quakedef.h +++ b/quakedef.h @@ -85,6 +85,7 @@ extern char engineversion[128]; #define MAX_SAVEGAMES 12 #define SAVEGAME_COMMENT_LENGTH 39 #define MAX_CLIENTNETWORKEYES 2 +#define MAX_LEVELNETWORKEYES 0 // no portal support #define MAX_OCCLUSION_QUERIES 256 #define MAX_WATERPLANES 2 @@ -147,7 +148,8 @@ extern char engineversion[128]; #define MAX_DEMONAME 16 ///< max demo name length for demos command #define MAX_SAVEGAMES 12 ///< max savegames listed in savegame menu #define SAVEGAME_COMMENT_LENGTH 39 ///< max comment length of savegame in menu -#define MAX_CLIENTNETWORKEYES 2 ///< max number of locations that can be added to pvs when culling network entities (must be at least 2 for prediction) +#define MAX_CLIENTNETWORKEYES 8 ///< max number of locations that can be added to pvs when culling network entities (must be at least 2 for prediction) +#define MAX_LEVELNETWORKEYES 64 ///< max number of locations that can be added to pvs when culling network entities (must be at least 2 for prediction) #define MAX_OCCLUSION_QUERIES 4096 ///< max number of GL_ARB_occlusion_query objects that can be used in one frame #define MAX_WATERPLANES 16 ///< max number of water planes visible (each one causes additional view renders) diff --git a/r_shadow.c b/r_shadow.c index 67449fc6..8a23ca0e 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -4520,26 +4520,34 @@ void R_DrawModelShadows(void) { if(ent->entitynumber != 0) { - // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities) - int entnum, entnum2, recursion; - entnum = entnum2 = ent->entitynumber; - for(recursion = 32; recursion > 0; --recursion) + if(ent->entitynumber >= MAX_EDICTS) // csqc entity { - entnum2 = cl.entities[entnum].state_current.tagentity; - if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2]) - entnum = entnum2; - else - break; + // FIXME handle this + VectorNegate(ent->modellight_lightdir, relativelightdirection); } - if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain + else { - VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection); - // transform into modelspace of OUR entity - Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp); - Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection); + // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities) + int entnum, entnum2, recursion; + entnum = entnum2 = ent->entitynumber; + for(recursion = 32; recursion > 0; --recursion) + { + entnum2 = cl.entities[entnum].state_current.tagentity; + if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2]) + entnum = entnum2; + else + break; + } + if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain + { + VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection); + // transform into modelspace of OUR entity + Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp); + Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection); + } + else + VectorNegate(ent->modellight_lightdir, relativelightdirection); } - else - VectorNegate(ent->modellight_lightdir, relativelightdirection); } else VectorNegate(ent->modellight_lightdir, relativelightdirection); diff --git a/render.h b/render.h index 31a83672..aa84b231 100644 --- a/render.h +++ b/render.h @@ -477,10 +477,12 @@ typedef struct r_waterstate_waterplane_s { rtexture_t *texture_refraction; rtexture_t *texture_reflection; + rtexture_t *texture_camera; mplane_t plane; int materialflags; // combined flags of all water surfaces on this plane unsigned char pvsbits[(MAX_MAP_LEAFS+7)>>3]; // FIXME: buffer overflow on huge maps qboolean pvsvalid; + int camera_entity; } r_waterstate_waterplane_t; @@ -493,6 +495,7 @@ typedef struct r_waterstate_s int waterwidth, waterheight; int texturewidth, textureheight; + int camerawidth, cameraheight; int maxwaterplanes; // same as MAX_WATERPLANES int numwaterplanes; diff --git a/sv_main.c b/sv_main.c index b66d7167..87c8af6f 100644 --- a/sv_main.c +++ b/sv_main.c @@ -1584,6 +1584,85 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) sv.sententities[s->number] = sv.sententitiesmark; } +#if MAX_LEVELNETWORKEYES > 0 +#define MAX_EYE_RECURSION 1 // increase if recursion gets supported by portals +void SV_AddCameraEyes(void) +{ + int e, i, j, k; + prvm_edict_t *ed; + int cameras[MAX_LEVELNETWORKEYES]; + vec3_t camera_origins[MAX_LEVELNETWORKEYES]; + int eye_levels[MAX_CLIENTNETWORKEYES]; + int n_cameras = 0; + vec3_t mi, ma; + prvm_eval_t *valendpos, *val; + + if(!prog->fieldoffsets.camera_transform) + return; + valendpos = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_endpos); + if(!valendpos) + return; + + for(i = 0; i < sv.writeentitiestoclient_numeyes; ++i) + eye_levels[i] = 0; + + // check line of sight to portal entities and add them to PVS + for (e = 1, ed = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ed = PRVM_NEXT_EDICT(ed)) + { + if (!ed->priv.server->free) + { + if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.camera_transform)) && val->function) + { + prog->globals.server->self = e; + prog->globals.server->other = sv.writeentitiestoclient_cliententitynumber; + VectorCopy(sv.writeentitiestoclient_eyes[0], valendpos->vector); + VectorCopy(sv.writeentitiestoclient_eyes[0], PRVM_G_VECTOR(OFS_PARM0)); + VectorClear(PRVM_G_VECTOR(OFS_PARM1)); + PRVM_ExecuteProgram(val->function, "QC function e.camera_transform is missing"); + if(!VectorCompare(valendpos->vector, sv.writeentitiestoclient_eyes[0])) + VectorCopy(valendpos->vector, camera_origins[n_cameras]); + cameras[n_cameras] = e; + ++n_cameras; + if(n_cameras >= MAX_LEVELNETWORKEYES) + break; + } + } + } + + if(!n_cameras) + return; + + // i is loop counter, is reset to 0 when an eye got added + // j is camera index to check + for(i = 0, j = 0; sv.writeentitiestoclient_numeyes < MAX_CLIENTNETWORKEYES && i < n_cameras; ++i, ++j, j %= n_cameras) + { + if(!cameras[j]) + continue; + ed = PRVM_EDICT_NUM(cameras[j]); + VectorAdd(ed->fields.server->origin, ed->fields.server->mins, mi); + VectorAdd(ed->fields.server->origin, ed->fields.server->maxs, ma); + for(k = 0; k < sv.writeentitiestoclient_numeyes; ++k) + if(eye_levels[k] <= MAX_EYE_RECURSION) + { + if(SV_CanSeeBox(sv_cullentities_trace_samples.integer, sv_cullentities_trace_enlarge.value, sv.writeentitiestoclient_eyes[k], mi, ma)) + { + eye_levels[sv.writeentitiestoclient_numeyes] = eye_levels[k] + 1; + VectorCopy(camera_origins[j], sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]); + // Con_Printf("added eye %d: %f %f %f because we can see %f %f %f .. %f %f %f from eye %d\n", j, sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes][0], sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes][1], sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes][2], mi[0], mi[1], mi[2], ma[0], ma[1], ma[2], k); + sv.writeentitiestoclient_numeyes++; + cameras[j] = 0; + i = 0; + break; + } + } + } +} +#else +void SV_AddCameraEyes(void) +{ +} +#endif + void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int maxsize) { qboolean need_empty = false; @@ -1634,7 +1713,12 @@ void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t * // Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n"); } - // TODO: check line of sight to portal entities and add them to PVS + SV_AddCameraEyes(); + + // build PVS from the new eyes + if (sv.worldmodel && sv.worldmodel->brush.FatPVS) + for(i = 1; i < sv.writeentitiestoclient_numeyes; ++i) + sv.writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv.writeentitiestoclient_eyes[i], 8, sv.writeentitiestoclient_pvs, sizeof(sv.writeentitiestoclient_pvs), sv.writeentitiestoclient_pvsbytes != 0); sv.sententitiesmark++; diff --git a/sv_phys.c b/sv_phys.c index 13a0cc15..d7ae93f4 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -1128,16 +1128,14 @@ qboolean SV_RunThink (prvm_edict_t *ent) SV_Impact Two entities have touched, so run their touch functions -returns true if the impact kept the origin of the touching entity intact ================== */ extern void VM_SetTraceGlobals(const trace_t *trace); extern sizebuf_t vm_tempstringsbuf; -qboolean SV_Impact (prvm_edict_t *e1, trace_t *trace) +void SV_Impact (prvm_edict_t *e1, trace_t *trace) { int restorevm_tempstringsbuf_cursize; int old_self, old_other; - vec3_t org; prvm_edict_t *e2 = (prvm_edict_t *)trace->ent; prvm_eval_t *val; @@ -1145,8 +1143,6 @@ qboolean SV_Impact (prvm_edict_t *e1, trace_t *trace) old_other = prog->globals.server->other; restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; - VectorCopy(e1->fields.server->origin, org); - VM_SetTraceGlobals(trace); prog->globals.server->time = sv.time; @@ -1179,8 +1175,6 @@ qboolean SV_Impact (prvm_edict_t *e1, trace_t *trace) prog->globals.server->self = old_self; prog->globals.server->other = old_other; vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; - - return VectorCompare(e1->fields.server->origin, org); } @@ -1468,7 +1462,7 @@ static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, q { int type; int bump; - vec3_t original; + vec3_t original, original_velocity; vec3_t end; VectorCopy(ent->fields.server->origin, original); @@ -1498,8 +1492,11 @@ static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, q if (trace->bmodelstartsolid && failonbmodelstartsolid) return true; - VectorCopy (trace->endpos, ent->fields.server->origin); + + VectorCopy(ent->fields.server->origin, original); + VectorCopy(ent->fields.server->velocity, original_velocity); + SV_LinkEdict(ent); #if 0 @@ -1514,9 +1511,9 @@ static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, q SV_LinkEdict_TouchAreaGrid(ent); if((ent->fields.server->solid >= SOLID_TRIGGER && trace->ent && (!((int)ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace->ent)))) - return SV_Impact (ent, trace); + SV_Impact (ent, trace); - return true; + return VectorCompare(ent->fields.server->origin, original) && VectorCompare(ent->fields.server->velocity, original_velocity); }