/* greebo: This gets called by the SelectObserver if the user drags a box and holds down * any of the selection modifiers. Possible selection candidates are determined and selected/deselected */ void RadiantSelectionSystem::SelectArea(const View& view, const Vector2& device_point, const Vector2& device_delta, SelectionSystem::EModifier modifier, bool face) { // If we are in replace mode, deselect all the components or previous selections if (modifier == SelectionSystem::eReplace) { if (face) { setSelectedAllComponents(false); } else { deselectAll(); } } { // Construct the selection test according to the area the user covered with his drag View scissored(view); ConstructSelectionTest(scissored, Rectangle::ConstructFromArea(device_point, device_delta)); SelectionVolume volume(scissored); // The posssible candidates go here SelectionPool pool; SelectablesList candidates; if (face) { ComponentSelector selectionTester(pool, volume, eFace); GlobalSceneGraph().foreachVisibleNodeInVolume(scissored, selectionTester); // Load them all into the vector for (SelectionPool::iterator i = pool.begin(); i != pool.end(); ++i) { candidates.push_back(i->second); } } else { testSelectScene(candidates, volume, scissored, Mode(), ComponentMode()); } // Cycle through the selection pool and toggle the candidates, but only if we are in toggle mode for (SelectablesList::iterator i = candidates.begin(); i != candidates.end(); i++) { (*i)->setSelected(!(modifier == SelectionSystem::eToggle && (*i)->isSelected())); } } }
void RotateManipulator::testSelect (const View& view, const Matrix4& pivot2world) { m_pivot.update(pivot2world, view.GetModelview(), view.GetProjection(), view.GetViewport()); updateCircleTransforms(); SelectionPool selector; { { Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_local2world_x)); SelectionIntersection best; LineStrip_BestPoint(local2view, m_circle_x.m_vertices.data(), m_circle_x.m_vertices.size(), best); selector.addSelectable(best, &m_selectable_x); } { Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_local2world_y)); SelectionIntersection best; LineStrip_BestPoint(local2view, m_circle_y.m_vertices.data(), m_circle_y.m_vertices.size(), best); selector.addSelectable(best, &m_selectable_y); } { Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_local2world_z)); SelectionIntersection best; LineStrip_BestPoint(local2view, m_circle_z.m_vertices.data(), m_circle_z.m_vertices.size(), best); selector.addSelectable(best, &m_selectable_z); } } { Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_viewpointSpace)); { SelectionIntersection best; LineLoop_BestPoint(local2view, m_circle_screen.m_vertices.data(), m_circle_screen.m_vertices.size(), best); selector.addSelectable(best, &m_selectable_screen); } { SelectionIntersection best; Circle_BestPoint(local2view, eClipCullCW, m_circle_sphere.m_vertices.data(), m_circle_sphere.m_vertices.size(), best); selector.addSelectable(best, &m_selectable_sphere); } } m_axis_screen = m_pivot.m_axis_screen; if (!selector.failed()) { (*selector.begin()).second->setSelected(true); } }
/* greebo: This gets called by the SelectObserver if the user drags a box and holds down * any of the selection modifiers. Possible selection candidates are determined and selected/deselected */ void RadiantSelectionSystem::SelectArea(const View& view, const float device_point[2], const float device_delta[2], SelectionSystem::EModifier modifier, bool face) { // If we are in replace mode, deselect all the components or previous selections if (modifier == SelectionSystem::eReplace) { if (face) { setSelectedAllComponents(false); } else { deselectAll(); } } #if defined (DEBUG_SELECTION) g_render_clipped.destroy(); #endif { // Construct the selection test according to the area the user covered with his drag View scissored(view); ConstructSelectionTest(scissored, SelectionBoxForArea(device_point, device_delta)); SelectionVolume volume(scissored); // The posssible candidates go here SelectionPool pool; if (face) { Scene_TestSelect_Component(pool, volume, scissored, eFace); } else { Scene_TestSelect(pool, volume, scissored, Mode(), ComponentMode()); } // Cycle through the selection pool and toggle the candidates, but only if we are in toggle mode for (SelectionPool::iterator i = pool.begin(); i != pool.end(); ++i) { (*i).second->setSelected(!(modifier == SelectionSystem::eToggle && (*i).second->isSelected())); } } }
void DragManipulator::testSelect(const View& view, const Matrix4& pivot2world) { SelectionPool selector; SelectionVolume test(view); if (GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive) { BooleanSelector booleanSelector; Scene_TestSelect_Primitive(booleanSelector, test, view); if (booleanSelector.isSelected()) { selector.addSelectable(SelectionIntersection(0, 0), &_dragSelectable); _selected = false; } else { _selected = Scene_forEachPlaneSelectable_selectPlanes(GlobalSceneGraph(), selector, test); } } // Check for entities that can be selected else if (GlobalSelectionSystem().Mode() == SelectionSystem::eEntity) { // Create a boolean selection pool (can have exactly one selectable or none) BooleanSelector booleanSelector; // Find the visible entities Scene_forEachVisible(GlobalSceneGraph(), view, testselect_entity_visible(booleanSelector, test)); // Check, if an entity could be found if (booleanSelector.isSelected()) { selector.addSelectable(SelectionIntersection(0, 0), &_dragSelectable); _selected = false; } } else { BestSelector bestSelector; Scene_TestSelect_Component_Selected(bestSelector, test, view, GlobalSelectionSystem().ComponentMode()); for (std::list<Selectable*>::iterator i = bestSelector.best().begin(); i != bestSelector.best().end(); ++i) { if (!(*i)->isSelected()) { GlobalSelectionSystem().setSelectedAllComponents(false); } _selected = false; selector.addSelectable(SelectionIntersection(0, 0), (*i)); _dragSelectable.setSelected(true); } } for (SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i) { (*i).second->setSelected(true); } }
void ScaleManipulator::testSelect (const View& view, const Matrix4& pivot2world) { m_pivot.update(pivot2world, view.GetModelview(), view.GetProjection(), view.GetViewport()); SelectionPool selector; { Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_worldSpace)); { SelectionIntersection best; Line_BestPoint(local2view, m_arrow_x.m_line, best); selector.addSelectable(best, &m_selectable_x); } { SelectionIntersection best; Line_BestPoint(local2view, m_arrow_y.m_line, best); selector.addSelectable(best, &m_selectable_y); } { SelectionIntersection best; Line_BestPoint(local2view, m_arrow_z.m_line, best); selector.addSelectable(best, &m_selectable_z); } } { Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_viewpointSpace)); { SelectionIntersection best; Quad_BestPoint(local2view, eClipCullCW, m_quad_screen.m_quad, best); selector.addSelectable(best, &m_selectable_screen); } } if (!selector.failed()) { (*selector.begin()).second->setSelected(true); } }
/* greebo: This gets called by SelectObserver if the user just clicks into the scene (without dragging) * It checks for any possible targets (in the "line of click") and takes the actions according * to the modifiers that are held down (Alt-Shift, etc.) */ void RadiantSelectionSystem::SelectPoint(const View& view, const Vector2& device_point, const Vector2& device_epsilon, SelectionSystem::EModifier modifier, bool face) { ASSERT_MESSAGE(fabs(device_point[0]) <= 1.0f && fabs(device_point[1]) <= 1.0f, "point-selection error"); // If the user is holding the replace modifiers (default: Alt-Shift), deselect the current selection if (modifier == SelectionSystem::eReplace) { if (face) { setSelectedAllComponents(false); } else { deselectAll(); } } { View scissored(view); // Construct a selection test according to a small box with 2*epsilon edge length ConstructSelectionTest(scissored, Rectangle::ConstructFromPoint(device_point, device_epsilon)); // Create a new SelectionPool instance and fill it with possible candidates SelectionVolume volume(scissored); // The possible candidates are stored in the SelectablesSet SelectablesList candidates; if (face) { SelectionPool selector; ComponentSelector selectionTester(selector, volume, eFace); GlobalSceneGraph().foreachVisibleNodeInVolume(scissored, selectionTester); // Load them all into the vector for (SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i) { candidates.push_back(i->second); } } else { testSelectScene(candidates, volume, scissored, Mode(), ComponentMode()); } // Was the selection test successful (have we found anything to select)? if (candidates.size() > 0) { // Yes, now determine how we should interpret the click switch (modifier) { // If we are in toggle mode (Shift-Left-Click by default), just toggle the // selection of the "topmost" item case SelectionSystem::eToggle: { Selectable* best = *candidates.begin(); // toggle selection of the object with least depth (=first in the list) best->setSelected(!best->isSelected()); } break; // greebo: eReplace mode gets active as soon as the user holds the replace modifiers down // and clicks (by default: Alt-Shift). eReplace is only active during the first click // afterwards we are in cycle mode. // if cycle mode not enabled, enable it case SelectionSystem::eReplace: { // select closest (=first in the list) (*candidates.begin())->setSelected(true); } break; // select the next object in the list from the one already selected // greebo: eCycle is set if the user keeps holding the replace modifiers (Alt-Shift) // and does NOT move the mouse between the clicks, otherwise we fall back into eReplace mode // Note: The mode is set in SelectObserver::testSelect() case SelectionSystem::eCycle: { // Cycle through the selection pool and activate the item right after the currently selected SelectablesList::iterator i = candidates.begin(); while (i != candidates.end()) { if ((*i)->isSelected()) { // unselect the currently selected one (*i)->setSelected(false); // check if there is a "next" item in the list, if not: select the first item ++i; if (i != candidates.end()) { (*i)->setSelected(true); } else { (*candidates.begin())->setSelected(true); } break; } ++i; } // while } // case break; default: break; } // switch } } }
void RadiantSelectionSystem::testSelectScene(SelectablesList& targetList, SelectionTest& test, const View& view, SelectionSystem::EMode mode, SelectionSystem::EComponentMode componentMode) { // The (temporary) storage pool SelectionPool selector; SelectionPool sel2; switch(mode) { case eEntity: { // Instantiate a walker class which is specialised for selecting entities EntitySelector entityTester(selector, test); GlobalSceneGraph().foreachVisibleNodeInVolume(view, entityTester); for (SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i) { targetList.push_back(i->second); } } break; case ePrimitive: { // Do we have a camera view (filled rendering?) if (view.fill() || !GlobalXYWnd().higherEntitySelectionPriority()) { // Test for any visible elements (primitives, entities), but don't select child primitives AnySelector anyTester(selector, test); GlobalSceneGraph().foreachVisibleNodeInVolume(view, anyTester); } else { // We have an orthoview, here, select entities first // First, obtain all the selectable entities EntitySelector entityTester(selector, test); GlobalSceneGraph().foreachVisibleNodeInVolume(view, entityTester); // Now retrieve all the selectable primitives PrimitiveSelector primitiveTester(sel2, test); GlobalSceneGraph().foreachVisibleNodeInVolume(view, primitiveTester); } // Add the first selection crop to the target vector for (SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i) { targetList.push_back(i->second); } // Add the secondary crop to the vector (if it has any entries) for (SelectionPool::iterator i = sel2.begin(); i != sel2.end(); ++i) { // Check for duplicates SelectablesList::iterator j; for (j = targetList.begin(); j != targetList.end(); ++j) { if (*j == i->second) break; } // Insert if not yet in the list if (j == targetList.end()) { targetList.push_back(i->second); } } } break; case eGroupPart: { // Retrieve all the selectable primitives of group nodes GroupChildPrimitiveSelector primitiveTester(selector, test); GlobalSceneGraph().foreachVisibleNodeInVolume(view, primitiveTester); // Add the selection crop to the target vector for (SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i) { targetList.push_back(i->second); } } break; case eComponent: { ComponentSelector selectionTester(selector, test, componentMode); foreachSelected(selectionTester); for (SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i) { targetList.push_back(i->second); } } break; } // switch }
/* greebo: This gets called by SelectObserver if the user just clicks into the scene (without dragging) * It checks for any possible targets (in the "line of click") and takes the actions according * to the modifiers that are held down (Alt-Shift, etc.) */ void RadiantSelectionSystem::SelectPoint(const View& view, const float device_point[2], const float device_epsilon[2], SelectionSystem::EModifier modifier, bool face) { ASSERT_MESSAGE(fabs(device_point[0]) <= 1.0f && fabs(device_point[1]) <= 1.0f, "point-selection error"); // If the user is holding the replace modifiers (default: Alt-Shift), deselect the current selection if (modifier == SelectionSystem::eReplace) { if (face) { setSelectedAllComponents(false); } else { deselectAll(); } } #if defined (DEBUG_SELECTION) g_render_clipped.destroy(); #endif { View scissored(view); // Construct a selection test according to a small box with 2*epsilon edge length ConstructSelectionTest(scissored, SelectionBoxForPoint(device_point, device_epsilon)); // Create a new SelectionPool instance and fill it with possible candidates SelectionVolume volume(scissored); // The possible candidates are stored in the SelectionPool SelectionPool selector; if (face) { Scene_TestSelect_Component(selector, volume, scissored, eFace); } else { Scene_TestSelect(selector, volume, scissored, Mode(), ComponentMode()); } // Was the selection test successful (have we found anything to select)? if (!selector.failed()) { // Yes, now determine how we should interpret the click switch (modifier) { // If we are in toggle mode (Shift-Left-Click by default), just toggle the // selection of the "topmost" item case SelectionSystem::eToggle: { SelectableSortedSet::iterator best = selector.begin(); // toggle selection of the object with least depth (=first in the list) if ((*best).second->isSelected()) (*best).second->setSelected(false); else (*best).second->setSelected(true); } break; // greebo: eReplace mode gets active as soon as the user holds the replace modifiers down // and clicks (by default: Alt-Shift). eReplace is only active during the first click // afterwards we are in cycle mode. // if cycle mode not enabled, enable it case SelectionSystem::eReplace: { // select closest (=first in the list) (*selector.begin()).second->setSelected(true); } break; // select the next object in the list from the one already selected // greebo: eCycle is set if the user keeps holding the replace modifiers (Alt-Shift) // and does NOT move the mouse between the clicks, otherwise we fall back into eReplace mode // Note: The mode is set in SelectObserver::testSelect() case SelectionSystem::eCycle: { // Cycle through the selection pool and activate the item right after the currently selected SelectionPool::iterator i = selector.begin(); while (i != selector.end()) { if ((*i).second->isSelected()) { // unselect the currently selected one (*i).second->setSelected(false); // check if there is a "next" item in the list, if not: select the first item ++i; if (i != selector.end()) { i->second->setSelected(true); } else { selector.begin()->second->setSelected(true); } break; } ++i; } // while } // case break; default: break; } // switch } } }
void TranslateManipulator::testSelect (const View& view, const Matrix4& pivot2world) { m_pivot.update(pivot2world, view.GetModelview(), view.GetProjection(), view.GetViewport()); SelectionPool selector; Vector3 x = m_pivot.m_worldSpace.x().getVector3().getNormalised(); bool show_x = manipulator_show_axis(m_pivot, x); Vector3 y = m_pivot.m_worldSpace.y().getVector3().getNormalised(); bool show_y = manipulator_show_axis(m_pivot, y); Vector3 z = m_pivot.m_worldSpace.z().getVector3().getNormalised(); bool show_z = manipulator_show_axis(m_pivot, z); { Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_viewpointSpace)); { SelectionIntersection best; Quad_BestPoint(local2view, eClipCullCW, m_quad_screen.m_quad, best); if (best.valid()) { best = SelectionIntersection(0, 0); selector.addSelectable(best, &m_selectable_screen); } } } { Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_worldSpace)); #if defined(DEBUG_SELECTION) g_render_clipped.construct(view.GetViewMatrix()); #endif if (show_x) { SelectionIntersection best; Line_BestPoint(local2view, m_arrow_x.m_line, best); Triangles_BestPoint(local2view, eClipCullCW, m_arrow_head_x.m_vertices.begin(), m_arrow_head_x.m_vertices.end(), best); selector.addSelectable(best, &m_selectable_x); } if (show_y) { SelectionIntersection best; Line_BestPoint(local2view, m_arrow_y.m_line, best); Triangles_BestPoint(local2view, eClipCullCW, m_arrow_head_y.m_vertices.begin(), m_arrow_head_y.m_vertices.end(), best); selector.addSelectable(best, &m_selectable_y); } if (show_z) { SelectionIntersection best; Line_BestPoint(local2view, m_arrow_z.m_line, best); Triangles_BestPoint(local2view, eClipCullCW, m_arrow_head_z.m_vertices.begin(), m_arrow_head_z.m_vertices.end(), best); selector.addSelectable(best, &m_selectable_z); } } if (!selector.failed()) { (*selector.begin()).second->setSelected(true); } }
void TranslateManipulator::testSelect(const render::View& view, const Matrix4& pivot2world) { _pivot.update(pivot2world, view.GetModelview(), view.GetProjection(), view.GetViewport()); SelectionPool selector; Vector3 x = _pivot._worldSpace.x().getVector3().getNormalised(); bool show_x = manipulator_show_axis(_pivot, x); Vector3 y = _pivot._worldSpace.y().getVector3().getNormalised(); bool show_y = manipulator_show_axis(_pivot, y); Vector3 z = _pivot._worldSpace.z().getVector3().getNormalised(); bool show_z = manipulator_show_axis(_pivot, z); { Matrix4 local2view(view.GetViewMatrix().getMultipliedBy(_pivot._viewpointSpace)); { SelectionIntersection best; Quad_BestPoint(local2view, eClipCullCW, &_quadScreen.front(), best); if(best.valid()) { best = SelectionIntersection(0, 0); selector.addSelectable(best, &_selectableScreen); } } } { Matrix4 local2view(view.GetViewMatrix().getMultipliedBy(_pivot._worldSpace)); if(show_x) { SelectionIntersection best; Line_BestPoint(local2view, &_arrowX.front(), best); Triangles_BestPoint(local2view, eClipCullCW, &_arrowHeadX._vertices.front(), &*(_arrowHeadX._vertices.end()-1)+1, best); selector.addSelectable(best, &_selectableX); } if(show_y) { SelectionIntersection best; Line_BestPoint(local2view, &_arrowY.front(), best); Triangles_BestPoint(local2view, eClipCullCW, &_arrowHeadY._vertices.front(), &*(_arrowHeadY._vertices.end()-1)+1, best); selector.addSelectable(best, &_selectableY); } if(show_z) { SelectionIntersection best; Line_BestPoint(local2view, &_arrowZ.front(), best); Triangles_BestPoint(local2view, eClipCullCW, &_arrowHeadZ._vertices.front(), &*(_arrowHeadZ._vertices.end()-1)+1, best); selector.addSelectable(best, &_selectableZ); } } // greebo: If any of the above arrows could be selected, select the first in the SelectionPool if(!selector.failed()) { (*selector.begin()).second->setSelected(true); } else { Selectable* selectable = NULL; if (registry::getValue<bool>(RKEY_TRANSLATE_CONSTRAINED)) { // None of the shown arrows (or quad) has been selected, select an axis based on the precedence Matrix4 local2view(view.GetViewMatrix().getMultipliedBy(_pivot._worldSpace)); // Get the (relative?) distance from the mouse pointer to the manipulator Vector3 delta = local2view.t().getProjected(); // Get the precedence (which axis has the absolute largest value in it) bool xGreaterY = (fabs(delta.x()) > fabs(delta.y())); // The precedence has to be interpreted according to which axes are visible if (show_z) { // Either XZ or YZ if (show_y) { // YZ selectable = (xGreaterY) ? &_selectableY : &_selectableZ; } else { // XZ selectable = (xGreaterY) ? &_selectableX : &_selectableZ; } } else { // XY selectable = (xGreaterY) ? &_selectableX : &_selectableY; } } else { // Don't constrain to axis, choose the freemove translator selectable = &_selectableScreen; } // If everything went ok, there is a selectable available, add it if (selectable != NULL) { selector.addSelectable(SelectionIntersection(0,0), selectable); selectable->setSelected(true); } } }
void DragManipulator::testSelect(const render::View& view, const Matrix4& pivot2world) { SelectionPool selector; SelectionVolume test(view); if (GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive) { // Find all entities BooleanSelector entitySelector; EntitySelector selectionTester(entitySelector, test); GlobalSceneGraph().foreachVisibleNodeInVolume(view, selectionTester); if (entitySelector.isSelected()) { // Found a selectable entity selector.addSelectable(SelectionIntersection(0, 0), &_dragSelectable); _selected = false; } else { // Find all primitives that are selectable BooleanSelector primitiveSelector; PrimitiveSelector primitiveTester(primitiveSelector, test); GlobalSceneGraph().foreachVisibleNodeInVolume(view, primitiveTester); if (primitiveSelector.isSelected()) { // Found a selectable primitive selector.addSelectable(SelectionIntersection(0, 0), &_dragSelectable); _selected = false; } else { // Entities and worldspawn primitives failed, so check for group children too // Find all group child primitives that are selectable BooleanSelector childPrimitiveSelector; GroupChildPrimitiveSelector childPrimitiveTester(childPrimitiveSelector, test); GlobalSceneGraph().foreachVisibleNodeInVolume(view, childPrimitiveTester); if (childPrimitiveSelector.isSelected()) { // Found a selectable group child primitive selector.addSelectable(SelectionIntersection(0, 0), &_dragSelectable); _selected = false; } else { // all direct hits failed, check for drag-selectable faces _selected = Scene_forEachPlaneSelectable_selectPlanes(selector, test); } } } } else if (GlobalSelectionSystem().Mode() == SelectionSystem::eGroupPart) { // Find all primitives that are selectable BooleanSelector booleanSelector; GroupChildPrimitiveSelector childPrimitiveTester(booleanSelector, test); GlobalSceneGraph().foreachVisibleNodeInVolume(view, childPrimitiveTester); if (booleanSelector.isSelected()) { // Found a selectable primitive selector.addSelectable(SelectionIntersection(0, 0), &_dragSelectable); _selected = false; } else { // Check for selectable faces _selected = Scene_forEachPlaneSelectable_selectPlanes(selector, test); } } // Check for entities that can be selected else if (GlobalSelectionSystem().Mode() == SelectionSystem::eEntity) { // Create a boolean selection pool (can have exactly one selectable or none) BooleanSelector booleanSelector; // Find the visible entities EntitySelector selectionTester(booleanSelector, test); GlobalSceneGraph().foreachVisibleNodeInVolume(view, selectionTester); // Check, if an entity could be found if (booleanSelector.isSelected()) { selector.addSelectable(SelectionIntersection(0, 0), &_dragSelectable); _selected = false; } } else { BestSelector bestSelector; ComponentSelector selectionTester(bestSelector, test, GlobalSelectionSystem().ComponentMode()); GlobalSelectionSystem().foreachSelected(selectionTester); for (std::list<Selectable*>::iterator i = bestSelector.best().begin(); i != bestSelector.best().end(); ++i) { // greebo: Disabled this, it caused the currently selected patch vertices being deselected. if (registry::getValue<bool>(RKEY_TRANSIENT_COMPONENT_SELECTION)) { if (!(*i)->isSelected()) { GlobalSelectionSystem().setSelectedAllComponents(false); } } _selected = false; selector.addSelectable(SelectionIntersection(0, 0), (*i)); _dragSelectable.setSelected(true); } } for (SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i) { i->second->setSelected(true); } }