Radium Engine  1.5.0
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 
13 namespace Ra {
14 namespace Gui {
15 
16 using namespace Ra::Core::Utils;
17 
18 ScaleGizmo::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 
48  Engine::Rendering::RenderObject* arrowDrawable = new Engine::Rendering::RenderObject(
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 
72  std::shared_ptr<Engine::Data::Mesh> mesh( new Engine::Data::Mesh( "Gizmo Plane" ) );
73  mesh->loadGeometry( std::move( plane ) );
74 
75  Engine::Rendering::RenderObject* planeDrawable = new Engine::Rendering::RenderObject(
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 
86 void 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 
108 void 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 
135 Core::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.
173  std::vector<Scalar> hits;
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 
222 void 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
Definition: Cage.cpp:3