* QE tool mouse move: highlight PlaneSelectables with alt/ctrl+alt, components in component modes

improve bestPlaneIndirect pickup (resolve, when corner is closest)
support 2d in class DragPlanes::bestPlaneIndirect
This commit is contained in:
Garux 2020-03-10 05:09:32 +03:00
parent a4b61f88e5
commit 7acdf92d50
10 changed files with 488 additions and 129 deletions

View File

@ -302,6 +302,7 @@ virtual void selectReversedPlanes( Selector& selector, const SelectedPlanes& sel
virtual void bestPlaneDirect( SelectionTest& test, Plane3& plane, SelectionIntersection& intersection ) = 0;
virtual void bestPlaneIndirect( SelectionTest& test, Plane3& plane, Vector3& intersection, float& dist ) = 0;
virtual void selectByPlane( const Plane3& plane ) = 0;
virtual void gatherPolygonsByPlane( const Plane3& plane, std::vector<std::vector<Vector3>>& polygons ) const = 0;
};

View File

@ -227,28 +227,28 @@ void bestPlaneIndirect( const AABB& aabb, SelectionTest& test, Plane3& plane, Ve
*/
const std::size_t edges[24] = {
0, 1,
1, 2,
2, 3,
3, 0,
0, 1, // x
3, 2,
7, 6,
4, 5,
5, 6,
6, 7,
2, 1, // y
3, 0,
6, 5,
7, 4,
0, 4,
1, 5,
2, 6,
3, 7,
4, 0, // z
5, 1,
6, 2,
7, 3,
};
const std::size_t adjacent_planes[24] = {
4, 2,
4, 0,
4, 3,
4, 1,
5, 2,
5, 0,
5, 3,
5, 2,
4, 0,
4, 1,
5, 0,
5, 1,
1, 2,
2, 0,
@ -256,31 +256,55 @@ void bestPlaneIndirect( const AABB& aabb, SelectionTest& test, Plane3& plane, Ve
3, 1,
};
float dot = 1;
const bool some_extent_zero = aabb.extents[0] == 0 || aabb.extents[1] == 0 || aabb.extents[2] == 0;
for ( std::size_t i = 0; i < 24; ++++i ){
Line line( corners[edges[i]], corners[edges[i + 1]] );
if( matrix4_clip_line_by_nearplane( test.getVolume().GetViewMatrix(), line ) == 2 ){
if( aabb.extents[i / 8] != 0.f && matrix4_clip_line_by_nearplane( test.getVolume().GetViewMatrix(), line ) == 2 ){
const Vector3 intersection_new = line_closest_point( line, g_vector3_identity );
const float dist_new = vector3_length_squared( intersection_new );
if( dist_new < dist ){
const float dot_new = fabs( vector3_dot( vector3_normalised( intersection_new ), vector3_normalised( line.end - line.start ) ) );
//effective epsilon is rather big: optimized 32 bit build is using doubles implicitly (floats might be straightly checked for equality); same code in brush.h is cool with way smaller epsilon
if( dist - dist_new > 1e-2f // new dist noticeably smaller
|| ( float_equal_epsilon( dist_new, dist, 1e-2f ) && dot_new < dot ) ){ // or ambiguous case. Resolve it by dot comparison
const Plane3& plane1 = planes[adjacent_planes[i]];
const Plane3& plane2 = planes[adjacent_planes[i + 1]];
if( plane3_distance_to_point( plane1, test.getVolume().getViewer() ) <= 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( plane3_distance_to_point( plane2, test.getVolume().getViewer() ) <= 0 ){
if( aabb.extents[( ( adjacent_planes[i + 1] >> 1 ) << 1 ) / 2] == 0 ) /* select the other, if zero bound */
plane = plane1;
else
plane = plane2;
auto assign_plane = [&plane, &intersection, intersection_new, &dist, dist_new, &dot, dot_new]( const Plane3& plane_new ){
plane = plane_new;
intersection = intersection_new;
dist = dist_new;
dot = dot_new;
};
if( test.getVolume().fill() ){
if( plane3_distance_to_point( plane1, test.getVolume().getViewer() ) <= 0 ){
if( aabb.extents[adjacent_planes[i] / 2] == 0 ) /* select the other, if zero bound */
assign_plane( plane2 );
else
assign_plane( plane1 );
}
else if( plane3_distance_to_point( plane2, test.getVolume().getViewer() ) <= 0 ){
if( aabb.extents[adjacent_planes[i + 1] / 2] == 0 ) /* select the other, if zero bound */
assign_plane( plane1 );
else
assign_plane( plane2 );
}
}
else if( some_extent_zero || fabs( vector3_length_squared( line.end - line.start ) ) > 1e-3 ){
if( fabs( vector3_dot( plane1.normal(), test.getVolume().getViewDir() ) ) < fabs( vector3_dot( plane2.normal(), test.getVolume().getViewDir() ) ) ){
if( aabb.extents[adjacent_planes[i] / 2] == 0 ) /* select the other, if zero bound */
assign_plane( plane2 );
else
assign_plane( plane1 );
}
else{
if( aabb.extents[adjacent_planes[i + 1] / 2] == 0 ) /* select the other, if zero bound */
assign_plane( plane1 );
else
assign_plane( plane2 );
}
}
}
}
@ -294,9 +318,38 @@ void selectByPlane( const AABB& aabb, const Plane3& plane, const Matrix4& rotati
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 );
return;
}
}
}
void gatherPolygonsByPlane( const AABB& aabb, const Plane3& plane, std::vector<std::vector<Vector3>>& polygons, const Matrix4& rotation = g_matrix4_identity ) const {
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 ){
if( plane3_equal( plane, planes[i] ) || plane3_equal( plane, plane3_flipped( planes[i] ) ) ){
const std::size_t index = i * 4;
polygons.emplace_back( std::initializer_list<Vector3>( { corners[indices[index]],
corners[indices[index + 1]],
corners[indices[index + 2]],
corners[indices[index + 3]] } ) );
return;
}
}
}
AABB evaluateResize( const Vector3& translation ) const {
Vector3 min = m_bounds.origin - m_bounds.extents;

View File

@ -40,6 +40,7 @@
class Selector;
class SelectionTest;
class SelectionIntersection;
class ComponentSelectionTestable
{
@ -49,6 +50,7 @@ STRING_CONSTANT( Name, "ComponentSelectionTestable" );
virtual bool isSelectedComponents() const = 0;
virtual void setSelectedComponents( bool select, SelectionSystem::EComponentMode mode ) = 0;
virtual void testSelectComponents( Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode ) = 0;
virtual void gatherComponentsHighlight( std::vector<std::vector<Vector3>>& polygons, SelectionIntersection& intersection, SelectionTest& test, SelectionSystem::EComponentMode mode ) const = 0;
};
typedef std::function<void( const Vector3& )> Vector3Callback;

View File

@ -544,6 +544,8 @@ void testSelectComponents( Selector& selector, SelectionTest& test, SelectionSys
m_curveCatmullRom.testSelect( selector, test );
}
}
void gatherComponentsHighlight( std::vector<std::vector<Vector3>>& polygons, SelectionIntersection& intersection, SelectionTest& test, SelectionSystem::EComponentMode mode ) const {
}
void transformComponents( const Matrix4& matrix ){
if ( m_curveNURBS.isSelected() ) {

View File

@ -1884,6 +1884,11 @@ void selectByPlane( const Plane3& plane ){
m_dragPlanes.selectByPlane( m_contained.aabb(), plane, rotation() );
}
}
void gatherPolygonsByPlane( const Plane3& plane, std::vector<std::vector<Vector3>>& polygons ) const {
if ( g_lightType == LIGHTTYPE_DOOM3 ) {
m_dragPlanes.gatherPolygonsByPlane( m_contained.aabb(), plane, polygons, rotation() );
}
}
bool isSelectedComponents() const {
@ -1906,6 +1911,8 @@ void setSelectedComponents( bool select, SelectionSystem::EComponentMode mode ){
}
void testSelectComponents( Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode ){
}
void gatherComponentsHighlight( std::vector<std::vector<Vector3>>& polygons, SelectionIntersection& intersection, SelectionTest& test, SelectionSystem::EComponentMode mode ) const {
}
void selectedChangedComponent( const Selectable& selectable ){
GlobalSelectionSystem().getObserver ( SelectionSystem::eComponent )( selectable );

View File

@ -1205,7 +1205,7 @@ void testSelect( SelectionTest& test, SelectionIntersection& best ){
Winding_testSelect( m_winding, test, best, m_plane.getPlanePoints() );
}
void testSelect_centroid( SelectionTest& test, SelectionIntersection& best ){
void testSelect_centroid( SelectionTest& test, SelectionIntersection& best ) const {
test.TestPoint( m_centroid, best );
}
@ -1502,12 +1502,12 @@ inline FaceVertexId next_vertex( const Faces& faces, FaceVertexId faceVertex ){
class SelectableEdge
{
public:
Vector3 getEdge() const {
const Winding& winding = getFace().getWinding();
return vector3_mid( winding[m_faceVertex.getVertex()].vertex, winding[Winding_next( winding, m_faceVertex.getVertex() )].vertex );
}
public:
Faces& m_faces;
FaceVertexId m_faceVertex;
@ -1530,11 +1530,11 @@ void testSelect( SelectionTest& test, SelectionIntersection& best ){
class SelectableVertex
{
public:
Vector3 getVertex() const {
return getFace().getWinding()[m_faceVertex.getVertex()].vertex;
}
public:
Faces& m_faces;
FaceVertexId m_faceVertex;
@ -2859,7 +2859,7 @@ void render( Renderer& renderer, const VolumeTest& volume, const Matrix4& localT
}
}
void testSelect( SelectionTest& test, SelectionIntersection& best ){
void testSelect( SelectionTest& test, SelectionIntersection& best ) const {
if ( !m_face->isFiltered() ) {
m_face->testSelect( test, best );
}
@ -3217,46 +3217,48 @@ void testSelect( Selector& selector, SelectionTest& test ){
Selector_add( selector, *this, best );
}
}
void gatherComponentsHighlight( std::vector<std::vector<Vector3>>& polygons, SelectionIntersection& intersection, SelectionTest& test ) const {
SelectionIntersection best;
m_edge->testSelect( test, best );
if ( SelectionIntersection_closer( best, intersection ) ) {
intersection = best;
polygons.clear();
polygons.emplace_back( std::initializer_list<Vector3>( { m_edge->getEdge() } ) );
}
}
void bestPlaneIndirect( const SelectionTest& test, Plane3& plane, Vector3& intersection, float& dist ) const {
void bestPlaneIndirect( const SelectionTest& test, Plane3& plane, Vector3& intersection, float& dist, float& dot ) const {
const Winding& winding = m_edge->getFace().getWinding();
FaceVertexId faceVertex = m_edge->m_faceVertex;
Line line( winding[faceVertex.getVertex()].vertex, winding[Winding_next( winding, faceVertex.getVertex() )].vertex );
if( matrix4_clip_line_by_nearplane( test.getVolume().GetViewMatrix(), line ) == 2 ){
const Vector3 intersection_new = line_closest_point( line, g_vector3_identity );
const float dist_new = vector3_length_squared( intersection_new );
if( dist_new < dist ){
const float dot_new = fabs( vector3_dot( vector3_normalised( intersection_new ), vector3_normalised( line.end - line.start ) ) );
if( dist - dist_new > 1e-6f // new dist noticeably smaller
|| ( float_equal_epsilon( dist_new, dist, 1e-6f ) && dot_new < dot ) ){ // or ambiguous case. Resolve it by dot comparison
const Plane3& plane1 = m_faceInstances[faceVertex.getFace()].getFace().plane3();
faceVertex = next_edge( m_edge->m_faces, faceVertex );
const Plane3& plane2 = m_faceInstances[faceVertex.getFace()].getFace().plane3();
auto assign_plane = [&plane, &intersection, intersection_new, &dist, dist_new, &dot, dot_new]( const Plane3& plane_new ){
plane = plane_new;
intersection = intersection_new;
dist = dist_new;
dot = dot_new;
};
if( test.getVolume().fill() ){
const Plane3& plane1 = m_faceInstances[faceVertex.getFace()].getFace().plane3();
if( plane3_distance_to_point( plane1, test.getVolume().getViewer() ) <= 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( plane3_distance_to_point( plane2, test.getVolume().getViewer() ) <= 0 ){
plane = plane2;
intersection = intersection_new;
dist = dist_new;
}
}
if( plane3_distance_to_point( plane1, test.getVolume().getViewer() ) <= 0 )
assign_plane( plane1 );
else if( plane3_distance_to_point( plane2, test.getVolume().getViewer() ) <= 0 )
assign_plane( plane2 );
}
else{
const Plane3& plane1 = m_faceInstances[faceVertex.getFace()].getFace().plane3();
faceVertex = next_edge( m_edge->m_faces, faceVertex );
const Plane3& plane2 = m_faceInstances[faceVertex.getFace()].getFace().plane3();
if( fabs( vector3_dot( plane1.normal(), test.getVolume().getViewDir() ) ) < fabs( vector3_dot( plane2.normal(), test.getVolume().getViewDir() ) ) ){
plane = plane1;
intersection = intersection_new;
dist = dist_new;
}
else{
plane = plane2;
intersection = intersection_new;
dist = dist_new;
}
else if( fabs( vector3_length_squared( line.end - line.start ) ) > 1e-3 ){
if( fabs( vector3_dot( plane1.normal(), test.getVolume().getViewDir() ) ) < fabs( vector3_dot( plane2.normal(), test.getVolume().getViewDir() ) ) )
assign_plane( plane1 );
else
assign_plane( plane2 );
}
}
}
@ -3313,6 +3315,15 @@ void testSelect( Selector& selector, SelectionTest& test ){
Selector_add( selector, *this, best );
}
}
void gatherComponentsHighlight( std::vector<std::vector<Vector3>>& polygons, SelectionIntersection& intersection, SelectionTest& test ) const {
SelectionIntersection best;
m_vertex->testSelect( test, best );
if ( SelectionIntersection_closer( best, intersection ) ) {
intersection = best;
polygons.clear();
polygons.emplace_back( std::initializer_list<Vector3>( { m_vertex->getVertex() } ) );
}
}
void selectVerticesOfFace( const FaceInstance& faceinstance ){
FaceVertexId faceVertex = m_vertex->m_faceVertex;
@ -3320,13 +3331,14 @@ void selectVerticesOfFace( const FaceInstance& faceinstance ){
{
if( &faceinstance == &m_faceInstances[faceVertex.getFace()] ){
setSelected( true );
return;
}
faceVertex = next_vertex( m_vertex->m_faces, faceVertex );
}
while ( faceVertex.getFace() != m_vertex->m_faceVertex.getFace() );
}
void gather( Brush::VertexModeVertices& vertexModeVertices ) const {
vertexModeVertices.emplace_back( m_vertex->getFace().getWinding()[m_vertex->m_faceVertex.getVertex()].vertex, isSelected() );
vertexModeVertices.emplace_back( m_vertex->getVertex(), isSelected() );
FaceVertexId faceVertex = m_vertex->m_faceVertex;
do
{
@ -3336,7 +3348,7 @@ void gather( Brush::VertexModeVertices& vertexModeVertices ) const {
while ( faceVertex.getFace() != m_vertex->m_faceVertex.getFace() );
}
bool vertex_select( const Vector3& vertex ){
if( vector3_length_squared( vertex - m_vertex->getFace().getWinding()[m_vertex->m_faceVertex.getVertex()].vertex ) < ( 0.1 * 0.1 ) ){
if( vector3_length_squared( vertex - m_vertex->getVertex() ) < ( 0.1 * 0.1 ) ){
setSelected( true );
return true;
}
@ -3778,6 +3790,71 @@ void testSelectComponents( Selector& selector, SelectionTest& test, SelectionSys
break;
}
}
void gatherComponentsHighlight( std::vector<std::vector<Vector3>>& polygons, SelectionIntersection& intersection, SelectionTest& test, SelectionSystem::EComponentMode mode ) const {
test.BeginMesh( localToWorld() );
switch ( mode )
{
case SelectionSystem::eVertex:
{
for ( const VertexInstance& i : m_vertexInstances )
{
i.gatherComponentsHighlight( polygons, intersection, test );
}
}
break;
case SelectionSystem::eEdge:
{
for ( const EdgeInstance& i : m_edgeInstances )
{
i.gatherComponentsHighlight( polygons, intersection, test );
}
}
break;
case SelectionSystem::eFace:
{
if ( test.getVolume().fill() ) {
const Plane3* plane = nullptr;
bool newint = false;
for ( const FaceInstance& i : m_faceInstances )
{
SelectionIntersection best;
i.testSelect( test, best );
if( best.valid() && intersection.equalEpsilon( best, 0.25f, 2e-6f ) ){
plane = &i.getFace().plane3();
}
else if ( SelectionIntersection_closer( best, intersection ) ) {
intersection = best;
newint = true;
plane = &i.getFace().plane3();
}
}
if( plane ){
if( newint || ( !polygons.empty() && polygons.back().size() >= 3 && !plane3_equal( *plane, plane3_for_points( polygons.back().data() ) ) ) ){
polygons.clear();
}
gatherPolygonsByPlane( *plane, polygons, false );
}
}
else
{
for ( const FaceInstance& i : m_faceInstances )
{
SelectionIntersection best;
i.getFace().testSelect_centroid( test, best );
if ( SelectionIntersection_closer( best, intersection ) ) {
intersection = best;
polygons.clear();
polygons.emplace_back( std::initializer_list<Vector3>( { i.getFace().centroid() } ) );
}
}
}
}
break;
default:
break;
}
}
void invertComponentSelection( SelectionSystem::EComponentMode mode ){
switch ( mode )
@ -3867,9 +3944,10 @@ void bestPlaneDirect( SelectionTest& test, Plane3& plane, SelectionIntersection&
}
void bestPlaneIndirect( SelectionTest& test, Plane3& plane, Vector3& intersection, float& dist ){
test.BeginMesh( localToWorld() );
float dot = 1;
for ( EdgeInstances::iterator i = m_edgeInstances.begin(); i != m_edgeInstances.end(); ++i )
{
( *i ).bestPlaneIndirect( test, plane, intersection, dist );
( *i ).bestPlaneIndirect( test, plane, intersection, dist, dot );
}
}
void selectByPlane( const Plane3& plane ){
@ -3877,6 +3955,20 @@ void selectByPlane( const Plane3& plane ){
if( plane3_equal( plane, fi.getFace().plane3() ) || plane3_equal( plane, plane3_flipped( fi.getFace().plane3() ) ) )
fi.setSelected( SelectionSystem::eFace, true );
}
void gatherPolygonsByPlane( const Plane3& plane, std::vector<std::vector<Vector3>>& polygons ) const {
gatherPolygonsByPlane( plane, polygons, true );
}
void gatherPolygonsByPlane( const Plane3& plane, std::vector<std::vector<Vector3>>& polygons, const bool reversed_plane_also ) const {
for ( const FaceInstance& fi : m_faceInstances )
if( plane3_equal( plane, fi.getFace().plane3() ) || ( reversed_plane_also && plane3_equal( plane, plane3_flipped( fi.getFace().plane3() ) ) ) )
if( fi.getFace().contributes() ){
const Winding& winding = fi.getFace().getWinding();
polygons.emplace_back( winding.numpoints );
for( std::size_t i = 0; i < winding.numpoints; ++i ){
polygons.back()[i] = winding[i].vertex;
}
}
}
void selectVerticesOnPlane( const Plane3& plane ){
for ( FaceInstance& fi : m_faceInstances )

View File

@ -906,6 +906,7 @@ void render( RenderStateFlags state ) const {
glPolygonOffset( 1, -1 );
glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( Colour4b ), colorarr1.data() );
glDrawArrays( GL_QUADS, start0? 2 : 0, GLsizei( count - ( start0? 2 : 4 ) ) );
glPolygonOffset( -1, 1 ); // restore default
}
}

View File

@ -1543,6 +1543,47 @@ void setSelectedComponents( bool select, SelectionSystem::EComponentMode mode ){
m_dragPlanes.setSelected( select );
}
}
void testSelectComponents( Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode ){
test.BeginMesh( localToWorld() );
switch ( mode )
{
case SelectionSystem::eVertex:
{
for ( PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
{
( *i ).testSelect( selector, test );
}
}
break;
default:
break;
}
}
void gatherComponentsHighlight( std::vector<std::vector<Vector3>>& polygons, SelectionIntersection& intersection, SelectionTest& test, SelectionSystem::EComponentMode mode ) const {
test.BeginMesh( localToWorld() );
switch ( mode )
{
case SelectionSystem::eVertex:
{
for ( const PatchControlInstance& pci : m_ctrl_instances )
{
SelectionIntersection best;
test.TestPoint( pci.m_ctrl->m_vertex, best );
if ( SelectionIntersection_closer( best, intersection ) ) {
intersection = best;
polygons.clear();
polygons.emplace_back( std::initializer_list<Vector3>( { pci.m_ctrl->m_vertex } ) );
}
}
}
break;
default:
break;
}
}
const AABB& getSelectedComponentsBounds() const {
m_aabb_component = AABB();
@ -1564,26 +1605,8 @@ void gatherSelectedComponents( const Vector3Callback& callback ) const {
}
}
void testSelectComponents( Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode ){
test.BeginMesh( localToWorld() );
switch ( mode )
{
case SelectionSystem::eVertex:
{
for ( PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
{
( *i ).testSelect( selector, test );
}
}
break;
default:
break;
}
}
bool selectedVertices(){
for ( PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
bool selectedVertices() const {
for ( PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
{
if ( ( *i ).m_selectable.isSelected() ) {
return true;
@ -1637,6 +1660,9 @@ void bestPlaneIndirect( SelectionTest& test, Plane3& plane, Vector3& intersectio
void selectByPlane( const Plane3& plane ){
m_dragPlanes.selectByPlane( m_patch.localAABB(), plane );
}
void gatherPolygonsByPlane( const Plane3& plane, std::vector<std::vector<Vector3>>& polygons ) const {
m_dragPlanes.gatherPolygonsByPlane( m_patch.localAABB(), plane, polygons );
}
void snapComponents( float snap ){

View File

@ -2325,6 +2325,20 @@ void OpenGLShader::construct( const char* name ){
state.m_sort = OpenGLState::eSortTranslucent;
}
#endif // 0
else if ( string_equal( name + 1, "PLANE_WIRE_OVERLAY" ) ) {
state.m_colour = Vector4( 1, 1, 0, 1 );
state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_OFFSETLINE;
state.m_sort = OpenGLState::eSortGUI1;
state.m_depthfunc = GL_LEQUAL;
state.m_linewidth = 2;
OpenGLState& hiddenLine = appendDefaultPass();
hiddenLine.m_colour = state.m_colour;
hiddenLine.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST | RENDER_LINESTIPPLE;
hiddenLine.m_sort = OpenGLState::eSortGUI0;
hiddenLine.m_depthfunc = GL_GREATER;
hiddenLine.m_linestipple_factor = 2;
}
else if ( string_equal( name + 1, "WIRE_OVERLAY" ) ) {
#if 0
state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_DEPTHTEST;

View File

@ -407,6 +407,9 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const
Vector3 current = g_vector3_axes[m_axisZ] * vector3_dot( m_planeSelected.normal(), ( point_on_plane( m_planeZ, m_view->GetViewMatrix(), x, y ) - m_startZ ) )
* ( m_planeSelected.normal()[m_axisZ] >= 0? 1 : -1 );
if( !std::isfinite( current[0] ) || !std::isfinite( current[1] ) || !std::isfinite( current[2] ) ) // catch INF case, is likely with top of the box in 2D
return;
if( snapbbox )
aabb_snap_translation( current, m_bounds );
else
@ -2951,10 +2954,7 @@ inline const Functor& Scene_forEachVisibleSelectedPlaneselectable( const Functor
return functor;
}
bool Scene_forEachPlaneSelectable_selectPlanes2( SelectionTest& test, TranslateAxis2& translateAxis ){
Plane3 plane( 0, 0, 0, 0 );
Vector3 intersectionPoint( FLT_MAX, FLT_MAX, FLT_MAX );
void Scene_forEachPlaneSelectable_bestPlane( SelectionTest& test, Plane3& plane, Vector3& intersectionPoint ){
SelectionIntersection intersection;
auto bestPlaneDirect = [&test, &plane, &intersection]( PlaneSelectable& planeSelectable ){
planeSelectable.bestPlaneDirect( test, plane, intersection );
@ -2967,6 +2967,12 @@ bool Scene_forEachPlaneSelectable_selectPlanes2( SelectionTest& test, TranslateA
};
Scene_forEachVisibleSelectedPlaneselectable( bestPlaneIndirect );
}
}
bool Scene_forEachPlaneSelectable_selectPlanes2( SelectionTest& test, TranslateAxis2& translateAxis ){
Plane3 plane( 0, 0, 0, 0 );
Vector3 intersectionPoint( FLT_MAX, FLT_MAX, FLT_MAX );
Scene_forEachPlaneSelectable_bestPlane( test, plane, intersectionPoint );
if( plane3_valid( plane ) ){
if( intersectionPoint == Vector3( FLT_MAX, FLT_MAX, FLT_MAX ) ){ // direct
@ -2988,23 +2994,24 @@ bool Scene_forEachPlaneSelectable_selectPlanes2( SelectionTest& test, TranslateA
}
bool Scene_forEachBrush_setupExtrude( SelectionTest& test, DragExtrudeFaces& extrudeFaces ){
Plane3 plane( 0, 0, 0, 0 );
Vector3 intersectionPoint( FLT_MAX, FLT_MAX, FLT_MAX );
if( g_SelectedFaceInstances.empty() ){
SelectionIntersection intersection;
auto bestPlaneDirect = [&test, &plane, &intersection]( BrushInstance& brushInstance ){
brushInstance.bestPlaneDirect( test, plane, intersection );
void Scene_forEachSelectedBrush_bestPlane( SelectionTest& test, Plane3& plane, Vector3& intersectionPoint ){
SelectionIntersection intersection;
auto bestPlaneDirect = [&test, &plane, &intersection]( BrushInstance& brushInstance ){
brushInstance.bestPlaneDirect( test, plane, intersection );
};
Scene_forEachVisibleSelectedBrush( bestPlaneDirect );
if( !plane3_valid( plane ) ){
float dist( FLT_MAX );
auto bestPlaneIndirect = [&test, &plane, &intersectionPoint, &dist]( BrushInstance& brushInstance ){
brushInstance.bestPlaneIndirect( test, plane, intersectionPoint, dist );
};
Scene_forEachVisibleSelectedBrush( bestPlaneDirect );
if( !plane3_valid( plane ) ){
float dist( FLT_MAX );
auto bestPlaneIndirect = [&test, &plane, &intersectionPoint, &dist]( BrushInstance& brushInstance ){
brushInstance.bestPlaneIndirect( test, plane, intersectionPoint, dist );
};
Scene_forEachVisibleSelectedBrush( bestPlaneIndirect );
}
Scene_forEachVisibleSelectedBrush( bestPlaneIndirect );
}
}
void Scene_forEachBrush_bestPlane( SelectionTest& test, Plane3& plane, Vector3& intersectionPoint ){
if( g_SelectedFaceInstances.empty() ){
Scene_forEachSelectedBrush_bestPlane( test, plane, intersectionPoint );
}
else{
SelectionIntersection intersection;
@ -3023,6 +3030,12 @@ bool Scene_forEachBrush_setupExtrude( SelectionTest& test, DragExtrudeFaces& ext
Scene_forEachVisibleBrush( GlobalSceneGraph(), bestPlaneIndirect );
}
}
}
bool Scene_forEachBrush_setupExtrude( SelectionTest& test, DragExtrudeFaces& extrudeFaces ){
Plane3 plane( 0, 0, 0, 0 );
Vector3 intersectionPoint( FLT_MAX, FLT_MAX, FLT_MAX );
Scene_forEachBrush_bestPlane( test, plane, intersectionPoint );
if( plane3_valid( plane ) ){
if( intersectionPoint == Vector3( FLT_MAX, FLT_MAX, FLT_MAX ) ){ // direct
@ -4201,20 +4214,8 @@ bool selection_selectVerticesOrFaceVertices( SelectionTest& test ){
}
/* otherwise select vertices of brush faces, which lay on best plane */
Plane3 plane( 0, 0, 0, 0 );
SelectionIntersection intersection;
auto bestPlaneDirect = [&test, &plane, &intersection]( BrushInstance& brushInstance ){
brushInstance.bestPlaneDirect( test, plane, intersection );
};
Scene_forEachVisibleSelectedBrush( bestPlaneDirect );
if( !plane3_valid( plane ) ){
Vector3 intersectionPoint;
float dist( FLT_MAX );
auto bestPlaneIndirect = [&test, &plane, &intersectionPoint, &dist]( BrushInstance& brushInstance ){
brushInstance.bestPlaneIndirect( test, plane, intersectionPoint, dist );
};
Scene_forEachVisibleSelectedBrush( bestPlaneIndirect );
}
Vector3 intersectionPoint( FLT_MAX, FLT_MAX, FLT_MAX );
Scene_forEachSelectedBrush_bestPlane( test, plane, intersectionPoint );
if( plane3_valid( plane ) ){
auto selectVerticesOnPlane = [&plane]( BrushInstance& brushInstance ){
@ -4227,6 +4228,29 @@ bool selection_selectVerticesOrFaceVertices( SelectionTest& test ){
}
template<typename Functor>
class ComponentSelectionTestableVisibleSelectedVisitor : public SelectionSystem::Visitor
{
const Functor& m_functor;
public:
ComponentSelectionTestableVisibleSelectedVisitor( const Functor& functor ) : m_functor( functor ){
}
void visit( scene::Instance& instance ) const {
ComponentSelectionTestable* componentSelectionTestable = Instance_getComponentSelectionTestable( instance );
if ( componentSelectionTestable != 0
&& instance.path().top().get().visible() ) {
m_functor( *componentSelectionTestable );
}
}
};
template<typename Functor>
inline const Functor& Scene_forEachVisibleSelectedComponentSelectionTestable( const Functor& functor ){
GlobalSelectionSystem().foreachSelected( ComponentSelectionTestableVisibleSelectedVisitor<Functor>( functor ) );
return functor;
}
static ModifierFlags g_modifiers = c_modifierNone; //AltDragManipulatorResize, extrude, uvtool skew, select primitives in component modes
static bool g_bTmpComponentMode = false;
@ -4247,8 +4271,11 @@ bool m_extrudeFaces;
public:
DragManipulator( Translatable& translatable ) : m_freeResize( m_resize ), m_axisResize( m_resize ), m_freeDragXY_Z( translatable ){
static Shader* m_state_wire;
DragManipulator( Translatable& translatable ) : m_freeResize( m_resize ), m_axisResize( m_resize ), m_freeDragXY_Z( translatable ), m_renderCircle( 2 << 3 ){
setSelected( false );
draw_circle( m_renderCircle.m_vertices.size() >> 3, 5, m_renderCircle.m_vertices.data(), RemapXYZ() );
}
Manipulatable* GetManipulatable(){
@ -4268,16 +4295,18 @@ void testSelect( const View& view, const Matrix4& pivot2world ){
SelectionPool selector;
SelectionVolume test( view );
if( g_modifiers == ( c_modifierAlt | c_modifierControl ) && ( GlobalSelectionSystem().countSelected() != 0 || !g_SelectedFaceInstances.empty() ) ){ // extrude
if( g_modifiers == ( c_modifierAlt | c_modifierControl )
&& GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive
&& ( GlobalSelectionSystem().countSelected() != 0 || !g_SelectedFaceInstances.empty() ) ){ // extrude
m_extrudeFaces = Scene_forEachBrush_setupExtrude( test, m_dragExtrudeFaces );
}
else if( GlobalSelectionSystem().countSelected() != 0 ){
if ( GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ){
if( g_modifiers == c_modifierAlt ){
if( view.fill() ){
if( view.fill() ){ // alt resize
m_selected2 = Scene_forEachPlaneSelectable_selectPlanes2( test, m_axisResize );
}
else{
else{ // alt vertices drag
m_selected = selection_selectVerticesOrFaceVertices( test );
}
}
@ -4295,7 +4324,7 @@ void testSelect( const View& view, const Matrix4& pivot2world ){
}
}
}
else{
else{ // components
BestSelector bestSelector;
Scene_TestSelect_Component_Selected( bestSelector, test, view, GlobalSelectionSystem().ComponentMode() ); /* drag components */
for ( Selectable* s : bestSelector.best() ){
@ -4353,7 +4382,126 @@ void setSelected( bool select ){
bool isSelected() const {
return m_dragSelected || m_selected || m_selected2 || m_newBrush || m_extrudeFaces;
}
void render( Renderer& renderer, const VolumeTest& volume, const Matrix4& pivot2world ){
if( !m_polygons.empty() ){
renderer.SetState( m_state_wire, Renderer::eWireframeOnly );
renderer.SetState( m_state_wire, Renderer::eFullMaterials );
if( m_polygons.back().size() == 1 ){
Pivot2World_viewplaneSpace( m_renderCircle.m_viewplaneSpace, matrix4_translation_for_vec3( m_polygons.back()[0] ), volume.GetModelview(), volume.GetProjection(), volume.GetViewport() );
renderer.addRenderable( m_renderCircle, m_renderCircle.m_viewplaneSpace );
}
else{
renderer.addRenderable( m_renderPoly, g_matrix4_identity );
}
}
}
void highlight( const View& view ){
SelectionVolume test( view );
std::vector<std::vector<Vector3>> polygons;
/* conditions structure respects one in testSelect() */
if( g_modifiers == ( c_modifierAlt | c_modifierControl )
&& GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive
&& ( GlobalSelectionSystem().countSelected() != 0 || !g_SelectedFaceInstances.empty() ) ){ // extrude
Plane3 plane( 0, 0, 0, 0 );
Vector3 intersectionPoint( FLT_MAX, FLT_MAX, FLT_MAX );
Scene_forEachBrush_bestPlane( test, plane, intersectionPoint );
if( plane3_valid( plane ) ){
auto gatherPolygonsByPlane = [plane, &polygons]( BrushInstance& brushInstance ){
if( brushInstance.isSelected() || brushInstance.isSelectedComponents() )
brushInstance.gatherPolygonsByPlane( plane, polygons, false );
};
Scene_forEachVisibleBrush( GlobalSceneGraph(), gatherPolygonsByPlane );
}
}
else if( GlobalSelectionSystem().countSelected() != 0 ){
if ( GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ){
if( g_modifiers == c_modifierAlt ){
if( view.fill() ){ // alt resize
Plane3 plane( 0, 0, 0, 0 );
Vector3 intersectionPoint( FLT_MAX, FLT_MAX, FLT_MAX );
Scene_forEachPlaneSelectable_bestPlane( test, plane, intersectionPoint );
if( plane3_valid( plane ) ){
auto gatherPolygonsByPlane = [plane, &polygons]( PlaneSelectable& planeSelectable ){
planeSelectable.gatherPolygonsByPlane( plane, polygons );
};
Scene_forEachVisibleSelectedPlaneselectable( gatherPolygonsByPlane );
}
}
else{ // alt vertices drag
SelectionIntersection intersection;
const SelectionSystem::EComponentMode mode = SelectionSystem::eVertex;
auto gatherComponentsHighlight = [&polygons, &intersection, &test, mode]( const ComponentSelectionTestable& componentSelectionTestable ){
componentSelectionTestable.gatherComponentsHighlight( polygons, intersection, test, mode );
};
Scene_forEachVisibleSelectedComponentSelectionTestable( gatherComponentsHighlight );
if( polygons.empty() ){
Plane3 plane( 0, 0, 0, 0 );
Vector3 intersectionPoint( FLT_MAX, FLT_MAX, FLT_MAX );
Scene_forEachSelectedBrush_bestPlane( test, plane, intersectionPoint );
if( plane3_valid( plane ) ){
auto gatherPolygonsByPlane = [plane, &polygons]( BrushInstance& brushInstance ){
brushInstance.gatherPolygonsByPlane( plane, polygons );
};
Scene_forEachVisibleSelectedBrush( gatherPolygonsByPlane );
}
}
}
}
}
else{ // components
SelectionIntersection intersection;
const SelectionSystem::EComponentMode mode = GlobalSelectionSystem().ComponentMode();
auto gatherComponentsHighlight = [&polygons, &intersection, &test, mode]( const ComponentSelectionTestable& componentSelectionTestable ){
componentSelectionTestable.gatherComponentsHighlight( polygons, intersection, test, mode );
};
Scene_forEachVisibleSelectedComponentSelectionTestable( gatherComponentsHighlight );
}
}
if( m_polygons != polygons ){
m_polygons.swap( polygons );
SceneChangeNotify();
}
}
private:
std::vector<std::vector<Vector3>> m_polygons;
struct RenderablePoly: public OpenGLRenderable
{
const std::vector<std::vector<Vector3>>& m_polygons;
RenderablePoly( const std::vector<std::vector<Vector3>>& polygons ) : m_polygons( polygons ){
}
void render( RenderStateFlags state ) const {
glPolygonOffset( -2, -2 );
for( const auto& poly : m_polygons ){
glVertexPointer( 3, GL_FLOAT, sizeof( m_polygons[0][0] ), poly[0].data() );
glDrawArrays( GL_POLYGON, 0, GLsizei( poly.size() ) );
}
glPolygonOffset( -1, 1 ); // restore default
}
};
RenderablePoly m_renderPoly{ m_polygons };
struct RenderableCircle : public OpenGLRenderable
{
Array<PointVertex> m_vertices;
Matrix4 m_viewplaneSpace;
RenderableCircle( std::size_t size ) : m_vertices( size ){
}
void render( RenderStateFlags state ) const {
glVertexPointer( 3, GL_FLOAT, sizeof( PointVertex ), &m_vertices.data()->vertex );
glDrawArrays( GL_LINE_LOOP, 0, GLsizei( m_vertices.size() ) );
}
};
RenderableCircle m_renderCircle;
};
Shader* DragManipulator::m_state_wire;
@ -6874,7 +7022,11 @@ bool SelectManipulator( const View& view, const float device_point[2], const flo
void HighlightManipulator( const View& view, const float device_point[2], const float device_epsilon[2] ){
Manipulatable::assign_static( view, device_point, device_epsilon ); //this b4 m_manipulator calls!
if ( ( !nothingSelected() && transformOrigin_isTranslatable() ) || ManipulatorMode() == eClip || ManipulatorMode() == eBuild || ManipulatorMode() == eUV ) {
if ( ( !nothingSelected() && transformOrigin_isTranslatable() )
|| ManipulatorMode() == eClip
|| ManipulatorMode() == eBuild
|| ManipulatorMode() == eUV
|| ManipulatorMode() == eDrag ) {
#if defined ( DEBUG_SELECTION )
g_render_clipped.destroy();
#endif
@ -6900,6 +7052,9 @@ void HighlightManipulator( const View& view, const float device_point[2], const
else if( ManipulatorMode() == eUV ){
m_manipulator->testSelect( scissored, GetPivot2World() );
}
else if( ManipulatorMode() == eDrag ){
m_drag_manipulator.highlight( scissored );
}
}
}
@ -7358,12 +7513,14 @@ static void constructStatic(){
UVManipulator::m_state_point = GlobalShaderCache().capture( "$BIGPOINT" );
RenderablePivot::StaticShader::instance() = GlobalShaderCache().capture( "$PIVOT" );
UVManipulator::m_state_line = GlobalShaderCache().capture( "$BLENDLINE" );
DragManipulator::m_state_wire = GlobalShaderCache().capture( "$PLANE_WIRE_OVERLAY" );
}
static void destroyStatic(){
#if defined( DEBUG_SELECTION )
GlobalShaderCache().release( "$DEBUG_CLIPPED" );
#endif
GlobalShaderCache().release( "$PLANE_WIRE_OVERLAY" );
GlobalShaderCache().release( "$BLENDLINE" );
GlobalShaderCache().release( "$PIVOT" );
GlobalShaderCache().release( "$BIGPOINT" );
@ -7805,7 +7962,11 @@ AABB RadiantSelectionSystem::getSelectionAABB() const {
void RadiantSelectionSystem::renderSolid( Renderer& renderer, const VolumeTest& volume ) const {
//if(view->TestPoint(m_object_pivot))
if ( !nothingSelected() || ManipulatorMode() == eClip || ManipulatorMode() == eBuild || ManipulatorMode() == eUV ) {
if ( !nothingSelected()
|| ManipulatorMode() == eClip
|| ManipulatorMode() == eBuild
|| ManipulatorMode() == eUV
|| ManipulatorMode() == eDrag ) {
renderer.Highlight( Renderer::ePrimitive, false );
renderer.Highlight( Renderer::eFace, false );