diff options
author | Lars Müller <34514239+appgurueu@users.noreply.github.com> | 2022-10-30 16:53:14 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-30 16:53:14 +0100 |
commit | 077627181ee2eac3c0dacc3d8dc49825837e474c (patch) | |
tree | a8a6298198738f2edb30bd7e733a7a0d2005affa /src | |
parent | b8292319924994352d56d6111faa73fe315d149a (diff) | |
download | minetest-077627181ee2eac3c0dacc3d8dc49825837e474c.tar.xz |
Allow rotating entity selectionboxes (#12379)
Diffstat (limited to 'src')
-rw-r--r-- | src/client/clientenvironment.cpp | 25 | ||||
-rw-r--r-- | src/client/game.cpp | 14 | ||||
-rw-r--r-- | src/client/hud.cpp | 31 | ||||
-rw-r--r-- | src/client/hud.h | 5 | ||||
-rw-r--r-- | src/environment.cpp | 14 | ||||
-rw-r--r-- | src/object_properties.cpp | 7 | ||||
-rw-r--r-- | src/object_properties.h | 1 | ||||
-rw-r--r-- | src/raycast.cpp | 23 | ||||
-rw-r--r-- | src/raycast.h | 6 | ||||
-rw-r--r-- | src/script/common/c_content.cpp | 10 | ||||
-rw-r--r-- | src/server/luaentity_sao.cpp | 5 | ||||
-rw-r--r-- | src/server/unit_sao.h | 14 | ||||
-rw-r--r-- | src/serverenvironment.cpp | 25 | ||||
-rw-r--r-- | src/util/pointedthing.cpp | 7 | ||||
-rw-r--r-- | src/util/pointedthing.h | 11 |
15 files changed, 145 insertions, 53 deletions
diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp index 0b6f1a325..1ce443bcc 100644 --- a/src/client/clientenvironment.cpp +++ b/src/client/clientenvironment.cpp @@ -505,15 +505,24 @@ void ClientEnvironment::getSelectedActiveObjects( if (!obj->getSelectionBox(&selection_box)) continue; - const v3f &pos = obj->getPosition(); - aabb3f offsetted_box(selection_box.MinEdge + pos, - selection_box.MaxEdge + pos); - v3f current_intersection; - v3s16 current_normal; - if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector, - ¤t_intersection, ¤t_normal)) { - objects.emplace_back((s16) obj->getId(), current_intersection, current_normal, + v3f current_normal, current_raw_normal; + const v3f rel_pos = shootline_on_map.start - obj->getPosition(); + bool collision; + GenericCAO* gcao = dynamic_cast<GenericCAO*>(obj); + if (gcao != nullptr && gcao->getProperties().rotate_selectionbox) { + gcao->getSceneNode()->updateAbsolutePosition(); + const v3f deg = obj->getSceneNode()->getAbsoluteTransformation().getRotationDegrees(); + collision = boxLineCollision(selection_box, deg, + rel_pos, line_vector, ¤t_intersection, ¤t_normal, ¤t_raw_normal); + } else { + collision = boxLineCollision(selection_box, rel_pos, line_vector, + ¤t_intersection, ¤t_normal); + current_raw_normal = current_normal; + } + if (collision) { + current_intersection += obj->getPosition(); + objects.emplace_back(obj->getId(), current_intersection, current_normal, current_raw_normal, (current_intersection - shootline_on_map.start).getLengthSQ()); } } diff --git a/src/client/game.cpp b/src/client/game.cpp index 91c93ef7f..cdcfde759 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -3297,7 +3297,7 @@ PointedThing Game::updatePointedThing( { std::vector<aabb3f> *selectionboxes = hud->getSelectionBoxes(); selectionboxes->clear(); - hud->setSelectedFaceNormal(v3f(0.0, 0.0, 0.0)); + hud->setSelectedFaceNormal(v3f()); static thread_local const bool show_entity_selectionbox = g_settings->getBool( "show_entity_selectionbox"); @@ -3321,7 +3321,13 @@ PointedThing Game::updatePointedThing( v3f pos = runData.selected_object->getPosition(); selectionboxes->push_back(aabb3f(selection_box)); hud->setSelectionPos(pos, camera_offset); + GenericCAO* gcao = dynamic_cast<GenericCAO*>(runData.selected_object); + if (gcao != nullptr && gcao->getProperties().rotate_selectionbox) + hud->setSelectionRotation(gcao->getSceneNode()->getAbsoluteTransformation().getRotationDegrees()); + else + hud->setSelectionRotation(v3f()); } + hud->setSelectedFaceNormal(result.raw_intersection_normal); } else if (result.type == POINTEDTHING_NODE) { // Update selection boxes MapNode n = map.getNode(result.node_undersurface); @@ -3339,10 +3345,8 @@ PointedThing Game::updatePointedThing( } hud->setSelectionPos(intToFloat(result.node_undersurface, BS), camera_offset); - hud->setSelectedFaceNormal(v3f( - result.intersection_normal.X, - result.intersection_normal.Y, - result.intersection_normal.Z)); + hud->setSelectionRotation(v3f()); + hud->setSelectedFaceNormal(result.intersection_normal); } // Update selection mesh light level and vertex colors diff --git a/src/client/hud.cpp b/src/client/hud.cpp index e8ccdbb2b..58f5ec5f1 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -826,28 +826,31 @@ void Hud::setSelectionPos(const v3f &pos, const v3s16 &camera_offset) void Hud::drawSelectionMesh() { + if (m_mode == HIGHLIGHT_NONE || (m_mode == HIGHLIGHT_HALO && !m_selection_mesh)) + return; + const video::SMaterial oldmaterial = driver->getMaterial2D(); + driver->setMaterial(m_selection_material); + const core::matrix4 oldtransform = driver->getTransform(video::ETS_WORLD); + + core::matrix4 translate; + translate.setTranslation(m_selection_pos_with_offset); + core::matrix4 rotation; + rotation.setRotationDegrees(m_selection_rotation); + driver->setTransform(video::ETS_WORLD, translate * rotation); + if (m_mode == HIGHLIGHT_BOX) { // Draw 3D selection boxes - video::SMaterial oldmaterial = driver->getMaterial2D(); - driver->setMaterial(m_selection_material); for (auto & selection_box : m_selection_boxes) { - aabb3f box = aabb3f( - selection_box.MinEdge + m_selection_pos_with_offset, - selection_box.MaxEdge + m_selection_pos_with_offset); - u32 r = (selectionbox_argb.getRed() * m_selection_mesh_color.getRed() / 255); u32 g = (selectionbox_argb.getGreen() * m_selection_mesh_color.getGreen() / 255); u32 b = (selectionbox_argb.getBlue() * m_selection_mesh_color.getBlue() / 255); - driver->draw3DBox(box, video::SColor(255, r, g, b)); + driver->draw3DBox(selection_box, video::SColor(255, r, g, b)); } - driver->setMaterial(oldmaterial); } else if (m_mode == HIGHLIGHT_HALO && m_selection_mesh) { // Draw selection mesh - video::SMaterial oldmaterial = driver->getMaterial2D(); - driver->setMaterial(m_selection_material); setMeshColor(m_selection_mesh, m_selection_mesh_color); video::SColor face_color(0, MYMIN(255, m_selection_mesh_color.getRed() * 1.5), @@ -855,16 +858,14 @@ void Hud::drawSelectionMesh() MYMIN(255, m_selection_mesh_color.getBlue() * 1.5)); setMeshColorByNormal(m_selection_mesh, m_selected_face_normal, face_color); - scene::IMesh* mesh = cloneMesh(m_selection_mesh); - translateMesh(mesh, m_selection_pos_with_offset); u32 mc = m_selection_mesh->getMeshBufferCount(); for (u32 i = 0; i < mc; i++) { - scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); + scene::IMeshBuffer *buf = m_selection_mesh->getMeshBuffer(i); driver->drawMeshBuffer(buf); } - mesh->drop(); - driver->setMaterial(oldmaterial); } + driver->setMaterial(oldmaterial); + driver->setTransform(video::ETS_WORLD, oldtransform); } enum Hud::BlockBoundsMode Hud::toggleBlockBounds() diff --git a/src/client/hud.h b/src/client/hud.h index fd79183a0..b6ff84243 100644 --- a/src/client/hud.h +++ b/src/client/hud.h @@ -75,6 +75,10 @@ public: v3f getSelectionPos() const { return m_selection_pos; } + void setSelectionRotation(v3f rotation) { m_selection_rotation = rotation; } + + v3f getSelectionRotation() const { return m_selection_rotation; } + void setSelectionMeshColor(const video::SColor &color) { m_selection_mesh_color = color; @@ -126,6 +130,7 @@ private: std::vector<aabb3f> m_halo_boxes; v3f m_selection_pos; v3f m_selection_pos_with_offset; + v3f m_selection_rotation; scene::IMesh *m_selection_mesh = nullptr; video::SColor m_selection_mesh_color; diff --git a/src/environment.cpp b/src/environment.cpp index b04f77557..514b15d01 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -202,21 +202,21 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result) // ID of the current box (loop counter) u16 id = 0; + // Do calculations relative to the node center + // to translate the ray rather than the boxes v3f npf = intToFloat(np, BS); - // This loop translates the boxes to their in-world place. + v3f rel_start = state->m_shootline.start - npf; for (aabb3f &box : boxes) { - box.MinEdge += npf; - box.MaxEdge += npf; - v3f intersection_point; - v3s16 intersection_normal; - if (!boxLineCollision(box, state->m_shootline.start, + v3f intersection_normal; + if (!boxLineCollision(box, rel_start, state->m_shootline.getVector(), &intersection_point, &intersection_normal)) { ++id; continue; } + intersection_point += npf; // translate back to world coords f32 distanceSq = (intersection_point - state->m_shootline.start).getLengthSQ(); // If this is the nearest collision, save it @@ -259,7 +259,7 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result) result.node_real_undersurface = floatToInt( fake_intersection, BS); result.node_abovesurface = result.node_real_undersurface - + result.intersection_normal; + + floatToInt(result.intersection_normal, 1.0f); // Push found PointedThing state->m_found.push(result); // If this is nearer than the old nearest object, diff --git a/src/object_properties.cpp b/src/object_properties.cpp index c7f6becf0..e4c656946 100644 --- a/src/object_properties.cpp +++ b/src/object_properties.cpp @@ -72,6 +72,7 @@ std::string ObjectProperties::dump() os << ", nametag_bgcolor=null "; os << ", selectionbox=" << PP(selectionbox.MinEdge) << "," << PP(selectionbox.MaxEdge); + os << ", rotate_selectionbox=" << rotate_selectionbox; os << ", pointable=" << pointable; os << ", static_save=" << static_save; os << ", eye_height=" << eye_height; @@ -169,6 +170,7 @@ void ObjectProperties::serialize(std::ostream &os) const else writeARGB8(os, nametag_bgcolor.value()); + writeU8(os, rotate_selectionbox); // Add stuff only at the bottom. // Never remove anything, because we don't want new versions of this } @@ -236,5 +238,10 @@ void ObjectProperties::deSerialize(std::istream &is) nametag_bgcolor = bgcolor; else nametag_bgcolor = nullopt; + + tmp = readU8(is); + if (is.eof()) + return; + rotate_selectionbox = tmp; } catch (SerializationError &e) {} } diff --git a/src/object_properties.h b/src/object_properties.h index 79866a22c..f4c425d7b 100644 --- a/src/object_properties.h +++ b/src/object_properties.h @@ -35,6 +35,7 @@ struct ObjectProperties // Values are BS=1 aabb3f collisionbox = aabb3f(-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f); aabb3f selectionbox = aabb3f(-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f); + bool rotate_selectionbox = false; bool pointable = true; std::string visual = "sprite"; std::string mesh = ""; diff --git a/src/raycast.cpp b/src/raycast.cpp index ebc40235d..ead024dd1 100644 --- a/src/raycast.cpp +++ b/src/raycast.cpp @@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "raycast.h" #include "irr_v3d.h" #include "irr_aabb3d.h" +#include <quaternion.h> #include "constants.h" bool RaycastSort::operator() (const PointedThing &pt1, @@ -68,7 +69,7 @@ RaycastState::RaycastState(const core::line3d<f32> &shootline, bool boxLineCollision(const aabb3f &box, const v3f &start, - const v3f &dir, v3f *collision_point, v3s16 *collision_normal) + const v3f &dir, v3f *collision_point, v3f *collision_normal) { if (box.isPointInside(start)) { *collision_point = start; @@ -135,3 +136,23 @@ bool boxLineCollision(const aabb3f &box, const v3f &start, } return false; } + +bool boxLineCollision(const aabb3f &box, const v3f &rotation, + const v3f &start, const v3f &dir, + v3f *collision_point, v3f *collision_normal, v3f *raw_collision_normal) +{ + // Inversely transform the ray rather than rotating the box faces; + // this allows us to continue using a simple ray - AABB intersection + core::quaternion rot(rotation * core::DEGTORAD); + rot.makeInverse(); + + bool collision = boxLineCollision(box, rot * start, rot * dir, collision_point, collision_normal); + if (!collision) return collision; + + // Transform the results back + rot.makeInverse(); + *collision_point = rot * *collision_point; + *raw_collision_normal = *collision_normal; + *collision_normal = rot * *collision_normal; + return collision; +} diff --git a/src/raycast.h b/src/raycast.h index 734efd6ad..8da075738 100644 --- a/src/raycast.h +++ b/src/raycast.h @@ -74,4 +74,8 @@ public: * @returns true if a collision point was found */ bool boxLineCollision(const aabb3f &box, const v3f &start, const v3f &dir, - v3f *collision_point, v3s16 *collision_normal); + v3f *collision_point, v3f *collision_normal); + +bool boxLineCollision(const aabb3f &box, const v3f &box_rotation, + const v3f &start, const v3f &dir, + v3f *collision_point, v3f *collision_normal, v3f *raw_collision_normal); diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index cbe2d328c..6203ea78c 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -236,10 +236,12 @@ void read_object_properties(lua_State *L, int index, lua_pop(L, 1); lua_getfield(L, -1, "selectionbox"); - if (lua_istable(L, -1)) + if (lua_istable(L, -1)) { + getboolfield(L, -1, "rotate", prop->rotate_selectionbox); prop->selectionbox = read_aabb3f(L, -1, 1.0); - else if (collisionbox_defined) + } else if (collisionbox_defined) { prop->selectionbox = prop->collisionbox; + } lua_pop(L, 1); getboolfield(L, -1, "pointable", prop->pointable); @@ -377,6 +379,8 @@ void push_object_properties(lua_State *L, ObjectProperties *prop) push_aabb3f(L, prop->collisionbox); lua_setfield(L, -2, "collisionbox"); push_aabb3f(L, prop->selectionbox); + lua_pushboolean(L, prop->rotate_selectionbox); + lua_setfield(L, -2, "rotate"); lua_setfield(L, -2, "selectionbox"); lua_pushboolean(L, prop->pointable); lua_setfield(L, -2, "pointable"); @@ -1880,7 +1884,7 @@ void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm, if (hitpoint && (pointed.type != POINTEDTHING_NOTHING)) { push_v3f(L, pointed.intersection_point / BS); // convert to node coords lua_setfield(L, -2, "intersection_point"); - push_v3s16(L, pointed.intersection_normal); + push_v3f(L, pointed.intersection_normal); lua_setfield(L, -2, "intersection_normal"); lua_pushinteger(L, pointed.box_id + 1); // change to Lua array index lua_setfield(L, -2, "box_id"); diff --git a/src/server/luaentity_sao.cpp b/src/server/luaentity_sao.cpp index b25f19b85..5624c0f55 100644 --- a/src/server/luaentity_sao.cpp +++ b/src/server/luaentity_sao.cpp @@ -197,6 +197,11 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) } } + if (fabs(m_prop.automatic_rotate) > 0.001f) { + m_rotation_add_yaw = modulo360f(m_rotation_add_yaw + dtime * core::RADTODEG * + m_prop.automatic_rotate); + } + if(m_registered) { m_env->getScriptIface()->luaentity_Step(m_id, dtime, moveresult_p); } diff --git a/src/server/unit_sao.h b/src/server/unit_sao.h index a21e055c5..dedb1874e 100644 --- a/src/server/unit_sao.h +++ b/src/server/unit_sao.h @@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "object_properties.h" #include "serveractiveobject.h" +#include <quaternion.h> +#include "util/numeric.h" class UnitSAO : public ServerActiveObject { @@ -36,6 +38,17 @@ public: // Rotation void setRotation(v3f rotation) { m_rotation = rotation; } const v3f &getRotation() const { return m_rotation; } + const v3f getTotalRotation() const { + // This replicates what happens clientside serverside + core::matrix4 rot; + setPitchYawRoll(rot, -m_rotation); + v3f res; + // First rotate by m_rotation, then rotate by the automatic rotate yaw + (core::quaternion(v3f(0, -m_rotation_add_yaw * core::DEGTORAD, 0)) + * core::quaternion(rot.getRotationDegrees() * core::DEGTORAD)) + .toEuler(res); + return res * core::RADTODEG; + } v3f getRadRotation() { return m_rotation * core::DEGTORAD; } // Deprecated @@ -95,6 +108,7 @@ protected: u16 m_hp = 1; v3f m_rotation; + f32 m_rotation_add_yaw = 0; ItemGroupList m_armor_groups; diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index 4cdb21a4b..f893064de 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -1771,16 +1771,27 @@ void ServerEnvironment::getSelectedActiveObjects( continue; v3f pos = obj->getBasePosition(); - - aabb3f offsetted_box(selection_box.MinEdge + pos, - selection_box.MaxEdge + pos); + v3f rel_pos = shootline_on_map.start - pos; v3f current_intersection; - v3s16 current_normal; - if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector, - ¤t_intersection, ¤t_normal)) { + v3f current_normal; + v3f current_raw_normal; + + ObjectProperties *props = obj->accessObjectProperties(); + bool collision; + UnitSAO* usao = dynamic_cast<UnitSAO*>(obj); + if (props->rotate_selectionbox && usao != nullptr) { + collision = boxLineCollision(selection_box, usao->getTotalRotation(), + rel_pos, line_vector, ¤t_intersection, ¤t_normal, ¤t_raw_normal); + } else { + collision = boxLineCollision(selection_box, rel_pos, line_vector, + ¤t_intersection, ¤t_normal); + current_raw_normal = current_normal; + } + if (collision) { + current_intersection += pos; objects.emplace_back( - (s16) obj->getId(), current_intersection, current_normal, + (s16) obj->getId(), current_intersection, current_normal, current_raw_normal, (current_intersection - shootline_on_map.start).getLengthSQ()); } } diff --git a/src/util/pointedthing.cpp b/src/util/pointedthing.cpp index 6aa37dfe8..f6b4b77b6 100644 --- a/src/util/pointedthing.cpp +++ b/src/util/pointedthing.cpp @@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <sstream> PointedThing::PointedThing(const v3s16 &under, const v3s16 &above, - const v3s16 &real_under, const v3f &point, const v3s16 &normal, + const v3s16 &real_under, const v3f &point, const v3f &normal, u16 box_id, f32 distSq): type(POINTEDTHING_NODE), node_undersurface(under), @@ -36,12 +36,13 @@ PointedThing::PointedThing(const v3s16 &under, const v3s16 &above, distanceSq(distSq) {} -PointedThing::PointedThing(u16 id, const v3f &point, const v3s16 &normal, - f32 distSq) : +PointedThing::PointedThing(u16 id, const v3f &point, + const v3f &normal, const v3f &raw_normal, f32 distSq) : type(POINTEDTHING_OBJECT), object_id(id), intersection_point(point), intersection_normal(normal), + raw_intersection_normal(raw_normal), distanceSq(distSq) {} diff --git a/src/util/pointedthing.h b/src/util/pointedthing.h index 68b183195..e4f2eb20c 100644 --- a/src/util/pointedthing.h +++ b/src/util/pointedthing.h @@ -74,7 +74,12 @@ struct PointedThing * This is perpendicular to the face the ray hits, * points outside of the box and it's length is 1. */ - v3s16 intersection_normal; + v3f intersection_normal; + /*! + * Only valid if type is POINTEDTHING_OBJECT. + * Raw normal vector of the intersection before applying rotation. + */ + v3f raw_intersection_normal; /*! * Only valid if type isn't POINTEDTHING_NONE. * Indicates which selection box is selected, if there are more of them. @@ -90,10 +95,10 @@ struct PointedThing PointedThing() = default; //! Constructor for POINTEDTHING_NODE PointedThing(const v3s16 &under, const v3s16 &above, - const v3s16 &real_under, const v3f &point, const v3s16 &normal, + const v3s16 &real_under, const v3f &point, const v3f &normal, u16 box_id, f32 distSq); //! Constructor for POINTEDTHING_OBJECT - PointedThing(u16 id, const v3f &point, const v3s16 &normal, f32 distSq); + PointedThing(u16 id, const v3f &point, const v3f &normal, const v3f &raw_normal, f32 distSq); std::string dump() const; void serialize(std::ostream &os) const; void deSerialize(std::istream &is); |