コード例 #1
0
ファイル: gl_mirror.c プロジェクト: DavidKnight247/xash3d
/*
================
R_PlaneForMirror

Get transformed mirrorplane and entity matrix
================
*/
void R_PlaneForMirror( msurface_t *surf, mplane_t *out, matrix4x4 m )
{
	cl_entity_t	*ent;

	ASSERT( out != NULL );

	ent = RI.currententity;

	// setup mirror plane
	*out = *surf->plane;

	if( surf->flags & SURF_PLANEBACK )
	{
		VectorNegate( out->normal, out->normal );
		out->dist = -out->dist;
	}

	if( !VectorIsNull( ent->origin ) || !VectorIsNull( ent->angles ))
	{
		mplane_t	tmp;

		if( !VectorIsNull( ent->angles )) Matrix4x4_CreateFromEntity( m, ent->angles, ent->origin, 1.0f );
		else Matrix4x4_CreateFromEntity( m, vec3_origin, ent->origin, 1.0f );

		tmp = *out;

		// transform mirror plane by entity matrix
		Matrix4x4_TransformPositivePlane( m, tmp.normal, tmp.dist, out->normal, &out->dist );
	}
	else Matrix4x4_LoadIdentity( m );
}
コード例 #2
0
ファイル: pm_surface.c プロジェクト: DeadZoneLuna/xash3d
/*
==================
PM_TraceTexture

find the face where the traceline hit
assume physentity is valid
==================
*/
msurface_t *PM_TraceSurface( physent_t *pe, vec3_t start, vec3_t end )
{
	matrix4x4		matrix;
	model_t		*bmodel;
	hull_t		*hull;
	vec3_t		start_l, end_l;
	vec3_t		offset;

	bmodel = pe->model;

	if( !bmodel || bmodel->type != mod_brush )
		return NULL;

	hull = &pe->model->hulls[0];
	VectorSubtract( hull->clip_mins, vec3_origin, offset );
	VectorAdd( offset, pe->origin, offset );

	VectorSubtract( start, offset, start_l );
	VectorSubtract( end, offset, end_l );

	// rotate start and end into the models frame of reference
	if( !VectorIsNull( pe->angles ))
	{
		Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
		Matrix4x4_VectorITransform( matrix, start, start_l );
		Matrix4x4_VectorITransform( matrix, end, end_l );
	}

	return PM_RecursiveSurfCheck( bmodel, &bmodel->nodes[hull->firstclipnode], start_l, end_l );
}
コード例 #3
0
/**
 * @brief Applies any configuration and tag alignment, populating the model-view
 * matrix for the entity in the process.
 */
void R_SetMatrixForEntity(r_entity_t *e) {

	if (e->parent) {
		vec3_t forward;

		if (!IS_MESH_MODEL(e->model)) {
			Com_Warn("Invalid model for linked entity\n");
			return;
		}

		const r_entity_t *p = e->parent;
		while (p->parent) {
			p = p->parent;
		}

		AngleVectors(p->angles, forward, NULL, NULL);

		VectorClear(e->origin);
		VectorClear(e->angles);

		Matrix4x4_CreateFromEntity(&e->matrix, e->origin, e->angles, e->scale);

		R_ApplyMeshModelTag(e);

		R_ApplyMeshModelConfig(e);

		Matrix4x4_Invert_Simple(&e->inverse_matrix, &e->matrix);

		Matrix4x4_Transform(&e->matrix, vec3_origin, e->origin);
		Matrix4x4_Transform(&e->matrix, vec3_forward, forward);

		VectorAngles(forward, e->angles);
		return;
	}

	Matrix4x4_CreateFromEntity(&e->matrix, e->origin, e->angles, e->scale);

	if (IS_MESH_MODEL(e->model)) {
		R_ApplyMeshModelConfig(e);
	}

	Matrix4x4_Invert_Simple(&e->inverse_matrix, &e->matrix);
}
コード例 #4
0
/*
=============
CL_TruePointContents

=============
*/
int CL_TruePointContents( const vec3_t p )
{
	int	i, contents;
	int	oldhull;
	hull_t	*hull;
	vec3_t	test, offset;
	physent_t	*pe;

	// sanity check
	if( !p )
		return CONTENTS_NONE;

	oldhull = clgame.pmove->usehull;

	// get base contents from world
	contents = PM_HullPointContents( &cl.worldmodel->hulls[0], 0, p );

	for( i = 0; i < clgame.pmove->nummoveent; i++ )
	{
		pe = &clgame.pmove->moveents[i];

		if( pe->solid != SOLID_NOT ) // disabled ?
			continue;

		// only brushes can have special contents
		if( !pe->model || pe->model->type != mod_brush )
			continue;

		// check water brushes accuracy
		clgame.pmove->usehull = 2;
		hull = PM_HullForBsp( pe, clgame.pmove, offset );
		clgame.pmove->usehull = oldhull;

		// offset the test point appropriately for this hull.
		VectorSubtract( p, offset, test );

		if( (pe->model->flags & MODEL_HAS_ORIGIN) && !VectorIsNull( pe->angles ))
		{
			matrix4x4	matrix;
	
			Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
			Matrix4x4_VectorITransform( matrix, p, test );
		};

		// test hull for intersection with this model
		if( PM_HullPointContents( hull, hull->firstclipnode, test ) == CONTENTS_EMPTY )
			continue;

		// compare contents ranking
		if( RankForContents( pe->skin ) > RankForContents( contents ))
			contents = pe->skin; // new content has more priority
	};

	return contents;
}
コード例 #5
0
/**
 * @brief
 */
static void Cl_ParseBaseline(void) {
	static entity_state_t null_state;

	const uint16_t number = Net_ReadShort(&net_message);
	const uint16_t bits = Net_ReadShort(&net_message);

	cl_entity_t *ent = &cl.entities[number];

	Net_ReadDeltaEntity(&net_message, &null_state, &ent->baseline, number, bits);

	// initialize clipping matrices
	if (ent->baseline.solid) {
		if (ent->baseline.solid == SOLID_BSP) {
			Matrix4x4_CreateFromEntity(&ent->matrix, ent->baseline.origin, ent->baseline.angles, 1.0);
			Matrix4x4_Invert_Simple(&ent->inverse_matrix, &ent->matrix);
		} else { // bounding-box entities
			Matrix4x4_CreateFromEntity(&ent->matrix, ent->baseline.origin, vec3_origin, 1.0);
			Matrix4x4_Invert_Simple(&ent->inverse_matrix, &ent->matrix);
		}
	}
}
コード例 #6
0
/*
=============
CL_WaterEntity

=============
*/
int CL_WaterEntity( const float *rgflPos )
{
	physent_t		*pe;
	hull_t		*hull;
	vec3_t		test, offset;
	int		i, oldhull;

	if( !rgflPos )
		return -1;

	oldhull = clgame.pmove->usehull;

	for( i = 0; i < clgame.pmove->nummoveent; i++ )
	{
		pe = &clgame.pmove->moveents[i];

		if( pe->solid != SOLID_NOT ) // disabled ?
			continue;

		// only brushes can have special contents
		if( !pe->model || pe->model->type != mod_brush )
			continue;

		// check water brushes accuracy
		clgame.pmove->usehull = 2;
		hull = PM_HullForBsp( pe, clgame.pmove, offset );
		clgame.pmove->usehull = oldhull;

		// offset the test point appropriately for this hull.
		VectorSubtract( rgflPos, offset, test );

		if( (pe->model->flags & MODEL_HAS_ORIGIN) && !VectorIsNull( pe->angles ))
		{
			matrix4x4	matrix;
	
			Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
			Matrix4x4_VectorITransform( matrix, rgflPos, test );
		};

		// test hull for intersection with this model
		if( PM_HullPointContents( hull, hull->firstclipnode, test ) == CONTENTS_EMPTY )
			continue;

		// found water entity
		return pe->info;
	}
	return -1;
}
コード例 #7
0
ファイル: cl_pmove.c プロジェクト: adamixik/xash3d
static float pfnTraceModel( physent_t *pe, float *start, float *end, trace_t *trace )
{
	int	old_usehull;
	vec3_t	start_l, end_l;
	vec3_t	offset, temp;
	qboolean	rotated;
	matrix4x4	matrix;
	hull_t	*hull;

	old_usehull = clgame.pmove->usehull;
	clgame.pmove->usehull = 2;

	hull = PM_HullForBsp( pe, clgame.pmove, offset );

	clgame.pmove->usehull = old_usehull;

	if( pe->solid == SOLID_BSP && !VectorIsNull( pe->angles ))
		rotated = true;
	else rotated = false;

 	if( rotated )
 	{
 		Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
 		Matrix4x4_VectorITransform( matrix, start, start_l );
 		Matrix4x4_VectorITransform( matrix, end, end_l );
 	}
 	else
 	{
 		VectorSubtract( start, offset, start_l );
 		VectorSubtract( end, offset, end_l );
 	}

	SV_RecursiveHullCheck( hull, hull->firstclipnode, 0, 1, start_l, end_l, trace );
	trace->ent = NULL;

	if( rotated )
	{
		VectorCopy( trace->plane.normal, temp );
		Matrix4x4_TransformPositivePlane( matrix, temp, trace->plane.dist, trace->plane.normal, &trace->plane.dist );
	}

	VectorLerp( start, trace->fraction, end, trace->endpos );

	return trace->fraction;
}
コード例 #8
0
ファイル: gl_rmain.c プロジェクト: jeefo/xash3d
/*
=============
R_TranslateForEntity
=============
*/
void R_TranslateForEntity( cl_entity_t *e )
{
	float	scale = 1.0f;

	if( e == clgame.entities || R_StaticEntity( e ))
	{
		R_LoadIdentity();
		return;
	}

	if( e->model->type != mod_brush && e->curstate.scale > 0.0f )
		scale = e->curstate.scale;

	Matrix4x4_CreateFromEntity( RI.objectMatrix, vec3_origin, e->origin, scale );
	Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, RI.objectMatrix );

	pglMatrixMode( GL_MODELVIEW );
	GL_LoadMatrix( RI.modelviewMatrix );
	tr.modelviewIdentity = false;
}
コード例 #9
0
ファイル: gl_decals.c プロジェクト: DavidKnight247/xash3d
// Shoots a decal onto the surface of the BSP.  position is the center of the decal in world coords
void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, vec3_t saxis, float scale )
{
	decalinfo_t	decalInfo;
	hull_t		*hull;
	cl_entity_t	*ent = NULL;
	model_t		*model = NULL;
	int		width, height;

	if( textureIndex <= 0 || textureIndex >= MAX_TEXTURES )
	{
		MsgDev( D_ERROR, "Decal has invalid texture!\n" );
		return;
	}

	if( entityIndex > 0 )
	{
		ent = CL_GetEntityByIndex( entityIndex );

		if( modelIndex > 0 ) model = Mod_Handle( modelIndex );
		else if( ent != NULL ) model = Mod_Handle( ent->curstate.modelindex );
		else return;
	}
	else if( modelIndex > 0 )
		model = Mod_Handle( modelIndex );
	else model = cl.worldmodel;

	if( !model ) return;
	
	if( model->type != mod_brush )
	{
		MsgDev( D_ERROR, "Decals must hit mod_brush!\n" );
		return;
	}

	decalInfo.m_pModel = model;
	hull = &model->hulls[0];	// always use #0 hull

	if( ent && !( flags & FDECAL_LOCAL_SPACE ))
	{
		vec3_t	pos_l;

		// transform decal position in local bmodel space
		if( !VectorIsNull( ent->angles ))
		{
			matrix4x4	matrix;

			Matrix4x4_CreateFromEntity( matrix, ent->angles, ent->origin, 1.0f );
			Matrix4x4_VectorITransform( matrix, pos, pos_l );
		}
		else
		{
			VectorSubtract( pos, ent->origin, pos_l );
		}

		VectorCopy( pos_l, decalInfo.m_Position );
		flags |= FDECAL_LOCAL_SPACE; // decal position moved into local space
	}
	else
	{
		// pass position in global
		VectorCopy( pos, decalInfo.m_Position );
	}

	// deal with the s axis if one was passed in
	if( saxis )
	{
		flags |= FDECAL_USESAXIS;
		VectorCopy( saxis, decalInfo.m_SAxis );
	}

	// this decal must use landmark for correct transition
	if(!( model->flags & MODEL_HAS_ORIGIN ))
	{
		flags |= FDECAL_USE_LANDMARK;
	}

	// more state used by R_DecalNode()
	decalInfo.m_iTexture = textureIndex;
	decalInfo.m_Entity = entityIndex;
	decalInfo.m_Flags = flags;

	R_GetDecalDimensions( textureIndex, &width, &height );
	decalInfo.m_Size = width >> 1;
	if(( height >> 1 ) > decalInfo.m_Size )
		decalInfo.m_Size = height >> 1;

	decalInfo.m_scale = bound( MIN_DECAL_SCALE, scale, MAX_DECAL_SCALE );

	// compute the decal dimensions in world space
	decalInfo.m_decalWidth = width / decalInfo.m_scale;
	decalInfo.m_decalHeight = height / decalInfo.m_scale;

	R_DecalNode( model, &model->nodes[hull->firstclipnode], &decalInfo );
}
コード例 #10
0
ファイル: gl_mirror.c プロジェクト: DavidKnight247/xash3d
/*
=================
R_FindBmodelMirrors

Check all bmodel surfaces and make personal mirror chain
=================
*/
void R_FindBmodelMirrors( cl_entity_t *e, qboolean static_entity )
{
	mextrasurf_t	*extrasurf;
	vec3_t		mins, maxs;
	msurface_t	*psurf;
	model_t		*clmodel;
	qboolean		rotated;
	int		i, clipFlags;

	clmodel = e->model;

	if( static_entity )
	{
		Matrix4x4_LoadIdentity( RI.objectMatrix );

		if( R_CullBox( clmodel->mins, clmodel->maxs, RI.clipFlags ))
			return;

		VectorCopy( RI.cullorigin, tr.modelorg );
		clipFlags = RI.clipFlags;
	}
	else
	{
		if( !VectorIsNull( e->angles ))
		{
			for( i = 0; i < 3; i++ )
			{
				mins[i] = e->origin[i] - clmodel->radius;
				maxs[i] = e->origin[i] + clmodel->radius;
			}
			rotated = true;
		}
		else
		{
			VectorAdd( e->origin, clmodel->mins, mins );
			VectorAdd( e->origin, clmodel->maxs, maxs );
			rotated = false;
		}

		if( R_CullBox( mins, maxs, RI.clipFlags ))
			return;

		if( !VectorIsNull( e->origin ) || !VectorIsNull( e->angles ))
		{
			if( rotated ) Matrix4x4_CreateFromEntity( RI.objectMatrix, e->angles, e->origin, 1.0f );
			else Matrix4x4_CreateFromEntity( RI.objectMatrix, vec3_origin, e->origin, 1.0f );
		}
		else Matrix4x4_LoadIdentity( RI.objectMatrix );

		e->visframe = tr.framecount; // visible

		if( rotated ) Matrix4x4_VectorITransform( RI.objectMatrix, RI.cullorigin, tr.modelorg );
		else VectorSubtract( RI.cullorigin, e->origin, tr.modelorg );

		clipFlags = 0;
	}

	psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
	for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ )
	{
		if(!( psurf->flags & SURF_REFLECT ))
			continue;

		if( R_CullSurface( psurf, clipFlags ))
			continue;

		extrasurf = SURF_INFO( psurf, RI.currentmodel );
		extrasurf->mirrorchain = tr.mirror_entities[tr.num_mirror_entities].chain;
		tr.mirror_entities[tr.num_mirror_entities].chain = extrasurf;
	}

	// store new mirror entity
	if( !static_entity && tr.mirror_entities[tr.num_mirror_entities].chain != NULL )
	{
		tr.mirror_entities[tr.num_mirror_entities].ent = RI.currententity;
		tr.num_mirror_entities++;
	}
}
コード例 #11
0
/**
 * @brief Draws bounding boxes for all non-linked entities in `ents`.
 */
static void R_DrawEntityBounds(const r_entities_t *ents, const vec4_t color) {

	if (!r_draw_entity_bounds->value) {
		return;
	}

	if (ents->count == 0) {
		return;
	}

	R_BindDiffuseTexture(r_image_state.null->texnum);

	R_EnableColorArray(true);

	R_BindAttributeInterleaveBuffer(&r_model_state.bound_vertice_buffer, R_ARRAY_MASK_ALL);
	R_BindAttributeBuffer(R_ARRAY_ELEMENTS, &r_model_state.bound_element_buffer);

	u8vec4_t bc;
	ColorDecompose(color, bc);

	for (int32_t i = 0; i < 8; ++i) {
		Vector4Set(r_model_state.bound_vertices[i].color, bc[0], bc[1], bc[2], bc[3]);
	}

	static matrix4x4_t mat, modelview;

	R_GetMatrix(R_MATRIX_MODELVIEW, &modelview);

	for (size_t i = 0; i < ents->count; i++) {
		const r_entity_t *e = ents->entities[i];

		if (e->parent || (e->effects & EF_WEAPON) || !IS_MESH_MODEL(e->model)) {
			continue;
		}

		VectorSet(r_model_state.bound_vertices[0].position, e->mins[0], e->mins[1], e->mins[2]);
		VectorSet(r_model_state.bound_vertices[1].position, e->maxs[0], e->mins[1], e->mins[2]);
		VectorSet(r_model_state.bound_vertices[2].position, e->maxs[0], e->maxs[1], e->mins[2]);
		VectorSet(r_model_state.bound_vertices[3].position, e->mins[0], e->maxs[1], e->mins[2]);

		VectorSet(r_model_state.bound_vertices[4].position, e->mins[0], e->mins[1], e->maxs[2]);
		VectorSet(r_model_state.bound_vertices[5].position, e->maxs[0], e->mins[1], e->maxs[2]);
		VectorSet(r_model_state.bound_vertices[6].position, e->maxs[0], e->maxs[1], e->maxs[2]);
		VectorSet(r_model_state.bound_vertices[7].position, e->mins[0], e->maxs[1], e->maxs[2]);

		R_UploadToBuffer(&r_model_state.bound_vertice_buffer, sizeof(r_bound_interleave_vertex_t) * 8,
		                 r_model_state.bound_vertices);

		// draw box
		const vec_t *origin;

		if (e->effects & EF_BOB) {
			origin = e->termination;
		} else {
			origin = e->origin;
		}

		Matrix4x4_CreateFromEntity(&mat, origin, vec3_origin, e->scale);

		Matrix4x4_Concat(&mat, &modelview, &mat);

		R_SetMatrix(R_MATRIX_MODELVIEW, &mat);

		R_DrawArrays(GL_LINES, 0, (GLint) r_model_state.bound_element_count - 6);

		// draw origin
		Matrix4x4_CreateFromEntity(&mat, origin, e->angles, e->scale);

		Matrix4x4_Concat(&mat, &modelview, &mat);

		R_SetMatrix(R_MATRIX_MODELVIEW, &mat);

		R_DrawArrays(GL_LINES, (GLint) r_model_state.bound_element_count - 6, 6);
	}

	R_SetMatrix(R_MATRIX_MODELVIEW, &modelview);

	R_UnbindAttributeBuffer(R_ARRAY_ELEMENTS);

	R_EnableColorArray(false);

	R_Color(NULL);
}
コード例 #12
0
ファイル: sv_phys.c プロジェクト: THE-Swank/xash3d
/*
============
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;
}
コード例 #13
0
ファイル: sv_phys.c プロジェクト: THE-Swank/xash3d
/*
=============
SV_Physics_Compound

a glue two entities together
=============
*/
void SV_Physics_Compound( edict_t *ent )
{
	edict_t	*parent;
	
	// regular thinking
	if( !SV_RunThink( ent )) return;

	parent = ent->v.aiment;

	if( !SV_IsValidEdict( parent ))
	{
		MsgDev( D_ERROR, "%s have MOVETYPE_COMPOUND with no corresponding ent!", SV_ClassName( ent ));
		ent->v.movetype = MOVETYPE_NONE;
		return;
	}

	if( ent->v.solid != SOLID_TRIGGER )
		ent->v.solid = SOLID_NOT;

	switch( parent->v.movetype )
	{
	case MOVETYPE_PUSH:
	case MOVETYPE_PUSHSTEP:
		break;
	default: return;
	}

	// not initialized ?
	if( ent->v.ltime == 0.0f )
	{
		VectorCopy( parent->v.origin, ent->v.oldorigin );
		VectorCopy( parent->v.angles, ent->v.avelocity );
		ent->v.ltime = host.frametime;
		return;
	}

	if( !VectorCompare( parent->v.origin, ent->v.oldorigin ) || !VectorCompare( parent->v.angles, ent->v.avelocity ))
	{
		matrix4x4	start_l, end_l, temp_l, child;

		// create parent old position
		Matrix4x4_CreateFromEntity( temp_l, ent->v.avelocity, ent->v.oldorigin, 1.0f );
		Matrix4x4_Invert_Simple( start_l, temp_l );

		// create parent actual position
		Matrix4x4_CreateFromEntity( end_l, parent->v.angles, parent->v.origin, 1.0f );

		// stupid quake bug!!!
		if( !( host.features & ENGINE_COMPENSATE_QUAKE_BUG ))
			ent->v.angles[PITCH] = -ent->v.angles[PITCH];

		// create child actual position
		Matrix4x4_CreateFromEntity( child, ent->v.angles, ent->v.origin, 1.0f );

		// transform child from start to end
		Matrix4x4_ConcatTransforms( temp_l, start_l, child );
		Matrix4x4_ConcatTransforms( child, end_l, temp_l );

		// create child final position
		Matrix4x4_ConvertToEntity( child, ent->v.angles, ent->v.origin );

		// stupid quake bug!!!
		if( !( host.features & ENGINE_COMPENSATE_QUAKE_BUG ))
			ent->v.angles[PITCH] = -ent->v.angles[PITCH];
	}

	// notsolid ents never touch triggers
	SV_LinkEdict( ent, (ent->v.solid == SOLID_NOT) ? false : true );

	// shuffle states
	VectorCopy( parent->v.origin, ent->v.oldorigin );
	VectorCopy( parent->v.angles, ent->v.avelocity );
}
コード例 #14
0
/**
 * @brief Called whenever an entity changes origin, mins, maxs, or solid to add it to
 * the clipping hull.
 */
void Sv_LinkEntity(g_entity_t *ent) {
	int32_t leafs[MAX_ENT_LEAFS];
	int32_t clusters[MAX_ENT_LEAFS];
	size_t i, j;
	int32_t top_node;

	if (ent == svs.game->entities) { // never bother with the world
		return;
	}

	// remove it from its current sector
	Sv_UnlinkEntity(ent);

	if (!ent->in_use) { // and if its free, we're done
		return;
	}

	// set the size
	VectorSubtract(ent->maxs, ent->mins, ent->size);

	// encode the size into the entity state for client prediction
	ent->s.solid = ent->solid;
	switch (ent->s.solid) {
		case SOLID_TRIGGER:
		case SOLID_PROJECTILE:
		case SOLID_DEAD:
		case SOLID_BOX:
			PackBounds(ent->mins, ent->maxs, &ent->s.bounds);
			break;
		default:
			PackBounds(vec3_origin, vec3_origin, &ent->s.bounds);
			break;
	}

	// set the absolute bounding box; ensure it is symmetrical
	Cm_EntityBounds(ent->solid, ent->s.origin, ent->s.angles, ent->mins, ent->maxs, ent->abs_mins, ent->abs_maxs);

	sv_entity_t *sent = &sv.entities[NUM_FOR_ENTITY(ent)];

	// link to PVS leafs
	sent->num_clusters = 0;
	sent->areas[0] = sent->areas[1] = 0;

	// get all leafs, including solids
	const size_t len = Cm_BoxLeafnums(ent->abs_mins, ent->abs_maxs, leafs, lengthof(leafs),
	                                  &top_node, 0);

	// set areas, allowing entities (doors) to occupy up to two
	for (i = 0; i < len; i++) {
		clusters[i] = Cm_LeafCluster(leafs[i]);
		const int32_t area = Cm_LeafArea(leafs[i]);
		if (area) {
			if (sent->areas[0] && sent->areas[0] != area) {
				if (sent->areas[1] && sent->areas[1] != area && sv.state == SV_LOADING) {
					Com_Warn("Object touching 3 areas at %s\n", vtos(ent->abs_mins));
				}
				sent->areas[1] = area;
			} else {
				sent->areas[0] = area;
			}
		}
	}

	if (len == MAX_ENT_LEAFS) { // use top_node
		sent->num_clusters = -1;
		sent->top_node = top_node;
	} else {
		sent->num_clusters = 0;
		for (i = 0; i < len; i++) {

			if (clusters[i] == -1) {
				continue;    // not a visible leaf
			}

			for (j = 0; j < i; j++)
				if (clusters[j] == clusters[i]) {
					break;
				}

			if (j == i) {
				if (sent->num_clusters == MAX_ENT_CLUSTERS) { // use top_node
					Com_Debug(DEBUG_SERVER, "%s exceeds MAX_ENT_CLUSTERS\n", etos(ent));
					sent->num_clusters = -1;
					sent->top_node = top_node;
					break;
				}

				sent->clusters[sent->num_clusters++] = clusters[i];
			}
		}
	}

	if (ent->solid == SOLID_NOT) {
		return;
	}

	// find the first sector that the ent's box crosses
	sv_sector_t *sector = sv_world.sectors;
	while (true) {

		if (sector->axis == -1) {
			break;
		}

		if (ent->abs_mins[sector->axis] > sector->dist) {
			sector = sector->children[0];
		} else if (ent->abs_maxs[sector->axis] < sector->dist) {
			sector = sector->children[1];
		} else {
			break;    // crosses the node
		}
	}

	// add it to the sector
	sent->sector = sector;
	sector->entities = g_list_prepend(sector->entities, ent);

	// and update its clipping matrices
	const vec_t *angles = ent->solid == SOLID_BSP ? ent->s.angles : vec3_origin;

	Matrix4x4_CreateFromEntity(&sent->matrix, ent->s.origin, angles, 1.0);
	Matrix4x4_Invert_Simple(&sent->inverse_matrix, &sent->matrix);
}