/* ============= SV_Submerged determine how deep the entity is ============= */ float SV_Submerged( edict_t *ent ) { vec3_t point; vec3_t halfmax; float waterlevel; VectorAverage( ent->v.absmin, ent->v.absmax, halfmax ); waterlevel = ent->v.absmin[2] - halfmax[2]; switch( ent->v.waterlevel ) { case 1: return SV_RecursiveWaterLevel( halfmax, 0.0f, waterlevel, 0 ) - waterlevel; case 3: VectorSet( point, halfmax[0], halfmax[1], ent->v.absmax[2] ); svs.groupmask = ent->v.groupinfo; if( SV_PointContents( point ) == CONTENTS_WATER ) { return (ent->v.maxs[2] - ent->v.mins[2]); } // intentionally fallthrough case 2: return SV_RecursiveWaterLevel( halfmax, ent->v.absmax[2] - halfmax[2], 0.0f, 0 ) - waterlevel; default: return 0.0f; } }
/* =============== R_TransEntityCompare Sorting translucent entities by rendermode then by distance =============== */ static int R_TransEntityCompare( const cl_entity_t **a, const cl_entity_t **b ) { cl_entity_t *ent1, *ent2; vec3_t vecLen, org; float len1, len2; ent1 = (cl_entity_t *)*a; ent2 = (cl_entity_t *)*b; // now sort by rendermode if( R_RankForRenderMode( ent1 ) > R_RankForRenderMode( ent2 )) return 1; if( R_RankForRenderMode( ent1 ) < R_RankForRenderMode( ent2 )) return -1; // then by distance if( ent1->model->type == mod_brush ) { VectorAverage( ent1->model->mins, ent1->model->maxs, org ); VectorAdd( ent1->origin, org, org ); VectorSubtract( RI.vieworg, org, vecLen ); } else VectorSubtract( RI.vieworg, ent1->origin, vecLen ); len1 = VectorLength( vecLen ); if( ent2->model->type == mod_brush ) { VectorAverage( ent2->model->mins, ent2->model->maxs, org ); VectorAdd( ent2->origin, org, org ); VectorSubtract( RI.vieworg, org, vecLen ); } else VectorSubtract( RI.vieworg, ent2->origin, vecLen ); len2 = VectorLength( vecLen ); if( len1 > len2 ) return -1; if( len1 < len2 ) return 1; return 0; }
// // sound engine implementation // qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin, float *pradius ) { cl_entity_t *ent; qboolean valid_origin; ASSERT( origin != NULL ); if( entnum == 0 ) return true; // static sound if(( entnum - 1 ) == cl.playernum ) { VectorCopy( cl.frame.local.client.origin, origin ); return true; } valid_origin = VectorIsNull( origin ) ? false : true; ent = CL_GetEntityByIndex( entnum ); // entity is not present on the client but has valid origin if( !ent || !ent->index ) return valid_origin; if( ent->curstate.messagenum == 0 ) { // entity is never has updates on the client // so we should use static origin instead return valid_origin; } #if 0 // uncomment this if you want enable additional check by PVS if( ent->curstate.messagenum != cl.parsecount ) return valid_origin; #endif // setup origin VectorAverage( ent->curstate.mins, ent->curstate.maxs, origin ); VectorAdd( origin, ent->curstate.origin, origin ); // setup radius if( pradius ) { if( ent->model != NULL && ent->model->radius ) *pradius = ent->model->radius; else *pradius = RadiusFromBounds( ent->curstate.mins, ent->curstate.maxs ); } return true; }
/* =============== V_SetupOverviewState Get initial overview values =============== */ void V_SetupOverviewState( void ) { ref_overview_t *ov = &clgame.overView; float mapAspect, screenAspect, aspect; ov->rotated = ( world.size[1] <= world.size[0] ) ? true : false; // calculate nearest aspect mapAspect = world.size[!ov->rotated] / world.size[ov->rotated]; screenAspect = (float)glState.width / (float)glState.height; aspect = max( mapAspect, screenAspect ); ov->zNear = world.maxs[2]; ov->zFar = world.mins[2]; ov->flZoom = ( 8192.0f / world.size[ov->rotated] ) / aspect; VectorAverage( world.mins, world.maxs, ov->origin ); }
/* ================= FinishBrush produces a final brush based on the buildBrush->sides array and links it to the current entity ================= */ brush_t *FinishBrush( void ) { brush_t *b; // create windings for sides and bounds for brush if( !CreateBrushWindings( buildBrush )) return NULL; // origin brushes are removed, but they set the rotation origin for the rest of the brushes in the entity. // after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush if( buildBrush->compileFlags & C_ORIGIN ) { char string[32]; vec3_t size, movedir, origin; if( numEntities == 1 ) { Msg( "Entity %i, Brush %i: origin brushes not allowed in world\n", mapEnt->mapEntityNum, entitySourceBrushes ); return NULL; } // calcualte movedir (Xash 0.4 style) VectorAverage( buildBrush->mins, buildBrush->maxs, origin ); VectorSubtract( buildBrush->maxs, buildBrush->mins, size ); if( size[2] > size[0] && size[2] > size[1] ) VectorSet( movedir, 0.0f, 1.0f, 0.0f ); // x-rotate else if( size[1] > size[2] && size[1] > size[0] ) VectorSet( movedir, 1.0f, 0.0f, 0.0f ); // y-rotate else if( size[0] > size[2] && size[0] > size[1] ) VectorSet( movedir, 0.0f, 0.0f, 1.0f ); // z-rotate else VectorClear( movedir ); // custom movedir #if 0 if( !VectorIsNull( movedir )) { com.snprintf( string, sizeof( string ), "%i %i %i", (int)movedir[0], (int)movedir[1], (int)movedir[2] ); SetKeyValue( &entities[numEntities - 1], "movedir", string ); } #endif if(!VectorIsNull( origin )) { com.snprintf( string, sizeof( string ), "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2] ); SetKeyValue( &entities[numEntities - 1], "origin", string ); VectorCopy( origin, entities[numEntities - 1].origin ); } // don't keep this brush return NULL; } // determine if the brush is an area portal if( buildBrush->compileFlags & C_AREAPORTAL ) { if( numEntities != 1 ) { Msg( "Entity %i, Brush %i: areaportals only allowed in world\n", mapEnt->mapEntityNum, entitySourceBrushes ); return NULL; } } AddBrushBevels(); b = CopyBrush( buildBrush ); b->entityNum = mapEnt->mapEntityNum; b->brushNum = entitySourceBrushes; b->original = b; // link opaque brushes to head of list, translucent brushes to end if( b->opaque || mapEnt->lastBrush == NULL ) { b->next = mapEnt->brushes; mapEnt->brushes = b; if( mapEnt->lastBrush == NULL ) mapEnt->lastBrush = b; } else { b->next = NULL; mapEnt->lastBrush->next = b; mapEnt->lastBrush = b; } // link colorMod volume brushes to the entity directly if( b->contentShader != NULL && b->contentShader->colorMod != NULL && b->contentShader->colorMod->type == CM_VOLUME ) { b->nextColorModBrush = mapEnt->colorModBrushes; mapEnt->colorModBrushes = b; } return b; }
/* ============ SV_PushRotate ============ */ static edict_t *SV_PushRotate( edict_t *pusher, float movetime ) { int i, e, block, oldsolid; matrix4x4 start_l, end_l; vec3_t lmove, amove; sv_pushed_t *p, *pushed_p; vec3_t org, org2, temp; edict_t *check; if( svgame.globals->changelevel || VectorIsNull( pusher->v.avelocity )) { pusher->v.ltime += movetime; return NULL; } for( i = 0; i < 3; i++ ) amove[i] = pusher->v.avelocity[i] * movetime; // create pusher initial position Matrix4x4_CreateFromEntity( start_l, pusher->v.angles, pusher->v.origin, 1.0f ); pushed_p = svgame.pushed; // save the pusher's original position pushed_p->ent = pusher; VectorCopy( pusher->v.origin, pushed_p->origin ); VectorCopy( pusher->v.angles, pushed_p->angles ); pushed_p++; // move the pusher to it's final position SV_AngularMove( pusher, movetime, pusher->v.friction ); SV_LinkEdict( pusher, false ); pusher->v.ltime += movetime; oldsolid = pusher->v.solid; // non-solid pushers can't push anything if( pusher->v.solid == SOLID_NOT ) return NULL; // create pusher final position Matrix4x4_CreateFromEntity( end_l, pusher->v.angles, pusher->v.origin, 1.0f ); // see if any solid entities are inside the final position for( e = 1; e < svgame.numEntities; e++ ) { check = EDICT_NUM( e ); if( !SV_IsValidEdict( check )) continue; // filter movetypes to collide with if( !SV_CanPushed( check )) continue; pusher->v.solid = SOLID_NOT; block = SV_TestEntityPosition( check, pusher ); pusher->v.solid = oldsolid; if( block ) continue; // if the entity is standing on the pusher, it will definately be moved if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher )) { 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] ) continue; // see if the ent's bbox is inside the pusher's final position if( !SV_TestEntityPosition( check, NULL )) continue; } // save original position of contacted entity pushed_p->ent = check; VectorCopy( check->v.origin, pushed_p->origin ); VectorCopy( check->v.angles, pushed_p->angles ); pushed_p->fixangle = check->v.fixangle; pushed_p++; // calculate destination position if( check->v.movetype == MOVETYPE_PUSHSTEP || check->v.movetype == MOVETYPE_STEP ) VectorAverage( check->v.absmin, check->v.absmax, org ); else VectorCopy( check->v.origin, org ); Matrix4x4_VectorITransform( start_l, org, temp ); Matrix4x4_VectorTransform( end_l, temp, org2 ); VectorSubtract( org2, org, lmove ); // i can't clear FL_ONGROUND in all cases because many bad things may be happen if( check->v.movetype != MOVETYPE_WALK ) { if( lmove[2] != 0.0f ) check->v.flags &= ~FL_ONGROUND; if( lmove[2] < 0.0f && !pusher->v.dmg ) lmove[2] = 0.0f; // let's the free falling } // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity( check, lmove, amove, &block ); pusher->v.solid = oldsolid; // pushed entity blocked by wall if( block && check->v.movetype != MOVETYPE_WALK ) check->v.flags &= ~FL_ONGROUND; // if it is still inside the pusher, block if( SV_TestEntityPosition( check, NULL ) && block ) { if( !SV_CanBlock( check )) continue; pusher->v.ltime -= movetime; // move back any entities we already moved // go backwards, so if the same entity was pushed // twice, it goes back to the original position for( p = pushed_p - 1; p >= svgame.pushed; p-- ) { VectorCopy( p->origin, p->ent->v.origin ); VectorCopy( p->angles, p->ent->v.angles ); SV_LinkEdict( p->ent, (p->ent == check) ? true : false ); p->ent->v.fixangle = p->fixangle; } return check; } } return NULL; }