Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 52 additions & 8 deletions source/MRViewer/MRMouseController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "MRPch/MRWasm.h"
#include "MRMesh/MR2to3.h"
#include "MRViewportCornerController.h"
#include "MRColorTheme.h"


#ifdef __EMSCRIPTEN__
Expand Down Expand Up @@ -404,21 +405,41 @@ void MouseController::resetAllIfNeeded_()

bool MouseController::tryHoverViewController_()
{
auto hoverSideArrows = [] ( RegionId region )
{
int reqId = region.get() - int( SideRegions::CCWArrow );
int childId = 0;
for ( auto child : getViewerInstance().basisViewController->children() )
{
bool reqChild = childId++ == reqId;
const Color& colorBg = ColorTheme::getRibbonColor( reqChild ? ColorTheme::RibbonColorsType::GradBtnStart : ColorTheme::RibbonColorsType::Background );
const Color& colorBorder = ColorTheme::getRibbonColor( reqChild ? ColorTheme::RibbonColorsType::RibbonButtonActive : ColorTheme::RibbonColorsType::GradBtnDisableStart );
if ( auto objMesh = child->asType<ObjectMesh>() )
{
objMesh->setFrontColor( colorBg, true );
objMesh->setFrontColor( colorBg, false );
objMesh->setBordersColor( colorBorder );
}
}
};

auto setHovered = [&] ( RegionId region )
{
if ( region == viewControllerHoveredRegion_ )
return;
viewControllerHoveredRegion_ = region;
if ( viewControllerHoveredRegion_ )
if ( viewControllerHoveredRegion_ && viewControllerHoveredRegion_ < int( SideRegions::CCWArrow ) )
{
getViewerInstance().setSceneDirty();
getViewerInstance().basisViewController->setTexturePerFace( getCornerControllerHoveredTextureMap( viewControllerHoveredRegion_ ) );

}
else
{
getViewerInstance().setSceneDirty();
getViewerInstance().basisViewController->setTexturePerFace( getCornerControllerTexureMap() );
}
hoverSideArrows( viewControllerHoveredRegion_ );
};

auto hoveredVpId = getViewerInstance().getHoveredViewportId();
Expand All @@ -435,7 +456,7 @@ bool MouseController::tryHoverViewController_()
}
auto screenPos = to2dim( getViewerInstance().viewportToScreen( to3dim( vp.getAxesPosition() ), vp.id ) );

if ( distanceSq( Vector2f( currentMousePos_ ), screenPos ) > sqr( vp.getAxesSize() ) )
if ( distanceSq( Vector2f( currentMousePos_ ), screenPos ) > sqr( vp.getAxesSize() * 2.0f ) )
{
setHovered( {} );
return false;
Expand All @@ -449,14 +470,26 @@ bool MouseController::tryHoverViewController_()
}

auto staticRenderParams = vp.getBaseRenderParams( vp.getAxesProjectionMatrix() );
auto [obj, pick] = vp.pickRenderObject( { { static_cast< VisualObject* >( getViewerInstance().basisViewController.get() ) } }, { .baseRenderParams = &staticRenderParams } );
if ( obj != getViewerInstance().basisViewController )
auto [obj, pick] = vp.pickRenderObject( { {
static_cast< VisualObject* >( getViewerInstance().basisViewController.get() ),
static_cast< VisualObject* >( getViewerInstance().basisViewController->children().front().get() ),
static_cast< VisualObject* >( getViewerInstance().basisViewController->children().back().get() )
} }, { .baseRenderParams = &staticRenderParams } );
if ( !obj )
{
setHovered( {} );
return false;
}

setHovered( getCornerControllerRegionByFace( pick.face ) );
RegionId hoveredId;
if ( obj == getViewerInstance().basisViewController )
hoveredId = getCornerControllerRegionByFace( pick.face );
else if ( obj == getViewerInstance().basisViewController->children().front() )
hoveredId = RegionId( int( SideRegions::CCWArrow ) );
else
hoveredId = RegionId( int( SideRegions::CWArrow ) );

setHovered( hoveredId );

return true;
}
Expand All @@ -469,11 +502,22 @@ bool MouseController::tryPressViewController_()
// validate pick just in case
const auto& vp = getViewerInstance().viewport();
auto staticRenderParams = vp.getBaseRenderParams( vp.getAxesProjectionMatrix() );
auto [obj, pick] = vp.pickRenderObject( { { static_cast< VisualObject* >( getViewerInstance().basisViewController.get() ) } }, { .baseRenderParams = &staticRenderParams } );
if ( obj != getViewerInstance().basisViewController )
auto [obj, pick] = vp.pickRenderObject( { {
static_cast< VisualObject* >( getViewerInstance().basisViewController.get() ),
static_cast< VisualObject* >( getViewerInstance().basisViewController->children().front().get() ),
static_cast< VisualObject* >( getViewerInstance().basisViewController->children().back().get() )
} }, { .baseRenderParams = &staticRenderParams } );
if ( !obj )
return false;

auto region = getCornerControllerRegionByFace( pick.face );
RegionId region;
if ( obj == getViewerInstance().basisViewController )
region = getCornerControllerRegionByFace( pick.face );
else if ( obj == getViewerInstance().basisViewController->children().front() )
region = RegionId( int( SideRegions::CCWArrow ) );
else
region = RegionId( int( SideRegions::CWArrow ) );

updateCurrentViewByControllerRegion( region );

return true;
Expand Down
36 changes: 36 additions & 0 deletions source/MRViewer/MRViewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ EMSCRIPTEN_KEEPALIVE void emsForceSettingsSave()

}
#endif
#include "MRMesh/MRCube.h"

static void glfw_mouse_press( GLFWwindow* /*window*/, int button, int action, int modifier )
{
Expand Down Expand Up @@ -334,6 +335,10 @@ void addLabel( ObjectMesh& obj, const std::string& str, const Vector3f& pos, boo
label->setLabel( { str, pos } );
label->setPivotPoint( Vector2f( 0.5f, 0.5f ) );
label->setVisualizeProperty( depthTest, VisualizeMaskType::DepthTest, ViewportMask::all() );
float fontSize = 20.0f;
if ( auto menu = getViewerInstance().getMenuPlugin() )
fontSize *= menu->menu_scaling();
label->setFontHeight( fontSize );
obj.addChild( label );
}

Expand Down Expand Up @@ -2094,6 +2099,15 @@ void Viewer::initBasisAxesObject_()

void Viewer::initBasisViewControllerObject_()
{
std::shared_ptr<Mesh> arrowMeshCCW = std::make_shared<Mesh>( makeCornerControllerRotationArrowMesh( 0.4f, Vector2f( 1.1f, 0.1f ), true ) );
std::shared_ptr<Mesh> arrowMeshCW = std::make_shared<Mesh>( makeCornerControllerRotationArrowMesh( 0.4f, Vector2f( 1.1f, 0.0f ), false ) );
auto arrowCCW = std::make_shared<ObjectMesh>();
auto arrowCW = std::make_shared<ObjectMesh>();
arrowCCW->setMesh( arrowMeshCCW );
arrowCCW->setName( "CCW" );
arrowCW->setMesh( arrowMeshCW );
arrowCW->setName( "CW" );

std::shared_ptr<Mesh> basisControllerMesh = std::make_shared<Mesh>( makeCornerControllerMesh( 0.8f ) );
basisViewController = std::make_shared<ObjectMesh>();
basisViewController->setMesh( basisControllerMesh );
Expand All @@ -2106,10 +2120,23 @@ void Viewer::initBasisViewControllerObject_()
basisViewController->setVisualizeProperty( true, MeshVisualizePropertyType::Texture, ViewportMask::all() );
}
basisViewController->setFlatShading( true );
arrowCCW->setFlatShading( true );
arrowCW->setFlatShading( true );
basisViewController->setVisualizeProperty( true, MeshVisualizePropertyType::BordersHighlight, ViewportMask::all() );
arrowCCW->setVisualizeProperty( true, MeshVisualizePropertyType::BordersHighlight, ViewportMask::all() );
arrowCW->setVisualizeProperty( true, MeshVisualizePropertyType::BordersHighlight, ViewportMask::all() );
basisViewController->setVisualizeProperty( true, MeshVisualizePropertyType::PolygonOffsetFromCamera, ViewportMask::all() );
arrowCCW->setVisualizeProperty( true, MeshVisualizePropertyType::PolygonOffsetFromCamera, ViewportMask::all() );
arrowCW->setVisualizeProperty( true, MeshVisualizePropertyType::PolygonOffsetFromCamera, ViewportMask::all() );
basisViewController->setVisualizeProperty( false, MeshVisualizePropertyType::EnableShading, ViewportMask::all() );
arrowCCW->setVisualizeProperty( false, MeshVisualizePropertyType::EnableShading, ViewportMask::all() );
arrowCW->setVisualizeProperty( false, MeshVisualizePropertyType::EnableShading, ViewportMask::all() );
basisViewController->setEdgeWidth( 0.2f );
arrowCCW->setEdgeWidth( 0.3f );
arrowCW->setEdgeWidth( 0.3f );

basisViewController->addChild( arrowCCW );
basisViewController->addChild( arrowCW );

colorUpdateConnections_.push_back( ColorTheme::instance().onChanged( [this] ()
{
Expand All @@ -2121,6 +2148,15 @@ void Viewer::initBasisViewControllerObject_()
basisViewController->setFrontColor( colorBg, true );
basisViewController->setFrontColor( colorBg, false );
basisViewController->setBordersColor( colorBorder );
for ( auto child : basisViewController->children() )
{
if ( auto visObj = child->asType<ObjectMesh>() )
{
visObj->setFrontColor( colorBg, true );
visObj->setFrontColor( colorBg, false );
visObj->setBordersColor( colorBorder );
}
}
} ) );
}

Expand Down
15 changes: 15 additions & 0 deletions source/MRViewer/MRViewport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,8 @@ void Viewport::drawAxesAndViewController() const
auto transBase = fullInversedM( viewportSpaceToClipSpace( pos ) );
auto transSide = fullInversedM( viewportSpaceToClipSpace( pos + to3dim( Vector2f::diagonal( basisAxesSize_ ) ) ) );

auto invRot = AffineXf3f::linear( Matrix3f( params_.cameraTrackballAngle ) ).inverse();

float scale = (transSide - transBase).length();
const auto basisAxesXf = AffineXf3f( Matrix3f::scale( scale ), transBase );
if ( basisVisible )
Expand All @@ -658,7 +660,20 @@ void Viewport::drawAxesAndViewController() const
{
getViewerInstance().basisViewController->setXf( basisAxesXf, id );
draw( *getViewerInstance().basisViewController, basisAxesXf, axesProjMat_, DepthFunction::Always );
for ( const auto& child : getViewerInstance().basisViewController->children() )
{
if ( auto visualChild = child->asType<VisualObject>() )
{
visualChild->setXf( invRot, id );
draw( *visualChild, basisAxesXf * invRot, axesProjMat_, DepthFunction::Always );
}
}
draw( *getViewerInstance().basisViewController, basisAxesXf, axesProjMat_ );
for ( const auto& child : getViewerInstance().basisViewController->children() )
{
if ( auto visualChild = child->asType<VisualObject>() )
draw( *visualChild, basisAxesXf * invRot, axesProjMat_ );
}
}
if ( basisVisible )
{
Expand Down
51 changes: 51 additions & 0 deletions source/MRViewer/MRViewportCornerController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "MRMesh/MRMeshTexture.h"
#include "MRMesh/MRVector.h"
#include "MRMesh/MRImageLoad.h"
#include "MRMesh/MR2DContoursTriangulation.h"

namespace MR
{
Expand Down Expand Up @@ -152,6 +153,49 @@ Mesh makeCornerControllerMesh( float size, float cornerRatio /*= 0.15f */ )
return outMesh;
}

Mesh makeCornerControllerRotationArrowMesh( float size, const Vector2f& shift, bool ccw )
{
Contours2d conts;
auto& cont = conts.emplace_back();
const int cAngleSteps = 10;
cont.resize( 2 * cAngleSteps + 4 );
double r1 = 1.2 * size;
double r2 = 1.4 * size;
double r3 = 0.9 * size;
Vector2d center = Vector2d( shift ) - Vector2d( r1, 0.0 );

double currentAngle = 0.0f;

double angleStep = PI * 0.25 / float( cAngleSteps - 1 );
for ( int i = 0; i < cAngleSteps; ++i )
{
currentAngle = i * angleStep;
cont[i] = center + Vector2d( r1 * std::cos( currentAngle ), r1 * std::sin( currentAngle ) );
}
cont[cAngleSteps] = center + Vector2d( r2 * std::cos( currentAngle ), r2 * std::sin( currentAngle ) );
auto arrowR = ( r1 + r3 + 0.15 * size ) * 0.5;
auto arrowAng = PI / 2.5;
cont[cAngleSteps + 1] = center + Vector2d( arrowR * std::cos( arrowAng ), arrowR * std::sin( arrowAng ) );
cont[cAngleSteps + 2] = center + Vector2d( ( r3 - r2 + r1 ) * std::cos( currentAngle ), ( r3 - r2 + r1 ) * std::sin( currentAngle ) );
for ( int i = 0; i < cAngleSteps; ++i )
{
currentAngle = ( cAngleSteps - i - 1 ) * angleStep;
cont[cAngleSteps + 3 + i] = center + Vector2d( r3 * std::cos( currentAngle ), r3 * std::sin( currentAngle ) );
}
cont.back() = cont.front();
Mesh mesh = PlanarTriangulation::triangulateContours( conts );
for ( auto& p : mesh.points )
p.z = -2 * size;

if ( ccw )
return mesh;

for ( auto& p : mesh.points )
p.y = 2 * shift.y - p.y;
mesh.topology.flipOrientation();
return mesh;
}

VertUVCoords makeCornerControllerUVCoords( float cornerRatio /*= 0.2f */ )
{
VertUVCoords uvs( 4 * 6 + 2 * 12 * 2 + 8 * 3 ); // 4x6 - verts on each side, 2x12 - verts on 2-rank corners (x2 to have disconnected edges), 8 - verts on 3-rank corners (x3 to have disconnected corners);
Expand Down Expand Up @@ -476,6 +520,13 @@ void updateCurrentViewByControllerRegion( RegionId rId )
vp.cameraLookAlong( { -1,-1,-1 }, { -1,-1,2 } );
break;

// side axes rotation
case int( SideRegions::CCWArrow ): // rotation
vp.transformView( AffineXf3f::xfAround( Matrix3f::rotation( vp.getBackwardDirection(), PI2_F ), vp.getCameraPoint() ) );
break;
case int( SideRegions::CWArrow ) : // rotation other way
vp.transformView( AffineXf3f::xfAround( Matrix3f::rotation( vp.getBackwardDirection(), -PI2_F ), vp.getCameraPoint() ) );
break;
default:
return;
}
Expand Down
15 changes: 15 additions & 0 deletions source/MRViewer/MRViewportCornerController.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ namespace MR
/// <returns>Cube mesh with specified face structure</returns>
MRVIEWER_API Mesh makeCornerControllerMesh( float size, float cornerRatio = 0.2f );

enum class SideRegions
{
CCWArrow = 26,
CWArrow = 27
};

/// <summary>
/// Makes planar arrow mesh that will be used for controlling in plane rotation in corner near cube controller
/// </summary>
/// <param name="size">vertical length projection of Arrow</param>
/// <param name="shift">shift in XY plane in world units (unis same as size)</param>
/// <param name="ccw">direction of arrow</param>
/// <returns><Planar arrow mesh/returns>
MRVIEWER_API Mesh makeCornerControllerRotationArrowMesh( float size, const Vector2f& shift, bool ccw );

/// <summary>
/// Creates UV coordinates for `makeCornerControllerMesh` output mesh for texture like:\n
/// "Right"" Left "\n
Expand Down
Loading