Esempio n. 1
0
/**
 * @brief Performs box traces against the world and all inline models, gives the hit position back
 * @param[in] mapTiles List of tiles the current (RMA-)map is composed of
 * @param[in] traceLine The start/stop position of the trace.
 * @param[in] traceBox The minimum/maximum extents of the collision box that is projected.
 * @param[in] levelmask A mask of the game levels to trace against. Mask 0x100 filters clips.
 * @param[in] brushmask Any brush detected must at least have one of these contents.
 * @param[in] brushreject Any brush detected with any of these contents will be ignored.
 * @param[in] list The local models list (a local model has a name starting with * followed by the model number)
 * @return a trace_t with the information of the closest brush intersected.
 * @sa CM_CompleteBoxTrace
 * @sa CM_HintedTransformedBoxTrace
 */
trace_t CM_EntCompleteBoxTrace (mapTiles_t* mapTiles, const Line& traceLine, const AABB* traceBox, int levelmask, int brushmask, int brushreject, const char** list)
{
	AABB lineBox(*traceBox);
	lineBox.shift(traceLine.start);		/* the traceBox in starting position */
	AABB lineBoxTemp(*traceBox);
	lineBoxTemp.shift(traceLine.stop);	/* in end position */
	lineBox.add(lineBoxTemp);			/* bounding box for the whole trace */
	/* Now lineBox specifies the whole volume to be traced through. */

	/* reconstruct a levelmask */
	const vec_t minZ = lineBox.getMinZ();
	const vec_t maxZ = lineBox.getMaxZ();
	int newLevelMask = 0;
	if (levelmask & TL_FLAG_ACTORCLIP)		/* if the passed levelmask contains the bit for the cliplevels, */
		newLevelMask = TL_FLAG_ACTORCLIP;	/* preserve it */
	for (int i = 0; i < PATHFINDING_HEIGHT; i++) {
		const vec_t lower = i * UNIT_HEIGHT;	/* the height bounds of the level */
		const vec_t upper = (i + 1) * UNIT_HEIGHT;
		if (minZ > upper || maxZ < lower)
			continue;
		newLevelMask |= (1 << i);
	}

	/* trace against world first */
	const trace_t tr = CM_CompleteBoxTrace(mapTiles, traceLine, *traceBox, newLevelMask, brushmask, brushreject);
	if (!list || tr.fraction == 0.0)
		return tr;

	trace_t trace = tr;
	for (const char** name = list; *name; name++) {
		/* check whether this is really an inline model */
		if (*name[0] != '*')
			Com_Error(ERR_DROP, "name in the inlineList is no inline model: '%s'", *name);
		const cBspModel_t* model = CM_InlineModel(mapTiles, *name);
		assert(model);
		if (model->headnode >= mapTiles->mapTiles[model->tile].numnodes + 6)
			continue;

		AABB modelBox;
		/* Quickly calculate the bounds of this model to see if they can overlap. */
		CM_CalculateWidestBoundingBox(model, modelBox);

		/* If the bounds of the extents box and the line do not overlap, then skip tracing this model. */
		if (!lineBox.doesIntersect(modelBox))
			continue;

		const trace_t newtr = CM_HintedTransformedBoxTrace(mapTiles->mapTiles[model->tile], traceLine, *traceBox,
				model->headnode, brushmask, brushreject, model->origin, model->angles, model->shift, trace.fraction);

		/* memorize the trace with the minimal fraction */
		if (newtr.fraction == 0.0)
			return newtr;
		if (newtr.fraction < trace.fraction)
			trace = newtr;
	}
	return trace;
}
Esempio n. 2
0
/**
 * @brief Performs box traces against the world and all inline models, gives the hit position back
 * @param[in] mapTiles List of tiles the current (RMA-)map is composed of
 * @param[in] start The position to start the trace.
 * @param[in] end The position where the trace ends.
 * @param[in] traceBox The minimum/maximum extents of the collision box that is projected.
 * @param[in] levelmask A mask of the game levels to trace against. Mask 0x100 filters clips.
 * @param[in] brushmask Any brush detected must at least have one of these contents.
 * @param[in] brushreject Any brush detected with any of these contents will be ignored.
 * @param[in] list The local models list (a local model has a name starting with * followed by the model number)
 * @return a trace_t with the information of the closest brush intersected.
 * @sa CM_CompleteBoxTrace
 * @sa CM_HintedTransformedBoxTrace
 */
trace_t CM_EntCompleteBoxTrace (mapTiles_t *mapTiles, const vec3_t start, const vec3_t end, const AABB* traceBox, int levelmask, int brushmask, int brushreject, const char **list)
{
	trace_t trace, newtr;
	const char **name;
	vec3_t bmins, bmaxs;

	/* trace against world first */
	trace = CM_CompleteBoxTrace(mapTiles, start, end, *traceBox, levelmask, brushmask, brushreject);
	if (!list || trace.fraction == 0.0)
		return trace;

	/* Find the original bounding box for the tracing line. */
	VectorSet(bmins, std::min(start[0], end[0]), std::min(start[1], end[1]), std::min(start[2], end[2]));
	VectorSet(bmaxs, std::max(start[0], end[0]), std::max(start[1], end[1]), std::max(start[2], end[2]));
	/* Now increase the bounding box by mins and maxs in both directions. */
	VectorAdd(bmins, traceBox->mins, bmins);
	VectorAdd(bmaxs, traceBox->maxs, bmaxs);
	/* Now bmins and bmaxs specify the whole volume to be traced through. */

	for (name = list; *name; name++) {
		vec3_t amins, amaxs;
		const cBspModel_t *model;

		/* check whether this is really an inline model */
		if (*name[0] != '*')
			Com_Error(ERR_DROP, "name in the inlineList is no inline model: '%s'", *name);
		model = CM_InlineModel(mapTiles, *name);
		assert(model);
		if (model->headnode >= mapTiles->mapTiles[model->tile].numnodes + 6)
			continue;

		/* Quickly calculate the bounds of this model to see if they can overlap. */
		CM_CalculateBoundingBox(model, amins, amaxs);

		/* If the bounds of the extents box and the line do not overlap, then skip tracing this model. */
		if (bmins[0] > amaxs[0]
		 || bmins[1] > amaxs[1]
		 || bmins[2] > amaxs[2]
		 || bmaxs[0] < amins[0]
		 || bmaxs[1] < amins[1]
		 || bmaxs[2] < amins[2])
			continue;

		newtr = CM_HintedTransformedBoxTrace(&mapTiles->mapTiles[model->tile], start, end, traceBox->mins, traceBox->maxs,
				model->headnode, brushmask, brushreject, model->origin, model->angles, model->shift, trace.fraction);

		/* memorize the trace with the minimal fraction */
		if (newtr.fraction == 0.0)
			return newtr;
		if (newtr.fraction < trace.fraction)
			trace = newtr;
	}
	return trace;
}
Esempio n. 3
0
/**
 * @brief Checks traces against the world and all inline models, gives the hit position back
 * @param[in] mapTiles List of tiles the current (RMA-)map is composed of
 * @param[in] start The position to start the trace.
 * @param[in] stop The position where the trace ends.
 * @param[out] end The position where the line hits a object or the stop position if nothing is in the line
 * @param[in] levelmask
 * @param[in] entlist The local models list
 * @sa TR_TestLineDM
 * @sa CM_TransformedBoxTrace
 */
bool CM_EntTestLineDM (mapTiles_t *mapTiles, const vec3_t start, const vec3_t stop, vec3_t end, const int levelmask, const char **entlist)
{
	trace_t trace;
	const char **name;
	bool blocked;
	float fraction = 2.0f;

	/* trace against world first */
	blocked = TR_TestLineDM(mapTiles, start, stop, end, levelmask);
	if (!entlist)
		return blocked;

	for (name = entlist; *name; name++) {
		const cBspModel_t *model;
		/* check whether this is really an inline model */
		if (*name[0] != '*') {
			/* Let's see what the data looks like... */
			Com_Error(ERR_DROP, "name in the inlineList is no inline model: '%s' (inlines: %p, name: %p)",
					*name, (void*)entlist, (void*)name);
		}
		model = CM_InlineModel(mapTiles, *name);
		assert(model);
		if (model->headnode >= mapTiles->mapTiles[model->tile].numnodes + 6)
			continue;

		/* check if we can safely exclude that the trace can hit the model */
		if (CM_LineMissesModel(start, stop, model))
			continue;

		trace = CM_HintedTransformedBoxTrace(&mapTiles->mapTiles[model->tile], start, end, vec3_origin, vec3_origin,
				model->headnode, MASK_ALL, 0, model->origin, model->angles, vec3_origin, fraction);
		/* if we started the trace in a wall */
		if (trace.startsolid) {
			VectorCopy(start, end);
			return true;
		}
		/* trace not finished */
		if (trace.fraction < fraction) {
			blocked = true;
			fraction = trace.fraction;
			VectorCopy(trace.endpos, end);
		}
	}

	/* return result */
	return blocked;
}
Esempio n. 4
0
/**
 * @brief Clip against solid entities
 * @sa CL_Trace
 * @sa SV_ClipMoveToEntities
 */
static void CL_ClipMoveToLEs (MoveClipCL* clip)
{
	if (clip->trace.allsolid)
		return;

	le_t* le = nullptr;
	while ((le = LE_GetNextInUse(le))) {
		int tile = 0;

		if (!(le->contents & clip->contentmask))
			continue;
		if (le == clip->passle || le == clip->passle2)
			continue;

		vec3_t angles, shift;
		const int32_t headnode = CL_HullForEntity(le, &tile, shift, angles);
		assert(headnode < MAX_MAP_NODES);

		vec3_t origin;
		VectorCopy(le->origin, origin);

		trace_t trace = CM_HintedTransformedBoxTrace(cl.mapTiles->mapTiles[tile], clip->moveLine, clip->objBox,
				headnode, clip->contentmask, 0, origin, angles, shift, 1.0);

		if (trace.fraction < clip->trace.fraction) {
			/* make sure we keep a startsolid from a previous trace */
			const bool oldStart = clip->trace.startsolid;
			trace.le = le;
			clip->trace = trace;
			clip->trace.startsolid |= oldStart;
		/* if true, plane is not valid */
		} else if (trace.allsolid) {
			trace.le = le;
			clip->trace = trace;
		/* if true, the initial point was in a solid area */
		} else if (trace.startsolid) {
			trace.le = le;
			clip->trace.startsolid = true;
		}
	}
}
Esempio n. 5
0
/**
 * @brief Checks traces against the world and all inline models
 * @param[in] mapTiles List of tiles the current (RMA-)map is composed of
 * @param[in] start The position to start the trace.
 * @param[in] stop The position where the trace ends.
 * @param[in] levelmask
 * @param[in] entlist The local models list
 * @sa TR_TestLine
 * @sa CM_InlineModel
 * @sa CM_TransformedBoxTrace
 * @return true - hit something
 * @return false - hit nothing
 */
bool CM_EntTestLine (mapTiles_t *mapTiles, const vec3_t start, const vec3_t stop, const int levelmask, const char **entlist)
{
	trace_t trace;
	const char **name;

	/* trace against world first */
	if (TR_TestLine(mapTiles, start, stop, levelmask))
		/* We hit the world, so we didn't make it anyway... */
		return true;

	/* no local models, so we made it. */
	if (!entlist)
		return false;

	for (name = entlist; *name; name++) {
		const cBspModel_t *model;
		/* check whether this is really an inline model */
		if (*name[0] != '*')
			Com_Error(ERR_DROP, "name in the inlineList is no inline model: '%s'", *name);
		model = CM_InlineModel(mapTiles, *name);
		assert(model);
		if (model->headnode >= mapTiles->mapTiles[model->tile].numnodes + 6)
			continue;

		/* check if we can safely exclude that the trace can hit the model */
		if (CM_LineMissesModel(start, stop, model))
			continue;

		trace = CM_HintedTransformedBoxTrace(&mapTiles->mapTiles[model->tile], start, stop, vec3_origin, vec3_origin,
				model->headnode, MASK_VISIBILILITY, 0, model->origin, model->angles, model->shift, 1.0);
		/* if we started the trace in a wall */
		/* or the trace is not finished */
		if (trace.startsolid || trace.fraction < 1.0)
			return true;
	}

	/* not blocked */
	return false;
}