/** * @param[in] tile Tile to check (normally 0 - except in assembled maps) * @param[in] start trace start vector * @param[in] end trace end vector * @param[in] mins box mins * @param[in] maxs box maxs * @param[in] headnode if < 0 we are in a leaf node * @param[in] contentmask content flags the trace should stop at (see MASK_*) * @param[in] brushrejects brushes the trace should ignore (see MASK_*) * @param[in] origin center for rotating objects * @param[in] angles current rotation status (in degrees) for rotating objects * @param[in] rmaShift how much the object was shifted by the RMA process (needed for doors) * @param[in] fraction The furthest distance needed to trace before we stop. * @brief Handles offseting and rotation of the end points for moving and rotating entities * @sa CM_BoxTrace */ trace_t CM_HintedTransformedBoxTrace (mapTile_t *tile, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, const int headnode, const int contentmask, const int brushrejects, const vec3_t origin, const vec3_t angles, const vec3_t rmaShift, const float fraction) { trace_t trace; vec3_t start_l, end_l; vec3_t forward, right, up; vec3_t temp; bool rotated; /* subtract origin offset */ VectorSubtract(start, origin, start_l); VectorSubtract(end, origin, end_l); /* rotate start and end into the models frame of reference */ if (headnode != tile->box_headnode && VectorNotEmpty(angles)) { rotated = true; } else { rotated = false; } if (rotated) { AngleVectors(angles, forward, right, up); VectorCopy(start_l, temp); start_l[0] = DotProduct(temp, forward); start_l[1] = -DotProduct(temp, right); start_l[2] = DotProduct(temp, up); VectorCopy(end_l, temp); end_l[0] = DotProduct(temp, forward); end_l[1] = -DotProduct(temp, right); end_l[2] = DotProduct(temp, up); } /* When tracing through a model, we want to use the nodes, planes etc. as calculated by ufo2map. * But nodes and planes have been shifted in case of an RMA. At least for doors we need to undo the shift. */ if (VectorNotEmpty(origin)) { /* only doors seem to have their origin set */ VectorAdd(start_l, rmaShift, start_l); /* undo the shift */ VectorAdd(end_l, rmaShift, end_l); } /* sweep the box through the model */ trace = TR_BoxTrace(tile, start_l, end_l, mins, maxs, headnode, contentmask, brushrejects, fraction); trace.mapTile = tile->idx; if (rotated && trace.fraction != 1.0) { vec3_t a; /** @todo figure out how to do this with existing angles */ VectorNegate(angles, a); AngleVectors(a, forward, right, up); VectorCopy(trace.plane.normal, temp); trace.plane.normal[0] = DotProduct(temp, forward); trace.plane.normal[1] = -DotProduct(temp, right); trace.plane.normal[2] = DotProduct(temp, up); } VectorInterpolation(start, end, trace.fraction, trace.endpos); return trace; }
/** * @brief Rotates AABB around given origin point; note that it will expand the box unless all angles are multiples of 90 degrees * @note Not fully verified so far */ void AABB::rotateAround (const vec3_t origin, const vec3_t angles) { /* reject non-rotations */ if (VectorEmpty(angles)) return; /* construct box-centered coordinates (center and corners) */ vec3_t center, halfDiagonal; VectorInterpolation(mins, maxs, 0.5f, center); VectorSubtract(maxs, center, halfDiagonal); /* offset coordinate frame to rotation origin */ VectorSubtract(center, origin, center); /* rotate center by given angles */ vec3_t m[3]; VectorCreateRotationMatrix(angles, m); vec3_t newCenter; VectorRotate(m, center, newCenter); /* short-circuit calculation of the rotated box half-extents */ /* shortcut is: instead of calculating all 8 AABB corners, use the symmetry by rotating box around it's center. */ VectorAbs(m[0]); VectorAbs(m[1]); VectorAbs(m[2]); vec3_t newHalfDiagonal; VectorRotate(m, halfDiagonal, newHalfDiagonal); /* de-offset coordinate frame from rotation origin */ VectorAdd(newCenter, origin, newCenter); /* finally, combine results into new AABB */ VectorAdd(newCenter, newHalfDiagonal, maxs); VectorSubtract(newCenter, newHalfDiagonal, mins); }