void CalculateMinsMaxs (const vec3_t angles, const vec3_t mins, const vec3_t maxs, const vec3_t origin, vec3_t absmin, vec3_t absmax) { /* expand for rotation */ if (VectorNotEmpty(angles)) { vec3_t minVec, maxVec, tmpMinVec, tmpMaxVec; vec3_t centerVec, halfVec, newCenterVec, newHalfVec; vec3_t m[3]; /* Find the center of the extents. */ VectorCenterFromMinsMaxs(mins, maxs, centerVec); /* Find the half height and half width of the extents. */ VectorSubtract(maxs, centerVec, halfVec); /* Rotate the center about the origin. */ VectorCreateRotationMatrix(angles, m); VectorRotate(m, centerVec, newCenterVec); VectorRotate(m, halfVec, newHalfVec); /* Set minVec and maxVec to bound around newCenterVec at halfVec size. */ VectorSubtract(newCenterVec, newHalfVec, tmpMinVec); VectorAdd(newCenterVec, newHalfVec, tmpMaxVec); /* rotation may have changed min and max of the box, so adjust it */ minVec[0] = min(tmpMinVec[0], tmpMaxVec[0]); minVec[1] = min(tmpMinVec[1], tmpMaxVec[1]); minVec[2] = min(tmpMinVec[2], tmpMaxVec[2]); maxVec[0] = max(tmpMinVec[0], tmpMaxVec[0]); maxVec[1] = max(tmpMinVec[1], tmpMaxVec[1]); maxVec[2] = max(tmpMinVec[2], tmpMaxVec[2]); /* Adjust the absolute mins/maxs */ VectorAdd(origin, minVec, absmin); VectorAdd(origin, maxVec, absmax); } else { /* normal */ VectorAdd(origin, mins, absmin); VectorAdd(origin, maxs, absmax); } }
/** * @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); }
/** * @brief This function recalculates the routing surrounding the entity name. * @sa CM_InlineModel * @sa CM_CheckUnit * @sa CM_UpdateConnection * @sa CMod_LoadSubmodels * @sa Grid_RecalcBoxRouting * @param[in] mapTiles List of tiles the current (RMA-)map is composed of * @param[in] routing The routing map (either server or client map) * @param[in] name Name of the inline model to compute the mins/maxs for * @param[in] box The box around the inline model (alternative to name) * @param[in] list The local models list (a local model has a name starting with * followed by the model number) */ void Grid_RecalcRouting (mapTiles_t *mapTiles, Routing &routing, const char *name, const GridBox &box, const char **list) { if (box.isZero()) { pos3_t min, max; vec3_t absmin, absmax; const cBspModel_t *model; unsigned int i; /* get inline model, if it is one */ if (*name != '*') { Com_Printf("Called Grid_RecalcRouting with no inline model\n"); return; } model = CM_InlineModel(mapTiles, name); if (!model) { Com_Printf("Called Grid_RecalcRouting with invalid inline model name '%s'\n", name); return; } #if 1 /* An attempt to fix the 'doors starting opened' bug (# 3456). * The main difference is the (missing) rotation of the halfVec. * The results are better, but do not fix the problem. */ CalculateMinsMaxs(model->angles, model->mins, model->maxs, model->origin, absmin, absmax); #else /* get the target model's dimensions */ if (VectorNotEmpty(model->angles)) { vec3_t minVec, maxVec; vec3_t centerVec, halfVec, newCenterVec; vec3_t m[3]; /* Find the center of the extents. */ VectorCenterFromMinsMaxs(model->mins, model->maxs, centerVec); /* Find the half height and half width of the extents. */ VectorSubtract(model->maxs, centerVec, halfVec); /* Rotate the center about the origin. */ VectorCreateRotationMatrix(model->angles, m); VectorRotate(m, centerVec, newCenterVec); /* Set minVec and maxVec to bound around newCenterVec at halfVec size. */ VectorSubtract(newCenterVec, halfVec, minVec); VectorAdd(newCenterVec, halfVec, maxVec); /* Now offset by origin then convert to position (Doors do not have 0 origins) */ VectorAdd(minVec, model->origin, absmin); VectorAdd(maxVec, model->origin, absmax); } else { /* normal */ /* Now offset by origin then convert to position (Doors do not have 0 origins) */ VectorAdd(model->mins, model->origin, absmin); VectorAdd(model->maxs, model->origin, absmax); } #endif VecToPos(absmin, min); VecToPos(absmax, max); /* fit min/max into the world size */ max[0] = std::min(max[0], (pos_t)(PATHFINDING_WIDTH - 1)); max[1] = std::min(max[1], (pos_t)(PATHFINDING_WIDTH - 1)); max[2] = std::min(max[2], (pos_t)(PATHFINDING_HEIGHT - 1)); for (i = 0; i < 3; i++) min[i] = std::max(min[i], (pos_t)0); /* We now have the dimensions, call the generic rerouting function. */ GridBox rerouteBox(min, max); Grid_RecalcBoxRouting(mapTiles, routing, rerouteBox, list); } else { /* use the passed box */ Grid_RecalcBoxRouting(mapTiles, routing, box, list); } }
/** * @brief This function recalculates the routing surrounding the entity name. * @sa CM_InlineModel * @sa CM_CheckUnit * @sa CM_UpdateConnection * @sa CMod_LoadSubmodels * @sa Grid_RecalcBoxRouting * @param[in] mapTiles List of tiles the current (RMA-)map is composed of * @param[in] map The routing map (either server or client map) * @param[in] name Name of the inline model to compute the mins/maxs for * @param[in] list The local models list (a local model has a name starting with * followed by the model number) */ void Grid_RecalcRouting (mapTiles_t *mapTiles, routing_t *map, const char *name, const char **list) { const cBspModel_t *model; pos3_t min, max; unsigned int i; double start, end; start = time(NULL); /* get inline model, if it is one */ if (*name != '*') { Com_Printf("Called Grid_RecalcRouting with no inline model\n"); return; } model = CM_InlineModel(mapTiles, name); if (!model) { Com_Printf("Called Grid_RecalcRouting with invalid inline model name '%s'\n", name); return; } Com_DPrintf(DEBUG_PATHING, "Model:%s origin(%f,%f,%f) angles(%f,%f,%f) mins(%f,%f,%f) maxs(%f,%f,%f)\n", name, model->origin[0], model->origin[1], model->origin[2], model->angles[0], model->angles[1], model->angles[2], model->mins[0], model->mins[1], model->mins[2], model->maxs[0], model->maxs[1], model->maxs[2]); /* get the target model's dimensions */ if (VectorNotEmpty(model->angles)) { vec3_t minVec, maxVec; vec3_t centerVec, halfVec, newCenterVec; vec3_t m[3]; /* Find the center of the extents. */ VectorCenterFromMinsMaxs(model->mins, model->maxs, centerVec); /* Find the half height and half width of the extents. */ VectorSubtract(model->maxs, centerVec, halfVec); /* Rotate the center about the origin. */ VectorCreateRotationMatrix(model->angles, m); VectorRotate(m, centerVec, newCenterVec); /* Set minVec and maxVec to bound around newCenterVec at halfVec size. */ VectorSubtract(newCenterVec, halfVec, minVec); VectorAdd(newCenterVec, halfVec, maxVec); /* Now offset by origin then convert to position (Doors do not have 0 origins) */ VectorAdd(minVec, model->origin, minVec); VecToPos(minVec, min); VectorAdd(maxVec, model->origin, maxVec); VecToPos(maxVec, max); } else { /* normal */ vec3_t temp; /* Now offset by origin then convert to position (Doors do not have 0 origins) */ VectorAdd(model->mins, model->origin, temp); VecToPos(temp, min); VectorAdd(model->maxs, model->origin, temp); VecToPos(temp, max); } /* fit min/max into the world size */ max[0] = min(max[0] + 1, PATHFINDING_WIDTH - 1); max[1] = min(max[1] + 1, PATHFINDING_WIDTH - 1); max[2] = min(max[2] + 1, PATHFINDING_HEIGHT - 1); for (i = 0; i < 3; i++) min[i] = max(min[i] - 1, 0); /* We now have the dimensions, call the generic rerouting function. */ Grid_RecalcBoxRouting(mapTiles, map, min, max, list); end = time(NULL); Com_DPrintf(DEBUG_ROUTING, "Retracing for model %s between (%i, %i, %i) and (%i, %i %i) in %5.1fs\n", name, min[0], min[1], min[2], max[0], max[1], max[2], end - start); }
/** * @brief This function recalculates the routing surrounding the entity name. * @sa CM_InlineModel * @sa CM_CheckUnit * @sa CM_UpdateConnection * @sa CMod_LoadSubmodels * @sa Grid_RecalcBoxRouting * @param[in] mapTiles List of tiles the current (RMA-)map is composed of * @param[in] routing The routing map (either server or client map) * @param[in] name Name of the inline model to compute the mins/maxs for * @param[in] box The box around the inline model (alternative to name) * @param[in] list The local models list (a local model has a name starting with * followed by the model number) */ void Grid_RecalcRouting (mapTiles_t* mapTiles, Routing& routing, const char* name, const GridBox& box, const char** list) { if (box.isZero()) { /* get inline model, if it is one */ if (*name != '*') { Com_Printf("Called Grid_RecalcRouting with no inline model\n"); return; } const cBspModel_t* model = CM_InlineModel(mapTiles, name); if (!model) { Com_Printf("Called Grid_RecalcRouting with invalid inline model name '%s'\n", name); return; } AABB absbox; #if 1 /* An attempt to fix the 'doors starting opened' bug (# 3456). * The main difference is the (missing) rotation of the halfVec. * The results are better, but do not fix the problem. */ CalculateMinsMaxs(model->angles, model->cbmBox, model->origin, absbox); #else /* get the target model's dimensions */ if (VectorNotEmpty(model->angles)) { vec3_t minVec, maxVec; vec3_t centerVec, halfVec, newCenterVec; vec3_t m[3]; /* Find the center of the extents. */ model->cbmBox.getCenter(centerVec); /* Find the half height and half width of the extents. */ VectorSubtract(model->cbmBox.maxs, centerVec, halfVec); /* Rotate the center about the origin. */ VectorCreateRotationMatrix(model->angles, m); VectorRotate(m, centerVec, newCenterVec); /* Set minVec and maxVec to bound around newCenterVec at halfVec size. */ VectorSubtract(newCenterVec, halfVec, minVec); VectorAdd(newCenterVec, halfVec, maxVec); /* Now offset by origin then convert to position (Doors do not have 0 origins) */ absbox.set(minVec, maxVec); absbox.shift(model->origin); } else { /* normal */ /* Now offset by origin then convert to position (Doors do not have 0 origins) */ absbox.set(model->cbmBox); absbox.shift(model->origin); } #endif GridBox rerouteBox(absbox); /* fit min/max into the world size */ rerouteBox.clipToMaxBoundaries(); /* We now have the dimensions, call the generic rerouting function. */ Grid_RecalcBoxRouting(mapTiles, routing, rerouteBox, list); } else { /* use the passed box */ Grid_RecalcBoxRouting(mapTiles, routing, box, list); } }