Radium Engine  1.5.20
Loading...
Searching...
No Matches
ScaleGizmo.cpp
1#include <Gui/Viewer/Gizmo/ScaleGizmo.hpp>
2
3#include <Core/Containers/VectorArray.hpp>
4#include <Core/Geometry/MeshPrimitives.hpp>
5#include <Core/Utils/Color.hpp>
6
7#include <Core/Asset/Camera.hpp>
8#include <Engine/Data/Mesh.hpp>
9#include <Engine/Rendering/RenderObject.hpp>
10#include <Engine/Rendering/RenderTechnique.hpp>
11#include <Engine/Scene/CameraComponent.hpp>
12
13namespace Ra {
14namespace Gui {
15
16using namespace Ra::Core::Utils;
17
18ScaleGizmo::ScaleGizmo( Engine::Scene::Component* c,
19 const Core::Transform& worldTo,
20 const Core::Transform& t,
21 Mode mode ) :
22 Gizmo( c, worldTo, t, mode ),
23 m_prevScale( Core::Vector3::Ones() ),
24 m_startPoint( Core::Vector3::Zero() ),
25 m_initialPix( Core::Vector2::Zero() ),
26 m_selectedAxis( -1 ),
27 m_selectedPlane( -1 ) {
28 constexpr Scalar arrowScale = .1_ra;
29 constexpr Scalar axisWidth = .05_ra;
30 constexpr Scalar arrowFrac = .125_ra;
31 constexpr Scalar radius = arrowScale * axisWidth / 2_ra;
32
33 for ( uint i = 0; i < 3; ++i ) {
34 Core::Vector3 cylinderEnd = Core::Vector3::Zero();
35 cylinderEnd[i] = ( 1_ra - arrowFrac );
36 Core::Geometry::TriangleMesh cylinder = Core::Geometry::makeCylinder(
37 Core::Vector3::Zero(), arrowScale * cylinderEnd, radius, 32 );
38 Core::Aabb boxBounds;
39 boxBounds.extend( Core::Vector3( -radius * 2_ra, -radius * 2_ra, -radius * 2_ra ) );
40 boxBounds.extend( Core::Vector3( radius * 2_ra, radius * 2_ra, radius * 2_ra ) );
41 boxBounds.translate( arrowScale * cylinderEnd );
42 Core::Geometry::TriangleMesh box = Core::Geometry::makeSharpBox( boxBounds );
43 cylinder.append( box );
44
45 std::shared_ptr<Engine::Data::Mesh> mesh( new Engine::Data::Mesh( "Scale Gizmo Arrow" ) );
46 mesh->loadGeometry( std::move( cylinder ) );
47
49 "Scale Gizmo Arrow", m_comp, Engine::Rendering::RenderObjectType::UI );
50 auto rt = std::shared_ptr<Engine::Rendering::RenderTechnique>( makeRenderTechnique( i ) );
51 arrowDrawable->setRenderTechnique( rt );
52 arrowDrawable->setMesh( mesh );
53 addRenderObject( arrowDrawable );
54 }
55
56 for ( uint i = 0; i < 3; ++i ) {
57 Core::Vector3 axis = Core::Vector3::Zero();
58 axis[( i == 0 ? 1 : ( i == 1 ? 0 : 2 ) )] = 1;
59 Core::Transform T = Core::Transform::Identity();
60 T.rotate( Core::AngleAxis( Core::Math::PiDiv2, axis ) );
61 T.translation()[( i + 1 ) % 3] += arrowFrac * arrowScale * 3;
62 T.translation()[( i + 2 ) % 3] += arrowFrac * arrowScale * 3;
63
64 Core::Geometry::TriangleMesh plane = Core::Geometry::makePlaneGrid(
65 1, 1, Core::Vector2( arrowFrac * arrowScale, arrowFrac * arrowScale ), T );
66
67 // \FIXME this hack is here to be sure the plane will be selected (see shader)
68 auto& normals = plane.normalsWithLock();
69 normals.getMap().fill( 0_ra );
70 plane.normalsUnlock();
71
73 mesh->loadGeometry( std::move( plane ) );
74
76 "Gizmo Plane", m_comp, Engine::Rendering::RenderObjectType::UI );
77 auto rt = std::shared_ptr<Engine::Rendering::RenderTechnique>( makeRenderTechnique( i ) );
78 planeDrawable->setRenderTechnique( rt );
79 planeDrawable->setMesh( mesh );
80 addRenderObject( planeDrawable );
81 }
82
83 updateTransform( mode, m_worldTo, m_transform );
84}
85
86void ScaleGizmo::updateTransform( Gizmo::Mode mode,
87 const Core::Transform& worldTo,
88 const Core::Transform& t ) {
89 m_mode = mode;
90 m_worldTo = worldTo;
91 m_transform = t;
92 Core::Transform displayTransform = Core::Transform::Identity();
93 displayTransform.translate( m_transform.translation() );
94 // always scale in LOCAL frame
95 {
96 Core::Matrix3 R = m_transform.rotation();
97 R.col( 0 ).normalize();
98 R.col( 1 ).normalize();
99 R.col( 2 ).normalize();
100 displayTransform.rotate( R );
101 }
102
103 for ( const auto& ro : ros() ) {
104 ro->setLocalTransform( m_worldTo * displayTransform );
105 }
106}
107
108void ScaleGizmo::selectConstraint( int drawableIdx ) {
109 // deselect previously selected axis. Due to "whole" selection clear all states
110 for ( uint i = 0; i < 6; ++i ) {
111 getControler( i )->clearState();
112 }
113 // prepare selection
114 m_selectedAxis = -1;
115 m_selectedPlane = -1;
116 // Return if no component is selected
117 if ( drawableIdx < 0 ) { return; }
118
119 // update the state of the selected component
120 auto found = std::find_if( ros().cbegin(), ros().cend(), [drawableIdx]( const auto& ro ) {
121 return ro->getIndex() == Core::Utils::Index( drawableIdx );
122 } );
123 if ( found != ros().cend() ) {
124 int i = int( std::distance( ros().cbegin(), found ) );
125 getControler( i )->setState();
126 ( i < 3 ) ? m_selectedAxis = i : m_selectedPlane = i - 3;
127 // Activate the axes correponding to the selected plane
128 if ( m_selectedPlane != -1 ) {
129 getControler( ( m_selectedPlane + 1 ) % 3 )->setState();
130 getControler( ( m_selectedPlane + 2 ) % 3 )->setState();
131 }
132 }
133}
134
135Core::Transform ScaleGizmo::mouseMove( const Core::Asset::Camera& cam,
136 const Core::Vector2& nextXY,
137 bool stepped,
138 bool whole ) {
139 static const Scalar step = .2_ra;
140
141 // Recolor gizmo
142 // TODO : this appearance management has nothing to do in this method.
143 // Find how to move this on the selectConstraint method.
144 if ( whole ) {
145 for ( uint i = 0; i < 6; ++i ) {
146 getControler( i )->setState();
147 }
148 }
149 else {
150 for ( uint i = 0; i < 6; ++i ) {
151 getControler( i )->clearState();
152 }
153 if ( m_selectedAxis > -1 ) { getControler( m_selectedAxis )->setState(); }
154
155 if ( m_selectedPlane > -1 ) {
156 getControler( m_selectedPlane + 3 )->setState();
157 // Activate the axes correponding to the selected plane
158 getControler( ( m_selectedPlane + 1 ) % 3 )->setState();
159 getControler( ( m_selectedPlane + 2 ) % 3 )->setState();
160 }
161 }
162
163 // T
164 if ( m_selectedAxis == -1 && m_selectedPlane == -1 && !whole ) { return m_transform; }
165
166 // Get gizmo center and translation axis / plane normal
167 int dir = whole ? 0 : std::max( m_selectedAxis, m_selectedPlane );
168 const Core::Vector3 origin = m_transform.translation();
169 Core::Vector3 scaleDir = Core::Vector3( m_transform.rotation() * Core::Vector3::Unit( dir ) );
170
171 // Project the clicked points against the axis defined by the scale axis,
172 // or the planes defined by the scale plane.
174 bool found = false;
175 Core::Vector3 endPoint;
176 if ( whole ) {
177 found = findPointOnPlane( cam, origin, scaleDir, m_initialPix + nextXY, endPoint, hits );
178 }
179 else if ( m_selectedAxis > -1 ) {
180 found = findPointOnAxis( cam, origin, scaleDir, m_initialPix + nextXY, endPoint, hits );
181 }
182 else if ( m_selectedPlane >= 0 ) {
183 found = findPointOnPlane( cam, origin, scaleDir, m_initialPix + nextXY, endPoint, hits );
184 }
185 if ( !found ) { return m_transform; }
186
187 // Initialize scale
188 if ( !m_start ) {
189 m_start = true;
190 m_startPos = m_transform.translation();
191 m_prevScale = Core::Vector3::Ones();
192 m_startPoint = endPoint;
193 }
194
195 // Prevent scale == 0
196 const Scalar a = ( endPoint - m_startPos ).squaredNorm();
197 if ( a < 1e-3_ra ) { return m_transform; }
198
199 // Get scale value
200 const Core::Vector3 b = m_startPoint - m_startPos;
201 Scalar scale = std::sqrt( a ) / b.norm();
202 if ( stepped ) { scale = int( scale / step + 1 ) * step; }
203
204 // Apply scale
205 m_transform.scale( m_prevScale );
206 if ( whole ) { m_prevScale = scale * Core::Vector3::Ones(); }
207 else if ( m_selectedAxis > -1 ) {
208 m_prevScale = Core::Vector3::Ones();
209 m_prevScale[m_selectedAxis] = scale;
210 }
211 else if ( m_selectedPlane >= 0 ) {
212 m_prevScale = Core::Vector3::Ones();
213 m_prevScale[( m_selectedPlane + 1 ) % 3] = scale;
214 m_prevScale[( m_selectedPlane + 2 ) % 3] = scale;
215 }
216 m_transform.scale( m_prevScale );
217 m_prevScale = m_prevScale.cwiseInverse();
218
219 return m_transform;
220}
221
222void ScaleGizmo::setInitialState( const Core::Asset::Camera& /*cam*/,
223 const Core::Vector2& /*initialXY*/ ) {
224 m_initialPix = Core::Vector2::Zero();
225 m_start = false;
226}
227
228} // namespace Gui
229} // namespace Ra
Camera class storing the Camera frame and the projection properties The view direction is -z in camer...
Definition Camera.hpp:16
NormalAttribHandle::Container & normalsWithLock()
void normalsUnlock()
Release lock on vertices normals.
bool append(const MultiIndexedGeometry &other)
Mesh, own a Core::Geometry::TriangleMesh.
Definition Mesh.hpp:411
A component is an element that can be updated by a system. It is also linked to some other components...
Definition Component.hpp:31
T distance(T... args)
T find_if(T... args)
T max(T... args)
T move(T... args)
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T sqrt(T... args)