// [7/8/2012] Renamed to Brush_ClipLineToFace ~hogsy BOOL Brush_ClipLineToFace(vec3_t p1,vec3_t p2,face_t *f) { float d1,d2,fr,*v; int i; d1 = Math_DotProduct(p1,f->plane.normal)-f->plane.dist; d2 = Math_DotProduct(p2, f->plane.normal)-f->plane.dist; if (d1 >= 0 && d2 >= 0) return FALSE; // totally outside else if(d1 <= 0 && d2 <= 0) return TRUE; // totally inside fr = d1 / (d1 - d2); if (d1 > 0) v = p1; else v = p2; for (i=0 ; i<3 ; i++) v[i] = p1[i] + fr*(p2[i] - p1[i]); return TRUE; }
void _EmitTextureCoordinates(vec3_t v,qtexture_t *q) { float s, t; s = Math_DotProduct(v,vecs[0]); t = Math_DotProduct(v,vecs[1]); s += shift[0]; t += shift[1]; s /= q->width; t /= q->height; glTexCoord2f(s,t); }
void Select_AplyMatrix (void) { brush_t *b; face_t *f; int i, j; vec3_t temp; for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) { for (f=b->brush_faces ; f ; f=f->next) { for (i=0 ; i<3 ; i++) { Math_VectorSubtract(f->planepts[i],select_origin, temp); for (j=0 ; j<3 ; j++) f->planepts[i][j] = Math_DotProduct(temp,select_matrix[j]) + select_origin[j]; } if (select_fliporder) { Math_VectorCopy(f->planepts[0],temp); Math_VectorCopy(f->planepts[2],f->planepts[0]); Math_VectorCopy(temp,f->planepts[2]); } } Brush_Build( b ); } Sys_UpdateWindows (W_ALL); }
/* Itersects a ray with a brush Returns the face hit and the distance along the ray the intersection occured at Returns NULL and 0 if not hit at all */ face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist) { face_t *f, *firstface=NULL; vec3_t p1, p2; float frac, d1, d2; int i; Math_VectorCopy(origin,p1); for (i=0 ; i<3 ; i++) p2[i] = p1[i] + dir[i]*16384; for (f=b->brush_faces ; f ; f=f->next) { d1 = Math_DotProduct(p1,f->plane.normal)-f->plane.dist; d2 = Math_DotProduct(p2,f->plane.normal)-f->plane.dist; if (d1 >= 0 && d2 >= 0) { *dist = 0; return NULL; // ray is on front side of face } if (d1 <=0 && d2 <= 0) continue; // clip the ray to the plane frac = d1 / (d1 - d2); if (d1 > 0) { firstface = f; for (i=0 ; i<3 ; i++) p1[i] = p1[i] + frac *(p2[i] - p1[i]); } else { for (i=0 ; i<3 ; i++) p2[i] = p1[i] + frac *(p2[i] - p1[i]); } } // find distance p1 is along dir Math_VectorSubtract(p1,origin,p1); d1 = Math_DotProduct(p1,dir); *dist = d1; return firstface; }
void Physics_WallFriction(ServerEntity_t *eEntity, trace_t *trLine) { MathVector3f_t forward, right, up; float d, i; MathVector3f_t into, side; Math_AngleVectors(eEntity->v.v_angle, forward, right, up); d = Math_DotProduct(trLine->plane.normal, forward); d += 0.5; if (d >= 0) return; // Cut the tangential velocity. i = Math_DotProduct(trLine->plane.normal, eEntity->v.velocity); Math_VectorScale(trLine->plane.normal, i, into); Math_VectorSubtract(eEntity->v.velocity, into, side); eEntity->v.velocity[0] = side[0] * (1 + d); eEntity->v.velocity[1] = side[1] * (1 + d); }
void SV_WallFriction (edict_t *ent, trace_t *trace) { vec3_t forward, right, up; float d, i; vec3_t into, side; Math_AngleVectors(ent->v.v_angle, forward, right, up); d = Math_DotProduct (trace->plane.normal, forward); d += 0.5; if (d >= 0) return; // Cut the tangential velocity i = Math_DotProduct (trace->plane.normal, ent->v.velocity); Math_VectorScale (trace->plane.normal, i, into); Math_VectorSubtract (ent->v.velocity, into, side); ent->v.velocity[0] = side[0] * (1 + d); ent->v.velocity[1] = side[1] * (1 + d); }
/* Returns the visible polygon on a face */ winding_t *MakeFaceWinding(brush_t *b,face_t *face) { winding_t *w; face_t *clip; plane_t plane; BOOL past; // get a poly that covers an effectively infinite area w = BasePolyForPlane (&face->plane); // chop the poly by all of the other faces past = FALSE; for (clip = b->brush_faces ; clip && w ; clip=clip->next) { if (clip == face) { past = TRUE; continue; } if(Math_DotProduct (face->plane.normal, clip->plane.normal) > 0.999 && fabs(face->plane.dist - clip->plane.dist) < 0.01 ) { // identical plane, use the later one if (past) { free (w); return NULL; } continue; } // flip the plane, because we want to keep the back side Math_VectorSubtract(vec3_origin,clip->plane.normal,plane.normal); plane.dist = -clip->plane.dist; w = ClipWinding(w,&plane,FALSE); if (!w) return w; } if (w->numpoints < 3) { free(w); w = NULL; } if (!w) printf ("unused plane\n"); return w; }
void EmitTextureCoordinates(float *xyzst,qtexture_t *q,face_t *f) { float s,t,ns,nt,ang,sinv,cosv; vec3_t vecs[2]; texdef_t *td; // get natural texture axis TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]); td = &f->texdef; ang = td->rotate/180.0f*pMath_PI; sinv = sin(ang); cosv = cos(ang); if (!td->scale[0]) td->scale[0] = 1.0f; if (!td->scale[1]) td->scale[1] = 1.0f; s = Math_DotProduct(xyzst,vecs[0]); t = Math_DotProduct(xyzst,vecs[1]); ns = cosv * s - sinv * t; nt = sinv * s + cosv * t; s = ns/td->scale[0] + td->shift[0]; t = nt/td->scale[1] + td->shift[1]; // gl scales everything from 0 to 1 s /= q->width; t /= q->height; xyzst[3] = s; xyzst[4] = t; }
void R_SetFrustum (float fovx, float fovy) { int i; if (r_stereo.value) fovx += 10; //silly hack so that polygons don't drop out becuase of stereo skew TurnVector(frustum[0].normal, vpn, vright, fovx/2 - 90); //left plane TurnVector(frustum[1].normal, vpn, vright, 90 - fovx/2); //right plane TurnVector(frustum[2].normal, vpn, vup, 90 - fovy/2); //bottom plane TurnVector(frustum[3].normal, vpn, vup, fovy/2 - 90); //top plane for (i=0 ; i<4 ; i++) { frustum[i].type = PLANE_ANYZ; frustum[i].dist = Math_DotProduct(r_origin, frustum[i].normal); //FIXME: shouldn't this always be zero? frustum[i].signbits = SignbitsForPlane (&frustum[i]); } }
void TextureAxisFromPlane(plane_t *pln,vec3_t xv,vec3_t yv) { int bestaxis,i; float dot,best; best = 0; bestaxis = 0; for(i = 0; i < 6; i++) { dot = Math_DotProduct(pln->normal,baseaxis[i*3]); if (dot > best) { best = dot; bestaxis = i; } } Math_VectorCopy(baseaxis[bestaxis*3+1],xv); Math_VectorCopy(baseaxis[bestaxis*3+2],yv); }
void Brush_MakeFacePlanes (brush_t *b) { face_t *f; int j; vec3_t t1, t2, t3; for (f=b->brush_faces ; f ; f=f->next) { // convert to a vector / dist plane for (j=0 ; j<3 ; j++) { t1[j] = f->planepts[0][j] - f->planepts[1][j]; t2[j] = f->planepts[2][j] - f->planepts[1][j]; t3[j] = f->planepts[1][j]; } Math_CrossProduct(t1,t2,f->plane.normal); if(Math_VectorCompare(f->plane.normal,vec3_origin)) printf("WARNING: brush plane with no normal!\n"); Math_VectorNormalize(f->plane.normal); f->plane.dist = Math_DotProduct(t3,f->plane.normal); } }
int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) { float backoff; float change; int i, blocked; blocked = 0; if (normal[2] > 0) blocked |= 1; // floor if (!normal[2]) blocked |= 2; // step backoff = Math_DotProduct (in, normal) * overbounce; for (i=0 ; i<3 ; i++) { change = normal[i]*backoff; out[i] = in[i] - change; if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) out[i] = 0; } return blocked; }
winding_t *BasePolyForPlane (plane_t *p) { int i, x; vec_t max, v; vec3_t org, vright, vup; winding_t *w; // find the major axis max = -BOGUS_RANGE; x = -1; for (i=0 ; i<3; i++) { v = fabs(p->normal[i]); if (v > max) { x = i; max = v; } } if (x==-1) Error("BasePolyForPlane: no axis found"); Math_VectorCopy(vec3_origin,vup); switch (x) { case 0: case 1: vup[2] = 1; break; case 2: vup[0] = 1; break; } v = Math_DotProduct(vup,p->normal); Math_VectorMA(vup,-v,p->normal,vup); Math_VectorNormalize(vup); Math_VectorScale(p->normal,p->dist,org); Math_CrossProduct(vup,p->normal,vright); Math_VectorScale(vup,8192,vup); Math_VectorScale(vright,8192,vright); // project a really big axis aligned box onto the plane w = NewWinding (4); Math_VectorSubtract(org,vright,w->points[0]); Math_VectorAdd(w->points[0],vup,w->points[0]); Math_VectorAdd(org,vright,w->points[1]); Math_VectorAdd(w->points[1],vup,w->points[1]); Math_VectorAdd(org,vright,w->points[2]); Math_VectorSubtract(w->points[2],vup,w->points[2]); Math_VectorSubtract(org,vright,w->points[3]); Math_VectorSubtract(w->points[3],vup,w->points[3]); w->numpoints = 4; return w; }
void Sky_ClipPoly (int nump, MathVector3f_t vecs, int stage) { bool bFront = false, bBack = false; float *norm,*v, d,e,dists[MAX_CLIP_VERTS]; int sides[MAX_CLIP_VERTS], newc[2], i,j; MathVector3f_t vNew[2][MAX_CLIP_VERTS]; if(nump > MAX_CLIP_VERTS-2) Sys_Error ("Sky_ClipPoly: MAX_CLIP_VERTS"); else if(stage == 6) // fully clipped { Sky_ProjectPoly (nump, vecs); return; } norm = vSkyClip[stage]; for (i=0, v = vecs ; i<nump ; i++, v+=3) { d = Math_DotProduct (v, norm); if (d > pMath_EPSILON_ON) { bFront = true; sides[i] = SIDE_FRONT; } else if (d < pMath_EPSILON_ON) { bBack = true; sides[i] = SIDE_BACK; } else sides[i] = SIDE_ON; dists[i] = d; } if(!bFront || !bBack) { // not clipped Sky_ClipPoly (nump, vecs, stage+1); return; } // clip it sides[i] = sides[0]; dists[i] = dists[0]; Math_VectorCopy (vecs, (vecs+(i*3)) ); newc[0] = newc[1] = 0; for (i=0, v = vecs ; i<nump ; i++, v+=3) { switch (sides[i]) { case SIDE_FRONT: Math_VectorCopy(v,vNew[0][newc[0]]); newc[0]++; break; case SIDE_BACK: Math_VectorCopy(v,vNew[1][newc[1]]); newc[1]++; break; case SIDE_ON: Math_VectorCopy(v,vNew[0][newc[0]]); newc[0]++; Math_VectorCopy(v,vNew[1][newc[1]]); newc[1]++; break; } if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) continue; d = dists[i]/(dists[i]-dists[i+1]); for (j=0 ; j<3 ; j++) { e = v[j] + d*(v[j+3] - v[j]); vNew[0][newc[0]][j] = e; vNew[1][newc[1]][j] = e; } newc[0]++; newc[1]++; } // Continue Sky_ClipPoly(newc[0],vNew[0][0],stage+1); Sky_ClipPoly(newc[1],vNew[1][0],stage+1); }
// [18/5/2013] TODO: Merge with SV_PushMove ~hogsy static void Server_PushRotate(edict_t *pusher,float movetime) { int i,e,num_moved,slaves_moved; edict_t *check,*block,*moved_edict[MAX_EDICTS],*ground,*slave,*master; vec3_t move,a,amove,entorig,pushorig,moved_from[MAX_EDICTS],org,org2,forward,right,up; bool bMoveIt; for (i = 0; i < 3; i++) amove[i] = pusher->v.avelocity[i] * movetime; Math_VectorNegate(amove,a); Math_AngleVectors(a,forward,right,up); Math_VectorCopy(pusher->v.angles,pushorig); // move the pusher to it's final position Math_VectorAdd(pusher->v.angles,amove,pusher->v.angles); pusher->v.ltime += movetime; SV_LinkEdict (pusher, false); slaves_moved = 0; master = pusher; while(master->v.aiment) { slave = PROG_TO_EDICT(master->v.aiment); slaves_moved++; Math_VectorCopy (slave->v.angles, moved_from[MAX_EDICTS - slaves_moved]); moved_edict[MAX_EDICTS - slaves_moved] = slave; if (slave->v.movedir[PITCH]) slave->v.angles[PITCH] = master->v.angles[PITCH]; else slave->v.angles[PITCH] += slave->v.avelocity[PITCH] * movetime; if (slave->v.movedir[YAW]) slave->v.angles[YAW] = master->v.angles[YAW]; else slave->v.angles[YAW] += slave->v.avelocity[YAW] * movetime; if (slave->v.movedir[ROLL]) slave->v.angles[ROLL] = master->v.angles[ROLL]; else slave->v.angles[ROLL] += slave->v.avelocity[ROLL] * movetime; slave->v.ltime = master->v.ltime; SV_LinkEdict(slave,false); master = slave; } // see if any solid entities are inside the final position num_moved = 0; check = NEXT_EDICT(sv.edicts); for (e = 1; e < sv.num_edicts; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_NOCLIP) continue; // if the entity is standing on the pusher, it will definitely be moved bMoveIt = false; ground = check->v.groundentity; if(check->v.flags & FL_ONGROUND) { if (ground == pusher) bMoveIt = true; else { for (i = 0; i < slaves_moved; i++) { if (ground == moved_edict[MAX_EDICTS - i - 1]) { bMoveIt = true; break; } } } } if(!bMoveIt) { if( check->v.absmin[0] >= pusher->v.absmax[0] || check->v.absmin[1] >= pusher->v.absmax[1] || check->v.absmin[2] >= pusher->v.absmax[2] || check->v.absmax[0] <= pusher->v.absmin[0] || check->v.absmax[1] <= pusher->v.absmin[1] || check->v.absmax[2] <= pusher->v.absmin[2]) { for (i = 0; i < slaves_moved; i++) { slave = moved_edict[MAX_EDICTS-i-1]; if( check->v.absmin[0] >= slave->v.absmax[0] || check->v.absmin[1] >= slave->v.absmax[1] || check->v.absmin[2] >= slave->v.absmax[2] || check->v.absmax[0] <= slave->v.absmin[0] || check->v.absmax[1] <= slave->v.absmin[1] || check->v.absmax[2] <= slave->v.absmin[2] ) continue; } if (i == slaves_moved) continue; } // See if the ent's bbox is inside the pusher's final position if(!SV_TestEntityPosition(check)) continue; } // remove the onground flag for non-players if(check->v.movetype != MOVETYPE_WALK) check->v.flags = check->v.flags & ~FL_ONGROUND; Math_VectorCopy(check->v.origin,entorig); Math_VectorCopy(check->v.origin,moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; // calculate destination position Math_VectorSubtract(check->v.origin,pusher->v.origin,org); org2[0] = Math_DotProduct(org,forward); org2[1] = -Math_DotProduct(org,right); org2[2] = Math_DotProduct(org,up); Math_VectorSubtract (org2,org,move); // try moving the contacted entity pusher->Physics.iSolid = SOLID_NOT; SV_PushEntity (check, move); //@@TODO: do we ever want to do anybody's angles? maybe just yaw??? if(check->monster.iType != 1) { #if 0 vec3_t vYaw; vYaw[YAW] = Math_AngleMod(pusher->v.angles[YAW]+check->v.angles[YAW]); Con_Printf("%i %i\n",(int)check->v.angles[YAW],(int)vYaw[YAW]); //check->v.angles[YAW] = vYaw[YAW]; //check->v.angles[YAW] = Math_AngleMod(vYaw[YAW]); #endif // move back any entities we already moved for (i = 0; i < num_moved; i++) { Math_VectorAdd(moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); moved_edict[i]->v.angles[YAW] += amove[YAW]/2.0f; SV_LinkEdict(moved_edict[i],false); } } pusher->Physics.iSolid = SOLID_BSP; // If it is still inside the pusher, block block = SV_TestEntityPosition (check); if (block) { // fail the move if (check->v.mins[0] == check->v.maxs[0]) continue; if (check->Physics.iSolid == SOLID_NOT || check->Physics.iSolid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; Math_VectorCopy(check->v.mins,check->v.maxs); continue; } Math_VectorCopy(entorig,check->v.origin); SV_LinkEdict(check,true); Math_VectorCopy(pushorig,pusher->v.angles); SV_LinkEdict(pusher,false); pusher->v.ltime -= movetime; for(i = 0; i < slaves_moved; i++) { slave = moved_edict[MAX_EDICTS - i - 1]; Math_VectorCopy(moved_from[MAX_EDICTS - i - 1], slave->v.angles); SV_LinkEdict(slave,false); slave->v.ltime -= movetime; } // if the pusher has a "blocked" function, call it // otherwise, just stay in place until the obstacle is gone if (pusher->v.blocked) pusher->v.blocked(pusher,check); // move back any entities we already moved for (i = 0; i < num_moved; i++) { Math_VectorCopy (moved_from[i], moved_edict[i]->v.origin); //@@TODO:: see above // if (!((int)moved_edict[i]->v.flags & (FL_CLIENT | FL_MONSTER))) Math_VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); moved_edict[i]->v.angles[YAW] -= amove[YAW]; SV_LinkEdict(moved_edict[i],false); } return; } } }
int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; int i, j; trace_t trace; vec3_t end; float time_left; int blocked; numbumps = 4; blocked = 0; Math_VectorCopy (ent->v.velocity, original_velocity); Math_VectorCopy (ent->v.velocity, primal_velocity); numplanes = 0; time_left = time; for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) { if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2]) break; for (i=0 ; i<3 ; i++) end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i]; trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, FALSE, ent); if(trace.bAllSolid) { // Entity is trapped in another solid Math_VectorCopy(mv3Origin, ent->v.velocity); return 3; } if (trace.fraction > 0) { // Actually covered some distance Math_VectorCopy (trace.endpos, ent->v.origin); Math_VectorCopy (ent->v.velocity, original_velocity); numplanes = 0; } if (trace.fraction == 1) break; // moved the entire distance if(!trace.ent) { Sys_Error ("SV_FlyMove: !trace.ent"); return 0; } if (trace.plane.normal[2] > 0.7) { blocked |= 1; // floor if (trace.ent->Physics.iSolid == SOLID_BSP) { ent->v.flags |= FL_ONGROUND; ent->v.groundentity = trace.ent; } } if (!trace.plane.normal[2]) { blocked |= 2; // step if (steptrace) *steptrace = trace; // save for player extrafriction } // Run the impact function Physics_Impact(ent,trace.ent); if (ent->free) break; // removed by the impact function time_left -= time_left * trace.fraction; // Cliped to another plane if(numplanes >= MAX_CLIP_PLANES) { // This shouldn't really happen Math_VectorCopy(mv3Origin, ent->v.velocity); return 3; } Math_VectorCopy (trace.plane.normal, planes[numplanes]); numplanes++; // Modify original_velocity so it parallels all of the clip planes for(i = 0; i < numplanes; i++) { ClipVelocity (original_velocity, planes[i], new_velocity, 1); for (j=0 ; j<numplanes ; j++) if (j != i) { if(Math_DotProduct(new_velocity,planes[j]) < 0) break; // not ok } if (j == numplanes) break; } if (i != numplanes) Math_VectorCopy (new_velocity, ent->v.velocity); else { // Go along the crease if (numplanes != 2) { Math_VectorCopy(mv3Origin, ent->v.velocity); return 7; } Math_CrossProduct(planes[0], planes[1], dir); d = Math_DotProduct(dir, ent->v.velocity); Math_VectorScale(dir, d, ent->v.velocity); } // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners if(Math_DotProduct(ent->v.velocity,primal_velocity) <= 0) { Math_VectorCopy(mv3Origin,ent->v.velocity); return blocked; } } return blocked; }
void SubdividePolygon (int numverts, float *verts) { int i, j, k; vec3_t mins, maxs; float m; float *v; vec3_t front[64], back[64]; int f, b; float dist[64]; float frac; glpoly_t *poly; float s, t; if(numverts > 60) Sys_Error ("numverts = %i", numverts); BoundPoly (numverts, verts, mins, maxs); for(i = 0; i < 3; i++) { m = (mins[i] + maxs[i]) * 0.5; m = gl_subdivide_size.value * floor (m/gl_subdivide_size.value + 0.5); if (maxs[i] - m < 8) continue; if (m - mins[i] < 8) continue; // cut it v = verts + i; for (j=0 ; j<numverts ; j++, v+= 3) dist[j] = *v - m; // wrap cases dist[j] = dist[0]; v-=i; Math_VectorCopy (verts, v); f = b = 0; v = verts; for (j=0 ; j<numverts ; j++, v+= 3) { if (dist[j] >= 0) { Math_VectorCopy (v, front[f]); f++; } if (dist[j] <= 0) { Math_VectorCopy (v, back[b]); b++; } if (dist[j] == 0 || dist[j+1] == 0) continue; if ( (dist[j] > 0) != (dist[j+1] > 0) ) { // clip point frac = dist[j] / (dist[j] - dist[j+1]); for (k=0 ; k<3 ; k++) front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]); f++; b++; } } SubdividePolygon (f, front[0]); SubdividePolygon (b, back[0]); return; } poly = (glpoly_t*)Hunk_Alloc (sizeof(glpoly_t) + (numverts-4) * VERTEXSIZE*sizeof(float)); poly->next = warpface->polys->next; warpface->polys->next = poly; poly->numverts = numverts; for (i=0 ; i<numverts ; i++, verts+= 3) { Math_VectorCopy (verts, poly->verts[i]); s = Math_DotProduct (verts, warpface->texinfo->vecs[0]); t = Math_DotProduct (verts, warpface->texinfo->vecs[1]); poly->verts[i][3] = s; poly->verts[i][4] = t; } }
/* Clips the winding to the plane, returning the new winding on the positive side Frees the input winding. If keepon is TRUE, an exactly on-plane winding will be saved, otherwise it will be clipped away. */ winding_t *ClipWinding (winding_t *in, plane_t *split, bool keepon) { vec_t dists[MAX_POINTS_ON_WINDING]; int sides[MAX_POINTS_ON_WINDING]; int counts[3]; vec_t dot; int i, j; vec_t *p1, *p2; vec3_t mid; winding_t *neww; int maxpts; counts[0] = counts[1] = counts[2] = 0; // determine sides for each point for (i=0 ; i<in->numpoints ; i++) { dot = Math_DotProduct(in->points[i],split->normal); dot -= split->dist; dists[i] = dot; if (dot > ON_EPSILON) sides[i] = SIDE_FRONT; else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK; else sides[i] = SIDE_ON; counts[sides[i]]++; } sides[i] = sides[0]; dists[i] = dists[0]; if (keepon && !counts[0] && !counts[1]) return in; if (!counts[0]) { FreeWinding (in); return NULL; } if (!counts[1]) return in; maxpts = in->numpoints+4; // can't use counts[0]+2 because // of fp grouping errors neww = NewWinding (maxpts); for (i=0 ; i<in->numpoints ; i++) { p1 = in->points[i]; if (sides[i] == SIDE_ON) { Math_VectorCopy(p1,neww->points[neww->numpoints]); neww->numpoints++; continue; } if (sides[i] == SIDE_FRONT) { Math_VectorCopy(p1,neww->points[neww->numpoints]); neww->numpoints++; } if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) continue; // generate a split point p2 = in->points[(i+1)%in->numpoints]; dot = dists[i] / (dists[i]-dists[i+1]); for (j=0 ; j<3 ; j++) { // avoid round off error when possible if (split->normal[j] == 1) mid[j] = split->dist; else if (split->normal[j] == -1) mid[j] = -split->dist; else mid[j] = p1[j] + dot*(p2[j]-p1[j]); } Math_VectorCopy(mid,neww->points[neww->numpoints]); neww->numpoints++; } if (neww->numpoints > maxpts) Error ("ClipWinding: points exceeded estimate"); // free the original winding FreeWinding (in); return neww; }
/* Adds the faces planepts to move_points, and rotates and adds the planepts of adjacent face if shear is set */ void Brush_SelectFaceForDragging (brush_t *b, face_t *f, bool shear) { int i; face_t *f2; winding_t *w; float d; brush_t *b2; int c; if(b->owner->eclass->fixedsize) return; c = 0; for (i=0 ; i<3 ; i++) c += AddPlanept (f->planepts[i]); if (c == 0) return; // allready completely added // select all points on this plane in all brushes the selection for(b2 = selected_brushes.next; b2 != &selected_brushes; b2 = b2->next) { if (b2 == b) continue; for (f2=b2->brush_faces ; f2 ; f2=f2->next) { for (i=0 ; i<3 ; i++) if(fabs(Math_DotProduct(f2->planepts[i],f->plane.normal) -f->plane.dist) > ON_EPSILON) break; if(i == 3) { // move this face as well Brush_SelectFaceForDragging(b2, f2, shear); break; } } } // if shearing, take all the planes adjacent to // selected faces and rotate their points so the // edge clipped by a selcted face has two of the points if(!shear) return; for (f2=b->brush_faces ; f2 ; f2=f2->next) { if (f2 == f) continue; w = MakeFaceWinding (b, f2); if (!w) continue; // any points on f will become new control points for (i=0 ; i<w->numpoints ; i++) { d = Math_DotProduct(w->points[i],f->plane.normal)-f->plane.dist; if (d > -ON_EPSILON && d < ON_EPSILON) break; } // // if none of the points were on the plane, // leave it alone // if (i != w->numpoints) { if (i == 0) { // see if the first clockwise point was the // last point on the winding d = Math_DotProduct(w->points[w->numpoints-1],f->plane.normal)-f->plane.dist; if (d > -ON_EPSILON && d < ON_EPSILON) i = w->numpoints - 1; } AddPlanept (f2->planepts[0]); Math_VectorCopy(w->points[i],f2->planepts[0]); if (++i == w->numpoints) i = 0; // see if the next point is also on the plane d = Math_DotProduct(w->points[i] , f->plane.normal) - f->plane.dist; if (d > -ON_EPSILON && d < ON_EPSILON) AddPlanept (f2->planepts[1]); Math_VectorCopy(w->points[i],f2->planepts[1]); if (++i == w->numpoints) i = 0; // the third point is never on the plane Math_VectorCopy(w->points[i],f2->planepts[2]); } free(w); } }
void Sky_ProcessEntities(void) { int i,k,mark; unsigned int j; float dot; bool bRotated; ClientEntity_t *e; msurface_t *s; glpoly_t *p; MathVector3f_t vTemp, forward, right, up; if (!r_drawentities.value) return; for (i=0 ; i<cl_numvisedicts ; i++) { e = cl_visedicts[i]; if (e->model->type != MODEL_TYPE_LEVEL) continue; if(R_CullModelForEntity(e)) continue; if(e->alpha == ENTALPHA_ZERO) continue; Math_VectorSubtract (r_refdef.vieworg, e->origin, modelorg); if(e->angles[0] || e->angles[1] || e->angles[2]) { bRotated = true; Math_AngleVectors(e->angles, forward, right, up); Math_VectorCopy(modelorg,vTemp); modelorg[0] = Math_DotProduct(vTemp,forward); modelorg[1] = -Math_DotProduct(vTemp,right); modelorg[2] = Math_DotProduct(vTemp,up); } else bRotated = false; s = &e->model->surfaces[e->model->firstmodelsurface]; for (j=0 ; j<e->model->nummodelsurfaces ; j++, s++) { if (s->flags & SURF_DRAWSKY) { dot = Math_DotProduct (modelorg, s->plane->normal) - s->plane->dist; if (((s->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(s->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { //copy the polygon and translate manually, since Sky_ProcessPoly needs it to be in world space mark = Hunk_LowMark(); p = (glpoly_t*)Hunk_Alloc (sizeof(*s->polys)); //FIXME: don't allocate for each poly p->numverts = s->polys->numverts; for (k=0; k<p->numverts; k++) { if(bRotated) { p->verts[k][0] = e->origin[0] + s->polys->verts[k][0] * forward[0] - s->polys->verts[k][1] * right[0] + s->polys->verts[k][2] * up[0]; p->verts[k][1] = e->origin[1] + s->polys->verts[k][0] * forward[1] - s->polys->verts[k][1] * right[1] + s->polys->verts[k][2] * up[1]; p->verts[k][2] = e->origin[2] + s->polys->verts[k][0] * forward[2] - s->polys->verts[k][1] * right[2] + s->polys->verts[k][2] * up[2]; } else Math_VectorAdd(s->polys->verts[k], e->origin, p->verts[k]); } Sky_ProcessPoly (p); Hunk_FreeToLowMark (mark); } } } } }