/* * BotImport_DebugLineShow */ static void BotImport_DebugLineShow(int line, Vec3 start, Vec3 end, int color) { Vec3 points[4], dir, cross, up = {0, 0, 1}; float dot; copyv3(start, points[0]); copyv3(start, points[1]); /* points[1][2] -= 2; */ copyv3(end, points[2]); /* points[2][2] -= 2; */ copyv3(end, points[3]); subv3(end, start, dir); normv3(dir); dot = dotv3(dir, up); if(dot > 0.99 || dot < -0.99) setv3(cross, 1, 0, 0); else crossv3(dir, up, cross); normv3(cross); saddv3(points[0], 2, cross, points[0]); saddv3(points[1], -2, cross, points[1]); saddv3(points[2], -2, cross, points[2]); saddv3(points[3], 2, cross, points[3]); BotImport_DebugPolygonShow(line, color, 4, points); }
/* exclude meas of eclipsing satellite (block IIA) ---------------------------*/ static void testeclipse(const obsd_t *obs, int n, const nav_t *nav, double *rs) { double rsun[3],esun[3],r,ang,erpv[5]={0},cosa; int i,j; const char *type; trace(3,"testeclipse:\n"); /* unit vector of sun direction (ecef) */ sunmoonpos(gpst2utc(obs[0].time),erpv,rsun,NULL,NULL); normv3(rsun,esun); for (i=0;i<n;i++) { type=nav->pcvs[obs[i].sat-1].type; if ((r=norm(rs+i*6,3))<=0.0) continue; #if 1 /* only block IIA */ if (*type&&!strstr(type,"BLOCK IIA")) continue; #endif /* sun-earth-satellite angle */ cosa=dot(rs+i*6,esun,3)/r; cosa=cosa<-1.0?-1.0:(cosa>1.0?1.0:cosa); ang=acos(cosa); /* test eclipse */ if (ang<PI/2.0||r*sin(ang)>RE_WGS84) continue; trace(2,"eclipsing sat excluded %s sat=%2d\n",time_str(obs[0].time,0), obs[i].sat); for (j=0;j<3;j++) rs[j+i*6]=0.0; } }
/* satellite antenna phase center variation ----------------------------------*/ static void satantpcv(const double *rs, const double *rr, const pcv_t *pcv, double *dant) { double ru[3],rz[3],eu[3],ez[3],nadir,cosa; int i; for (i=0;i<3;i++) { ru[i]=rr[i]-rs[i]; rz[i]=-rs[i]; } if (!normv3(ru,eu)||!normv3(rz,ez)) return; cosa=dot(eu,ez,3); cosa=cosa<-1.0?-1.0:(cosa>1.0?1.0:cosa); nadir=acos(cosa); antmodel_s(pcv,nadir,dant); }
void weapon_grenadelauncher_fire(Gentity *ent) { Gentity *m; normv3(forward); m = fire_grenade(ent, muzzle, forward); m->damage *= s_quadFactor; m->splashDamage *= s_quadFactor; }
void weapon_proxlauncher_fire(Gentity *ent) { Gentity *m; /* extra vertical velocity */ forward[2] += 0.2f; normv3(forward); m = fire_prox(ent, muzzle, forward); m->damage *= s_quadFactor; m->splashDamage *= s_quadFactor; }
void G_BounceProjectile(Vec3 start, Vec3 impact, Vec3 dir, Vec3 endout) { Vec3 v, newv; float dot; subv3(impact, start, v); dot = dotv3(v, dir); saddv3(v, -2*dot, dir, newv); normv3(newv); saddv3(impact, 8192, newv, endout); }
void R_InitSkyTexCoords(float heightCloud) { int i, s, t; float radiusWorld = 4096; float p; float sRad, tRad; Vec3 skyVec; Vec3 v; /* init zfar so MakeSkyVec works even though * a world hasn't been bounded */ backEnd.viewParms.zFar = 1024; for(i = 0; i < 6; i++){ for(t = 0; t <= SKY_SUBDIVISIONS; t++) for(s = 0; s <= SKY_SUBDIVISIONS; s++){ /* compute vector from view origin to sky side integral point */ MakeSkyVec((s - HALF_SKY_SUBDIVISIONS) / ( float )HALF_SKY_SUBDIVISIONS, (t - HALF_SKY_SUBDIVISIONS) / ( float )HALF_SKY_SUBDIVISIONS, i, NULL, skyVec); /* compute parametric value 'p' that intersects with cloud layer */ p = (1.0f / (2 * dotv3(skyVec, skyVec))) * (-2 * skyVec[2] * radiusWorld + 2 * sqrt(SQR(skyVec[2]) * SQR(radiusWorld) + 2 * SQR(skyVec[0]) * radiusWorld * heightCloud + SQR(skyVec[0]) * SQR(heightCloud) + 2 * SQR(skyVec[1]) * radiusWorld * heightCloud + SQR(skyVec[1]) * SQR(heightCloud) + 2 * SQR(skyVec[2]) * radiusWorld * heightCloud + SQR(skyVec[2]) * SQR(heightCloud))); s_cloudTexP[i][t][s] = p; /* compute intersection point based on p */ scalev3(skyVec, p, v); v[2] += radiusWorld; /* compute vector from world origin to intersection point 'v' */ normv3(v); sRad = Q_acos(v[0]); tRad = Q_acos(v[1]); s_cloudTexCoords[i][t][s][0] = sRad; s_cloudTexCoords[i][t][s][1] = tRad; } } }
/* satellite antenna phase center offset --------------------------------------- * compute satellite antenna phase center offset in ecef * args : gtime_t time I time (gpst) * double *rs I satellite position and velocity (ecef) * {x,y,z,vx,vy,vz} (m|m/s) * pcv_t *pcv I satellite antenna parameter * double *dant I satellite antenna phase center offset (ecef) * {dx,dy,dz} (m) * return : none *-----------------------------------------------------------------------------*/ extern void satantoff(gtime_t time, const double *rs, const pcv_t *pcv, double *dant) { double ex[3],ey[3],ez[3],es[3],r[3],rsun[3],gmst; int i; trace(4,"satantoff: time=%s\n",time_str(time,3)); /* sun position in ecef */ sunmoonpos(gpst2utc(time),NULL,rsun,NULL,&gmst); /* unit vectors of satellite fixed coordinates */ for (i=0;i<3;i++) r[i]=-rs[i]; if (!normv3(r,ez)) return; for (i=0;i<3;i++) r[i]=rsun[i]-rs[i]; if (!normv3(r,es)) return; cross3(ez,es,r); if (!normv3(r,ey)) return; cross3(ey,ez,ex); for (i=0;i<3;i++) { /* use L1 value */ dant[i]=pcv->off[0][0]*ex[i]+pcv->off[0][1]*ey[i]+pcv->off[0][2]*ez[i]; } }
/* Used for spatializing s_channels */ static void S_SpatializeOrigin(Vec3 origin, int master_vol, int *left_vol, int *right_vol) { Scalar dot; Scalar dist; Scalar lscale, rscale, scale; Vec3 source_vec; Vec3 vec; const float dist_mult = SOUND_ATTENUATE; /* calculate stereo seperation and distance attenuation */ subv3(origin, listener_origin, source_vec); dist = normv3(source_vec); dist -= SOUND_FULLVOLUME; if(dist < 0) dist = 0; /* close enough to be at full volume */ dist *= dist_mult; /* different attenuation levels */ rotv3(source_vec, listener_axis, vec); dot = -vec[1]; if(dma.channels == 1) { /* no attenuation = no spatialization */ rscale = 1.0; lscale = 1.0; } else { rscale = 0.5 * (1.0 + dot); lscale = 0.5 * (1.0 - dot); if(rscale < 0) rscale = 0; if(lscale < 0) lscale = 0; } /* add in distance effect */ scale = (1.0 - dist) * rscale; *right_vol = (master_vol * scale); if(*right_vol < 0) *right_vol = 0; scale = (1.0 - dist) * lscale; *left_vol = (master_vol * scale); if(*left_vol < 0) *left_vol = 0; }
/* * R_SetupEntityLighting * * Calculates all the lighting values that will be used * by the Calc_* functions */ void R_SetupEntityLighting(const trRefdef_t *refdef, trRefEntity_t *ent) { int i; dlight_t *dl; float power; Vec3 dir; float d; Vec3 lightDir; Vec3 lightOrigin; /* lighting calculations */ if(ent->lightingCalculated){ return; } ent->lightingCalculated = qtrue; /* * trace a sample point down to find ambient light * */ if(ent->e.renderfx & RF_LIGHTING_ORIGIN){ /* seperate lightOrigins are needed so an object that is * sinking into the ground can still be lit, and so * multi-part models can be lit identically */ copyv3(ent->e.lightingOrigin, lightOrigin); }else{ copyv3(ent->e.origin, lightOrigin); } /* if NOWORLDMODEL, only use dynamic lights (menu system, etc) */ if(!(refdef->rdflags & RDF_NOWORLDMODEL) && tr.world->lightGridData){ R_SetupEntityLightingGrid(ent); }else{ ent->ambientLight[0] = ent->ambientLight[1] = ent->ambientLight[2] = tr.identityLight * 150; ent->directedLight[0] = ent->directedLight[1] = ent->directedLight[2] = tr.identityLight * 150; copyv3(tr.sunDirection, ent->lightDir); } /* bonus items and view weapons have a fixed minimum add */ if(1 /* ent->e.renderfx & RF_MINLIGHT */){ /* give everything a minimum light add */ ent->ambientLight[0] += tr.identityLight * 32; ent->ambientLight[1] += tr.identityLight * 32; ent->ambientLight[2] += tr.identityLight * 32; } /* * modify the light by dynamic lights * */ d = lenv3(ent->directedLight); scalev3(ent->lightDir, d, lightDir); for(i = 0; i < refdef->num_dlights; i++){ dl = &refdef->dlights[i]; subv3(dl->origin, lightOrigin, dir); d = normv3(dir); power = DLIGHT_AT_RADIUS * (dl->radius * dl->radius); if(d < DLIGHT_MINIMUM_RADIUS){ d = DLIGHT_MINIMUM_RADIUS; } d = power / (d * d); saddv3(ent->directedLight, d, dl->color, ent->directedLight); saddv3(lightDir, d, dir, lightDir); } /* clamp ambient */ for(i = 0; i < 3; i++) if(ent->ambientLight[i] > tr.identityLightByte){ ent->ambientLight[i] = tr.identityLightByte; } if(r_debugLight->integer){ LogLight(ent); } /* save out the byte packet version */ ((byte*)&ent->ambientLightInt)[0] = ri.ftol(ent->ambientLight[0]); ((byte*)&ent->ambientLightInt)[1] = ri.ftol(ent->ambientLight[1]); ((byte*)&ent->ambientLightInt)[2] = ri.ftol(ent->ambientLight[2]); ((byte*)&ent->ambientLightInt)[3] = 0xff; /* transform the direction to local space */ normv3(lightDir); ent->lightDir[0] = dotv3(lightDir, ent->e.axis[0]); ent->lightDir[1] = dotv3(lightDir, ent->e.axis[1]); ent->lightDir[2] = dotv3(lightDir, ent->e.axis[2]); }
/* * R_SubdividePatchToGrid */ srfGridMesh_t * R_SubdividePatchToGrid(int width, int height, Drawvert points[MAX_PATCH_SIZE*MAX_PATCH_SIZE]) { int i, j, k, l; drawVert_t_cleared(prev); drawVert_t_cleared(next); drawVert_t_cleared(mid); float len, maxLen; int dir; int t; Drawvert ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; float errorTable[2][MAX_GRID_SIZE]; for(i = 0; i < width; i++) for(j = 0; j < height; j++) ctrl[j][i] = points[j*width+i]; for(dir = 0; dir < 2; dir++){ for(j = 0; j < MAX_GRID_SIZE; j++) errorTable[dir][j] = 0; /* horizontal subdivisions */ for(j = 0; j + 2 < width; j += 2){ /* check subdivided midpoints against control points */ /* FIXME: also check midpoints of adjacent patches against the control points * this would basically stitch all patches in the same LOD group together. */ maxLen = 0; for(i = 0; i < height; i++){ Vec3 midxyz; Vec3 midxyz2; Vec3 dir; Vec3 projected; float d; /* calculate the point on the curve */ for(l = 0; l < 3; l++) midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2 + ctrl[i][j+2].xyz[l]) * 0.25f; /* see how far off the line it is * using dist-from-line will not account for internal * texture warping, but it gives a lot less polygons than * dist-from-midpoint */ subv3(midxyz, ctrl[i][j].xyz, midxyz); subv3(ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir); normv3(dir); d = dotv3(midxyz, dir); scalev3(dir, d, projected); subv3(midxyz, projected, midxyz2); len = lensqrv3(midxyz2); /* we will do the sqrt later */ if(len > maxLen){ maxLen = len; } } maxLen = sqrt(maxLen); /* if all the points are on the lines, remove the entire columns */ if(maxLen < 0.1f){ errorTable[dir][j+1] = 999; continue; } /* see if we want to insert subdivided columns */ if(width + 2 > MAX_GRID_SIZE){ errorTable[dir][j+1] = 1.0f/maxLen; continue; /* can't subdivide any more */ } if(maxLen <= r_subdivisions->value){ errorTable[dir][j+1] = 1.0f/maxLen; continue; /* didn't need subdivision */ } errorTable[dir][j+2] = 1.0f/maxLen; /* insert two columns and replace the peak */ width += 2; for(i = 0; i < height; i++){ LerpDrawVert(&ctrl[i][j], &ctrl[i][j+1], &prev); LerpDrawVert(&ctrl[i][j+1], &ctrl[i][j+2], &next); LerpDrawVert(&prev, &next, &mid); for(k = width - 1; k > j + 3; k--) ctrl[i][k] = ctrl[i][k-2]; ctrl[i][j + 1] = prev; ctrl[i][j + 2] = mid; ctrl[i][j + 3] = next; } /* back up and recheck this set again, it may need more subdivision */ j -= 2; } Transpose(width, height, ctrl); t = width; width = height; height = t; } /* put all the aproximating points on the curve */ PutPointsOnCurve(ctrl, width, height); /* cull out any rows or columns that are colinear */ for(i = 1; i < width-1; i++){ if(errorTable[0][i] != 999){ continue; } for(j = i+1; j < width; j++){ for(k = 0; k < height; k++) ctrl[k][j-1] = ctrl[k][j]; errorTable[0][j-1] = errorTable[0][j]; } width--; } for(i = 1; i < height-1; i++){ if(errorTable[1][i] != 999){ continue; } for(j = i+1; j < height; j++){ for(k = 0; k < width; k++) ctrl[j-1][k] = ctrl[j][k]; errorTable[1][j-1] = errorTable[1][j]; } height--; } #if 1 /* flip for longest tristrips as an optimization * the results should be visually identical with or * without this step */ if(height > width){ Transpose(width, height, ctrl); InvertErrorTable(errorTable, width, height); t = width; width = height; height = t; InvertCtrl(width, height, ctrl); } #endif /* calculate normals */ MakeMeshNormals(width, height, ctrl); return R_CreateSurfaceGridMesh(width, height, ctrl, errorTable); }
static int Pickup_Powerup(Gentity *ent, Gentity *other) { int quantity; int i; Gclient *client; if(!other->client->ps.powerups[ent->item->tag]) /* round timing to seconds to make multiple powerup timers * count in sync */ other->client->ps.powerups[ent->item->tag] = level.time - (level.time % 1000); if(ent->count) quantity = ent->count; else quantity = ent->item->quantity; other->client->ps.powerups[ent->item->tag] += quantity * 1000; /* give any nearby players a "denied" anti-reward */ for(i = 0; i < level.maxclients; i++){ Vec3 delta; float len; Vec3 forward; Trace tr; client = &level.clients[i]; if(client == other->client) continue; if(client->pers.connected == CON_DISCONNECTED) continue; if(client->ps.stats[STAT_HEALTH] <= 0) continue; /* if same team in team game, no sound * cannot use OnSameTeam as it expects to g_entities, not clients */ if(g_gametype.integer >= GT_TEAM && other->client->sess.team == client->sess.team) continue; /* if too far away, no sound */ subv3(ent->s.traj.base, client->ps.origin, delta); len = normv3(delta); if(len > 192) continue; /* if not facing, no sound */ anglev3s(client->ps.viewangles, forward, NULL, NULL); if(dotv3(delta, forward) < 0.4) continue; /* if not line of sight, no sound */ trap_Trace(&tr, client->ps.origin, NULL, NULL, ent->s.traj.base, ENTITYNUM_NONE, CONTENTS_SOLID); if(tr.fraction != 1.0) continue; /* anti-reward */ client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_DENIEDREWARD; } return RESPAWN_POWERUP; }
/* satellite position and clock with ssr correction --------------------------*/ static int satpos_ssr(gtime_t time, gtime_t teph, int sat, const nav_t *nav, int opt, double *rs, double *dts, double *var, int *svh) { const ssr_t *ssr; eph_t *eph; double t1,t2,t3,er[3],ea[3],ec[3],rc[3],deph[3],dclk,dant[3]={0},tk; int i,sys; trace(4,"satpos_ssr: time=%s sat=%2d\n",time_str(time,3),sat); ssr=nav->ssr+sat-1; if (!ssr->t0[0].time) { trace(2,"no ssr orbit correction: %s sat=%2d\n",time_str(time,0),sat); return 0; } if (!ssr->t0[1].time) { trace(2,"no ssr clock correction: %s sat=%2d\n",time_str(time,0),sat); return 0; } /* inconsistency between orbit and clock correction */ if (ssr->iod[0]!=ssr->iod[1]) { trace(2,"inconsist ssr correction: %s sat=%2d iod=%d %d\n", time_str(time,0),sat,ssr->iod[0],ssr->iod[1]); *svh=-1; return 0; } t1=timediff(time,ssr->t0[0]); t2=timediff(time,ssr->t0[1]); t3=timediff(time,ssr->t0[2]); /* ssr orbit and clock correction (ref [4]) */ if (fabs(t1)>MAXAGESSR||fabs(t2)>MAXAGESSR) { trace(2,"age of ssr error: %s sat=%2d t=%.0f %.0f\n",time_str(time,0), sat,t1,t2); *svh=-1; return 0; } if (ssr->udi[0]>=1.0) t1-=ssr->udi[0]/2.0; if (ssr->udi[1]>=1.0) t2-=ssr->udi[0]/2.0; for (i=0;i<3;i++) deph[i]=ssr->deph[i]+ssr->ddeph[i]*t1; dclk=ssr->dclk[0]+ssr->dclk[1]*t2+ssr->dclk[2]*t2*t2; /* ssr highrate clock correction (ref [4]) */ if (ssr->iod[0]==ssr->iod[2]&&ssr->t0[2].time&&fabs(t3)<MAXAGESSR_HRCLK) { dclk+=ssr->hrclk; } if (norm(deph,3)>MAXECORSSR||fabs(dclk)>MAXCCORSSR) { trace(3,"invalid ssr correction: %s deph=%.1f dclk=%.1f\n", time_str(time,0),norm(deph,3),dclk); *svh=-1; return 0; } /* satellite postion and clock by broadcast ephemeris */ if (!ephpos(time,teph,sat,nav,ssr->iode,rs,dts,var,svh)) return 0; /* satellite clock for gps, galileo and qzss */ sys=satsys(sat,NULL); if (sys==SYS_GPS||sys==SYS_GAL||sys==SYS_QZS||sys==SYS_CMP) { if (!(eph=seleph(teph,sat,ssr->iode,nav))) return 0; /* satellite clock by clock parameters */ tk=timediff(time,eph->toc); dts[0]=eph->f0+eph->f1*tk+eph->f2*tk*tk; dts[1]=eph->f1+2.0*eph->f2*tk; /* relativity correction */ dts[0]-=2.0*dot(rs,rs+3,3)/CLIGHT/CLIGHT; } /* radial-along-cross directions in ecef */ if (!normv3(rs+3,ea)) return 0; cross3(rs,rs+3,rc); if (!normv3(rc,ec)) { *svh=-1; return 0; } cross3(ea,ec,er); /* satellite antenna offset correction */ if (opt) { satantoff(time,rs,sat,nav,dant); } for (i=0;i<3;i++) { rs[i]+=-(er[i]*deph[0]+ea[i]*deph[1]+ec[i]*deph[2])+dant[i]; } /* t_corr = t_sv - (dts(brdc) + dclk(ssr) / CLIGHT) (ref [10] eq.3.12-7) */ dts[0]+=dclk/CLIGHT; /* variance by ssr ura */ *var=var_urassr(ssr->ura); trace(5,"satpos_ssr: %s sat=%2d deph=%6.3f %6.3f %6.3f er=%6.3f %6.3f %6.3f dclk=%6.3f var=%6.3f\n", time_str(time,2),sat,deph[0],deph[1],deph[2],er[0],er[1],er[2],dclk,*var); return 1; }
static void KamikazeShockWave(Vec3 origin, Gentity *attacker, float damage, float push, float radius) { float dist; Gentity *ent; int entityList[MAX_GENTITIES]; int numListedEntities; Vec3 mins, maxs; Vec3 v; Vec3 dir; int i, e; if(radius < 1) radius = 1; for(i = 0; i < 3; i++){ mins[i] = origin[i] - radius; maxs[i] = origin[i] + radius; } numListedEntities = trap_EntitiesInBox(mins, maxs, entityList, MAX_GENTITIES); for(e = 0; e < numListedEntities; e++){ ent = &g_entities[entityList[ e ]]; /* dont hit things we have already hit */ if(ent->kamikazeShockTime > level.time) continue; /* find the distance from the edge of the bounding box */ for(i = 0; i < 3; i++){ if(origin[i] < ent->r.absmin[i]) v[i] = ent->r.absmin[i] - origin[i]; else if(origin[i] > ent->r.absmax[i]) v[i] = origin[i] - ent->r.absmax[i]; else v[i] = 0; } dist = lenv3(v); if(dist >= radius) continue; /* if( CanDamage (ent, origin) ) { */ subv3 (ent->r.currentOrigin, origin, dir); dir[2] += 24; G_Damage(ent, NULL, attacker, dir, origin, damage, DAMAGE_RADIUS|DAMAGE_NO_TEAM_PROTECTION, MOD_KAMIKAZE); dir[2] = 0; normv3(dir); if(ent->client){ ent->client->ps.velocity[0] = dir[0] * push; ent->client->ps.velocity[1] = dir[1] * push; ent->client->ps.velocity[2] = 100; } ent->kamikazeShockTime = level.time + 3000; /* } */ } }
qbool PM_SlideMove(Pmove *pm, Pml *pml, qbool gravity) { int i, j, k, bumpcount, numbumps, numplanes; Vec3 dir; float d, time_left, into; Vec3 planes[MAX_CLIP_PLANES]; Vec3 primal_velocity, clipVelocity; Trace trace; Vec3 end, endVelocity, endClipVelocity; numbumps = 4; copyv3(pm->ps->velocity, primal_velocity); if(gravity){ copyv3(pm->ps->velocity, endVelocity); endVelocity[2] -= pm->ps->gravity * pml->frametime; pm->ps->velocity[2] = (pm->ps->velocity[2] + endVelocity[2]) * 0.5f; primal_velocity[2] = endVelocity[2]; if(pml->groundPlane){ /* slide along the ground plane */ PM_ClipVelocity(pm->ps->velocity, pml->groundTrace.plane.normal, pm->ps->velocity, OVERCLIP); } } time_left = pml->frametime; /* never turn against the ground plane */ if(pml->groundPlane){ numplanes = 1; copyv3(pml->groundTrace.plane.normal, planes[0]); }else numplanes = 0; /* never turn against original velocity */ norm2v3(pm->ps->velocity, planes[numplanes]); numplanes++; for(bumpcount=0; bumpcount < numbumps; bumpcount++){ /* calculate position we are trying to move to */ saddv3(pm->ps->origin, time_left, pm->ps->velocity, end); /* see if we can make it there */ pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask); if(trace.allsolid){ /* entity is completely trapped in another solid */ pm->ps->velocity[2] = 0; /* don't build up falling damage, but allow sideways acceleration */ return qtrue; } if(trace.fraction > 0) /* actually covered some distance */ copyv3 (trace.endpos, pm->ps->origin); if(trace.fraction == 1) break; /* moved the entire distance */ /* save entity for contact */ PM_AddTouchEnt(pm, trace.entityNum); time_left -= time_left * trace.fraction; if(numplanes >= MAX_CLIP_PLANES){ /* this shouldn't really happen */ clearv3(pm->ps->velocity); return qtrue; } /* * if this is the same plane we hit before, nudge velocity * out along it, which fixes some epsilon issues with * non-axial planes * */ for(i = 0; i < numplanes; i++) if(dotv3(trace.plane.normal, planes[i]) > 0.99f){ addv3(trace.plane.normal, pm->ps->velocity, pm->ps->velocity); break; } if(i < numplanes) continue; copyv3 (trace.plane.normal, planes[numplanes]); numplanes++; /* * modify velocity so it parallels all of the clip planes */ /* find a plane that it enters */ for(i = 0; i < numplanes; i++){ into = dotv3(pm->ps->velocity, planes[i]); if(into >= 0.1f) continue; /* move doesn't interact with the plane */ /* see how hard we are hitting things */ if(-into > pml->impactSpeed) pml->impactSpeed = -into; /* slide along the plane */ PM_ClipVelocity(pm->ps->velocity, planes[i], clipVelocity, OVERCLIP); /* slide along the plane */ PM_ClipVelocity(endVelocity, planes[i], endClipVelocity, OVERCLIP); /* see if there is a second plane that the new move enters */ for(j = 0; j < numplanes; j++){ if(j == i) continue; if(dotv3(clipVelocity, planes[j]) >= 0.1f) continue; /* move doesn't interact with the plane */ /* try clipping the move to the plane */ PM_ClipVelocity(clipVelocity, planes[j], clipVelocity, OVERCLIP); PM_ClipVelocity(endClipVelocity, planes[j], endClipVelocity, OVERCLIP); /* see if it goes back into the first clip plane */ if(dotv3(clipVelocity, planes[i]) >= 0) continue; /* slide the original velocity along the crease */ crossv3 (planes[i], planes[j], dir); normv3(dir); d = dotv3(dir, pm->ps->velocity); scalev3(dir, d, clipVelocity); crossv3 (planes[i], planes[j], dir); normv3(dir); d = dotv3(dir, endVelocity); scalev3(dir, d, endClipVelocity); /* see if there is a third plane the the new move enters */ for(k = 0; k < numplanes; k++){ if(k == i || k == j) continue; if(dotv3(clipVelocity, planes[k]) >= 0.1f) continue; /* move doesn't interact with the plane */ /* stop dead at a triple plane interaction */ clearv3(pm->ps->velocity); return qtrue; } } /* if we have fixed all interactions, try another move */ copyv3(clipVelocity, pm->ps->velocity); copyv3(endClipVelocity, endVelocity); break; } } if(gravity) copyv3(endVelocity, pm->ps->velocity); /* don't change velocity if in a timer (FIXME: is this correct?) */ if(pm->ps->pm_time) copyv3(primal_velocity, pm->ps->velocity); return (bumpcount != 0); }