* new manipulator, applying skew transform
This commit is contained in:
parent
fadace9d69
commit
14ee12354d
|
|
@ -86,6 +86,7 @@ enum EManipulatorMode
|
|||
eTranslate,
|
||||
eRotate,
|
||||
eScale,
|
||||
eSkew,
|
||||
eDrag,
|
||||
eClip,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -70,8 +70,27 @@ typedef Vector3 Translation;
|
|||
typedef Quaternion Rotation;
|
||||
typedef Vector3 Scale;
|
||||
|
||||
inline Matrix4 matrix4_transform_for_components( const Translation& translation, const Rotation& rotation, const Scale& scale ){
|
||||
//simple one axis skew
|
||||
/// [0] [4]x(y) [8]x(z) [12]
|
||||
/// [1]y(x) [5] [9]y(z) [13]
|
||||
/// [2]z(x) [6]z(y) [10] [14]
|
||||
/// [3] [7] [11] [15]
|
||||
struct Skew{
|
||||
std::size_t index;
|
||||
float amount;
|
||||
Skew(){
|
||||
}
|
||||
Skew( std::size_t index_, float amount_ ) : index( index_ ), amount( amount_ ){
|
||||
}
|
||||
bool operator!= ( const Skew& other ){
|
||||
return index != other.index || amount != other.amount;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline Matrix4 matrix4_transform_for_components( const Translation& translation, const Rotation& rotation, const Scale& scale, const Skew& skew ){
|
||||
Matrix4 result( matrix4_rotation_for_quaternion_quantised( rotation ) );
|
||||
result[skew.index] += skew.amount;
|
||||
vector4_to_vector3( result.x() ) *= scale.x();
|
||||
vector4_to_vector3( result.y() ) *= scale.y();
|
||||
vector4_to_vector3( result.z() ) *= scale.z();
|
||||
|
|
@ -87,7 +106,7 @@ const TransformModifierType TRANSFORM_COMPONENT = true;
|
|||
|
||||
/// \brief A transformable scene-graph instance.
|
||||
///
|
||||
/// A transformable instance may be translated, rotated or scaled.
|
||||
/// A transformable instance may be translated, rotated, scaled or skewed.
|
||||
/// The state of the instanced node's geometrical representation
|
||||
/// will be the product of its geometry and the transforms of each
|
||||
/// of its instances, applied in the order they appear in a graph
|
||||
|
|
@ -103,12 +122,14 @@ virtual void setType( TransformModifierType type ) = 0;
|
|||
virtual void setTranslation( const Translation& value ) = 0;
|
||||
virtual void setRotation( const Rotation& value ) = 0;
|
||||
virtual void setScale( const Scale& value ) = 0;
|
||||
virtual void setSkew( const Skew& value ) = 0;
|
||||
virtual void freezeTransform() = 0;
|
||||
};
|
||||
|
||||
const Translation c_translation_identity = Translation( 0, 0, 0 );
|
||||
const Rotation c_rotation_identity = c_quaternion_identity;
|
||||
const Scale c_scale_identity = Scale( 1, 1, 1 );
|
||||
const Skew c_skew_identity = Skew( 4, 0 );
|
||||
|
||||
|
||||
class TransformModifier : public Transformable
|
||||
|
|
@ -116,6 +137,7 @@ class TransformModifier : public Transformable
|
|||
Translation m_translation;
|
||||
Rotation m_rotation;
|
||||
Scale m_scale;
|
||||
Skew m_skew;
|
||||
Callback m_changed;
|
||||
Callback m_apply;
|
||||
TransformModifierType m_type;
|
||||
|
|
@ -125,6 +147,7 @@ TransformModifier( const Callback& changed, const Callback& apply ) :
|
|||
m_translation( c_translation_identity ),
|
||||
m_rotation( c_quaternion_identity ),
|
||||
m_scale( c_scale_identity ),
|
||||
m_skew( c_skew_identity ),
|
||||
m_changed( changed ),
|
||||
m_apply( apply ),
|
||||
m_type( TRANSFORM_PRIMITIVE ){
|
||||
|
|
@ -147,14 +170,20 @@ void setScale( const Scale& value ){
|
|||
m_scale = value;
|
||||
m_changed();
|
||||
}
|
||||
void setSkew( const Skew& value ){
|
||||
m_skew = value;
|
||||
m_changed();
|
||||
}
|
||||
void freezeTransform(){
|
||||
if ( m_translation != c_translation_identity
|
||||
|| m_rotation != c_rotation_identity
|
||||
|| m_scale != c_scale_identity ) {
|
||||
|| m_scale != c_scale_identity
|
||||
|| m_skew != c_skew_identity ) {
|
||||
m_apply();
|
||||
m_translation = c_translation_identity;
|
||||
m_rotation = c_rotation_identity;
|
||||
m_scale = c_scale_identity;
|
||||
m_skew = c_skew_identity;
|
||||
m_changed();
|
||||
}
|
||||
}
|
||||
|
|
@ -167,8 +196,11 @@ const Rotation& getRotation() const {
|
|||
const Scale& getScale() const {
|
||||
return m_scale;
|
||||
}
|
||||
const Skew& getSkew() const {
|
||||
return m_skew;
|
||||
}
|
||||
Matrix4 calculateTransform() const {
|
||||
return matrix4_transform_for_components( getTranslation(), getRotation(), getScale() );
|
||||
return matrix4_transform_for_components( getTranslation(), getRotation(), getScale(), getSkew() );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1405,6 +1405,10 @@ void ScaleToolExport( const BoolImportCallback& importCallback ){
|
|||
importCallback( GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eScale );
|
||||
}
|
||||
|
||||
void SkewToolExport( const BoolImportCallback& importCallback ){
|
||||
importCallback( GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eSkew );
|
||||
}
|
||||
|
||||
void DragToolExport( const BoolImportCallback& importCallback ){
|
||||
importCallback( GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eDrag );
|
||||
}
|
||||
|
|
@ -1425,6 +1429,10 @@ FreeCaller1<const BoolImportCallback&, ScaleToolExport> g_scalemode_button_calle
|
|||
BoolExportCallback g_scalemode_button_callback( g_scalemode_button_caller );
|
||||
ToggleItem g_scalemode_button( g_scalemode_button_callback );
|
||||
|
||||
FreeCaller1<const BoolImportCallback&, SkewToolExport> g_skewmode_button_caller;
|
||||
BoolExportCallback g_skewmode_button_callback( g_skewmode_button_caller );
|
||||
ToggleItem g_skewmode_button( g_skewmode_button_callback );
|
||||
|
||||
FreeCaller1<const BoolImportCallback&, DragToolExport> g_dragmode_button_caller;
|
||||
BoolExportCallback g_dragmode_button_callback( g_dragmode_button_caller );
|
||||
ToggleItem g_dragmode_button( g_dragmode_button_callback );
|
||||
|
|
@ -1437,6 +1445,7 @@ void ToolChanged(){
|
|||
g_translatemode_button.update();
|
||||
g_rotatemode_button.update();
|
||||
g_scalemode_button.update();
|
||||
g_skewmode_button.update();
|
||||
g_dragmode_button.update();
|
||||
g_clipper_button.update();
|
||||
}
|
||||
|
|
@ -1522,8 +1531,28 @@ void ScaleMode(){
|
|||
}
|
||||
}
|
||||
|
||||
const char* const c_SkewMode_status = "Transform Tool: transform objects and components";
|
||||
|
||||
const char* const c_ClipperMode_status = "Clipper Tool: apply clip planes to objects";
|
||||
void SkewMode(){
|
||||
if ( g_currentToolMode == SkewMode && g_defaultToolMode != SkewMode ) {
|
||||
g_defaultToolMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_currentToolMode = SkewMode;
|
||||
g_currentToolModeSupportsComponentEditing = true;
|
||||
|
||||
OnClipMode( false );
|
||||
|
||||
Sys_Status( c_SkewMode_status );
|
||||
GlobalSelectionSystem().SetManipulatorMode( SelectionSystem::eSkew );
|
||||
ToolChanged();
|
||||
ModeChangeNotify();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char* const c_ClipperMode_status = "Clipper Tool: apply clip planes to brushes";
|
||||
|
||||
|
||||
void ClipperMode(){
|
||||
|
|
@ -1551,8 +1580,8 @@ void ToggleRotateScaleModes(){
|
|||
return g_currentToolMode == RotateMode? ScaleMode() : RotateMode();
|
||||
}
|
||||
|
||||
void ToggleDragScaleModes(){
|
||||
return g_currentToolMode == DragMode? ScaleMode() : DragMode();
|
||||
void ToggleDragSkewModes(){
|
||||
return g_currentToolMode == DragMode? SkewMode() : DragMode();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2388,7 +2417,7 @@ void Misc_registerShortcuts(){
|
|||
//refresh models
|
||||
command_connect_accelerator( "RefreshReferences" );
|
||||
command_connect_accelerator( "MouseRotateOrScale" );
|
||||
command_connect_accelerator( "MouseDragOrScale" );
|
||||
command_connect_accelerator( "MouseDragOrTransform" );
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2462,7 +2491,8 @@ void XYWnd_constructToolbar( GtkToolbar* toolbar ){
|
|||
void Manipulators_constructToolbar( GtkToolbar* toolbar ){
|
||||
toolbar_append_toggle_button( toolbar, "Translate (W)", "select_mousetranslate.png", "MouseTranslate" );
|
||||
toolbar_append_toggle_button( toolbar, "Rotate (R)", "select_mouserotate.png", "MouseRotate" );
|
||||
toolbar_append_toggle_button( toolbar, "Scale (Q)", "select_mousescale.png", "MouseScale" );
|
||||
toolbar_append_toggle_button( toolbar, "Scale", "select_mousescale.png", "MouseScale" );
|
||||
toolbar_append_toggle_button( toolbar, "Transform (Q)", "texture_vertexlock.png", "MouseTransform" );
|
||||
toolbar_append_toggle_button( toolbar, "Resize (Q)", "select_mouseresize.png", "MouseDrag" );
|
||||
|
||||
Clipper_constructToolbar( toolbar );
|
||||
|
|
@ -3495,9 +3525,10 @@ void MainFrame_Construct(){
|
|||
GlobalToggles_insert( "MouseTranslate", FreeCaller<TranslateMode>(), ToggleItem::AddCallbackCaller( g_translatemode_button ), Accelerator( 'W' ) );
|
||||
GlobalToggles_insert( "MouseRotate", FreeCaller<RotateMode>(), ToggleItem::AddCallbackCaller( g_rotatemode_button ), Accelerator( 'R' ) );
|
||||
GlobalToggles_insert( "MouseScale", FreeCaller<ScaleMode>(), ToggleItem::AddCallbackCaller( g_scalemode_button ) );
|
||||
GlobalToggles_insert( "MouseTransform", FreeCaller<SkewMode>(), ToggleItem::AddCallbackCaller( g_skewmode_button ) );
|
||||
GlobalToggles_insert( "MouseDrag", FreeCaller<DragMode>(), ToggleItem::AddCallbackCaller( g_dragmode_button ) );
|
||||
GlobalCommands_insert( "MouseRotateOrScale", FreeCaller<ToggleRotateScaleModes>() );
|
||||
GlobalCommands_insert( "MouseDragOrScale", FreeCaller<ToggleDragScaleModes>(), Accelerator( 'Q' ) );
|
||||
GlobalCommands_insert( "MouseDragOrTransform", FreeCaller<ToggleDragSkewModes>(), Accelerator( 'Q' ) );
|
||||
|
||||
GlobalCommands_insert( "gtkThemeDlg", FreeCaller<gtkThemeDlg>() );
|
||||
GlobalCommands_insert( "OpenGLFont", FreeCaller<OpenGLFont_select>() );
|
||||
|
|
|
|||
|
|
@ -562,6 +562,53 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const
|
|||
};
|
||||
|
||||
|
||||
class Skewable
|
||||
{
|
||||
public:
|
||||
virtual void skew( const Skew& skew ) = 0;
|
||||
};
|
||||
|
||||
|
||||
class SkewAxis : public Manipulatable
|
||||
{
|
||||
private:
|
||||
Vector3 m_start;
|
||||
Vector3 m_axis_which;
|
||||
int m_axis_by;
|
||||
int m_axis_by_sign;
|
||||
Skewable& m_skewable;
|
||||
|
||||
float m_axis_by_extent;
|
||||
AABB m_bounds;
|
||||
|
||||
public:
|
||||
SkewAxis( Skewable& skewable )
|
||||
: m_skewable( skewable ){
|
||||
}
|
||||
void Construct( const Matrix4& device2manip, const float x, const float y, const AABB& bounds, const Vector3& transform_origin ){
|
||||
point_on_axis( m_start, m_axis_which, device2manip, x, y );
|
||||
m_bounds = bounds;
|
||||
m_axis_by_extent = bounds.origin[m_axis_by] + bounds.extents[m_axis_by] * m_axis_by_sign - transform_origin[m_axis_by];
|
||||
}
|
||||
void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ){
|
||||
Vector3 current;
|
||||
point_on_axis( current, m_axis_which, device2manip, x, y );
|
||||
current = vector3_scaled( m_axis_which, distance_for_axis( m_start, current, m_axis_which ) );
|
||||
|
||||
translation_local2object( current, current, manip2object );
|
||||
vector3_snap( current, GetSnapGridSize() );
|
||||
|
||||
const int axis_which_index = m_axis_which[0] > 0? 0 : m_axis_which[1] > 0? 1 : 2;
|
||||
// globalOutputStream() << m_axis_which << " by axis " << m_axis_by << "\n";
|
||||
m_skewable.skew( Skew( m_axis_by * 4 + axis_which_index, m_axis_by_extent != 0.f? current[axis_which_index] / m_axis_by_extent : 0 ) );
|
||||
}
|
||||
void SetAxes( const Vector3& axis_which, int axis_by, int axis_by_sign ){
|
||||
m_axis_which = axis_which;
|
||||
m_axis_by = axis_by;
|
||||
m_axis_by_sign = axis_by_sign;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1728,10 +1775,6 @@ ScaleManipulator( Scalable& scalable, std::size_t segments, float length ) :
|
|||
draw_quad( 16, m_quad_screen.m_quad );
|
||||
}
|
||||
|
||||
Pivot2World& getPivot(){
|
||||
return m_pivot;
|
||||
}
|
||||
|
||||
void UpdateColours(){
|
||||
m_arrow_x.setColour( colourSelected( g_colour_x, m_selectable_x.isSelected() ) );
|
||||
m_arrow_y.setColour( colourSelected( g_colour_y, m_selectable_y.isSelected() ) );
|
||||
|
|
@ -1838,6 +1881,190 @@ bool isSelected() const {
|
|||
};
|
||||
|
||||
|
||||
class SkewManipulator : public Manipulator {
|
||||
struct RenderableLine : public OpenGLRenderable {
|
||||
PointVertex m_line[2];
|
||||
|
||||
RenderableLine() {
|
||||
}
|
||||
void render( RenderStateFlags state ) const {
|
||||
glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( PointVertex ), &m_line[0].colour );
|
||||
glVertexPointer( 3, GL_FLOAT, sizeof( PointVertex ), &m_line[0].vertex );
|
||||
glDrawArrays( GL_LINES, 0, 2 );
|
||||
}
|
||||
void setColour( const Colour4b& colour ) {
|
||||
m_line[0].colour = colour;
|
||||
m_line[1].colour = colour;
|
||||
}
|
||||
};
|
||||
SkewAxis m_skew;
|
||||
const AABB& m_bounds;
|
||||
Matrix4& m_pivot2world;
|
||||
const bool& m_pivotIsCustom;
|
||||
/*
|
||||
RenderableLine m_lineXy_;
|
||||
RenderableLine m_lineXy;
|
||||
RenderableLine m_lineXz_;
|
||||
RenderableLine m_lineXz;
|
||||
RenderableLine m_lineYz_;
|
||||
RenderableLine m_lineYz;
|
||||
RenderableLine m_lineYx_;
|
||||
RenderableLine m_lineYx;
|
||||
RenderableLine m_lineZx_;
|
||||
RenderableLine m_lineZx;
|
||||
RenderableLine m_lineZy_;
|
||||
RenderableLine m_lineZy;
|
||||
*/
|
||||
RenderableLine m_lines[3][2][2];
|
||||
SelectableBool m_selectables[3][2][2];
|
||||
Selectable* m_selectable_prev_ptr;
|
||||
Pivot2World m_pivot;
|
||||
Matrix4 m_worldSpace;
|
||||
public:
|
||||
static Shader* m_state_wire;
|
||||
SkewManipulator( Skewable& skewable, const AABB& bounds, Matrix4& pivot2world, const bool& pivotIsCustom ) :
|
||||
m_skew( skewable ),
|
||||
m_bounds( bounds ),
|
||||
m_pivot2world( pivot2world ),
|
||||
m_pivotIsCustom( pivotIsCustom ),
|
||||
m_selectable_prev_ptr( 0 ) {
|
||||
for ( int i = 0; i < 3; ++i ){
|
||||
for ( int j = 0; j < 2; ++j ){
|
||||
const int x = i;
|
||||
const int y = ( i + j + 1 )%3;
|
||||
Vertex3f& xy_ = m_lines[i][j][0].m_line[0].vertex;
|
||||
Vertex3f& x_y_ = m_lines[i][j][0].m_line[1].vertex;
|
||||
Vertex3f& xy = m_lines[i][j][1].m_line[0].vertex;
|
||||
Vertex3f& x_y = m_lines[i][j][1].m_line[1].vertex;
|
||||
xy = x_y = xy_ = x_y_ = vertex3f_identity;
|
||||
xy[x] = xy_[x] = 1;
|
||||
x_y[x] = x_y_[x] = -1;
|
||||
xy[y] = x_y[y] = 1;
|
||||
xy_[y] = x_y_[y] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateColours() {
|
||||
for ( int i = 0; i < 3; ++i )
|
||||
for ( int j = 0; j < 2; ++j )
|
||||
for ( int k = 0; k < 2; ++k )
|
||||
m_lines[i][j][k].setColour( colourSelected( g_colour_screen, m_selectables[i][j][k].isSelected() ) );
|
||||
}
|
||||
|
||||
void updateModelview( const VolumeTest& volume, const Matrix4& pivot2world ){
|
||||
//m_pivot.update( matrix4_translation_for_vec3( matrix4_get_translation_vec3( pivot2world ) ), volume.GetModelview(), volume.GetProjection(), volume.GetViewport() );
|
||||
m_pivot.update( g_matrix4_identity, volume.GetModelview(), volume.GetProjection(), volume.GetViewport() ); //no shaking in cam due to low precision this way; smooth and a bit incorrect result
|
||||
// globalOutputStream() << m_pivot.m_worldSpace << "\n";
|
||||
AABB bo = aabb_for_oriented_aabb( m_bounds, matrix4_full_inverse( m_pivot.m_worldSpace ) );
|
||||
for ( int i = 0; i < 3; ++i ){
|
||||
if( bo.extents[i] < 16 )
|
||||
bo.extents[i] = 18;
|
||||
else
|
||||
bo.extents[i] += 2.0f;
|
||||
}
|
||||
bo = aabb_for_oriented_aabb( bo, m_pivot.m_worldSpace );
|
||||
m_worldSpace = matrix4_multiplied_by_matrix4( matrix4_translation_for_vec3( bo.origin ), matrix4_scale_for_vec3( bo.extents ) );
|
||||
matrix4_premultiply_by_matrix4( m_worldSpace, matrix4_translation_for_vec3( -matrix4_get_translation_vec3( pivot2world ) ) );
|
||||
matrix4_premultiply_by_matrix4( m_worldSpace, pivot2world );
|
||||
|
||||
// globalOutputStream() << m_worldSpace << "\n";
|
||||
// globalOutputStream() << pivot2world << "\n";
|
||||
}
|
||||
|
||||
void render( Renderer& renderer, const VolumeTest& volume, const Matrix4& pivot2world ) {
|
||||
updateModelview( volume, pivot2world );
|
||||
|
||||
// temp hack
|
||||
UpdateColours();
|
||||
|
||||
renderer.SetState( m_state_wire, Renderer::eWireframeOnly );
|
||||
renderer.SetState( m_state_wire, Renderer::eFullMaterials );
|
||||
|
||||
for ( int i = 0; i < 3; ++i )
|
||||
for ( int j = 0; j < 2; ++j ){
|
||||
const Vector3 dir = ( m_lines[i][j][0].m_line[0].vertex - m_lines[i][j][1].m_line[0].vertex ) / 2;
|
||||
const float dot = vector3_dot( dir, m_pivot.m_axis_screen );
|
||||
if( dot > 0.9999f )
|
||||
renderer.addRenderable( m_lines[i][j][0], m_worldSpace );
|
||||
else if( dot < -0.9999f )
|
||||
renderer.addRenderable( m_lines[i][j][1], m_worldSpace );
|
||||
else{
|
||||
renderer.addRenderable( m_lines[i][j][0], m_worldSpace );
renderer.addRenderable( m_lines[i][j][1], m_worldSpace );
|
||||
}
|
||||
}
|
||||
}
|
||||
void testSelect( const View& view, const Matrix4& pivot2world ) {
|
||||
updateModelview( view, pivot2world );
|
||||
|
||||
SelectionPool selector;
|
||||
|
||||
Matrix4 local2view( matrix4_multiplied_by_matrix4( view.GetViewMatrix(), m_worldSpace ) );
|
||||
for ( int i = 0; i < 3; ++i )
|
||||
for ( int j = 0; j < 2; ++j )
|
||||
for ( int k = 0; k < 2; ++k ){
|
||||
SelectionIntersection best;
|
||||
Line_BestPoint( local2view, m_lines[i][j][k].m_line, best );
|
||||
selector.addSelectable( best, &m_selectables[i][j][k] );
|
||||
}
|
||||
|
||||
|
||||
if( !selector.failed() ) {
|
||||
( *selector.begin() ).second->setSelected( true );
|
||||
if( !m_pivotIsCustom )
|
||||
for ( int i = 0; i < 3; ++i )
|
||||
for ( int j = 0; j < 2; ++j )
|
||||
for ( int k = 0; k < 2; ++k )
|
||||
if( m_selectables[i][j][k].isSelected() ){
|
||||
const int axis_by = ( i + j + 1 ) % 3;
|
||||
Vector3 origin = m_bounds.origin;
|
||||
origin[axis_by] += k? -m_bounds.extents[axis_by] : m_bounds.extents[axis_by];
|
||||
m_pivot2world = matrix4_translation_for_vec3( origin );
|
||||
}
|
||||
if( m_selectable_prev_ptr != ( *selector.begin() ).second ) {
|
||||
m_selectable_prev_ptr = ( *selector.begin() ).second;
|
||||
SceneChangeNotify();
|
||||
}
|
||||
}
|
||||
else if( m_selectable_prev_ptr ) {
|
||||
m_selectable_prev_ptr = 0;
|
||||
SceneChangeNotify();
|
||||
}
|
||||
}
|
||||
|
||||
Manipulatable* GetManipulatable() {
|
||||
for ( int i = 0; i < 3; ++i )
|
||||
for ( int j = 0; j < 2; ++j )
|
||||
for ( int k = 0; k < 2; ++k )
|
||||
if( m_selectables[i][j][k].isSelected() ){
|
||||
Vector3 axis_which( g_vector3_identity );
|
||||
axis_which[i] = 1;
|
||||
m_skew.SetAxes( axis_which, ( i + j + 1 ) % 3, k? 1 : -1 );
|
||||
return &m_skew;
|
||||
}
|
||||
return &m_skew;
|
||||
}
|
||||
|
||||
void setSelected( bool select ) {
|
||||
for ( int i = 0; i < 3; ++i )
|
||||
for ( int j = 0; j < 2; ++j )
|
||||
for ( int k = 0; k < 2; ++k )
|
||||
m_selectables[i][j][k].setSelected( select );
|
||||
}
|
||||
bool isSelected() const {
|
||||
bool selected = false;
|
||||
for ( int i = 0; i < 3; ++i )
|
||||
for ( int j = 0; j < 2; ++j )
|
||||
for ( int k = 0; k < 2; ++k )
|
||||
selected |= m_selectables[i][j][k].isSelected();
|
||||
return selected;
|
||||
}
|
||||
};
|
||||
|
||||
Shader* SkewManipulator::m_state_wire;
|
||||
|
||||
|
||||
|
||||
inline PlaneSelectable* Instance_getPlaneSelectable( scene::Instance& instance ){
|
||||
return InstanceTypeCast<PlaneSelectable>::cast( instance );
|
||||
}
|
||||
|
|
@ -2461,6 +2688,12 @@ void translation_for_pivoted_scale( Vector3& parent_translation, const Vector3&
|
|||
translation_for_pivoted_matrix_transform( parent_translation, local_transform, world_pivot, localToWorld, localToParent );
|
||||
}
|
||||
|
||||
void translation_for_pivoted_skew( Vector3& parent_translation, const Skew& local_skew, const Vector3& world_pivot, const Matrix4& localToWorld, const Matrix4& localToParent ){
|
||||
Matrix4 local_transform( g_matrix4_identity );
|
||||
local_transform[local_skew.index] = local_skew.amount;
|
||||
translation_for_pivoted_matrix_transform( parent_translation, local_transform, world_pivot, localToWorld, localToParent );
|
||||
}
|
||||
|
||||
class rotate_selected : public SelectionSystem::Visitor
|
||||
{
|
||||
const Quaternion& m_rotate;
|
||||
|
|
@ -2557,6 +2790,51 @@ void Scene_Scale_Selected( scene::Graph& graph, const Vector3& scaling, const Ve
|
|||
}
|
||||
}
|
||||
|
||||
class skew_selected : public SelectionSystem::Visitor
|
||||
{
|
||||
const Skew& m_skew;
|
||||
const Vector3& m_world_pivot;
|
||||
public:
|
||||
skew_selected( const Skew& skew, const Vector3& world_pivot )
|
||||
: m_skew( skew ), m_world_pivot( world_pivot ){
|
||||
}
|
||||
void visit( scene::Instance& instance ) const {
|
||||
TransformNode* transformNode = Node_getTransformNode( instance.path().top() );
|
||||
if ( transformNode != 0 ) {
|
||||
Transformable* transform = Instance_getTransformable( instance );
|
||||
if ( transform != 0 ) {
|
||||
transform->setType( TRANSFORM_PRIMITIVE );
|
||||
transform->setScale( c_scale_identity );
|
||||
transform->setTranslation( c_translation_identity );
|
||||
|
||||
transform->setType( TRANSFORM_PRIMITIVE );
|
||||
transform->setSkew( m_skew );
|
||||
{
|
||||
Editable* editable = Node_getEditable( instance.path().top() );
|
||||
const Matrix4& localPivot = editable != 0 ? editable->getLocalPivot() : g_matrix4_identity;
|
||||
|
||||
Vector3 parent_translation;
|
||||
translation_for_pivoted_skew(
|
||||
parent_translation,
|
||||
m_skew,
|
||||
m_world_pivot,
|
||||
matrix4_multiplied_by_matrix4( matrix4_translation_for_vec3( matrix4_get_translation_vec3( instance.localToWorld() ) ), localPivot ),
|
||||
matrix4_multiplied_by_matrix4( matrix4_translation_for_vec3( matrix4_get_translation_vec3( transformNode->localToParent() ) ), localPivot )
|
||||
);
|
||||
|
||||
transform->setTranslation( parent_translation );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void Scene_Skew_Selected( scene::Graph& graph, const Skew& skew, const Vector3& world_pivot ){
|
||||
if ( GlobalSelectionSystem().countSelected() != 0 ) {
|
||||
GlobalSelectionSystem().foreachSelected( skew_selected( skew, world_pivot ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class translate_component_selected : public SelectionSystem::Visitor
|
||||
{
|
||||
|
|
@ -2634,6 +2912,33 @@ void Scene_Scale_Component_Selected( scene::Graph& graph, const Vector3& scaling
|
|||
}
|
||||
}
|
||||
|
||||
class skew_component_selected : public SelectionSystem::Visitor
|
||||
{
|
||||
const Skew& m_skew;
|
||||
const Vector3& m_world_pivot;
|
||||
public:
|
||||
skew_component_selected( const Skew& skew, const Vector3& world_pivot )
|
||||
: m_skew( skew ), m_world_pivot( world_pivot ){
|
||||
}
|
||||
void visit( scene::Instance& instance ) const {
|
||||
Transformable* transform = Instance_getTransformable( instance );
|
||||
if ( transform != 0 ) {
|
||||
Vector3 parent_translation;
|
||||
translation_for_pivoted_skew( parent_translation, m_skew, m_world_pivot, instance.localToWorld(), Node_getTransformNode( instance.path().top() )->localToParent() );
|
||||
|
||||
transform->setType( TRANSFORM_COMPONENT );
|
||||
transform->setSkew( m_skew );
|
||||
transform->setTranslation( parent_translation );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void Scene_Skew_Component_Selected( scene::Graph& graph, const Skew& skew, const Vector3& world_pivot ){
|
||||
if ( GlobalSelectionSystem().countSelectedComponents() != 0 ) {
|
||||
GlobalSelectionSystem().foreachSelectedComponent( skew_component_selected( skew, world_pivot ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class BooleanSelector : public Selector
|
||||
{
|
||||
|
|
@ -2854,7 +3159,7 @@ bool isSelected() const {
|
|||
class TransformOriginTranslatable
|
||||
{
|
||||
public:
|
||||
virtual void transformOriginTranslate( const Vector3& translation, const bool set[3], const AABB& bounds ) = 0;
|
||||
virtual void transformOriginTranslate( const Vector3& translation, const bool set[3] ) = 0;
|
||||
};
|
||||
|
||||
class TransformOriginTranslate : public Manipulatable
|
||||
|
|
@ -2862,14 +3167,12 @@ class TransformOriginTranslate : public Manipulatable
|
|||
private:
|
||||
Vector3 m_start;
|
||||
TransformOriginTranslatable& m_transformOriginTranslatable;
|
||||
AABB m_bounds;
|
||||
public:
|
||||
TransformOriginTranslate( TransformOriginTranslatable& transformOriginTranslatable )
|
||||
: m_transformOriginTranslatable( transformOriginTranslatable ){
|
||||
}
|
||||
void Construct( const Matrix4& device2manip, const float x, const float y, const AABB& bounds, const Vector3& transform_origin ){
|
||||
point_on_plane( m_start, device2manip, 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 ){
|
||||
Vector3 current;
|
||||
|
|
@ -2896,7 +3199,7 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const
|
|||
|
||||
translation_local2object( current, current, manip2object );
|
||||
|
||||
m_transformOriginTranslatable.transformOriginTranslate( current, set, m_bounds );
|
||||
m_transformOriginTranslatable.transformOriginTranslate( current, set );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -3033,15 +3336,18 @@ class RadiantSelectionSystem :
|
|||
public Translatable,
|
||||
public Rotatable,
|
||||
public Scalable,
|
||||
public Skewable,
|
||||
public TransformOriginTranslatable,
|
||||
public Renderable
|
||||
{
|
||||
mutable Matrix4 m_pivot2world;
|
||||
mutable AABB m_bounds;
|
||||
Matrix4 m_pivot2world_start;
|
||||
Matrix4 m_manip2pivot_start;
|
||||
Translation m_translation;
|
||||
Rotation m_rotation;
|
||||
Scale m_scale;
|
||||
Skew m_skew;
|
||||
public:
|
||||
static Shader* m_state;
|
||||
bool m_bPreferPointEntsIn2D;
|
||||
|
|
@ -3060,6 +3366,7 @@ SelectionCounter m_count_component;
|
|||
TranslateManipulator m_translate_manipulator;
|
||||
RotateManipulator m_rotate_manipulator;
|
||||
ScaleManipulator m_scale_manipulator;
|
||||
SkewManipulator m_skew_manipulator;
|
||||
DragManipulator m_drag_manipulator;
|
||||
ClipManipulator m_clip_manipulator;
|
||||
mutable TransformOriginManipulator m_transformOrigin_manipulator;
|
||||
|
|
@ -3073,10 +3380,7 @@ Signal1<const Selectable&> m_selectionChanged_callbacks;
|
|||
void ConstructPivot() const;
|
||||
void ConstructPivotRotation() const;
|
||||
void setCustomTransformOrigin( const Vector3& origin, const bool set[3] ) const;
|
||||
void setCustomTransformOrigin( const Vector3& origin, const bool set[3], const AABB& bounds ) const;
|
||||
public:
|
||||
AABB getSelectionAABB() const;
|
||||
private:
|
||||
mutable bool m_pivotChanged;
|
||||
bool m_pivot_moving;
|
||||
mutable bool m_pivotIsCustom;
|
||||
|
|
@ -3110,6 +3414,7 @@ RadiantSelectionSystem() :
|
|||
m_translate_manipulator( *this, 2, 64 ),
|
||||
m_rotate_manipulator( *this, 8, 64 ),
|
||||
m_scale_manipulator( *this, 0, 64 ),
|
||||
m_skew_manipulator( *this, m_bounds, m_pivot2world, m_pivotIsCustom ),
|
||||
m_transformOrigin_manipulator( *this ),
|
||||
m_pivotChanged( false ),
|
||||
m_pivot_moving( false ),
|
||||
|
|
@ -3152,6 +3457,7 @@ void SetManipulatorMode( EManipulatorMode mode ){
|
|||
case eTranslate: m_manipulator = &m_translate_manipulator; break;
|
||||
case eRotate: m_manipulator = &m_rotate_manipulator; break;
|
||||
case eScale: m_manipulator = &m_scale_manipulator; break;
|
||||
case eSkew: m_manipulator = &m_skew_manipulator; break;
|
||||
case eDrag: m_manipulator = &m_drag_manipulator; break;
|
||||
case eClip: m_manipulator = &m_clip_manipulator; break;
|
||||
}
|
||||
|
|
@ -3284,12 +3590,12 @@ bool SelectManipulator( const View& view, const float device_point[2], const flo
|
|||
Matrix4 device2manip;
|
||||
ConstructDevice2Manip( device2manip, m_pivot2world_start, view.GetModelview(), view.GetProjection(), view.GetViewport() );
|
||||
if( m_pivot_moving ){
|
||||
m_manipulator->GetManipulatable()->Construct( device2manip, device_point[0], device_point[1], getSelectionAABB(), vector4_to_vector3( GetPivot2World().t() ) );
|
||||
m_manipulator->GetManipulatable()->Construct( device2manip, device_point[0], device_point[1], m_bounds, vector4_to_vector3( GetPivot2World().t() ) );
|
||||
|
||||
m_undo_begun = false;
|
||||
}
|
||||
else if( movingOrigin ){
|
||||
m_transformOrigin_manipulator.GetManipulatable()->Construct( device2manip, device_point[0], device_point[1], getSelectionAABB(), vector4_to_vector3( GetPivot2World().t() ) );
|
||||
m_transformOrigin_manipulator.GetManipulatable()->Construct( device2manip, device_point[0], device_point[1], m_bounds, vector4_to_vector3( GetPivot2World().t() ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3623,6 +3929,9 @@ void rotate( const Quaternion& rotation ){
|
|||
|
||||
matrix4_assign_rotation_for_pivot( m_pivot2world, m_selection.back() );
|
||||
}
|
||||
#ifdef SELECTIONSYSTEM_AXIAL_PIVOTS
|
||||
matrix4_assign_rotation( m_pivot2world, matrix4_rotation_for_quaternion_quantised( m_rotation ) );
|
||||
#endif
|
||||
|
||||
SceneChangeNotify();
|
||||
}
|
||||
|
|
@ -3649,6 +3958,22 @@ void outputScale( TextOutputStream& ostream ){
|
|||
ostream << " -scale " << m_scale.x() << " " << m_scale.y() << " " << m_scale.z();
|
||||
}
|
||||
|
||||
void skew( const Skew& skew ){
|
||||
if ( !nothingSelected() ) {
|
||||
m_skew = skew;
|
||||
|
||||
if ( Mode() == eComponent ) {
|
||||
Scene_Skew_Component_Selected( GlobalSceneGraph(), m_skew, vector4_to_vector3( m_pivot2world.t() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
Scene_Skew_Selected( GlobalSceneGraph(), m_skew, vector4_to_vector3( m_pivot2world.t() ) );
|
||||
}
|
||||
m_pivot2world[skew.index] = skew.amount;
|
||||
SceneChangeNotify();
|
||||
}
|
||||
}
|
||||
|
||||
void rotateSelected( const Quaternion& rotation, bool snapOrigin = false ){
|
||||
if( snapOrigin && !m_pivotIsCustom ){
|
||||
m_pivot2world.tx() = float_snapped( m_pivot2world.tx(), GetSnapGridSize() );
|
||||
|
|
@ -3677,13 +4002,14 @@ void scaleSelected( const Vector3& scaling, bool snapOrigin = false ){
|
|||
|
||||
bool transformOrigin_isTranslatable() const{
|
||||
return ManipulatorMode() == eScale
|
||||
|| ManipulatorMode() == eSkew
|
||||
|| ManipulatorMode() == eRotate
|
||||
|| ManipulatorMode() == eTranslate;
|
||||
}
|
||||
|
||||
void transformOriginTranslate( const Vector3& translation, const bool set[3], const AABB& bounds ){
|
||||
void transformOriginTranslate( const Vector3& translation, const bool set[3] ){
|
||||
m_pivot2world = m_pivot2world_start;
|
||||
setCustomTransformOrigin( translation + vector4_to_vector3( m_pivot2world_start.t() ), set, bounds );
|
||||
setCustomTransformOrigin( translation + vector4_to_vector3( m_pivot2world_start.t() ), set );
|
||||
SceneChangeNotify();
|
||||
}
|
||||
|
||||
|
|
@ -3734,12 +4060,14 @@ static void constructStatic(){
|
|||
TranslateManipulator::m_state_fill = GlobalShaderCache().capture( "$FLATSHADE_OVERLAY" );
|
||||
RotateManipulator::m_state_outer = GlobalShaderCache().capture( "$WIRE_OVERLAY" );
|
||||
TransformOriginManipulator::m_state = GlobalShaderCache().capture( "$BIGPOINT" );
|
||||
SkewManipulator::m_state_wire = GlobalShaderCache().capture( "$WIRE_OVERLAY" );
|
||||
}
|
||||
|
||||
static void destroyStatic(){
|
||||
#if defined( DEBUG_SELECTION )
|
||||
GlobalShaderCache().release( "$DEBUG_CLIPPED" );
|
||||
#endif
|
||||
GlobalShaderCache().release( "$WIRE_OVERLAY" );
|
||||
GlobalShaderCache().release( "$BIGPOINT" );
|
||||
GlobalShaderCache().release( "$WIRE_OVERLAY" );
|
||||
GlobalShaderCache().release( "$FLATSHADE_OVERLAY" );
|
||||
|
|
@ -3960,6 +4288,10 @@ bool RadiantSelectionSystem::endMove(){
|
|||
command << "scaleTool";
|
||||
outputScale( command );
|
||||
}
|
||||
else if ( ManipulatorMode() == eSkew ) {
|
||||
command << "transformTool";
|
||||
// outputScale( command );
|
||||
}
|
||||
else if ( ManipulatorMode() == eDrag ) {
|
||||
command << "dragTool";
|
||||
}
|
||||
|
|
@ -4084,46 +4416,47 @@ void RadiantSelectionSystem::ConstructPivotRotation() const {
|
|||
}
|
||||
|
||||
void RadiantSelectionSystem::ConstructPivot() const {
|
||||
if ( !m_pivotChanged || m_pivot_moving || m_pivotIsCustom ) {
|
||||
if ( !m_pivotChanged || m_pivot_moving ) {
|
||||
return;
|
||||
}
|
||||
m_pivotChanged = false;
|
||||
|
||||
if ( !nothingSelected() ) {
|
||||
AABB bounds( getSelectionAABB() );
|
||||
Vector3 m_object_pivot = bounds.origin;
|
||||
m_bounds = getSelectionAABB();
|
||||
if( !m_pivotIsCustom ){
|
||||
Vector3 object_pivot = m_bounds.origin;
|
||||
|
||||
//vector3_snap( m_object_pivot, GetSnapGridSize() );
|
||||
//globalOutputStream() << m_object_pivot << "\n";
|
||||
m_pivot2world = matrix4_translation_for_vec3( m_object_pivot );
|
||||
//vector3_snap( object_pivot, GetSnapGridSize() );
|
||||
//globalOutputStream() << object_pivot << "\n";
|
||||
m_pivot2world = matrix4_translation_for_vec3( object_pivot );
|
||||
}
|
||||
else{
|
||||
// m_pivot2world = matrix4_translation_for_vec3( vector4_to_vector3( m_pivot2world.t() ) );
|
||||
matrix4_assign_rotation( m_pivot2world, g_matrix4_identity );
|
||||
}
|
||||
|
||||
ConstructPivotRotation();
|
||||
}
|
||||
}
|
||||
|
||||
void RadiantSelectionSystem::setCustomTransformOrigin( const Vector3& origin, const bool set[3] ) const {
|
||||
AABB bounds( getSelectionAABB() );
|
||||
setCustomTransformOrigin( origin, set, bounds );
|
||||
}
|
||||
|
||||
void RadiantSelectionSystem::setCustomTransformOrigin( const Vector3& origin, const bool set[3], const AABB& bounds ) const {
|
||||
if ( !nothingSelected() && transformOrigin_isTranslatable() ) {
|
||||
|
||||
//globalOutputStream() << origin << "\n";
|
||||
for( std::size_t i = 0; i < 3; i++ ){
|
||||
float value = origin[i];
|
||||
if( set[i] ){
|
||||
float bestsnapDist = fabs( bounds.origin[i] - value );
|
||||
float bestsnapTo = bounds.origin[i];
|
||||
float othersnapDist = fabs( bounds.origin[i] + bounds.extents[i] - value );
|
||||
float bestsnapDist = fabs( m_bounds.origin[i] - value );
|
||||
float bestsnapTo = m_bounds.origin[i];
|
||||
float othersnapDist = fabs( m_bounds.origin[i] + m_bounds.extents[i] - value );
|
||||
if( othersnapDist < bestsnapDist ){
|
||||
bestsnapDist = othersnapDist;
|
||||
bestsnapTo = bounds.origin[i] + bounds.extents[i];
|
||||
bestsnapTo = m_bounds.origin[i] + m_bounds.extents[i];
|
||||
}
|
||||
othersnapDist = fabs( bounds.origin[i] - bounds.extents[i] - value );
|
||||
othersnapDist = fabs( m_bounds.origin[i] - m_bounds.extents[i] - value );
|
||||
if( othersnapDist < bestsnapDist ){
|
||||
bestsnapDist = othersnapDist;
|
||||
bestsnapTo = bounds.origin[i] - bounds.extents[i];
|
||||
bestsnapTo = m_bounds.origin[i] - m_bounds.extents[i];
|
||||
}
|
||||
othersnapDist = fabs( float_snapped( value, GetSnapGridSize() ) - value );
|
||||
if( othersnapDist < bestsnapDist ){
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user