View Single Post
Source-like filtered trace hull in HL1
Old
  (#1)
Immortal_BLG
Member
 
Status: Offline
Posts: 171
Join Date: Nov 2007
Location: Russian Federation
Smile Source-like filtered trace hull in HL1 - 14-07-2010

WARNING THIS CODE IS VERY SLOW!!! (Profiling(in microseconds): provided function ~= 0.044809, UTIL_TraceLine() ~= 0.001445)

Code:
class ITraceFilter
{
	public:
		virtual inline const bool ShouldHitEntity (edict_t *const edict) = 0;

	//
	// Group: Private operators.
	//
	private:
		inline ITraceFilter &operator = (const ITraceFilter &/*right*/);	// Avoid "warning C4512: 'ITraceFilter' : assignment operator could not be generated".
};

//-----------------------------------------------------------------------------
// Classes need not inherit from these
//-----------------------------------------------------------------------------
class TraceFilter_HitWorldOnly : public ITraceFilter
{
	public:
		inline const bool ShouldHitEntity (edict_t *const edict)
		{
			return ENTINDEX (edict) == 0u;
		}
};

class TraceFilter_HitAll : public ITraceFilter
{
	public:
		virtual inline const bool ShouldHitEntity (edict_t *const edict)
		{
			return true;
		}
};

class TraceFilter_PassEntity : public ITraceFilter
{
	private:
		const edict_t *m_passEdict;

	public:
		inline TraceFilter_PassEntity (const edict_t *const passEdict) :
			m_passEdict (passEdict)
		{ /* VOID */ }

	public:
		inline const bool ShouldHitEntity (edict_t *const edict)
		{
			return m_passEdict != edict;
		}
};

//-----------------------------------------------------------------------------
// Trace filter that can take a list of entities to ignore
//-----------------------------------------------------------------------------
class TraceFilter_SimpleList : public ITraceFilter
{
	protected:
		vector <edict_t *> m_passEntities;

	public:
		inline TraceFilter_SimpleList (void) { /* VOID */ }

	public:
		virtual inline const bool ShouldHitEntity (edict_t *const edict)
		{
			for (unsigned int index (0u); index < m_passEntities.size (); ++index)
				if (edict == m_passEntities[index])
					return false;

			return true;
		}

		//-----------------------------------------------------------------------------
		// Purpose: Add an entity to my list of entities to ignore in the trace
		//-----------------------------------------------------------------------------
		inline void AddEntityToIgnore (edict_t *const edict)
		{
			m_passEntities.push_back (edict);
		}
};

//-----------------------------------------------------------------------------
// Trace filter that can take a classname to ignore
//-----------------------------------------------------------------------------
class TraceFilter_SkipClassName : public ITraceFilter
{
	private:
		const char *const m_className;

	public:
		inline TraceFilter_SkipClassName (const char *const className) :
			m_className (className)
		{ /* VOID */ }

	public:
		virtual inline const bool ShouldHitEntity (SDK::Classes::Edict *const edict)
		{
			return !FClassnameIs (edict, m_className);
		}
};

//-----------------------------------------------------------------------------
// Trace filter that can take a list of entities to ignore
//-----------------------------------------------------------------------------
class TraceFilter_SimpleClassNameList : public ITraceFilter
{
	private:
		vector <const char *> m_passClassNames;

	public:
		virtual inline const bool ShouldHitEntity (SDK::Classes::Edict *const edict)
		{
			for (unsigned int index (0u); index < m_passClassNames.size (); ++index)
				if (FClassnameIs (edict, m_passClassNames[index]))
					return false;

			return true;
		}

		//-----------------------------------------------------------------------------
		// Purpose: Add an entity to my list of entities to ignore in the trace
		//-----------------------------------------------------------------------------
		inline void AddClassnameToIgnore (const char *const className)
		{
			m_passClassNames.push_back (className);
		}
};

class TraceFilter_Chain : public ITraceFilter
{
	private:
		ITraceFilter &m_traceFilter1;
		ITraceFilter &m_traceFilter2;

	public:
		inline TraceFilter_Chain (ITraceFilter &traceFilter1, ITraceFilter &traceFilter2) :
			m_traceFilter1 (traceFilter1),
			m_traceFilter2 (traceFilter2)
		{ /* VOID */ }

	public:
		virtual inline const bool ShouldHitEntity (edict_t *const edict)
		{
			return m_traceFilter1.ShouldHitEntity (edict) && m_traceFilter2.ShouldHitEntity (edict);
		}
};

void TraceHull (const Vector &source, const Vector &destination, const int hullNumber, ITraceFilter &traceFilter, TraceResult &traceResult)
{
	TraceResult tempTraceResult;
	edict_t *entity (INDEXENT (0u));	// worldspawn

	if (traceFilter.ShouldHitEntity (entity))
		g_engfuncs.pfnTraceModel (source, destination, hullNumber, entity, &traceResult);
	else
	{
		// Fill in a default trace result
		memset (&traceResult, 0, sizeof (traceResult));

		traceResult.flFraction = 1.0f;
		traceResult.fAllSolid = true;
		traceResult.vecEndPos = destination;
	}

	// For each entity....
	for (unsigned short index (1u/* Skip worldspawn entity.... */); index < gpGlobals->maxEntities; ++index)
	{
		++entity;

		if (FNullEnt (entity) || entity->v.mins == vec3_origin || entity->v.maxs == vec3_origin)
			continue;

		// Reliability check.
		assert (entity->v.classname > 0);	// MAY HAPPEN?!?!?!?!?!?

		if (!traceFilter.ShouldHitEntity (entity))
			continue;

		g_engfuncs.pfnTraceModel (source, destination, hullNumber, entity, &tempTraceResult);

		if (tempTraceResult.flFraction < traceResult.flFraction)
			traceResult = tempTraceResult;
	}
}
  
Reply With Quote