本文整理汇总了C++中VectorNormalize2函数的典型用法代码示例。如果您正苦于以下问题:C++ VectorNormalize2函数的具体用法?C++ VectorNormalize2怎么用?C++ VectorNormalize2使用的例子?那么, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了VectorNormalize2函数的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: PM_SlideMove_Helo
bool PM_SlideMove_Helo() {
int bumpcount, numbumps;
vec3_t dir;
float d;
int numplanes;
vec3_t planes[MAX_CLIP_PLANES];
vec3_t primal_velocity;
vec3_t clipVelocity;
int i, j, k;
trace_t trace;
vec3_t end;
float time_left;
float into;
vec3_t endVelocity;
vec3_t endClipVelocity;
numbumps = 4;
VectorCopy (pm->ps->velocity, primal_velocity);
time_left = pml.frametime;
// never turn against the ground plane
if ( pml.groundPlane ) {
numplanes = 1;
VectorCopy( pml.groundTrace.plane.normal, planes[0] );
} else {
numplanes = 0;
}
// never turn against original velocity
VectorNormalize2( pm->ps->velocity, planes[numplanes] );
numplanes++;
for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {
VectorMA(pm->ps->origin, time_left, pm->ps->velocity, end ); // calculate position we are trying to move to
// see if we can make it there
pm->trace ( &trace,
pm->ps->origin,
pm->mins,
pm->maxs,
end,
pm->ps->clientNum,
pm->tracemask,
false);
if (trace.allsolid) {
pm->trace ( &trace,
pm->ps->origin,
0,
0,
end,
pm->ps->clientNum,
pm->tracemask,
false);
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 true;
}
}
if (trace.fraction > 0) {
// actually covered some distance
VectorCopy (trace.endpos, pm->ps->origin);
}
if (trace.fraction == 1) {
break; // moved the entire distance
}
// save entity for contact
if( trace.entityNum != ENTITYNUM_WORLD ||
pm->ps->stats[STAT_HEALTH] <= 0 ||
(trace.entityNum == ENTITYNUM_WORLD &&
// !(trace.surfaceFlags & SURF_NOIMPACT) &&
!(trace.surfaceFlags & SURF_SKY)) ) {
PM_AddTouchEnt_Helo( trace.entityNum );
}
time_left -= time_left * trace.fraction;
if (numplanes >= MAX_CLIP_PLANES) {
// this shouldn't really happen
VectorClear( pm->ps->velocity );
return true;
}
//
// 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 ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) {
VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );
break;
//.........这里部分代码省略.........
示例2: R_MarkFragments
/*
=================
R_MarkFragments
=================
*/
int R_MarkFragments(int numPoints, const vec3_t * points, const vec3_t projection,
int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t * fragmentBuffer)
{
int numsurfaces, numPlanes;
int i, j, k, m, n;
surfaceType_t *surfaces[64];
vec3_t mins, maxs;
int returnedFragments;
int returnedPoints;
vec3_t normals[MAX_VERTS_ON_POLY + 2];
float dists[MAX_VERTS_ON_POLY + 2];
vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
int numClipPoints;
float *v;
srfSurfaceFace_t *face;
srfGridMesh_t *cv;
srfTriangles_t *trisurf;
srfVert_t *dv;
srfTriangle_t *tri;
vec3_t normal;
vec3_t projectionDir;
vec3_t v1, v2;
//increment view count for double check prevention
tr.viewCountNoReset++;
//
VectorNormalize2(projection, projectionDir);
// find all the brushes that are to be considered
ClearBounds(mins, maxs);
for(i = 0; i < numPoints; i++)
{
vec3_t temp;
AddPointToBounds(points[i], mins, maxs);
VectorAdd(points[i], projection, temp);
AddPointToBounds(temp, mins, maxs);
// make sure we get all the leafs (also the one(s) in front of the hit surface)
VectorMA(points[i], -20, projectionDir, temp);
AddPointToBounds(temp, mins, maxs);
}
if(numPoints > MAX_VERTS_ON_POLY)
numPoints = MAX_VERTS_ON_POLY;
// create the bounding planes for the to be projected polygon
for(i = 0; i < numPoints; i++)
{
VectorSubtract(points[(i + 1) % numPoints], points[i], v1);
VectorAdd(points[i], projection, v2);
VectorSubtract(points[i], v2, v2);
CrossProduct(v1, v2, normals[i]);
VectorNormalizeFast(normals[i]);
dists[i] = DotProduct(normals[i], points[i]);
}
// add near and far clipping planes for projection
VectorCopy(projectionDir, normals[numPoints]);
dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;
VectorCopy(projectionDir, normals[numPoints + 1]);
VectorInverse(normals[numPoints + 1]);
dists[numPoints + 1] = DotProduct(normals[numPoints + 1], points[0]) - 20;
numPlanes = numPoints + 2;
numsurfaces = 0;
R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir);
//assert(numsurfaces <= 64);
//assert(numsurfaces != 64);
returnedPoints = 0;
returnedFragments = 0;
for(i = 0; i < numsurfaces; i++)
{
if(*surfaces[i] == SF_GRID)
{
cv = (srfGridMesh_t *) surfaces[i];
for(m = 0; m < cv->height - 1; m++)
{
for(n = 0; n < cv->width - 1; n++)
{
// We triangulate the grid and chop all triangles within
// the bounding planes of the to be projected polygon.
// LOD is not taken into account, not such a big deal though.
//
// It's probably much nicer to chop the grid itself and deal
// with this grid as a normal SF_GRID surface so LOD will
// be applied. However the LOD of that chopped grid must
// be synced with the LOD of the original curve.
// One way to do this; the chopped grid shares vertices with
// the original curve. When LOD is applied to the original
// curve the unused vertices are flagged. Now the chopped curve
// should skip the flagged vertices. This still leaves the
// problems with the vertices at the chopped grid edges.
//
// To avoid issues when LOD applied to "hollow curves" (like
//.........这里部分代码省略.........
示例3: CG_ImpactMark
void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir,
float orientation, float red, float green, float blue, float alpha,
qboolean alphaFade, float radius, qboolean temporary, int duration ) {
vec3_t axis[3];
float texCoordScale;
vec3_t originalPoints[4];
byte colors[4];
int i, j;
int numFragments;
markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf;
vec5_t markPoints[MAX_MARK_POINTS]; // Ridah, made it vec5_t so it includes S/T
vec3_t projection;
int multMaxFragments = 1;
if ( !cg_markTime.integer ) {
return;
}
if ( radius <= 0 ) {
// just ignore it, don't error out
return;
// CG_Error( "CG_ImpactMark called with <= 0 radius" );
}
// Ridah, if no duration, use the default
if ( duration < 0 ) {
if ( duration == -2 ) {
multMaxFragments = -1; // use original mapping
}
// duration = MARK_TOTAL_TIME;
duration = cg_markTime.integer;
}
// create the texture axis
VectorNormalize2( dir, axis[0] );
PerpendicularVector( axis[1], axis[0] );
RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
CrossProduct( axis[0], axis[2], axis[1] );
texCoordScale = 0.5 * 1.0 / radius;
// create the full polygon
for ( i = 0 ; i < 3 ; i++ ) {
originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
}
// get the fragments
//VectorScale( dir, -20, projection );
VectorScale( dir, radius * 2, projection );
numFragments = trap_CM_MarkFragments( (int)orientation, (void *)originalPoints,
projection, MAX_MARK_POINTS, (float *)&markPoints[0],
MAX_MARK_FRAGMENTS * multMaxFragments, markFragments );
colors[0] = red * 255;
colors[1] = green * 255;
colors[2] = blue * 255;
colors[3] = alpha * 255;
for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
polyVert_t *v;
polyVert_t verts[MAX_VERTS_ON_POLY];
markPoly_t *mark;
qboolean hasST;
// we have an upper limit on the complexity of polygons
// that we store persistantly
if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
mf->numPoints = MAX_VERTS_ON_POLY;
}
if ( mf->numPoints < 0 ) {
hasST = qtrue;
mf->numPoints *= -1;
} else {
hasST = qfalse;
}
for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
vec3_t delta;
VectorCopy( markPoints[mf->firstPoint + j], v->xyz );
if ( !hasST ) {
VectorSubtract( v->xyz, origin, delta );
v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
} else {
v->st[0] = markPoints[mf->firstPoint + j][3];
v->st[1] = markPoints[mf->firstPoint + j][4];
}
*(int *)v->modulate = *(int *)colors;
}
// if it is a temporary (shadow) mark, add it immediately and forget about it
if ( temporary ) {
trap_R_AddPolyToScene( markShader, mf->numPoints, verts );
continue;
//.........这里部分代码省略.........
示例4: R_SetupEntityLightingGrid
//.........这里部分代码省略.........
}
VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin );
for ( i = 0 ; i < 3 ; i++ ) {
float v;
v = lightOrigin[i]*tr.world->lightGridInverseSize[i];
pos[i] = floor( v );
frac[i] = v - pos[i];
if ( pos[i] < 0 ) {
pos[i] = 0;
} else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) {
pos[i] = tr.world->lightGridBounds[i] - 1;
}
}
VectorClear( ent->ambientLight );
VectorClear( ent->directedLight );
VectorClear( direction );
assert( tr.world->lightGridData ); // NULL with -nolight maps
// trilerp the light value
gridStep[0] = 8;
gridStep[1] = 8 * tr.world->lightGridBounds[0];
gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
gridData = tr.world->lightGridData + pos[0] * gridStep[0]
+ pos[1] * gridStep[1] + pos[2] * gridStep[2];
totalFactor = 0;
for ( i = 0 ; i < 8 ; i++ ) {
float factor;
byte *data;
int lat, lng;
vec3_t normal;
#if idppc
float d0, d1, d2, d3, d4, d5;
#endif
factor = 1.0;
data = gridData;
for ( j = 0 ; j < 3 ; j++ ) {
if ( i & (1<<j) ) {
factor *= frac[j];
data += gridStep[j];
} else {
factor *= (1.0f - frac[j]);
}
}
if ( !(data[0]+data[1]+data[2]) ) {
continue; // ignore samples in walls
}
totalFactor += factor;
#if idppc
d0 = data[0]; d1 = data[1]; d2 = data[2];
d3 = data[3]; d4 = data[4]; d5 = data[5];
ent->ambientLight[0] += factor * d0;
ent->ambientLight[1] += factor * d1;
ent->ambientLight[2] += factor * d2;
ent->directedLight[0] += factor * d3;
ent->directedLight[1] += factor * d4;
ent->directedLight[2] += factor * d5;
#else
ent->ambientLight[0] += factor * data[0];
ent->ambientLight[1] += factor * data[1];
ent->ambientLight[2] += factor * data[2];
ent->directedLight[0] += factor * data[3];
ent->directedLight[1] += factor * data[4];
ent->directedLight[2] += factor * data[5];
#endif
lat = data[7];
lng = data[6];
lat *= (FUNCTABLE_SIZE/256);
lng *= (FUNCTABLE_SIZE/256);
// decode X as cos( lat ) * sin( long )
// decode Y as sin( lat ) * sin( long )
// decode Z as cos( long )
normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
VectorMA( direction, factor, normal, direction );
}
if ( totalFactor > 0 && totalFactor < 0.99 ) {
totalFactor = 1.0f / totalFactor;
VectorScale( ent->ambientLight, totalFactor, ent->ambientLight );
VectorScale( ent->directedLight, totalFactor, ent->directedLight );
}
VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );
VectorNormalize2( direction, ent->lightDir );
}
示例5: CG_ImpactMark
void CG_ImpactMark( qhandle_t markShader, const vector3 *origin, const vector3 *dir,
float orientation, float red, float green, float blue, float alpha,
qboolean alphaFade, float radius, qboolean temporary ) {
vector3 axis[3];
float texCoordScale;
vector3 originalPoints[4];
byte colors[4];
int i, j;
int numFragments;
markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf;
vector3 markPoints[MAX_MARK_POINTS];
vector3 projection;
assert(markShader);
if ( !cg_marks.integer ) {
return;
}
else if (cg_marks.integer == 2)
{
trap->R_AddDecalToScene(markShader, origin, dir, orientation, red, green, blue, alpha,
alphaFade, radius, temporary);
return;
}
if ( radius <= 0 ) {
trap->Error( ERR_DROP, "CG_ImpactMark called with <= 0 radius" );
}
//if ( markTotal >= MAX_MARK_POLYS ) {
// return;
//}
// create the texture axis
VectorNormalize2( dir, &axis[0] );
PerpendicularVector( &axis[1], &axis[0] );
RotatePointAroundVector( &axis[2], &axis[0], &axis[1], orientation );
CrossProduct( &axis[0], &axis[2], &axis[1] );
texCoordScale = 0.5 * 1.0 / radius;
// create the full polygon
for ( i = 0 ; i < 3 ; i++ ) {
originalPoints[0].data[i] = origin->data[i] - radius * axis[1].data[i] - radius * axis[2].data[i];
originalPoints[1].data[i] = origin->data[i] + radius * axis[1].data[i] - radius * axis[2].data[i];
originalPoints[2].data[i] = origin->data[i] + radius * axis[1].data[i] + radius * axis[2].data[i];
originalPoints[3].data[i] = origin->data[i] - radius * axis[1].data[i] + radius * axis[2].data[i];
}
// get the fragments
VectorScale( dir, -20, &projection );
numFragments = trap->R_MarkFragments( 4, originalPoints,
&projection, MAX_MARK_POINTS, &markPoints[0],
MAX_MARK_FRAGMENTS, markFragments );
colors[0] = red * 255;
colors[1] = green * 255;
colors[2] = blue * 255;
colors[3] = alpha * 255;
for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
polyVert_t *v;
polyVert_t verts[MAX_VERTS_ON_POLY];
markPoly_t *mark;
// we have an upper limit on the complexity of polygons
// that we store persistantly
if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
mf->numPoints = MAX_VERTS_ON_POLY;
}
for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
vector3 delta;
VectorCopy( &markPoints[mf->firstPoint + j], &v->xyz );
VectorSubtract( &v->xyz, origin, &delta );
v->st[0] = 0.5 + DotProduct( &delta, &axis[1] ) * texCoordScale;
v->st[1] = 0.5 + DotProduct( &delta, &axis[2] ) * texCoordScale;
*(int *)v->modulate = *(int *)colors;
}
// if it is a temporary (shadow) mark, add it immediately and forget about it
if ( temporary ) {
trap->R_AddPolysToScene( markShader, mf->numPoints, verts, 1 );
continue;
}
// otherwise save it persistantly
mark = CG_AllocMark();
mark->time = cg.time;
mark->alphaFade = alphaFade;
mark->markShader = markShader;
mark->poly.numVerts = mf->numPoints;
mark->color[0] = red;
mark->color[1] = green;
mark->color[2] = blue;
mark->color[3] = alpha;
memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
markTotal++;
}
//.........这里部分代码省略.........
示例6: FlameJunc_think__target_flamethrower
void FlameJunc_think__target_flamethrower( edict_t *self )
{
vec3_t oldorg;
trace_t tr;
VectorCopy( self->s.origin, oldorg );
// move it
VectorMA( self->s.origin, FRAMETIME, self->velocity, self->s.origin );
tr = gi.trace( oldorg, jmins, jmaxs, self->s.origin, NULL, MASK_SOLID );
if (tr.fraction < 1)
{ // copied from ClipVelocity()
#define STOP_EPSILON 0.1
float backoff;
float change;
int i;
// go through alpha surfaces
if (tr.contents & MASK_ALPHA)
{
vec3_t start, unitvel;
float maxdist, dist;
if (tr.startsolid)
maxdist = VectorLength( self->velocity ) * FRAMETIME;
else
maxdist = VectorLength( self->velocity ) * (1 - tr.fraction) * FRAMETIME;
VectorNormalize2( self->velocity, unitvel );
VectorCopy( tr.endpos, start );
dist = 4;
VectorMA( start, dist, unitvel, start );
tr.startsolid = 1; // to get us started
while ((dist < maxdist) && tr.startsolid && (tr.contents & MASK_ALPHA))
{
tr = gi.trace ( start, jmins, jmaxs, self->s.origin, NULL, MASK_SOLID );
dist += 4;
VectorMA( start, 4, unitvel, start );
}
if (dist >= maxdist || tr.fraction == 1)
{
tr.fraction = 1;
goto skip_clip;
}
}
backoff = DotProduct (self->velocity, tr.plane.normal) * 1.5; //slide
for (i=0 ; i<3 ; i++)
{
change = tr.plane.normal[i]*backoff;
self->velocity[i] = self->velocity[i] - change;
if (self->velocity[i] > -STOP_EPSILON && self->velocity[i] < STOP_EPSILON)
self->velocity[i] = 0;
}
VectorCopy( tr.endpos, self->s.origin );
VectorMA( self->s.origin, 4, tr.plane.normal, self->s.origin );
VectorNormalize2( self->velocity, self->last_step_pos );
if (!self->acc)
{
// slow it down
VectorScale( self->velocity, 0.5, self->velocity );
}
self->acc = true;
if (strstr(tr.surface->name, "wood")) // spawn some smoke
{
static vec3_t last_pos;
static float last_time;
vec3_t sm_pos;
// so we don't spawn too many sprites over each other
if (last_time > (level.time - 0.5))
{
if (VectorDistance( last_pos, tr.endpos ) < 32)
goto skip_smoke;
}
last_time = level.time;
VectorCopy( tr.endpos, last_pos );
VectorMA( tr.endpos, 16, tr.plane.normal, sm_pos );
sm_pos[2] -= 12;
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_SFXSMOKE);
gi.WritePosition (sm_pos);
gi.WriteByte (48);
gi.WriteByte (0);
gi.multicast (tr.endpos, MULTICAST_PVS);
//.........这里部分代码省略.........
示例7: AddWindingToConvexHull
void AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal ) {
int i, j, k;
float *p, *copy;
vec3_t dir;
float d;
int numHullPoints, numNew;
vec3_t hullPoints[MAX_HULL_POINTS];
vec3_t newHullPoints[MAX_HULL_POINTS];
vec3_t hullDirs[MAX_HULL_POINTS];
qboolean hullSide[MAX_HULL_POINTS];
qboolean outside;
if ( !*hull ) {
*hull = CopyWinding( w );
return;
}
numHullPoints = (*hull)->numpoints;
Com_Memcpy( hullPoints, (*hull)->p, numHullPoints * sizeof(vec3_t) );
for ( i = 0 ; i < w->numpoints ; i++ ) {
p = w->p[i];
// calculate hull side vectors
for ( j = 0 ; j < numHullPoints ; j++ ) {
k = ( j + 1 ) % numHullPoints;
VectorSubtract( hullPoints[k], hullPoints[j], dir );
VectorNormalize2( dir, dir );
CrossProduct( normal, dir, hullDirs[j] );
}
outside = qfalse;
for ( j = 0 ; j < numHullPoints ; j++ ) {
VectorSubtract( p, hullPoints[j], dir );
d = DotProduct( dir, hullDirs[j] );
if ( d >= ON_EPSILON ) {
outside = qtrue;
}
if ( d >= -ON_EPSILON ) {
hullSide[j] = qtrue;
} else {
hullSide[j] = qfalse;
}
}
// if the point is effectively inside, do nothing
if ( !outside ) {
continue;
}
// find the back side to front side transition
for ( j = 0 ; j < numHullPoints ; j++ ) {
if ( !hullSide[ j % numHullPoints ] && hullSide[ (j + 1) % numHullPoints ] ) {
break;
}
}
if ( j == numHullPoints ) {
continue;
}
// insert the point here
VectorCopy( p, newHullPoints[0] );
numNew = 1;
// copy over all points that aren't double fronts
j = (j+1)%numHullPoints;
for ( k = 0 ; k < numHullPoints ; k++ ) {
if ( hullSide[ (j+k) % numHullPoints ] && hullSide[ (j+k+1) % numHullPoints ] ) {
continue;
}
copy = hullPoints[ (j+k+1) % numHullPoints ];
VectorCopy( copy, newHullPoints[numNew] );
numNew++;
}
numHullPoints = numNew;
Com_Memcpy( hullPoints, newHullPoints, numHullPoints * sizeof(vec3_t) );
}
FreeWinding( *hull );
w = AllocWinding( numHullPoints );
w->numpoints = numHullPoints;
*hull = w;
Com_Memcpy( w->p, hullPoints, numHullPoints * sizeof(vec3_t) );
}
示例8: PM_SlideMove
qboolean PM_SlideMove( float gravMod ) {
int bumpcount, numbumps;
vec3_t dir;
float d;
int numplanes;
vec3_t normal, planes[MAX_CLIP_PLANES];
vec3_t primal_velocity;
vec3_t clipVelocity;
int i, j, k;
trace_t trace;
vec3_t end;
float time_left;
float into;
vec3_t endVelocity;
vec3_t endClipVelocity;
qboolean damageSelf = qtrue;
int slideMoveContents = pm->tracemask;
if ( pm->ps->clientNum >= MAX_CLIENTS
&& !PM_ControlledByPlayer() )
{ //a non-player client, not an NPC under player control
if ( pml.walking //walking on the ground
|| (pm->ps->groundEntityNum != ENTITYNUM_NONE //in air
&& PM_InSpecialJump( pm->ps->legsAnim )//in a special jump
&& !(pm->ps->eFlags&EF_FORCE_GRIPPED)//not being gripped
&& !(pm->ps->pm_flags&PMF_TIME_KNOCKBACK)
&& pm->gent
&& pm->gent->forcePushTime < level.time) )//not being pushed
{ //
// If we're a vehicle, ignore this if we're being driven
if ( !pm->gent //not an game ent
|| !pm->gent->client //not a client
|| pm->gent->client->NPC_class != CLASS_VEHICLE//not a vehicle
|| !pm->gent->m_pVehicle //no vehicle
|| !pm->gent->m_pVehicle->m_pPilot//no pilot
|| pm->gent->m_pVehicle->m_pPilot->s.number >= MAX_CLIENTS )//pilot is not the player
{ //then treat do not enter brushes as SOLID
slideMoveContents |= CONTENTS_BOTCLIP;
}
}
}
numbumps = 4;
VectorCopy (pm->ps->velocity, primal_velocity);
VectorCopy (pm->ps->velocity, endVelocity);
if ( gravMod )
{
if ( !(pm->ps->eFlags&EF_FORCE_GRIPPED) && !(pm->ps->eFlags&EF_FORCE_DRAINED) )
{
endVelocity[2] -= pm->ps->gravity * pml.frametime * gravMod;
}
pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
primal_velocity[2] = endVelocity[2];
if ( pml.groundPlane )
{
if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) )
{ // 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;
VectorCopy( pml.groundTrace.plane.normal, planes[0] );
if ( !PM_GroundSlideOkay( planes[0][2] ) )
{
planes[0][2] = 0;
VectorNormalize( planes[0] );
}
}
else
{
numplanes = 0;
}
// never turn against original velocity
VectorNormalize2( pm->ps->velocity, planes[numplanes] );
numplanes++;
for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {
// calculate position we are trying to move to
VectorMA( 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, slideMoveContents, (EG2_Collision)0, 0 );
if ( (trace.contents&CONTENTS_BOTCLIP)
&& (slideMoveContents&CONTENTS_BOTCLIP) )
{ //hit a do not enter brush
if ( trace.allsolid || trace.startsolid )//inside the botclip
{ //crap, we're in a do not enter brush, take it out for the remainder of the traces and re-trace this one right now without it
slideMoveContents &= ~CONTENTS_BOTCLIP;
//.........这里部分代码省略.........
示例9: CL_CameraMove
/**
* @brief Update the camera position. This can be done in two different reasons. The first is the user input, the second
* is an active camera route. The camera route overrides the user input and is lerping the movement until the final position
* is reached.
*/
void CL_CameraMove (void)
{
float frac;
vec3_t delta;
int i;
/* get relevant variables */
const float rotspeed =
(cl_camrotspeed->value > MIN_CAMROT_SPEED) ? ((cl_camrotspeed->value < MAX_CAMROT_SPEED) ? cl_camrotspeed->value : MAX_CAMROT_SPEED) : MIN_CAMROT_SPEED;
const float movespeed =
(cl_cammovespeed->value > MIN_CAMMOVE_SPEED) ?
((cl_cammovespeed->value < MAX_CAMMOVE_SPEED) ? cl_cammovespeed->value / cl.cam.zoom : MAX_CAMMOVE_SPEED / cl.cam.zoom) : MIN_CAMMOVE_SPEED / cl.cam.zoom;
const float moveaccel =
(cl_cammoveaccel->value > MIN_CAMMOVE_ACCEL) ?
((cl_cammoveaccel->value < MAX_CAMMOVE_ACCEL) ? cl_cammoveaccel->value / cl.cam.zoom : MAX_CAMMOVE_ACCEL / cl.cam.zoom) : MIN_CAMMOVE_ACCEL / cl.cam.zoom;
if (cls.state != ca_active)
return;
if (!viddef.viewWidth || !viddef.viewHeight)
return;
/* calculate camera omega */
/* stop acceleration */
frac = cls.frametime * moveaccel * 2.5;
for (i = 0; i < 2; i++) {
if (fabs(cl.cam.omega[i]) > frac) {
if (cl.cam.omega[i] > 0)
cl.cam.omega[i] -= frac;
else
cl.cam.omega[i] += frac;
} else
cl.cam.omega[i] = 0;
/* rotational acceleration */
if (i == YAW)
cl.cam.omega[i] += CL_GetKeyMouseState(STATE_ROT) * frac * 2;
else
cl.cam.omega[i] += CL_GetKeyMouseState(STATE_TILT) * frac * 2;
if (cl.cam.omega[i] > rotspeed)
cl.cam.omega[i] = rotspeed;
if (-cl.cam.omega[i] > rotspeed)
cl.cam.omega[i] = -rotspeed;
}
cl.cam.omega[ROLL] = 0;
/* calculate new camera angles for this frame */
VectorMA(cl.cam.angles, cls.frametime, cl.cam.omega, cl.cam.angles);
if (cl.cam.angles[PITCH] > cl_campitchmax->value)
cl.cam.angles[PITCH] = cl_campitchmax->value;
if (cl.cam.angles[PITCH] < cl_campitchmin->value)
cl.cam.angles[PITCH] = cl_campitchmin->value;
AngleVectors(cl.cam.angles, cl.cam.axis[0], cl.cam.axis[1], cl.cam.axis[2]);
/* camera route overrides user input */
if (cameraRoute) {
/* camera route */
frac = cls.frametime * moveaccel * 2;
if (VectorDist(cl.cam.origin, routeFrom) > routeDist - 200) {
VectorMA(cl.cam.speed, -frac, routeDelta, cl.cam.speed);
VectorNormalize2(cl.cam.speed, delta);
if (DotProduct(delta, routeDelta) < 0.05) {
cameraRoute = false;
CL_BlockBattlescapeEvents(false);
}
} else
VectorMA(cl.cam.speed, frac, routeDelta, cl.cam.speed);
} else {
/* normal camera movement */
/* calculate ground-based movement vectors */
const float angle = cl.cam.angles[YAW] * torad;
const float sy = sin(angle);
const float cy = cos(angle);
vec3_t g_forward, g_right;
VectorSet(g_forward, cy, sy, 0.0);
VectorSet(g_right, sy, -cy, 0.0);
/* calculate camera speed */
/* stop acceleration */
frac = cls.frametime * moveaccel;
if (VectorLength(cl.cam.speed) > frac) {
VectorNormalize2(cl.cam.speed, delta);
VectorMA(cl.cam.speed, -frac, delta, cl.cam.speed);
} else
VectorClear(cl.cam.speed);
/* acceleration */
frac = cls.frametime * moveaccel * 3.5;
VectorClear(delta);
//.........这里部分代码省略.........
示例10: CM_TraceThroughVerticalCylinder
/*
================
CM_TraceThroughVerticalCylinder
get the first intersection of the ray with the cylinder
the cylinder extends halfheight above and below the origin
================
*/
void CM_TraceThroughVerticalCylinder( traceWork_t *tw, vec3_t origin, float radius, float halfheight, vec3_t start, vec3_t end, int contents) {
float length, fraction, l1, l2;
//float a;
float b, c, d, sqrtd;
vec3_t v1, dir, start2d, end2d, org2d, intersection;
// 2d coordinates
VectorSet(start2d, start[0], start[1], 0);
VectorSet(end2d, end[0], end[1], 0);
VectorSet(org2d, origin[0], origin[1], 0);
// if start is between lower and upper cylinder bounds
if (start[2] <= origin[2] + halfheight &&
start[2] >= origin[2] - halfheight) {
// if inside the cylinder
VectorSubtract(start2d, org2d, dir);
l1 = VectorLengthSquared(dir);
if (l1 < Square(radius)) {
tw->trace.startsolid = qtrue;
// if end is between lower and upper cylinder bounds
if (end[2] <= origin[2] + halfheight &&
end[2] >= origin[2] - halfheight) {
// test for allsolid
VectorSubtract(end2d, org2d, dir);
l1 = VectorLengthSquared(dir);
if (l1 < Square(radius)) {
tw->trace.allsolid = qtrue;
tw->trace.fraction = 0;
tw->trace.contents = contents;
}
}
return;
}
}
//
VectorSubtract(end2d, start2d, dir);
length = VectorNormalize(dir);
//
l1 = CM_DistanceFromLineSquared(org2d, start2d, end2d, dir);
VectorSubtract(end2d, org2d, v1);
l2 = VectorLengthSquared(v1);
// if no intersection with the cylinder and the end point is at least an epsilon away
if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
return;
}
//
//
// (start[0] - origin[0] - t * dir[0]) ^ 2 + (start[1] - origin[1] - t * dir[1]) ^ 2 = radius ^ 2
// (v1[0] + t * dir[0]) ^ 2 + (v1[1] + t * dir[1]) ^ 2 = radius ^ 2;
// v1[0] ^ 2 + 2 * v1[0] * t * dir[0] + (t * dir[0]) ^ 2 +
// v1[1] ^ 2 + 2 * v1[1] * t * dir[1] + (t * dir[1]) ^ 2 = radius ^ 2
// t ^ 2 * (dir[0] ^ 2 + dir[1] ^ 2) + t * (2 * v1[0] * dir[0] + 2 * v1[1] * dir[1]) +
// v1[0] ^ 2 + v1[1] ^ 2 - radius ^ 2 = 0
//
VectorSubtract(start, origin, v1);
// dir is normalized so we can use a = 1
//a = 1.0f;// * (dir[0] * dir[0] + dir[1] * dir[1]);
b = 2.0f * (v1[0] * dir[0] + v1[1] * dir[1]);
c = v1[0] * v1[0] + v1[1] * v1[1] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);
d = b * b - 4.0f * c;// * a;
if (d > 0) {
sqrtd = SquareRootFloat(d);
// = (- b + sqrtd) * 0.5f;// / (2.0f * a);
fraction = (- b - sqrtd) * 0.5f;// / (2.0f * a);
//
if (fraction < 0) {
fraction = 0;
}
else {
fraction /= length;
}
if ( fraction < tw->trace.fraction ) {
VectorSubtract(end, start, dir);
VectorMA(start, fraction, dir, intersection);
// if the intersection is between the cylinder lower and upper bound
if (intersection[2] <= origin[2] + halfheight &&
intersection[2] >= origin[2] - halfheight) {
//
tw->trace.fraction = fraction;
VectorSubtract(intersection, origin, dir);
dir[2] = 0;
#ifdef CAPSULE_DEBUG
l2 = VectorLength(dir);
if (l2 <= radius) {
int bah = 1;
}
#endif
#if 1 // ZTM: NOTE: Old method caused CM_Trace to fail assert at bottom of CM_Trace sometimes.
VectorNormalize2(dir, tw->trace.plane.normal);
#else
{
//.........这里部分代码省略.........
示例11: CM_TraceThroughLeaf
//.........这里部分代码省略.........
}
#define RADIUS_EPSILON 1.0f
/*
================
CM_TraceThroughSphere
get the first intersection of the ray with the sphere
================
*/
void CM_TraceThroughSphere( traceWork_t *tw, vec3_t origin, float radius, vec3_t start, vec3_t end, int contents ) {
float l1, l2, length, fraction;
//float a;
float b, c, d, sqrtd;
vec3_t v1, dir, intersection;
// if inside the sphere
VectorSubtract(start, origin, dir);
l1 = VectorLengthSquared(dir);
if (l1 < Square(radius)) {
tw->trace.startsolid = qtrue;
// test for allsolid
VectorSubtract(end, origin, dir);
l1 = VectorLengthSquared(dir);
if (l1 < Square(radius)) {
tw->trace.allsolid = qtrue;
tw->trace.fraction = 0;
tw->trace.contents = contents;
}
return;
}
//
VectorSubtract(end, start, dir);
length = VectorNormalize(dir);
//
l1 = CM_DistanceFromLineSquared(origin, start, end, dir);
VectorSubtract(end, origin, v1);
l2 = VectorLengthSquared(v1);
// if no intersection with the sphere and the end point is at least an epsilon away
if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
return;
}
//
// | origin - (start + t * dir) | = radius
// a = dir[0]^2 + dir[1]^2 + dir[2]^2;
// b = 2 * (dir[0] * (start[0] - origin[0]) + dir[1] * (start[1] - origin[1]) + dir[2] * (start[2] - origin[2]));
// c = (start[0] - origin[0])^2 + (start[1] - origin[1])^2 + (start[2] - origin[2])^2 - radius^2;
//
VectorSubtract(start, origin, v1);
// dir is normalized so a = 1
//a = 1.0f;//dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2];
b = 2.0f * (dir[0] * v1[0] + dir[1] * v1[1] + dir[2] * v1[2]);
c = v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);
d = b * b - 4.0f * c;// * a;
if (d > 0) {
sqrtd = SquareRootFloat(d);
// = (- b + sqrtd) * 0.5f; // / (2.0f * a);
fraction = (- b - sqrtd) * 0.5f; // / (2.0f * a);
//
if (fraction < 0) {
fraction = 0;
}
else {
fraction /= length;
}
if ( fraction < tw->trace.fraction ) {
tw->trace.fraction = fraction;
VectorSubtract(end, start, dir);
VectorMA(start, fraction, dir, intersection);
VectorSubtract(intersection, origin, dir);
#ifdef CAPSULE_DEBUG
l2 = VectorLength(dir);
if (l2 < radius) {
int bah = 1;
}
#endif
#if 1 // ZTM: NOTE: Old method caused CM_Trace to fail assert at bottom of CM_Trace sometimes.
VectorNormalize2(dir, tw->trace.plane.normal);
#else
{
float scale;
scale = 1 / (radius+RADIUS_EPSILON);
VectorScale(dir, scale, dir);
VectorCopy(dir, tw->trace.plane.normal);
}
#endif
VectorAdd( tw->modelOrigin, intersection, intersection);
tw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection);
tw->trace.contents = contents;
}
}
else if (d == 0) {
//t1 = (- b ) / 2;
// slide along the sphere
}
// no intersection at all
}
示例12: R_SetupEntityLightingGrid
//.........这里部分代码省略.........
for( j = 0; j < 3; j++ )
{
//if( ambient )
{
for( i = 0; i < 4; i++ )
{
for( k = 0; k < MAXLIGHTMAPS; k++ )
{
if( ( s = lightarray[i*2].styles[k] ) != 255 )
ent->ambientLight[j] += t[i*2] * lightarray[i*2].ambientLight[k][j] * tr.lightStyles[s].rgb[j];
if( ( s = lightarray[i*2+1].styles[k] ) != 255 )
ent->ambientLight[j] += t[i*2+1] * lightarray[i*2+1].ambientLight[k][j] * tr.lightStyles[s].rgb[j];
}
}
}
//if( diffuse || radius )
{
for( i = 0; i < 4; i++ )
{
for( k = 0; k < MAXLIGHTMAPS; k++ )
{
if( ( s = lightarray[i*2].styles[k] ) != 255 )
ent->directedLight[j] += t[i*2] * lightarray[i*2].directLight[k][j] * tr.lightStyles[s].rgb[j];
if( ( s = lightarray[i*2+1].styles[k] ) != 255 )
ent->directedLight[j] += t[i*2+1] * lightarray[i*2+1].directLight[k][j] * tr.lightStyles[s].rgb[j];
}
}
}
}
VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );
VectorNormalize2( direction, ent->lightDir );
#if 0
//VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin );
for ( i = 0 ; i < 3 ; i++ ) {
float v;
v = lightOrigin[i]*tr.world->lightGridInverseSize[i];
pos[i] = floor( v );
frac[i] = v - pos[i];
if ( pos[i] < 0 ) {
pos[i] = 0;
} else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) {
pos[i] = tr.world->lightGridBounds[i] - 1;
}
}
VectorClear( ent->ambientLight );
VectorClear( ent->directedLight );
VectorClear( direction );
assert( tr.world->lightGridData ); // NULL with -nolight maps
// trilerp the light value
gridStep[0] = 8;
gridStep[1] = 8 * tr.world->lightGridBounds[0];
gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
gridData = tr.world->lightGridData + pos[0] * gridStep[0]
+ pos[1] * gridStep[1] + pos[2] * gridStep[2];
totalFactor = 0;
示例13: SV_movestep
//.........这里部分代码省略.........
// If so, allow the move so he can get out.
VectorMA(e->s.origin,2048,e->movedir,laser_end);
laser_trace = gi.trace(e->s.origin,NULL,NULL,laser_end,NULL,CONTENTS_SOLID|CONTENTS_MONSTER);
if(laser_trace.ent == ent)
continue;
VectorCopy(laser_trace.endpos,laser_end);
laser_mins[0] = min(e->s.origin[0],laser_end[0]);
laser_mins[1] = min(e->s.origin[1],laser_end[1]);
laser_mins[2] = min(e->s.origin[2],laser_end[2]);
laser_maxs[0] = max(e->s.origin[0],laser_end[0]);
laser_maxs[1] = max(e->s.origin[1],laser_end[1]);
laser_maxs[2] = max(e->s.origin[2],laser_end[2]);
monster_mins[0] = min(oldorg[0],trace.endpos[0]) + ent->mins[0];
monster_mins[1] = min(oldorg[1],trace.endpos[1]) + ent->mins[1];
monster_mins[2] = min(oldorg[2],trace.endpos[2]) + ent->mins[2];
monster_maxs[0] = max(oldorg[0],trace.endpos[0]) + ent->maxs[0];
monster_maxs[1] = max(oldorg[1],trace.endpos[1]) + ent->maxs[1];
monster_maxs[2] = max(oldorg[2],trace.endpos[2]) + ent->maxs[2];
if( monster_maxs[0] < laser_mins[0] ) continue;
if( monster_maxs[1] < laser_mins[1] ) continue;
if( monster_maxs[2] < laser_mins[2] ) continue;
if( monster_mins[0] > laser_maxs[0] ) continue;
if( monster_mins[1] > laser_maxs[1] ) continue;
if( monster_mins[2] > laser_maxs[2] ) continue;
// If we arrive here, some part of the bounding box surrounding
// monster's total movement intersects laser bounding box.
// If laser is parallel to x, y, or z, we definitely
// know this move will put monster in path of laser
if ( (e->movedir[0] == 1.) || (e->movedir[1] == 1.) || (e->movedir[2] == 1.))
return false;
// Shift psuedo laser towards monster's current position up to
// the total distance he's proposing moving.
delta = min(16,dist);
VectorNormalize2(move,dir);
while(delta < dist+15.875)
{
if(delta > dist) delta = dist;
VectorMA(e->s.origin, -delta,dir,laser_start);
VectorMA(e->s.old_origin,-delta,dir,laser_end);
laser_trace = gi.trace(laser_start,NULL,NULL,laser_end,world,CONTENTS_SOLID|CONTENTS_MONSTER);
if(laser_trace.ent == ent)
return false;
delta += 16;
}
}
}
if ((trace.fraction == 1) && !jump && canjump && (ent->monsterinfo.jumpdn > 0))
{
end[2] = oldorg[2] + move[2] - ent->monsterinfo.jumpdn;
trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID | MASK_WATER);
if(trace.fraction < 1 && (trace.plane.normal[2] > 0.9) && (trace.contents & MASK_SOLID) && (neworg[2] - 16 > trace.endpos[2]))
{
if(!trace.ent || (!trace.ent->client && !(trace.ent->svflags & SVF_MONSTER) && !(trace.ent->svflags & SVF_DEADMONSTER)))
jump = -1;
}
}
if ((trace.fraction == 1) && !jump)
{
// if monster had the ground pulled out, go ahead and fall
if ( ent->flags & FL_PARTIALGROUND )
{
VectorAdd (ent->s.origin, move, ent->s.origin);
if (relink)
{
示例14: MM_ClipVelocity
qboolean MM_SlideMove
(
qboolean gravity
)
{
int bumpcount;
vec3_t dir;
float d;
int numplanes;
vec3_t planes[ 5 ];
vec3_t clipVelocity;
int i;
int j;
int k;
trace_t trace;
vec3_t end;
float time_left;
qboolean bBlockEnt;
if( gravity )
{
mm->velocity[ 2 ] = mm->velocity[ 2 ] - mm->frametime * sv_gravity->integer;
if( mm->groundPlane )
MM_ClipVelocity( mm->velocity, mm->groundPlaneNormal, mm->velocity, OVERCLIP );
}
time_left = mm->frametime;
if( mm->groundPlane ) {
numplanes = 1;
VectorCopy( mm->groundPlaneNormal, planes[ 0 ] );
} else {
numplanes = 0;
}
// never turn against original velocity
VectorNormalize2( mm->velocity, planes[ numplanes ] );
numplanes++;
for( bumpcount = 0; bumpcount < 4; bumpcount++ )
{
// calculate position we are trying to move to
VectorMA( mm->origin, time_left, mm->velocity, end );
// see if we can make it there
gi.Trace( &trace, mm->origin, mm->mins, mm->maxs, end, mm->entityNum, mm->tracemask, qtrue, qfalse );
if( trace.allsolid )
break;
if( trace.fraction > 0 ) {
// actually covered some distance
VectorCopy( trace.endpos, mm->origin );
}
if( trace.fraction == 1 )
return bumpcount != 0;
// save entity for contact
bBlockEnt = MM_AddTouchEnt( trace.entityNum );
if( trace.plane.normal[ 2 ] < MIN_WALK_NORMAL )
{
if( trace.plane.normal[ 2 ] > -0.999f && bBlockEnt && mm->groundPlane )
{
if( !mm->hit_obstacle )
{
mm->hit_obstacle = true;
VectorCopy( mm->origin, mm->hit_origin );
}
VectorAdd( mm->obstacle_normal, trace.plane.normal, mm->obstacle_normal );
}
}
else
{
memcpy( &mml.groundTrace, &trace, sizeof( mml.groundTrace ) );
mml.validGroundTrace = true;
}
time_left -= time_left * trace.fraction;
if( numplanes >= MAX_CLIP_PLANES )
{
VectorClear( mm->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( DotProduct( trace.plane.normal, planes[ i ] ) > 0.99 )
{
VectorAdd( trace.plane.normal, mm->velocity, mm->velocity );
break;
//.........这里部分代码省略.........
示例15: MakeMeshNormals
// Handles all the complicated wrapping and degenerate cases.
static void MakeMeshNormals( int width, int height, idWorldVertex ctrl[ MAX_GRID_SIZE ][ MAX_GRID_SIZE ] ) {
static int neighbors[ 8 ][ 2 ] =
{
{0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
};
bool wrapWidth = true;
for ( int i = 0; i < height; i++ ) {
float len = ( ctrl[ i ][ 0 ].xyz - ctrl[ i ][ width - 1 ].xyz ).LengthSqr();
if ( len > 1.0 ) {
wrapWidth = false;
break;
}
}
bool wrapHeight = true;
for ( int i = 0; i < width; i++ ) {
float len = ( ctrl[ 0 ][ i ].xyz - ctrl[ height - 1 ][ i ].xyz ).LengthSqr();
if ( len > 1.0 ) {
wrapHeight = false;
break;
}
}
for ( int i = 0; i < width; i++ ) {
for ( int j = 0; j < height; j++ ) {
int count = 0;
idWorldVertex& dv = ctrl[ j ][ i ];
idVec3 base = dv.xyz;
vec3_t around[ 8 ];
bool good[ 8 ];
for ( int k = 0; k < 8; k++ ) {
VectorClear( around[ k ] );
good[ k ] = false;
for ( int dist = 1; dist <= 3; dist++ ) {
int x = i + neighbors[ k ][ 0 ] * dist;
int y = j + neighbors[ k ][ 1 ] * dist;
if ( wrapWidth ) {
if ( x < 0 ) {
x = width - 1 + x;
} else if ( x >= width ) {
x = 1 + x - width;
}
}
if ( wrapHeight ) {
if ( y < 0 ) {
y = height - 1 + y;
} else if ( y >= height ) {
y = 1 + y - height;
}
}
if ( x < 0 || x >= width || y < 0 || y >= height ) {
break; // edge of patch
}
idVec3 temp = ctrl[ y ][ x ].xyz - base;
vec3_t oldtemp;
temp.ToOldVec3( oldtemp );
if ( VectorNormalize2( oldtemp, oldtemp ) == 0 ) {
continue; // degenerate edge, get more dist
} else {
good[ k ] = true;
VectorCopy( oldtemp, around[ k ] );
break; // good edge
}
}
}
vec3_t sum;
VectorClear( sum );
for ( int k = 0; k < 8; k++ ) {
if ( !good[ k ] || !good[ ( k + 1 ) & 7 ] ) {
continue; // didn't get two points
}
vec3_t normal;
CrossProduct( around[ ( k + 1 ) & 7 ], around[ k ], normal );
if ( VectorNormalize2( normal, normal ) == 0 ) {
continue;
}
VectorAdd( normal, sum, sum );
count++;
}
if ( count == 0 ) {
count = 1;
}
vec3_t old;
VectorNormalize2( sum, old );
dv.normal.FromOldVec3( old );
}
}
}