binds... * alt + m1 in camera: new resizing mode for brushes, curves and doom3 lights with direct and indirect selection methods

This commit is contained in:
Garux 2018-10-06 02:31:05 +03:00
parent f99cf57f27
commit 9c91f4fa78
7 changed files with 410 additions and 30 deletions

View File

@ -290,6 +290,7 @@ public:
virtual bool contains( const Plane3& plane ) const = 0;
};
/// \todo Support localToWorld.
class PlaneSelectable
{
public:
@ -297,6 +298,10 @@ STRING_CONSTANT( Name, "PlaneSelectable" );
virtual void selectPlanes( Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback ) = 0;
virtual void selectReversedPlanes( Selector& selector, const SelectedPlanes& selectedPlanes ) = 0;
virtual void bestPlaneDirect( SelectionTest& test, Plane3& plane, SelectionIntersection& intersection ) = 0;
virtual void bestPlaneIndirect( SelectionTest& test, Plane3& plane, Vector3& intersection, float& dist, const Vector3& viewer ) = 0;
virtual void selectByPlane( const Plane3& plane ) = 0;
};

View File

@ -159,6 +159,143 @@ void selectReversedPlanes( const AABB& aabb, Selector& selector, const SelectedP
if ( selectedPlanes.contains( plane3_flipped( planes[i] ) ) )
Selector_add( selector, m_selectables[i] );
}
void bestPlaneDirect( const AABB& aabb, SelectionTest& test, Plane3& plane, SelectionIntersection& intersection, const Matrix4& rotation = g_matrix4_identity ){
AABB aabb_ = aabb;
for( std::size_t i = 0; i < 3; ++i ) /* make sides of flat patches more selectable */
if( aabb_.extents[i] < 1 )
aabb_.extents[i] = 4;
Vector3 corners[8];
aabb_corners_oriented( aabb_, rotation, corners );
Plane3 planes[6];
aabb_planes_oriented( aabb_, rotation, planes );
const std::size_t indices[24] = {
2, 1, 5, 6, //+x //right
3, 7, 4, 0, //-x //left
1, 0, 4, 5, //+y //front
3, 2, 6, 7, //-y //back
0, 1, 2, 3, //+z //top
7, 6, 5, 4, //-z //bottom
};
for ( std::size_t i = 0; i < 6; ++i ){
const std::size_t index = i * 4;
SelectionIntersection intersection_new;
test.TestQuads( VertexPointer( reinterpret_cast<VertexPointer::pointer>( corners ), sizeof( Vector3 ) ), IndexPointer( &indices[index], 4 ), intersection_new );
if( SelectionIntersection_closer( intersection_new, intersection ) ){
intersection = intersection_new;
plane = planes[i];
}
}
m_bounds = aabb;
}
void bestPlaneIndirect( const AABB& aabb, SelectionTest& test, Plane3& plane, Vector3& intersection, float& dist, const Vector3& viewer, const Matrix4& rotation = g_matrix4_identity ){
Vector3 corners[8];
aabb_corners_oriented( aabb, rotation, corners );
Plane3 planes[6];
aabb_planes_oriented( aabb, rotation, planes );
/*
const std::size_t indices[24] = {
2, 1, 5, 6, //+x //right
3, 7, 4, 0, //-x //left
1, 0, 4, 5, //+y //front
3, 2, 6, 7, //-y //back
0, 1, 2, 3, //+z //top
7, 6, 5, 4, //-z //bottom
};
*/
/*
0 ----- 1
/| /|
/ | / |
/ | / |
3 ----- 2 |
| 4|_|___|5
| / | /
| / | /
|/ | /
7|_____|/6
*/
const std::size_t edges[24] = {
0, 1,
1, 2,
2, 3,
3, 0,
4, 5,
5, 6,
6, 7,
7, 4,
0, 4,
1, 5,
2, 6,
3, 7,
};
const std::size_t adjacent_planes[24] = {
4, 2,
4, 0,
4, 3,
4, 1,
5, 2,
5, 0,
5, 3,
5, 1,
1, 2,
2, 0,
0, 3,
3, 1,
};
for( std::size_t i = 0; i < 8; ++i ){
corners[i] = vector4_projected( matrix4_transformed_vector4( test.getVolume().GetViewMatrix(), Vector4( corners[i], 1 ) ) );
}
for ( std::size_t i = 0; i < 24; ++++i ){
const Vector3 intersection_new = line_closest_point( Line( corners[edges[i]], corners[edges[i + 1]] ), g_vector3_identity );
const float dist_new = vector3_length_squared( intersection_new );
if( dist_new < dist ){
const Plane3& plane1 = planes[adjacent_planes[i]];
const Plane3& plane2 = planes[adjacent_planes[i + 1]];
if( ( vector3_dot( plane1.normal(), viewer ) - plane1.dist() ) <= 0 ){
if( aabb.extents[( ( adjacent_planes[i] >> 1 ) << 1 ) / 2] == 0 ) /* select the other, if zero bound */
plane = plane2;
else
plane = plane1;
intersection = intersection_new;
dist = dist_new;
}
else{
if( ( vector3_dot( plane2.normal(), viewer ) - plane2.dist() ) <= 0 ){
if( aabb.extents[( ( adjacent_planes[i + 1] >> 1 ) << 1 ) / 2] == 0 ) /* select the other, if zero bound */
plane = plane1;
else
plane = plane2;
intersection = intersection_new;
dist = dist_new;
}
}
}
}
m_bounds = aabb;
}
void selectByPlane( const AABB& aabb, const Plane3& plane, const Matrix4& rotation = g_matrix4_identity ){
Plane3 planes[6];
aabb_planes_oriented( aabb, rotation, planes );
for ( std::size_t i = 0; i < 6; ++i ){
if( plane3_equal( plane, planes[i] ) || plane3_equal( plane, plane3_flipped( planes[i] ) ) ){
m_selectables[i].setSelected( true );
}
}
}
AABB evaluateResize( const Vector3& translation ) const {
Vector3 min = m_bounds.origin - m_bounds.extents;
Vector3 max = m_bounds.origin + m_bounds.extents;

View File

@ -1867,6 +1867,25 @@ void selectReversedPlanes( Selector& selector, const SelectedPlanes& selectedPla
}
}
void bestPlaneDirect( SelectionTest& test, Plane3& plane, SelectionIntersection& intersection ){
if ( g_lightType == LIGHTTYPE_DOOM3 ) {
test.BeginMesh( localToWorld() );
m_dragPlanes.bestPlaneDirect( m_contained.aabb(), test, plane, intersection, rotation() );
}
}
void bestPlaneIndirect( SelectionTest& test, Plane3& plane, Vector3& intersection, float& dist, const Vector3& viewer ){
if ( g_lightType == LIGHTTYPE_DOOM3 ) {
test.BeginMesh( localToWorld() );
m_dragPlanes.bestPlaneIndirect( m_contained.aabb(), test, plane, intersection, dist, viewer, rotation() );
}
}
void selectByPlane( const Plane3& plane ){
if ( g_lightType == LIGHTTYPE_DOOM3 ) {
m_dragPlanes.selectByPlane( m_contained.aabb(), plane, rotation() );
}
}
bool isSelectedComponents() const {
if ( g_lightType == LIGHTTYPE_DOOM3 ) {
return m_dragPlanes.isSelected();

View File

@ -1509,6 +1509,16 @@ Face& getFace() const {
void testSelect( SelectionTest& test, SelectionIntersection& best ){
test.TestPoint( getEdge(), best );
}
Vector3 bestPlaneIndirect( const SelectionTest& test ) const {
const Winding& winding = getFace().getWinding();
Vector3 points[2];
points[0] = winding[m_faceVertex.getVertex()].vertex;
points[1] = winding[Winding_next( winding, m_faceVertex.getVertex() )].vertex;
for( std::size_t i = 0; i < 2; ++i ){
points[i] = vector4_projected( matrix4_transformed_vector4( test.getVolume().GetViewMatrix(), Vector4( points[i], 1 ) ) );
}
return line_closest_point( Line( points[0], points[1] ), g_vector3_identity );
}
};
class SelectableVertex
@ -3042,6 +3052,28 @@ void testSelect( Selector& selector, SelectionTest& test ){
Selector_add( selector, *this, best );
}
}
void bestPlaneIndirect( const SelectionTest& test, Plane3& plane, Vector3& intersection, float& dist, const Vector3& viewer ) const {
const Vector3 intersection_new = m_edge->bestPlaneIndirect( test );
const float dist_new = vector3_length_squared( intersection_new );
if( dist_new < dist ){
FaceVertexId faceVertex = m_edge->m_faceVertex;
const Plane3& plane1 = m_faceInstances[faceVertex.getFace()].getFace().plane3();
if( ( vector3_dot( plane1.normal(), viewer ) - plane1.dist() ) <= 0 ){
plane = plane1;
intersection = intersection_new;
dist = dist_new;
}
else{
faceVertex = next_edge( m_edge->m_faces, faceVertex );
const Plane3& plane2 = m_faceInstances[faceVertex.getFace()].getFace().plane3();
if( ( vector3_dot( plane2.normal(), viewer ) - plane2.dist() ) <= 0 ){
plane = plane2;
intersection = intersection_new;
dist = dist_new;
}
}
}
}
};
class VertexInstance : public Selectable
@ -3588,6 +3620,31 @@ void selectReversedPlanes( Selector& selector, const SelectedPlanes& selectedPla
}
}
void bestPlaneDirect( SelectionTest& test, Plane3& plane, SelectionIntersection& intersection ){
test.BeginMesh( localToWorld() );
for ( FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i )
{
SelectionIntersection intersection_new;
( *i ).testSelect( test, intersection_new );
if( SelectionIntersection_closer( intersection_new, intersection ) ){
intersection = intersection_new;
plane = ( *i ).getFace().plane3();
}
}
}
void bestPlaneIndirect( SelectionTest& test, Plane3& plane, Vector3& intersection, float& dist, const Vector3& viewer ){
test.BeginMesh( localToWorld() );
for ( EdgeInstances::iterator i = m_edgeInstances.begin(); i != m_edgeInstances.end(); ++i )
{
( *i ).bestPlaneIndirect( test, plane, intersection, dist, viewer );
}
}
void selectByPlane( const Plane3& plane ){
for ( FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i )
if( plane3_equal( plane, ( *i ).getFace().plane3() ) || plane3_equal( plane, plane3_flipped( ( *i ).getFace().plane3() ) ) )
( *i ).setSelected( SelectionSystem::eFace, true );
}
void selectVerticesOnPlanes( SelectionTest& test ){
FaceInstances_ptrs bestInstances;

View File

@ -1617,6 +1617,18 @@ void selectReversedPlanes( Selector& selector, const SelectedPlanes& selectedPla
m_dragPlanes.selectReversedPlanes( m_patch.localAABB(), selector, selectedPlanes );
}
void bestPlaneDirect( SelectionTest& test, Plane3& plane, SelectionIntersection& intersection ){
test.BeginMesh( localToWorld() );
m_dragPlanes.bestPlaneDirect( m_patch.localAABB(), test, plane, intersection );
}
void bestPlaneIndirect( SelectionTest& test, Plane3& plane, Vector3& intersection, float& dist, const Vector3& viewer ){
test.BeginMesh( localToWorld() );
m_dragPlanes.bestPlaneIndirect( m_patch.localAABB(), test, plane, intersection, dist, viewer );
}
void selectByPlane( const Plane3& plane ){
m_dragPlanes.selectByPlane( m_patch.localAABB(), plane );
}
void snapComponents( float snap ){
if ( selectedVertices() ) {

View File

@ -438,6 +438,49 @@ void SetAxis( const Vector3& axis ){
}
};
class TranslateAxis2 : public Manipulatable
{
private:
Vector3 m_0;
std::size_t m_axisZ;
Plane3 m_planeZ;
Vector3 m_startZ;
Translatable& m_translatable;
AABB m_bounds;
public:
TranslateAxis2( Translatable& translatable )
: m_translatable( translatable ){
}
void Construct( const Matrix4& device2manip, const float x, const float y, const AABB& bounds, const Vector3& transform_origin ){
if( m_0 == g_vector3_identity ) /* special value to indicate missing good point to start with */
m_0 = transform_origin;
#if 0
Vector3 xydir( m_view->getViewDir() );
#else
Vector3 xydir( m_view->getViewer() - m_0 );
#endif
xydir[m_axisZ] = 0;
vector3_normalise( xydir );
m_planeZ = Plane3( xydir, vector3_dot( xydir, m_0 ) );
m_startZ = point_on_plane( m_planeZ, m_view->GetViewMatrix(), x, y );
m_bounds = bounds;
}
void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox, const bool alt ){
Vector3 current = ( point_on_plane( m_planeZ, m_view->GetViewMatrix(), x, y ) - m_startZ ) * g_vector3_axes[m_axisZ];
if( snapbbox )
aabb_snap_translation( current, m_bounds );
else
vector3_snap( current, GetSnapGridSize() );
m_translatable.translate( current );
}
void set0( const Vector3& start, std::size_t axis ){
m_0 = start;
m_axisZ = axis;
}
};
class TranslateFree : public Manipulatable
{
private:
@ -2701,6 +2744,99 @@ bool Scene_forEachPlaneSelectable_selectPlanes( scene::Graph& graph, Selector& s
}
class PlaneSelectable_bestPlaneDirect : public scene::Graph::Walker
{
SelectionTest& m_test;
Plane3& m_plane;
mutable SelectionIntersection m_intersection;
public:
PlaneSelectable_bestPlaneDirect( SelectionTest& test, Plane3& plane )
: m_test( test ), m_plane( plane ), m_intersection(){
}
bool pre( const scene::Path& path, scene::Instance& instance ) const {
if ( path.top().get().visible() ) {
Selectable* selectable = Instance_getSelectable( instance );
if ( selectable != 0 && selectable->isSelected() ) {
PlaneSelectable* planeSelectable = Instance_getPlaneSelectable( instance );
if ( planeSelectable != 0 ) {
planeSelectable->bestPlaneDirect( m_test, m_plane, m_intersection );
}
}
}
return true;
}
};
class PlaneSelectable_bestPlaneIndirect : public scene::Graph::Walker
{
SelectionTest& m_test;
Plane3& m_plane;
Vector3& m_intersection;
const Vector3& m_viewer;
mutable float m_dist;
public:
PlaneSelectable_bestPlaneIndirect( SelectionTest& test, Plane3& plane, Vector3& intersection, const Vector3& viewer )
: m_test( test ), m_plane( plane ), m_intersection( intersection ), m_viewer( viewer ), m_dist( FLT_MAX ){
}
bool pre( const scene::Path& path, scene::Instance& instance ) const {
if ( path.top().get().visible() ) {
Selectable* selectable = Instance_getSelectable( instance );
if ( selectable != 0 && selectable->isSelected() ) {
PlaneSelectable* planeSelectable = Instance_getPlaneSelectable( instance );
if ( planeSelectable != 0 ) {
planeSelectable->bestPlaneIndirect( m_test, m_plane, m_intersection, m_dist, m_viewer );
}
}
}
return true;
}
};
class PlaneSelectable_selectByPlane : public scene::Graph::Walker
{
const Plane3 m_plane;
public:
PlaneSelectable_selectByPlane( const Plane3& plane )
: m_plane( plane ){
}
bool pre( const scene::Path& path, scene::Instance& instance ) const {
if ( path.top().get().visible() ) {
Selectable* selectable = Instance_getSelectable( instance );
if ( selectable != 0 && selectable->isSelected() ) {
PlaneSelectable* planeSelectable = Instance_getPlaneSelectable( instance );
if ( planeSelectable != 0 ) {
planeSelectable->selectByPlane( m_plane );
}
}
}
return true;
}
};
bool Scene_forEachPlaneSelectable_selectPlanes2( scene::Graph& graph, SelectionTest& test, const Vector3& viewer, TranslateAxis2& translateAxis ){
Plane3 plane( 0, 0, 0, 0 );
graph.traverse( PlaneSelectable_bestPlaneDirect( test, plane ) );
if( plane3_valid( plane ) ){
test.BeginMesh( g_matrix4_identity );
translateAxis.set0( point_on_plane( plane, test.getVolume().GetViewMatrix(), 0, 0 ), vector3_max_abs_component_index( plane.normal() ) );
}
else{
Vector3 intersection;
graph.traverse( PlaneSelectable_bestPlaneIndirect( test, plane, intersection, viewer ) );
if( plane3_valid( plane ) ){
test.BeginMesh( g_matrix4_identity );
/* may introduce some screen space offset in manipulatable to handle far-from-edge clicks perfectly; thought clicking not so far isn't too nasty, right? */
translateAxis.set0( vector4_projected( matrix4_transformed_vector4( test.getScreen2world(), Vector4( intersection, 1 ) ) ), vector3_max_abs_component_index( plane.normal() ) );
}
}
if( plane3_valid( plane ) ){
graph.traverse( PlaneSelectable_selectByPlane( plane ) );
}
return plane3_valid( plane );
}
#include "brush.h"
class TestedBrushFacesSelectVeritces : public scene::Graph::Walker
@ -3617,6 +3753,7 @@ bool g_bTmpComponentMode = false;
class DragManipulator : public Manipulator
{
TranslateFree m_freeResize;
TranslateAxis2 m_axisResize;
TranslateFree m_freeDrag;
TranslateFreeXY_Z m_freeDragXY_Z;
ResizeTranslatable m_resize;
@ -3624,11 +3761,12 @@ DragTranslatable m_drag;
DragNewBrush m_dragNewBrush;
bool m_dragSelected; //drag selected primitives or components
bool m_selected; //components selected temporally for drag
bool m_selected2; //planeselectables in cam with alt
bool m_newBrush;
public:
DragManipulator() : m_freeResize( m_resize ), m_freeDrag( m_drag ), m_freeDragXY_Z( m_drag ), m_selected( false ), m_newBrush( false ){
DragManipulator() : m_freeResize( m_resize ), m_axisResize( m_resize ), m_freeDrag( m_drag ), m_freeDragXY_Z( m_drag ), m_dragSelected( false ), m_selected( false ), m_selected2( false ), m_newBrush( false ){
}
Manipulatable* GetManipulatable(){
@ -3636,6 +3774,8 @@ Manipulatable* GetManipulatable(){
return &m_dragNewBrush;
else if( m_selected )
return &m_freeResize;
else if( m_selected2 )
return &m_axisResize;
else if( Manipulatable::m_view->fill() )
return &m_freeDragXY_Z;
else
@ -3648,32 +3788,37 @@ void testSelect( const View& view, const Matrix4& pivot2world ){
if( GlobalSelectionSystem().countSelected() != 0 ){
if ( GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ){
BooleanSelector booleanSelector;
Scene_TestSelect_Primitive( booleanSelector, test, view );
if ( booleanSelector.isSelected() ) { /* hit a primitive */
if( g_bAltResize_AltSelect ){
DeepBestSelector deepSelector;
Scene_TestSelect_Component_Selected( deepSelector, test, view, SelectionSystem::eVertex ); /* try to quickly select hit vertices */
for ( std::list<Selectable*>::iterator i = deepSelector.best().begin(); i != deepSelector.best().end(); ++i )
selector.addSelectable( SelectionIntersection( 0, 0 ), ( *i ) );
if( deepSelector.best().empty() ) /* otherwise drag clicked face's vertices */
Scene_forEachTestedBrushFace_selectVertices( GlobalSceneGraph(), test );
m_selected = true;
}
else{ /* drag a primitive */
m_dragSelected = true;
test.BeginMesh( g_matrix4_identity, true );
m_freeDragXY_Z.set0( vector4_projected( matrix4_transformed_vector4( test.getScreen2world(), Vector4( 0, 0, booleanSelector.bestIntersection().depth(), 1 ) ) ) );
}
if( g_bAltResize_AltSelect && view.fill() ){
m_selected2 = Scene_forEachPlaneSelectable_selectPlanes2( GlobalSceneGraph(), test, Manipulatable::m_view->getViewer(), m_axisResize );
}
else{ /* haven't hit a primitive */
if( g_bAltResize_AltSelect ){
Scene_forEachBrushPlane_selectVertices( GlobalSceneGraph(), test ); /* select vertices on planeSelectables */
m_selected = true;
else{
BooleanSelector booleanSelector;
Scene_TestSelect_Primitive( booleanSelector, test, view );
if ( booleanSelector.isSelected() ) { /* hit a primitive */
if( g_bAltResize_AltSelect ){
DeepBestSelector deepSelector;
Scene_TestSelect_Component_Selected( deepSelector, test, view, SelectionSystem::eVertex ); /* try to quickly select hit vertices */
for ( std::list<Selectable*>::iterator i = deepSelector.best().begin(); i != deepSelector.best().end(); ++i )
selector.addSelectable( SelectionIntersection( 0, 0 ), ( *i ) );
if( deepSelector.best().empty() ) /* otherwise drag clicked face's vertices */
Scene_forEachTestedBrushFace_selectVertices( GlobalSceneGraph(), test );
m_selected = true;
}
else{ /* drag a primitive */
m_dragSelected = true;
test.BeginMesh( g_matrix4_identity, true );
m_freeDragXY_Z.set0( vector4_projected( matrix4_transformed_vector4( test.getScreen2world(), Vector4( 0, 0, booleanSelector.bestIntersection().depth(), 1 ) ) ) );
}
}
else{
m_selected = Scene_forEachPlaneSelectable_selectPlanes( GlobalSceneGraph(), selector, test ); /* select faces on planeSelectables */
else{ /* haven't hit a primitive */
if( g_bAltResize_AltSelect ){
Scene_forEachBrushPlane_selectVertices( GlobalSceneGraph(), test ); /* select vertices on planeSelectables */
m_selected = true;
}
else{
m_selected = Scene_forEachPlaneSelectable_selectPlanes( GlobalSceneGraph(), selector, test ); /* select faces on planeSelectables */
}
}
}
}
@ -3698,7 +3843,7 @@ void testSelect( const View& view, const Matrix4& pivot2world ){
for ( SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i )
( *i ).second->setSelected( true );
g_bTmpComponentMode = m_selected;
g_bTmpComponentMode = m_selected | m_selected2;
}
else if( GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ){
m_newBrush = true;
@ -3722,10 +3867,11 @@ void testSelect( const View& view, const Matrix4& pivot2world ){
void setSelected( bool select ){
m_dragSelected = select;
m_selected = select;
m_selected2 = select;
m_newBrush = select;
}
bool isSelected() const {
return m_dragSelected || m_selected || m_newBrush;
return m_dragSelected || m_selected || m_selected2 || m_newBrush;
}
};
@ -5226,9 +5372,13 @@ bool RadiantSelectionSystem::endMove(){
freezeTransforms();
if ( Mode() == ePrimitive && ManipulatorMode() == eDrag ) {
// if ( Mode() == ePrimitive && ManipulatorMode() == eDrag ) {
// g_bTmpComponentMode = false;
// Scene_SelectAll_Component( false, g_bAltResize_AltSelect? SelectionSystem::eVertex : SelectionSystem::eFace );
// }
if( g_bTmpComponentMode ){
g_bTmpComponentMode = false;
Scene_SelectAll_Component( false, g_bAltResize_AltSelect? SelectionSystem::eVertex : SelectionSystem::eFace );
setSelectedAllComponents( false );
}
m_pivot_moving = false;

View File

@ -102,7 +102,7 @@ void construct(){
m_frustum = frustum_from_viewproj( m_viewproj );
m_viewer = viewer_from_viewproj( m_viewproj );
m_viewdir = vector3_normalised( fill()? Vector3( -m_modelview[2], -m_modelview[6], -m_modelview[10] ) : Vector3( m_modelview[2], m_modelview[6], m_modelview[10] ) );
m_viewdir = vector3_normalised( fill()? Vector3( -m_modelview[2], -m_modelview[6], -m_modelview[10] ) : Vector3( m_modelview[2], m_modelview[6], m_modelview[10] ) );
}
public:
View( bool fill = false ) :