2024-08-16 14:37:22 +02:00
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.89 WIP
//
2017-12-31 10:50:49 +01:00
// The MIT License(MIT)
2021-07-08 16:09:40 +02:00
//
// Copyright(c) 2021 Cedric Guillemet
//
2017-12-31 10:50:49 +01:00
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
2021-07-08 16:09:40 +02:00
//
2017-12-31 10:50:49 +01:00
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
2021-07-08 16:09:40 +02:00
//
2017-12-31 10:50:49 +01:00
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
2024-08-16 14:37:22 +02:00
//
2017-12-31 10:50:49 +01:00
# ifndef IMGUI_DEFINE_MATH_OPERATORS
# define IMGUI_DEFINE_MATH_OPERATORS
# endif
2024-08-16 14:37:22 +02:00
# include "imgui.h"
2017-12-31 10:50:49 +01:00
# include "imgui_internal.h"
# include "ImGuizmo.h"
2024-08-16 14:37:22 +02:00
# if defined(_MSC_VER) || defined(__MINGW32__)
# include <malloc.h>
# endif
# if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
2021-07-08 16:09:40 +02:00
# define _malloca(x) alloca(x)
# define _freea(x)
# endif
2017-12-31 10:50:49 +01:00
// includes patches for multiview from
// https://github.com/CedricGuillemet/ImGuizmo/issues/15
2024-08-16 14:37:22 +02:00
namespace IMGUIZMO_NAMESPACE
2017-12-31 10:50:49 +01:00
{
static const float ZPI = 3.14159265358979323846f ;
static const float RAD2DEG = ( 180.f / ZPI ) ;
static const float DEG2RAD = ( ZPI / 180.f ) ;
const float screenRotateSize = 0.06f ;
2024-08-16 14:37:22 +02:00
// scale a bit so translate axis do not touch when in universal
const float rotationDisplayFactor = 1.2f ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
static OPERATION operator & ( OPERATION lhs , OPERATION rhs )
{
return static_cast < OPERATION > ( static_cast < int > ( lhs ) & static_cast < int > ( rhs ) ) ;
}
static bool operator ! = ( OPERATION lhs , int rhs )
{
return static_cast < int > ( lhs ) ! = rhs ;
}
static bool Intersects ( OPERATION lhs , OPERATION rhs )
{
return ( lhs & rhs ) ! = 0 ;
}
// True if lhs contains rhs
static bool Contains ( OPERATION lhs , OPERATION rhs )
{
return ( lhs & rhs ) = = rhs ;
}
2017-12-31 10:50:49 +01:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// utility and math
2021-07-08 16:09:40 +02:00
void FPU_MatrixF_x_MatrixF ( const float * a , const float * b , float * r )
2017-12-31 10:50:49 +01:00
{
r [ 0 ] = a [ 0 ] * b [ 0 ] + a [ 1 ] * b [ 4 ] + a [ 2 ] * b [ 8 ] + a [ 3 ] * b [ 12 ] ;
r [ 1 ] = a [ 0 ] * b [ 1 ] + a [ 1 ] * b [ 5 ] + a [ 2 ] * b [ 9 ] + a [ 3 ] * b [ 13 ] ;
r [ 2 ] = a [ 0 ] * b [ 2 ] + a [ 1 ] * b [ 6 ] + a [ 2 ] * b [ 10 ] + a [ 3 ] * b [ 14 ] ;
r [ 3 ] = a [ 0 ] * b [ 3 ] + a [ 1 ] * b [ 7 ] + a [ 2 ] * b [ 11 ] + a [ 3 ] * b [ 15 ] ;
r [ 4 ] = a [ 4 ] * b [ 0 ] + a [ 5 ] * b [ 4 ] + a [ 6 ] * b [ 8 ] + a [ 7 ] * b [ 12 ] ;
r [ 5 ] = a [ 4 ] * b [ 1 ] + a [ 5 ] * b [ 5 ] + a [ 6 ] * b [ 9 ] + a [ 7 ] * b [ 13 ] ;
r [ 6 ] = a [ 4 ] * b [ 2 ] + a [ 5 ] * b [ 6 ] + a [ 6 ] * b [ 10 ] + a [ 7 ] * b [ 14 ] ;
r [ 7 ] = a [ 4 ] * b [ 3 ] + a [ 5 ] * b [ 7 ] + a [ 6 ] * b [ 11 ] + a [ 7 ] * b [ 15 ] ;
r [ 8 ] = a [ 8 ] * b [ 0 ] + a [ 9 ] * b [ 4 ] + a [ 10 ] * b [ 8 ] + a [ 11 ] * b [ 12 ] ;
r [ 9 ] = a [ 8 ] * b [ 1 ] + a [ 9 ] * b [ 5 ] + a [ 10 ] * b [ 9 ] + a [ 11 ] * b [ 13 ] ;
r [ 10 ] = a [ 8 ] * b [ 2 ] + a [ 9 ] * b [ 6 ] + a [ 10 ] * b [ 10 ] + a [ 11 ] * b [ 14 ] ;
r [ 11 ] = a [ 8 ] * b [ 3 ] + a [ 9 ] * b [ 7 ] + a [ 10 ] * b [ 11 ] + a [ 11 ] * b [ 15 ] ;
r [ 12 ] = a [ 12 ] * b [ 0 ] + a [ 13 ] * b [ 4 ] + a [ 14 ] * b [ 8 ] + a [ 15 ] * b [ 12 ] ;
r [ 13 ] = a [ 12 ] * b [ 1 ] + a [ 13 ] * b [ 5 ] + a [ 14 ] * b [ 9 ] + a [ 15 ] * b [ 13 ] ;
r [ 14 ] = a [ 12 ] * b [ 2 ] + a [ 13 ] * b [ 6 ] + a [ 14 ] * b [ 10 ] + a [ 15 ] * b [ 14 ] ;
r [ 15 ] = a [ 12 ] * b [ 3 ] + a [ 13 ] * b [ 7 ] + a [ 14 ] * b [ 11 ] + a [ 15 ] * b [ 15 ] ;
}
2021-07-08 16:09:40 +02:00
void Frustum ( float left , float right , float bottom , float top , float znear , float zfar , float * m16 )
{
float temp , temp2 , temp3 , temp4 ;
temp = 2.0f * znear ;
temp2 = right - left ;
temp3 = top - bottom ;
temp4 = zfar - znear ;
m16 [ 0 ] = temp / temp2 ;
m16 [ 1 ] = 0.0 ;
m16 [ 2 ] = 0.0 ;
m16 [ 3 ] = 0.0 ;
m16 [ 4 ] = 0.0 ;
m16 [ 5 ] = temp / temp3 ;
m16 [ 6 ] = 0.0 ;
m16 [ 7 ] = 0.0 ;
m16 [ 8 ] = ( right + left ) / temp2 ;
m16 [ 9 ] = ( top + bottom ) / temp3 ;
m16 [ 10 ] = ( - zfar - znear ) / temp4 ;
m16 [ 11 ] = - 1.0f ;
m16 [ 12 ] = 0.0 ;
m16 [ 13 ] = 0.0 ;
m16 [ 14 ] = ( - temp * zfar ) / temp4 ;
m16 [ 15 ] = 0.0 ;
}
void Perspective ( float fovyInDegrees , float aspectRatio , float znear , float zfar , float * m16 )
{
float ymax , xmax ;
ymax = znear * tanf ( fovyInDegrees * DEG2RAD ) ;
xmax = ymax * aspectRatio ;
Frustum ( - xmax , xmax , - ymax , ymax , znear , zfar , m16 ) ;
}
void Cross ( const float * a , const float * b , float * r )
{
r [ 0 ] = a [ 1 ] * b [ 2 ] - a [ 2 ] * b [ 1 ] ;
r [ 1 ] = a [ 2 ] * b [ 0 ] - a [ 0 ] * b [ 2 ] ;
r [ 2 ] = a [ 0 ] * b [ 1 ] - a [ 1 ] * b [ 0 ] ;
}
float Dot ( const float * a , const float * b )
{
return a [ 0 ] * b [ 0 ] + a [ 1 ] * b [ 1 ] + a [ 2 ] * b [ 2 ] ;
}
void Normalize ( const float * a , float * r )
{
float il = 1.f / ( sqrtf ( Dot ( a , a ) ) + FLT_EPSILON ) ;
r [ 0 ] = a [ 0 ] * il ;
r [ 1 ] = a [ 1 ] * il ;
r [ 2 ] = a [ 2 ] * il ;
}
void LookAt ( const float * eye , const float * at , const float * up , float * m16 )
{
float X [ 3 ] , Y [ 3 ] , Z [ 3 ] , tmp [ 3 ] ;
tmp [ 0 ] = eye [ 0 ] - at [ 0 ] ;
tmp [ 1 ] = eye [ 1 ] - at [ 1 ] ;
tmp [ 2 ] = eye [ 2 ] - at [ 2 ] ;
Normalize ( tmp , Z ) ;
Normalize ( up , Y ) ;
Cross ( Y , Z , tmp ) ;
Normalize ( tmp , X ) ;
Cross ( Z , X , tmp ) ;
Normalize ( tmp , Y ) ;
m16 [ 0 ] = X [ 0 ] ;
m16 [ 1 ] = Y [ 0 ] ;
m16 [ 2 ] = Z [ 0 ] ;
m16 [ 3 ] = 0.0f ;
m16 [ 4 ] = X [ 1 ] ;
m16 [ 5 ] = Y [ 1 ] ;
m16 [ 6 ] = Z [ 1 ] ;
m16 [ 7 ] = 0.0f ;
m16 [ 8 ] = X [ 2 ] ;
m16 [ 9 ] = Y [ 2 ] ;
m16 [ 10 ] = Z [ 2 ] ;
m16 [ 11 ] = 0.0f ;
m16 [ 12 ] = - Dot ( X , eye ) ;
m16 [ 13 ] = - Dot ( Y , eye ) ;
m16 [ 14 ] = - Dot ( Z , eye ) ;
m16 [ 15 ] = 1.0f ;
}
template < typename T > T Clamp ( T x , T y , T z ) { return ( ( x < y ) ? y : ( ( x > z ) ? z : x ) ) ; }
2017-12-31 10:50:49 +01:00
template < typename T > T max ( T x , T y ) { return ( x > y ) ? x : y ; }
template < typename T > T min ( T x , T y ) { return ( x < y ) ? x : y ; }
2021-07-08 16:09:40 +02:00
template < typename T > bool IsWithin ( T x , T y , T z ) { return ( x > = y ) & & ( x < = z ) ; }
2017-12-31 10:50:49 +01:00
struct matrix_t ;
struct vec_t
{
public :
float x , y , z , w ;
void Lerp ( const vec_t & v , float t )
{
x + = ( v . x - x ) * t ;
y + = ( v . y - y ) * t ;
z + = ( v . z - z ) * t ;
w + = ( v . w - w ) * t ;
}
void Set ( float v ) { x = y = z = w = v ; }
void Set ( float _x , float _y , float _z = 0.f , float _w = 0.f ) { x = _x ; y = _y ; z = _z ; w = _w ; }
vec_t & operator - = ( const vec_t & v ) { x - = v . x ; y - = v . y ; z - = v . z ; w - = v . w ; return * this ; }
vec_t & operator + = ( const vec_t & v ) { x + = v . x ; y + = v . y ; z + = v . z ; w + = v . w ; return * this ; }
vec_t & operator * = ( const vec_t & v ) { x * = v . x ; y * = v . y ; z * = v . z ; w * = v . w ; return * this ; }
vec_t & operator * = ( float v ) { x * = v ; y * = v ; z * = v ; w * = v ; return * this ; }
vec_t operator * ( float f ) const ;
vec_t operator - ( ) const ;
vec_t operator - ( const vec_t & v ) const ;
vec_t operator + ( const vec_t & v ) const ;
vec_t operator * ( const vec_t & v ) const ;
const vec_t & operator + ( ) const { return ( * this ) ; }
2021-07-08 16:09:40 +02:00
float Length ( ) const { return sqrtf ( x * x + y * y + z * z ) ; } ;
float LengthSq ( ) const { return ( x * x + y * y + z * z ) ; } ;
2024-08-16 14:37:22 +02:00
vec_t Normalize ( ) { ( * this ) * = ( 1.f / ( Length ( ) > FLT_EPSILON ? Length ( ) : FLT_EPSILON ) ) ; return ( * this ) ; }
2017-12-31 10:50:49 +01:00
vec_t Normalize ( const vec_t & v ) { this - > Set ( v . x , v . y , v . z , v . w ) ; this - > Normalize ( ) ; return ( * this ) ; }
vec_t Abs ( ) const ;
2021-07-08 16:09:40 +02:00
2017-12-31 10:50:49 +01:00
void Cross ( const vec_t & v )
{
vec_t res ;
res . x = y * v . z - z * v . y ;
res . y = z * v . x - x * v . z ;
res . z = x * v . y - y * v . x ;
x = res . x ;
y = res . y ;
z = res . z ;
w = 0.f ;
}
2021-07-08 16:09:40 +02:00
2017-12-31 10:50:49 +01:00
void Cross ( const vec_t & v1 , const vec_t & v2 )
{
x = v1 . y * v2 . z - v1 . z * v2 . y ;
y = v1 . z * v2 . x - v1 . x * v2 . z ;
z = v1 . x * v2 . y - v1 . y * v2 . x ;
w = 0.f ;
}
2021-07-08 16:09:40 +02:00
float Dot ( const vec_t & v ) const
2017-12-31 10:50:49 +01:00
{
return ( x * v . x ) + ( y * v . y ) + ( z * v . z ) + ( w * v . w ) ;
}
2021-07-08 16:09:40 +02:00
float Dot3 ( const vec_t & v ) const
2017-12-31 10:50:49 +01:00
{
return ( x * v . x ) + ( y * v . y ) + ( z * v . z ) ;
}
2021-07-08 16:09:40 +02:00
2017-12-31 10:50:49 +01:00
void Transform ( const matrix_t & matrix ) ;
2021-07-08 16:09:40 +02:00
void Transform ( const vec_t & s , const matrix_t & matrix ) ;
2017-12-31 10:50:49 +01:00
void TransformVector ( const matrix_t & matrix ) ;
void TransformPoint ( const matrix_t & matrix ) ;
void TransformVector ( const vec_t & v , const matrix_t & matrix ) { ( * this ) = v ; this - > TransformVector ( matrix ) ; }
void TransformPoint ( const vec_t & v , const matrix_t & matrix ) { ( * this ) = v ; this - > TransformPoint ( matrix ) ; }
float & operator [ ] ( size_t index ) { return ( ( float * ) & x ) [ index ] ; }
const float & operator [ ] ( size_t index ) const { return ( ( float * ) & x ) [ index ] ; }
2024-08-16 14:37:22 +02:00
bool operator ! = ( const vec_t & other ) const { return memcmp ( this , & other , sizeof ( vec_t ) ) ! = 0 ; }
2017-12-31 10:50:49 +01:00
} ;
vec_t makeVect ( float _x , float _y , float _z = 0.f , float _w = 0.f ) { vec_t res ; res . x = _x ; res . y = _y ; res . z = _z ; res . w = _w ; return res ; }
2021-07-08 16:09:40 +02:00
vec_t makeVect ( ImVec2 v ) { vec_t res ; res . x = v . x ; res . y = v . y ; res . z = 0.f ; res . w = 0.f ; return res ; }
vec_t vec_t : : operator * ( float f ) const { return makeVect ( x * f , y * f , z * f , w * f ) ; }
2017-12-31 10:50:49 +01:00
vec_t vec_t : : operator - ( ) const { return makeVect ( - x , - y , - z , - w ) ; }
vec_t vec_t : : operator - ( const vec_t & v ) const { return makeVect ( x - v . x , y - v . y , z - v . z , w - v . w ) ; }
vec_t vec_t : : operator + ( const vec_t & v ) const { return makeVect ( x + v . x , y + v . y , z + v . z , w + v . w ) ; }
vec_t vec_t : : operator * ( const vec_t & v ) const { return makeVect ( x * v . x , y * v . y , z * v . z , w * v . w ) ; }
vec_t vec_t : : Abs ( ) const { return makeVect ( fabsf ( x ) , fabsf ( y ) , fabsf ( z ) ) ; }
vec_t Normalized ( const vec_t & v ) { vec_t res ; res = v ; res . Normalize ( ) ; return res ; }
vec_t Cross ( const vec_t & v1 , const vec_t & v2 )
{
vec_t res ;
res . x = v1 . y * v2 . z - v1 . z * v2 . y ;
res . y = v1 . z * v2 . x - v1 . x * v2 . z ;
res . z = v1 . x * v2 . y - v1 . y * v2 . x ;
res . w = 0.f ;
return res ;
}
2021-07-08 16:09:40 +02:00
float Dot ( const vec_t & v1 , const vec_t & v2 )
2017-12-31 10:50:49 +01:00
{
return ( v1 . x * v2 . x ) + ( v1 . y * v2 . y ) + ( v1 . z * v2 . z ) ;
}
2021-07-08 16:09:40 +02:00
vec_t BuildPlan ( const vec_t & p_point1 , const vec_t & p_normal )
2017-12-31 10:50:49 +01:00
{
vec_t normal , res ;
normal . Normalize ( p_normal ) ;
res . w = normal . Dot ( p_point1 ) ;
res . x = normal . x ;
res . y = normal . y ;
res . z = normal . z ;
return res ;
}
struct matrix_t
{
public :
union
{
float m [ 4 ] [ 4 ] ;
float m16 [ 16 ] ;
struct
{
vec_t right , up , dir , position ;
} v ;
vec_t component [ 4 ] ;
} ;
2021-07-08 16:09:40 +02:00
operator float * ( ) { return m16 ; }
2017-12-31 10:50:49 +01:00
operator const float * ( ) const { return m16 ; }
void Translation ( float _x , float _y , float _z ) { this - > Translation ( makeVect ( _x , _y , _z ) ) ; }
void Translation ( const vec_t & vt )
{
v . right . Set ( 1.f , 0.f , 0.f , 0.f ) ;
v . up . Set ( 0.f , 1.f , 0.f , 0.f ) ;
v . dir . Set ( 0.f , 0.f , 1.f , 0.f ) ;
v . position . Set ( vt . x , vt . y , vt . z , 1.f ) ;
}
void Scale ( float _x , float _y , float _z )
{
v . right . Set ( _x , 0.f , 0.f , 0.f ) ;
v . up . Set ( 0.f , _y , 0.f , 0.f ) ;
v . dir . Set ( 0.f , 0.f , _z , 0.f ) ;
v . position . Set ( 0.f , 0.f , 0.f , 1.f ) ;
}
void Scale ( const vec_t & s ) { Scale ( s . x , s . y , s . z ) ; }
matrix_t & operator * = ( const matrix_t & mat )
{
matrix_t tmpMat ;
tmpMat = * this ;
tmpMat . Multiply ( mat ) ;
* this = tmpMat ;
return * this ;
}
matrix_t operator * ( const matrix_t & mat ) const
{
matrix_t matT ;
matT . Multiply ( * this , mat ) ;
return matT ;
}
2021-07-08 16:09:40 +02:00
void Multiply ( const matrix_t & matrix )
2017-12-31 10:50:49 +01:00
{
matrix_t tmp ;
tmp = * this ;
FPU_MatrixF_x_MatrixF ( ( float * ) & tmp , ( float * ) & matrix , ( float * ) this ) ;
}
2021-07-08 16:09:40 +02:00
void Multiply ( const matrix_t & m1 , const matrix_t & m2 )
2017-12-31 10:50:49 +01:00
{
FPU_MatrixF_x_MatrixF ( ( float * ) & m1 , ( float * ) & m2 , ( float * ) this ) ;
}
float GetDeterminant ( ) const
{
return m [ 0 ] [ 0 ] * m [ 1 ] [ 1 ] * m [ 2 ] [ 2 ] + m [ 0 ] [ 1 ] * m [ 1 ] [ 2 ] * m [ 2 ] [ 0 ] + m [ 0 ] [ 2 ] * m [ 1 ] [ 0 ] * m [ 2 ] [ 1 ] -
m [ 0 ] [ 2 ] * m [ 1 ] [ 1 ] * m [ 2 ] [ 0 ] - m [ 0 ] [ 1 ] * m [ 1 ] [ 0 ] * m [ 2 ] [ 2 ] - m [ 0 ] [ 0 ] * m [ 1 ] [ 2 ] * m [ 2 ] [ 1 ] ;
}
2021-07-08 16:09:40 +02:00
float Inverse ( const matrix_t & srcMatrix , bool affine = false ) ;
void SetToIdentity ( )
2017-12-31 10:50:49 +01:00
{
v . right . Set ( 1.f , 0.f , 0.f , 0.f ) ;
v . up . Set ( 0.f , 1.f , 0.f , 0.f ) ;
v . dir . Set ( 0.f , 0.f , 1.f , 0.f ) ;
v . position . Set ( 0.f , 0.f , 0.f , 1.f ) ;
}
void Transpose ( )
{
matrix_t tmpm ;
for ( int l = 0 ; l < 4 ; l + + )
{
for ( int c = 0 ; c < 4 ; c + + )
{
tmpm . m [ l ] [ c ] = m [ c ] [ l ] ;
}
}
( * this ) = tmpm ;
}
2021-07-08 16:09:40 +02:00
void RotationAxis ( const vec_t & axis , float angle ) ;
2017-12-31 10:50:49 +01:00
void OrthoNormalize ( )
{
v . right . Normalize ( ) ;
v . up . Normalize ( ) ;
v . dir . Normalize ( ) ;
}
} ;
void vec_t : : Transform ( const matrix_t & matrix )
{
vec_t out ;
out . x = x * matrix . m [ 0 ] [ 0 ] + y * matrix . m [ 1 ] [ 0 ] + z * matrix . m [ 2 ] [ 0 ] + w * matrix . m [ 3 ] [ 0 ] ;
out . y = x * matrix . m [ 0 ] [ 1 ] + y * matrix . m [ 1 ] [ 1 ] + z * matrix . m [ 2 ] [ 1 ] + w * matrix . m [ 3 ] [ 1 ] ;
out . z = x * matrix . m [ 0 ] [ 2 ] + y * matrix . m [ 1 ] [ 2 ] + z * matrix . m [ 2 ] [ 2 ] + w * matrix . m [ 3 ] [ 2 ] ;
out . w = x * matrix . m [ 0 ] [ 3 ] + y * matrix . m [ 1 ] [ 3 ] + z * matrix . m [ 2 ] [ 3 ] + w * matrix . m [ 3 ] [ 3 ] ;
x = out . x ;
y = out . y ;
z = out . z ;
w = out . w ;
}
2021-07-08 16:09:40 +02:00
void vec_t : : Transform ( const vec_t & s , const matrix_t & matrix )
2017-12-31 10:50:49 +01:00
{
* this = s ;
Transform ( matrix ) ;
}
void vec_t : : TransformPoint ( const matrix_t & matrix )
{
vec_t out ;
out . x = x * matrix . m [ 0 ] [ 0 ] + y * matrix . m [ 1 ] [ 0 ] + z * matrix . m [ 2 ] [ 0 ] + matrix . m [ 3 ] [ 0 ] ;
out . y = x * matrix . m [ 0 ] [ 1 ] + y * matrix . m [ 1 ] [ 1 ] + z * matrix . m [ 2 ] [ 1 ] + matrix . m [ 3 ] [ 1 ] ;
out . z = x * matrix . m [ 0 ] [ 2 ] + y * matrix . m [ 1 ] [ 2 ] + z * matrix . m [ 2 ] [ 2 ] + matrix . m [ 3 ] [ 2 ] ;
out . w = x * matrix . m [ 0 ] [ 3 ] + y * matrix . m [ 1 ] [ 3 ] + z * matrix . m [ 2 ] [ 3 ] + matrix . m [ 3 ] [ 3 ] ;
x = out . x ;
y = out . y ;
z = out . z ;
w = out . w ;
}
void vec_t : : TransformVector ( const matrix_t & matrix )
{
vec_t out ;
out . x = x * matrix . m [ 0 ] [ 0 ] + y * matrix . m [ 1 ] [ 0 ] + z * matrix . m [ 2 ] [ 0 ] ;
out . y = x * matrix . m [ 0 ] [ 1 ] + y * matrix . m [ 1 ] [ 1 ] + z * matrix . m [ 2 ] [ 1 ] ;
out . z = x * matrix . m [ 0 ] [ 2 ] + y * matrix . m [ 1 ] [ 2 ] + z * matrix . m [ 2 ] [ 2 ] ;
out . w = x * matrix . m [ 0 ] [ 3 ] + y * matrix . m [ 1 ] [ 3 ] + z * matrix . m [ 2 ] [ 3 ] ;
x = out . x ;
y = out . y ;
z = out . z ;
w = out . w ;
}
2021-07-08 16:09:40 +02:00
float matrix_t : : Inverse ( const matrix_t & srcMatrix , bool affine )
2017-12-31 10:50:49 +01:00
{
float det = 0 ;
if ( affine )
{
det = GetDeterminant ( ) ;
float s = 1 / det ;
m [ 0 ] [ 0 ] = ( srcMatrix . m [ 1 ] [ 1 ] * srcMatrix . m [ 2 ] [ 2 ] - srcMatrix . m [ 1 ] [ 2 ] * srcMatrix . m [ 2 ] [ 1 ] ) * s ;
m [ 0 ] [ 1 ] = ( srcMatrix . m [ 2 ] [ 1 ] * srcMatrix . m [ 0 ] [ 2 ] - srcMatrix . m [ 2 ] [ 2 ] * srcMatrix . m [ 0 ] [ 1 ] ) * s ;
m [ 0 ] [ 2 ] = ( srcMatrix . m [ 0 ] [ 1 ] * srcMatrix . m [ 1 ] [ 2 ] - srcMatrix . m [ 0 ] [ 2 ] * srcMatrix . m [ 1 ] [ 1 ] ) * s ;
m [ 1 ] [ 0 ] = ( srcMatrix . m [ 1 ] [ 2 ] * srcMatrix . m [ 2 ] [ 0 ] - srcMatrix . m [ 1 ] [ 0 ] * srcMatrix . m [ 2 ] [ 2 ] ) * s ;
m [ 1 ] [ 1 ] = ( srcMatrix . m [ 2 ] [ 2 ] * srcMatrix . m [ 0 ] [ 0 ] - srcMatrix . m [ 2 ] [ 0 ] * srcMatrix . m [ 0 ] [ 2 ] ) * s ;
m [ 1 ] [ 2 ] = ( srcMatrix . m [ 0 ] [ 2 ] * srcMatrix . m [ 1 ] [ 0 ] - srcMatrix . m [ 0 ] [ 0 ] * srcMatrix . m [ 1 ] [ 2 ] ) * s ;
m [ 2 ] [ 0 ] = ( srcMatrix . m [ 1 ] [ 0 ] * srcMatrix . m [ 2 ] [ 1 ] - srcMatrix . m [ 1 ] [ 1 ] * srcMatrix . m [ 2 ] [ 0 ] ) * s ;
m [ 2 ] [ 1 ] = ( srcMatrix . m [ 2 ] [ 0 ] * srcMatrix . m [ 0 ] [ 1 ] - srcMatrix . m [ 2 ] [ 1 ] * srcMatrix . m [ 0 ] [ 0 ] ) * s ;
m [ 2 ] [ 2 ] = ( srcMatrix . m [ 0 ] [ 0 ] * srcMatrix . m [ 1 ] [ 1 ] - srcMatrix . m [ 0 ] [ 1 ] * srcMatrix . m [ 1 ] [ 0 ] ) * s ;
m [ 3 ] [ 0 ] = - ( m [ 0 ] [ 0 ] * srcMatrix . m [ 3 ] [ 0 ] + m [ 1 ] [ 0 ] * srcMatrix . m [ 3 ] [ 1 ] + m [ 2 ] [ 0 ] * srcMatrix . m [ 3 ] [ 2 ] ) ;
m [ 3 ] [ 1 ] = - ( m [ 0 ] [ 1 ] * srcMatrix . m [ 3 ] [ 0 ] + m [ 1 ] [ 1 ] * srcMatrix . m [ 3 ] [ 1 ] + m [ 2 ] [ 1 ] * srcMatrix . m [ 3 ] [ 2 ] ) ;
m [ 3 ] [ 2 ] = - ( m [ 0 ] [ 2 ] * srcMatrix . m [ 3 ] [ 0 ] + m [ 1 ] [ 2 ] * srcMatrix . m [ 3 ] [ 1 ] + m [ 2 ] [ 2 ] * srcMatrix . m [ 3 ] [ 2 ] ) ;
}
else
{
// transpose matrix
float src [ 16 ] ;
for ( int i = 0 ; i < 4 ; + + i )
{
src [ i ] = srcMatrix . m16 [ i * 4 ] ;
src [ i + 4 ] = srcMatrix . m16 [ i * 4 + 1 ] ;
src [ i + 8 ] = srcMatrix . m16 [ i * 4 + 2 ] ;
src [ i + 12 ] = srcMatrix . m16 [ i * 4 + 3 ] ;
}
// calculate pairs for first 8 elements (cofactors)
float tmp [ 12 ] ; // temp array for pairs
tmp [ 0 ] = src [ 10 ] * src [ 15 ] ;
tmp [ 1 ] = src [ 11 ] * src [ 14 ] ;
tmp [ 2 ] = src [ 9 ] * src [ 15 ] ;
tmp [ 3 ] = src [ 11 ] * src [ 13 ] ;
tmp [ 4 ] = src [ 9 ] * src [ 14 ] ;
tmp [ 5 ] = src [ 10 ] * src [ 13 ] ;
tmp [ 6 ] = src [ 8 ] * src [ 15 ] ;
tmp [ 7 ] = src [ 11 ] * src [ 12 ] ;
tmp [ 8 ] = src [ 8 ] * src [ 14 ] ;
tmp [ 9 ] = src [ 10 ] * src [ 12 ] ;
tmp [ 10 ] = src [ 8 ] * src [ 13 ] ;
tmp [ 11 ] = src [ 9 ] * src [ 12 ] ;
// calculate first 8 elements (cofactors)
m16 [ 0 ] = ( tmp [ 0 ] * src [ 5 ] + tmp [ 3 ] * src [ 6 ] + tmp [ 4 ] * src [ 7 ] ) - ( tmp [ 1 ] * src [ 5 ] + tmp [ 2 ] * src [ 6 ] + tmp [ 5 ] * src [ 7 ] ) ;
m16 [ 1 ] = ( tmp [ 1 ] * src [ 4 ] + tmp [ 6 ] * src [ 6 ] + tmp [ 9 ] * src [ 7 ] ) - ( tmp [ 0 ] * src [ 4 ] + tmp [ 7 ] * src [ 6 ] + tmp [ 8 ] * src [ 7 ] ) ;
m16 [ 2 ] = ( tmp [ 2 ] * src [ 4 ] + tmp [ 7 ] * src [ 5 ] + tmp [ 10 ] * src [ 7 ] ) - ( tmp [ 3 ] * src [ 4 ] + tmp [ 6 ] * src [ 5 ] + tmp [ 11 ] * src [ 7 ] ) ;
m16 [ 3 ] = ( tmp [ 5 ] * src [ 4 ] + tmp [ 8 ] * src [ 5 ] + tmp [ 11 ] * src [ 6 ] ) - ( tmp [ 4 ] * src [ 4 ] + tmp [ 9 ] * src [ 5 ] + tmp [ 10 ] * src [ 6 ] ) ;
m16 [ 4 ] = ( tmp [ 1 ] * src [ 1 ] + tmp [ 2 ] * src [ 2 ] + tmp [ 5 ] * src [ 3 ] ) - ( tmp [ 0 ] * src [ 1 ] + tmp [ 3 ] * src [ 2 ] + tmp [ 4 ] * src [ 3 ] ) ;
m16 [ 5 ] = ( tmp [ 0 ] * src [ 0 ] + tmp [ 7 ] * src [ 2 ] + tmp [ 8 ] * src [ 3 ] ) - ( tmp [ 1 ] * src [ 0 ] + tmp [ 6 ] * src [ 2 ] + tmp [ 9 ] * src [ 3 ] ) ;
m16 [ 6 ] = ( tmp [ 3 ] * src [ 0 ] + tmp [ 6 ] * src [ 1 ] + tmp [ 11 ] * src [ 3 ] ) - ( tmp [ 2 ] * src [ 0 ] + tmp [ 7 ] * src [ 1 ] + tmp [ 10 ] * src [ 3 ] ) ;
m16 [ 7 ] = ( tmp [ 4 ] * src [ 0 ] + tmp [ 9 ] * src [ 1 ] + tmp [ 10 ] * src [ 2 ] ) - ( tmp [ 5 ] * src [ 0 ] + tmp [ 8 ] * src [ 1 ] + tmp [ 11 ] * src [ 2 ] ) ;
// calculate pairs for second 8 elements (cofactors)
tmp [ 0 ] = src [ 2 ] * src [ 7 ] ;
tmp [ 1 ] = src [ 3 ] * src [ 6 ] ;
tmp [ 2 ] = src [ 1 ] * src [ 7 ] ;
tmp [ 3 ] = src [ 3 ] * src [ 5 ] ;
tmp [ 4 ] = src [ 1 ] * src [ 6 ] ;
tmp [ 5 ] = src [ 2 ] * src [ 5 ] ;
tmp [ 6 ] = src [ 0 ] * src [ 7 ] ;
tmp [ 7 ] = src [ 3 ] * src [ 4 ] ;
tmp [ 8 ] = src [ 0 ] * src [ 6 ] ;
tmp [ 9 ] = src [ 2 ] * src [ 4 ] ;
tmp [ 10 ] = src [ 0 ] * src [ 5 ] ;
tmp [ 11 ] = src [ 1 ] * src [ 4 ] ;
// calculate second 8 elements (cofactors)
m16 [ 8 ] = ( tmp [ 0 ] * src [ 13 ] + tmp [ 3 ] * src [ 14 ] + tmp [ 4 ] * src [ 15 ] ) - ( tmp [ 1 ] * src [ 13 ] + tmp [ 2 ] * src [ 14 ] + tmp [ 5 ] * src [ 15 ] ) ;
m16 [ 9 ] = ( tmp [ 1 ] * src [ 12 ] + tmp [ 6 ] * src [ 14 ] + tmp [ 9 ] * src [ 15 ] ) - ( tmp [ 0 ] * src [ 12 ] + tmp [ 7 ] * src [ 14 ] + tmp [ 8 ] * src [ 15 ] ) ;
m16 [ 10 ] = ( tmp [ 2 ] * src [ 12 ] + tmp [ 7 ] * src [ 13 ] + tmp [ 10 ] * src [ 15 ] ) - ( tmp [ 3 ] * src [ 12 ] + tmp [ 6 ] * src [ 13 ] + tmp [ 11 ] * src [ 15 ] ) ;
m16 [ 11 ] = ( tmp [ 5 ] * src [ 12 ] + tmp [ 8 ] * src [ 13 ] + tmp [ 11 ] * src [ 14 ] ) - ( tmp [ 4 ] * src [ 12 ] + tmp [ 9 ] * src [ 13 ] + tmp [ 10 ] * src [ 14 ] ) ;
m16 [ 12 ] = ( tmp [ 2 ] * src [ 10 ] + tmp [ 5 ] * src [ 11 ] + tmp [ 1 ] * src [ 9 ] ) - ( tmp [ 4 ] * src [ 11 ] + tmp [ 0 ] * src [ 9 ] + tmp [ 3 ] * src [ 10 ] ) ;
m16 [ 13 ] = ( tmp [ 8 ] * src [ 11 ] + tmp [ 0 ] * src [ 8 ] + tmp [ 7 ] * src [ 10 ] ) - ( tmp [ 6 ] * src [ 10 ] + tmp [ 9 ] * src [ 11 ] + tmp [ 1 ] * src [ 8 ] ) ;
m16 [ 14 ] = ( tmp [ 6 ] * src [ 9 ] + tmp [ 11 ] * src [ 11 ] + tmp [ 3 ] * src [ 8 ] ) - ( tmp [ 10 ] * src [ 11 ] + tmp [ 2 ] * src [ 8 ] + tmp [ 7 ] * src [ 9 ] ) ;
m16 [ 15 ] = ( tmp [ 10 ] * src [ 10 ] + tmp [ 4 ] * src [ 8 ] + tmp [ 9 ] * src [ 9 ] ) - ( tmp [ 8 ] * src [ 9 ] + tmp [ 11 ] * src [ 10 ] + tmp [ 5 ] * src [ 8 ] ) ;
// calculate determinant
det = src [ 0 ] * m16 [ 0 ] + src [ 1 ] * m16 [ 1 ] + src [ 2 ] * m16 [ 2 ] + src [ 3 ] * m16 [ 3 ] ;
// calculate matrix inverse
float invdet = 1 / det ;
for ( int j = 0 ; j < 16 ; + + j )
{
m16 [ j ] * = invdet ;
}
}
return det ;
}
2021-07-08 16:09:40 +02:00
void matrix_t : : RotationAxis ( const vec_t & axis , float angle )
2017-12-31 10:50:49 +01:00
{
float length2 = axis . LengthSq ( ) ;
if ( length2 < FLT_EPSILON )
{
SetToIdentity ( ) ;
return ;
}
vec_t n = axis * ( 1.f / sqrtf ( length2 ) ) ;
float s = sinf ( angle ) ;
float c = cosf ( angle ) ;
float k = 1.f - c ;
float xx = n . x * n . x * k + c ;
float yy = n . y * n . y * k + c ;
float zz = n . z * n . z * k + c ;
float xy = n . x * n . y * k ;
float yz = n . y * n . z * k ;
float zx = n . z * n . x * k ;
float xs = n . x * s ;
float ys = n . y * s ;
float zs = n . z * s ;
m [ 0 ] [ 0 ] = xx ;
m [ 0 ] [ 1 ] = xy + zs ;
m [ 0 ] [ 2 ] = zx - ys ;
m [ 0 ] [ 3 ] = 0.f ;
m [ 1 ] [ 0 ] = xy - zs ;
m [ 1 ] [ 1 ] = yy ;
m [ 1 ] [ 2 ] = yz + xs ;
m [ 1 ] [ 3 ] = 0.f ;
m [ 2 ] [ 0 ] = zx + ys ;
m [ 2 ] [ 1 ] = yz - xs ;
m [ 2 ] [ 2 ] = zz ;
m [ 2 ] [ 3 ] = 0.f ;
m [ 3 ] [ 0 ] = 0.f ;
m [ 3 ] [ 1 ] = 0.f ;
m [ 3 ] [ 2 ] = 0.f ;
m [ 3 ] [ 3 ] = 1.f ;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2021-07-08 16:09:40 +02:00
//
2017-12-31 10:50:49 +01:00
enum MOVETYPE
{
2021-07-08 16:09:40 +02:00
MT_NONE ,
MT_MOVE_X ,
MT_MOVE_Y ,
MT_MOVE_Z ,
MT_MOVE_YZ ,
MT_MOVE_ZX ,
MT_MOVE_XY ,
MT_MOVE_SCREEN ,
MT_ROTATE_X ,
MT_ROTATE_Y ,
MT_ROTATE_Z ,
MT_ROTATE_SCREEN ,
MT_SCALE_X ,
MT_SCALE_Y ,
MT_SCALE_Z ,
MT_SCALE_XYZ
2017-12-31 10:50:49 +01:00
} ;
2021-07-08 16:09:40 +02:00
static bool IsTranslateType ( int type )
{
return type > = MT_MOVE_X & & type < = MT_MOVE_SCREEN ;
}
static bool IsRotateType ( int type )
{
return type > = MT_ROTATE_X & & type < = MT_ROTATE_SCREEN ;
}
static bool IsScaleType ( int type )
{
return type > = MT_SCALE_X & & type < = MT_SCALE_XYZ ;
}
// Matches MT_MOVE_AB order
static const OPERATION TRANSLATE_PLANS [ 3 ] = { TRANSLATE_Y | TRANSLATE_Z , TRANSLATE_X | TRANSLATE_Z , TRANSLATE_X | TRANSLATE_Y } ;
2024-08-16 14:37:22 +02:00
Style : : Style ( )
{
// default values
TranslationLineThickness = 3.0f ;
TranslationLineArrowSize = 6.0f ;
RotationLineThickness = 2.0f ;
RotationOuterLineThickness = 3.0f ;
ScaleLineThickness = 3.0f ;
ScaleLineCircleSize = 6.0f ;
HatchedAxisLineThickness = 6.0f ;
CenterCircleSize = 6.0f ;
// initialize default colors
Colors [ DIRECTION_X ] = ImVec4 ( 0.666f , 0.000f , 0.000f , 1.000f ) ;
Colors [ DIRECTION_Y ] = ImVec4 ( 0.000f , 0.666f , 0.000f , 1.000f ) ;
Colors [ DIRECTION_Z ] = ImVec4 ( 0.000f , 0.000f , 0.666f , 1.000f ) ;
Colors [ PLANE_X ] = ImVec4 ( 0.666f , 0.000f , 0.000f , 0.380f ) ;
Colors [ PLANE_Y ] = ImVec4 ( 0.000f , 0.666f , 0.000f , 0.380f ) ;
Colors [ PLANE_Z ] = ImVec4 ( 0.000f , 0.000f , 0.666f , 0.380f ) ;
Colors [ SELECTION ] = ImVec4 ( 1.000f , 0.500f , 0.062f , 0.541f ) ;
Colors [ INACTIVE ] = ImVec4 ( 0.600f , 0.600f , 0.600f , 0.600f ) ;
Colors [ TRANSLATION_LINE ] = ImVec4 ( 0.666f , 0.666f , 0.666f , 0.666f ) ;
Colors [ SCALE_LINE ] = ImVec4 ( 0.250f , 0.250f , 0.250f , 1.000f ) ;
Colors [ ROTATION_USING_BORDER ] = ImVec4 ( 1.000f , 0.500f , 0.062f , 1.000f ) ;
Colors [ ROTATION_USING_FILL ] = ImVec4 ( 1.000f , 0.500f , 0.062f , 0.500f ) ;
Colors [ HATCHED_AXIS_LINES ] = ImVec4 ( 0.000f , 0.000f , 0.000f , 0.500f ) ;
Colors [ TEXT ] = ImVec4 ( 1.000f , 1.000f , 1.000f , 1.000f ) ;
Colors [ TEXT_SHADOW ] = ImVec4 ( 0.000f , 0.000f , 0.000f , 1.000f ) ;
}
2017-12-31 10:50:49 +01:00
struct Context
{
Context ( ) : mbUsing ( false ) , mbEnable ( true ) , mbUsingBounds ( false )
{
}
ImDrawList * mDrawList ;
2024-08-16 14:37:22 +02:00
Style mStyle ;
2017-12-31 10:50:49 +01:00
MODE mMode ;
matrix_t mViewMat ;
matrix_t mProjectionMat ;
matrix_t mModel ;
2024-08-16 14:37:22 +02:00
matrix_t mModelLocal ; // orthonormalized model
2017-12-31 10:50:49 +01:00
matrix_t mModelInverse ;
matrix_t mModelSource ;
matrix_t mModelSourceInverse ;
matrix_t mMVP ;
2024-08-16 14:37:22 +02:00
matrix_t mMVPLocal ; // MVP with full model matrix whereas mMVP's model matrix might only be translation in case of World space edition
2017-12-31 10:50:49 +01:00
matrix_t mViewProjection ;
vec_t mModelScaleOrigin ;
vec_t mCameraEye ;
vec_t mCameraRight ;
vec_t mCameraDir ;
vec_t mCameraUp ;
vec_t mRayOrigin ;
vec_t mRayVector ;
float mRadiusSquareCenter ;
ImVec2 mScreenSquareCenter ;
ImVec2 mScreenSquareMin ;
ImVec2 mScreenSquareMax ;
float mScreenFactor ;
vec_t mRelativeOrigin ;
bool mbUsing ;
bool mbEnable ;
2024-08-16 14:37:22 +02:00
bool mbMouseOver ;
2021-07-08 16:09:40 +02:00
bool mReversed ; // reversed projection matrix
2017-12-31 10:50:49 +01:00
// translation
vec_t mTranslationPlan ;
vec_t mTranslationPlanOrigin ;
vec_t mMatrixOrigin ;
2021-07-08 16:09:40 +02:00
vec_t mTranslationLastDelta ;
2017-12-31 10:50:49 +01:00
// rotation
vec_t mRotationVectorSource ;
float mRotationAngle ;
float mRotationAngleOrigin ;
//vec_t mWorldToLocalAxis;
// scale
vec_t mScale ;
vec_t mScaleValueOrigin ;
2021-07-08 16:09:40 +02:00
vec_t mScaleLast ;
2017-12-31 10:50:49 +01:00
float mSaveMousePosx ;
// save axis factor when using gizmo
bool mBelowAxisLimit [ 3 ] ;
bool mBelowPlaneLimit [ 3 ] ;
float mAxisFactor [ 3 ] ;
2024-08-16 14:37:22 +02:00
float mAxisLimit = 0.0025f ;
float mPlaneLimit = 0.02f ;
2017-12-31 10:50:49 +01:00
// bounds stretching
vec_t mBoundsPivot ;
vec_t mBoundsAnchor ;
vec_t mBoundsPlan ;
vec_t mBoundsLocalPivot ;
int mBoundsBestAxis ;
int mBoundsAxis [ 2 ] ;
bool mbUsingBounds ;
matrix_t mBoundsMatrix ;
//
int mCurrentOperation ;
float mX = 0.f ;
float mY = 0.f ;
float mWidth = 0.f ;
float mHeight = 0.f ;
float mXMax = 0.f ;
float mYMax = 0.f ;
2021-07-08 16:09:40 +02:00
float mDisplayRatio = 1.f ;
bool mIsOrthographic = false ;
int mActualID = - 1 ;
int mEditingID = - 1 ;
OPERATION mOperation = OPERATION ( - 1 ) ;
bool mAllowAxisFlip = true ;
float mGizmoSizeClipSpace = 0.1f ;
2017-12-31 10:50:49 +01:00
} ;
static Context gContext ;
static const vec_t directionUnary [ 3 ] = { makeVect ( 1.f , 0.f , 0.f ) , makeVect ( 0.f , 1.f , 0.f ) , makeVect ( 0.f , 0.f , 1.f ) } ;
2021-07-08 16:09:40 +02:00
static const char * translationInfoMask [ ] = { " X : %5.3f " , " Y : %5.3f " , " Z : %5.3f " ,
" Y : %5.3f Z : %5.3f " , " X : %5.3f Z : %5.3f " , " X : %5.3f Y : %5.3f " ,
" X : %5.3f Y : %5.3f Z : %5.3f " } ;
static const char * scaleInfoMask [ ] = { " X : %5.2f " , " Y : %5.2f " , " Z : %5.2f " , " XYZ : %5.2f " } ;
static const char * rotationInfoMask [ ] = { " X : %5.2f deg %5.2f rad " , " Y : %5.2f deg %5.2f rad " , " Z : %5.2f deg %5.2f rad " , " Screen : %5.2f deg %5.2f rad " } ;
static const int translationInfoIndex [ ] = { 0 , 0 , 0 , 1 , 0 , 0 , 2 , 0 , 0 , 1 , 2 , 0 , 0 , 2 , 0 , 0 , 1 , 0 , 0 , 1 , 2 } ;
2017-12-31 10:50:49 +01:00
static const float quadMin = 0.5f ;
static const float quadMax = 0.8f ;
static const float quadUV [ 8 ] = { quadMin , quadMin , quadMin , quadMax , quadMax , quadMax , quadMax , quadMin } ;
static const int halfCircleSegmentCount = 64 ;
static const float snapTension = 0.5f ;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2021-07-08 16:09:40 +02:00
//
static int GetMoveType ( OPERATION op , vec_t * gizmoHitProportion ) ;
static int GetRotateType ( OPERATION op ) ;
static int GetScaleType ( OPERATION op ) ;
2017-12-31 10:50:49 +01:00
2024-08-16 14:37:22 +02:00
Style & GetStyle ( )
{
return gContext . mStyle ;
}
static ImU32 GetColorU32 ( int idx )
{
IM_ASSERT ( idx < COLOR : : COUNT ) ;
return ImGui : : ColorConvertFloat4ToU32 ( gContext . mStyle . Colors [ idx ] ) ;
}
2021-07-08 16:09:40 +02:00
static ImVec2 worldToPos ( const vec_t & worldPos , const matrix_t & mat , ImVec2 position = ImVec2 ( gContext . mX , gContext . mY ) , ImVec2 size = ImVec2 ( gContext . mWidth , gContext . mHeight ) )
2017-12-31 10:50:49 +01:00
{
vec_t trans ;
trans . TransformPoint ( worldPos , mat ) ;
trans * = 0.5f / trans . w ;
trans + = makeVect ( 0.5f , 0.5f ) ;
trans . y = 1.f - trans . y ;
2021-07-08 16:09:40 +02:00
trans . x * = size . x ;
trans . y * = size . y ;
trans . x + = position . x ;
trans . y + = position . y ;
2017-12-31 10:50:49 +01:00
return ImVec2 ( trans . x , trans . y ) ;
}
2021-07-08 16:09:40 +02:00
static void ComputeCameraRay ( vec_t & rayOrigin , vec_t & rayDir , ImVec2 position = ImVec2 ( gContext . mX , gContext . mY ) , ImVec2 size = ImVec2 ( gContext . mWidth , gContext . mHeight ) )
2017-12-31 10:50:49 +01:00
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
matrix_t mViewProjInverse ;
mViewProjInverse . Inverse ( gContext . mViewMat * gContext . mProjectionMat ) ;
2021-07-08 16:09:40 +02:00
const float mox = ( ( io . MousePos . x - position . x ) / size . x ) * 2.f - 1.f ;
const float moy = ( 1.f - ( ( io . MousePos . y - position . y ) / size . y ) ) * 2.f - 1.f ;
const float zNear = gContext . mReversed ? ( 1.f - FLT_EPSILON ) : 0.f ;
const float zFar = gContext . mReversed ? 0.f : ( 1.f - FLT_EPSILON ) ;
rayOrigin . Transform ( makeVect ( mox , moy , zNear , 1.f ) , mViewProjInverse ) ;
2017-12-31 10:50:49 +01:00
rayOrigin * = 1.f / rayOrigin . w ;
vec_t rayEnd ;
2021-07-08 16:09:40 +02:00
rayEnd . Transform ( makeVect ( mox , moy , zFar , 1.f ) , mViewProjInverse ) ;
2017-12-31 10:50:49 +01:00
rayEnd * = 1.f / rayEnd . w ;
rayDir = Normalized ( rayEnd - rayOrigin ) ;
}
2024-08-16 14:37:22 +02:00
static float GetSegmentLengthClipSpace ( const vec_t & start , const vec_t & end , const bool localCoordinates = false )
2021-07-08 16:09:40 +02:00
{
vec_t startOfSegment = start ;
2024-08-16 14:37:22 +02:00
const matrix_t & mvp = localCoordinates ? gContext . mMVPLocal : gContext . mMVP ;
startOfSegment . TransformPoint ( mvp ) ;
2021-07-08 16:09:40 +02:00
if ( fabsf ( startOfSegment . w ) > FLT_EPSILON ) // check for axis aligned with camera direction
{
startOfSegment * = 1.f / startOfSegment . w ;
}
vec_t endOfSegment = end ;
2024-08-16 14:37:22 +02:00
endOfSegment . TransformPoint ( mvp ) ;
2021-07-08 16:09:40 +02:00
if ( fabsf ( endOfSegment . w ) > FLT_EPSILON ) // check for axis aligned with camera direction
{
endOfSegment * = 1.f / endOfSegment . w ;
}
vec_t clipSpaceAxis = endOfSegment - startOfSegment ;
2024-08-16 14:37:22 +02:00
if ( gContext . mDisplayRatio < 1.0 )
clipSpaceAxis . x * = gContext . mDisplayRatio ;
else
clipSpaceAxis . y / = gContext . mDisplayRatio ;
2021-07-08 16:09:40 +02:00
float segmentLengthInClipSpace = sqrtf ( clipSpaceAxis . x * clipSpaceAxis . x + clipSpaceAxis . y * clipSpaceAxis . y ) ;
return segmentLengthInClipSpace ;
}
static float GetParallelogram ( const vec_t & ptO , const vec_t & ptA , const vec_t & ptB )
{
vec_t pts [ ] = { ptO , ptA , ptB } ;
for ( unsigned int i = 0 ; i < 3 ; i + + )
{
pts [ i ] . TransformPoint ( gContext . mMVP ) ;
if ( fabsf ( pts [ i ] . w ) > FLT_EPSILON ) // check for axis aligned with camera direction
{
pts [ i ] * = 1.f / pts [ i ] . w ;
}
}
vec_t segA = pts [ 1 ] - pts [ 0 ] ;
vec_t segB = pts [ 2 ] - pts [ 0 ] ;
segA . y / = gContext . mDisplayRatio ;
segB . y / = gContext . mDisplayRatio ;
vec_t segAOrtho = makeVect ( - segA . y , segA . x ) ;
segAOrtho . Normalize ( ) ;
float dt = segAOrtho . Dot3 ( segB ) ;
float surface = sqrtf ( segA . x * segA . x + segA . y * segA . y ) * fabsf ( dt ) ;
return surface ;
}
inline vec_t PointOnSegment ( const vec_t & point , const vec_t & vertPos1 , const vec_t & vertPos2 )
{
vec_t c = point - vertPos1 ;
vec_t V ;
V . Normalize ( vertPos2 - vertPos1 ) ;
float d = ( vertPos2 - vertPos1 ) . Length ( ) ;
float t = V . Dot3 ( c ) ;
if ( t < 0.f )
{
return vertPos1 ;
}
if ( t > d )
{
return vertPos2 ;
}
return vertPos1 + V * t ;
}
static float IntersectRayPlane ( const vec_t & rOrigin , const vec_t & rVector , const vec_t & plan )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
const float numer = plan . Dot3 ( rOrigin ) - plan . w ;
const float denom = plan . Dot3 ( rVector ) ;
2017-12-31 10:50:49 +01:00
if ( fabsf ( denom ) < FLT_EPSILON ) // normal is orthogonal to vector, cant intersect
2021-07-08 16:09:40 +02:00
{
2017-12-31 10:50:49 +01:00
return - 1.0f ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
return - ( numer / denom ) ;
}
2021-07-08 16:09:40 +02:00
static float DistanceToPlane ( const vec_t & point , const vec_t & plan )
{
return plan . Dot3 ( point ) + plan . w ;
}
static bool IsInContextRect ( ImVec2 p )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
return IsWithin ( p . x , gContext . mX , gContext . mXMax ) & & IsWithin ( p . y , gContext . mY , gContext . mYMax ) ;
2017-12-31 10:50:49 +01:00
}
2024-08-16 14:37:22 +02:00
static bool IsHoveringWindow ( )
{
ImGuiContext & g = * ImGui : : GetCurrentContext ( ) ;
ImGuiWindow * window = ImGui : : FindWindowByName ( gContext . mDrawList - > _OwnerName ) ;
if ( g . HoveredWindow = = window ) // Mouse hovering drawlist window
return true ;
if ( g . HoveredWindow ! = NULL ) // Any other window is hovered
return false ;
if ( ImGui : : IsMouseHoveringRect ( window - > InnerRect . Min , window - > InnerRect . Max , false ) ) // Hovering drawlist window rect, while no other window is hovered (for _NoInputs windows)
return true ;
return false ;
}
2017-12-31 10:50:49 +01:00
void SetRect ( float x , float y , float width , float height )
{
2021-07-08 16:09:40 +02:00
gContext . mX = x ;
gContext . mY = y ;
gContext . mWidth = width ;
gContext . mHeight = height ;
gContext . mXMax = gContext . mX + gContext . mWidth ;
gContext . mYMax = gContext . mY + gContext . mXMax ;
gContext . mDisplayRatio = width / height ;
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
void SetOrthographic ( bool isOrthographic )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
gContext . mIsOrthographic = isOrthographic ;
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
void SetDrawlist ( ImDrawList * drawlist )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
gContext . mDrawList = drawlist ? drawlist : ImGui : : GetWindowDrawList ( ) ;
}
void SetImGuiContext ( ImGuiContext * ctx )
{
ImGui : : SetCurrentContext ( ctx ) ;
}
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
void BeginFrame ( )
{
2017-12-31 10:50:49 +01:00
const ImU32 flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus ;
2021-07-08 16:09:40 +02:00
# ifdef IMGUI_HAS_VIEWPORT
ImGui : : SetNextWindowSize ( ImGui : : GetMainViewport ( ) - > Size ) ;
ImGui : : SetNextWindowPos ( ImGui : : GetMainViewport ( ) - > Pos ) ;
# else
ImGuiIO & io = ImGui : : GetIO ( ) ;
2017-12-31 10:50:49 +01:00
ImGui : : SetNextWindowSize ( io . DisplaySize ) ;
2021-07-08 16:09:40 +02:00
ImGui : : SetNextWindowPos ( ImVec2 ( 0 , 0 ) ) ;
# endif
ImGui : : PushStyleColor ( ImGuiCol_WindowBg , 0 ) ;
ImGui : : PushStyleColor ( ImGuiCol_Border , 0 ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , 0.0f ) ;
2017-12-31 10:50:49 +01:00
ImGui : : Begin ( " gizmo " , NULL , flags ) ;
gContext . mDrawList = ImGui : : GetWindowDrawList ( ) ;
ImGui : : End ( ) ;
2021-07-08 16:09:40 +02:00
ImGui : : PopStyleVar ( ) ;
ImGui : : PopStyleColor ( 2 ) ;
2017-12-31 10:50:49 +01:00
}
bool IsUsing ( )
2024-08-16 14:37:22 +02:00
{
return ( gContext . mbUsing & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) ) | | gContext . mbUsingBounds ;
}
bool IsUsingAny ( )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
return gContext . mbUsing | | gContext . mbUsingBounds ;
2017-12-31 10:50:49 +01:00
}
bool IsOver ( )
{
2021-07-08 16:09:40 +02:00
return ( Intersects ( gContext . mOperation , TRANSLATE ) & & GetMoveType ( gContext . mOperation , NULL ) ! = MT_NONE ) | |
( Intersects ( gContext . mOperation , ROTATE ) & & GetRotateType ( gContext . mOperation ) ! = MT_NONE ) | |
( Intersects ( gContext . mOperation , SCALE ) & & GetScaleType ( gContext . mOperation ) ! = MT_NONE ) | | IsUsing ( ) ;
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
bool IsOver ( OPERATION op )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
if ( IsUsing ( ) )
{
return true ;
}
if ( Intersects ( op , SCALE ) & & GetScaleType ( op ) ! = MT_NONE )
{
return true ;
}
if ( Intersects ( op , ROTATE ) & & GetRotateType ( op ) ! = MT_NONE )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
return true ;
}
if ( Intersects ( op , TRANSLATE ) & & GetMoveType ( op , NULL ) ! = MT_NONE )
{
return true ;
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
return false ;
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
void Enable ( bool enable )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
gContext . mbEnable = enable ;
if ( ! enable )
{
gContext . mbUsing = false ;
gContext . mbUsingBounds = false ;
}
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
static void ComputeContext ( const float * view , const float * projection , float * matrix , MODE mode )
2017-12-31 10:50:49 +01:00
{
gContext . mMode = mode ;
gContext . mViewMat = * ( matrix_t * ) view ;
gContext . mProjectionMat = * ( matrix_t * ) projection ;
2024-08-16 14:37:22 +02:00
gContext . mbMouseOver = IsHoveringWindow ( ) ;
gContext . mModelLocal = * ( matrix_t * ) matrix ;
gContext . mModelLocal . OrthoNormalize ( ) ;
2021-07-08 16:09:40 +02:00
2017-12-31 10:50:49 +01:00
if ( mode = = LOCAL )
{
2024-08-16 14:37:22 +02:00
gContext . mModel = gContext . mModelLocal ;
2017-12-31 10:50:49 +01:00
}
else
{
gContext . mModel . Translation ( ( ( matrix_t * ) matrix ) - > v . position ) ;
}
gContext . mModelSource = * ( matrix_t * ) matrix ;
gContext . mModelScaleOrigin . Set ( gContext . mModelSource . v . right . Length ( ) , gContext . mModelSource . v . up . Length ( ) , gContext . mModelSource . v . dir . Length ( ) ) ;
gContext . mModelInverse . Inverse ( gContext . mModel ) ;
gContext . mModelSourceInverse . Inverse ( gContext . mModelSource ) ;
gContext . mViewProjection = gContext . mViewMat * gContext . mProjectionMat ;
gContext . mMVP = gContext . mModel * gContext . mViewProjection ;
2024-08-16 14:37:22 +02:00
gContext . mMVPLocal = gContext . mModelLocal * gContext . mViewProjection ;
2017-12-31 10:50:49 +01:00
matrix_t viewInverse ;
viewInverse . Inverse ( gContext . mViewMat ) ;
gContext . mCameraDir = viewInverse . v . dir ;
gContext . mCameraEye = viewInverse . v . position ;
gContext . mCameraRight = viewInverse . v . right ;
gContext . mCameraUp = viewInverse . v . up ;
2021-07-08 16:09:40 +02:00
// projection reverse
vec_t nearPos , farPos ;
nearPos . Transform ( makeVect ( 0 , 0 , 1.f , 1.f ) , gContext . mProjectionMat ) ;
farPos . Transform ( makeVect ( 0 , 0 , 2.f , 1.f ) , gContext . mProjectionMat ) ;
gContext . mReversed = ( nearPos . z / nearPos . w ) > ( farPos . z / farPos . w ) ;
// compute scale from the size of camera right vector projected on screen at the matrix position
vec_t pointRight = viewInverse . v . right ;
pointRight . TransformPoint ( gContext . mViewProjection ) ;
gContext . mScreenFactor = gContext . mGizmoSizeClipSpace / ( pointRight . x / pointRight . w - gContext . mMVP . v . position . x / gContext . mMVP . v . position . w ) ;
vec_t rightViewInverse = viewInverse . v . right ;
rightViewInverse . TransformVector ( gContext . mModelInverse ) ;
float rightLength = GetSegmentLengthClipSpace ( makeVect ( 0.f , 0.f ) , rightViewInverse ) ;
gContext . mScreenFactor = gContext . mGizmoSizeClipSpace / rightLength ;
2017-12-31 10:50:49 +01:00
ImVec2 centerSSpace = worldToPos ( makeVect ( 0.f , 0.f ) , gContext . mMVP ) ;
gContext . mScreenSquareCenter = centerSSpace ;
gContext . mScreenSquareMin = ImVec2 ( centerSSpace . x - 10.f , centerSSpace . y - 10.f ) ;
gContext . mScreenSquareMax = ImVec2 ( centerSSpace . x + 10.f , centerSSpace . y + 10.f ) ;
ComputeCameraRay ( gContext . mRayOrigin , gContext . mRayVector ) ;
}
2021-07-08 16:09:40 +02:00
static void ComputeColors ( ImU32 * colors , int type , OPERATION operation )
2017-12-31 10:50:49 +01:00
{
if ( gContext . mbEnable )
{
2024-08-16 14:37:22 +02:00
ImU32 selectionColor = GetColorU32 ( SELECTION ) ;
2017-12-31 10:50:49 +01:00
switch ( operation )
{
case TRANSLATE :
2021-07-08 16:09:40 +02:00
colors [ 0 ] = ( type = = MT_MOVE_SCREEN ) ? selectionColor : IM_COL32_WHITE ;
2017-12-31 10:50:49 +01:00
for ( int i = 0 ; i < 3 ; i + + )
{
2024-08-16 14:37:22 +02:00
colors [ i + 1 ] = ( type = = ( int ) ( MT_MOVE_X + i ) ) ? selectionColor : GetColorU32 ( DIRECTION_X + i ) ;
colors [ i + 4 ] = ( type = = ( int ) ( MT_MOVE_YZ + i ) ) ? selectionColor : GetColorU32 ( PLANE_X + i ) ;
2021-07-08 16:09:40 +02:00
colors [ i + 4 ] = ( type = = MT_MOVE_SCREEN ) ? selectionColor : colors [ i + 4 ] ;
2017-12-31 10:50:49 +01:00
}
break ;
case ROTATE :
2021-07-08 16:09:40 +02:00
colors [ 0 ] = ( type = = MT_ROTATE_SCREEN ) ? selectionColor : IM_COL32_WHITE ;
2017-12-31 10:50:49 +01:00
for ( int i = 0 ; i < 3 ; i + + )
2021-07-08 16:09:40 +02:00
{
2024-08-16 14:37:22 +02:00
colors [ i + 1 ] = ( type = = ( int ) ( MT_ROTATE_X + i ) ) ? selectionColor : GetColorU32 ( DIRECTION_X + i ) ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
break ;
2024-08-16 14:37:22 +02:00
case SCALEU :
2017-12-31 10:50:49 +01:00
case SCALE :
2021-07-08 16:09:40 +02:00
colors [ 0 ] = ( type = = MT_SCALE_XYZ ) ? selectionColor : IM_COL32_WHITE ;
2017-12-31 10:50:49 +01:00
for ( int i = 0 ; i < 3 ; i + + )
2021-07-08 16:09:40 +02:00
{
2024-08-16 14:37:22 +02:00
colors [ i + 1 ] = ( type = = ( int ) ( MT_SCALE_X + i ) ) ? selectionColor : GetColorU32 ( DIRECTION_X + i ) ;
2021-07-08 16:09:40 +02:00
}
break ;
// note: this internal function is only called with three possible values for operation
default :
2017-12-31 10:50:49 +01:00
break ;
}
}
else
{
2024-08-16 14:37:22 +02:00
ImU32 inactiveColor = GetColorU32 ( INACTIVE ) ;
2017-12-31 10:50:49 +01:00
for ( int i = 0 ; i < 7 ; i + + )
2021-07-08 16:09:40 +02:00
{
2017-12-31 10:50:49 +01:00
colors [ i ] = inactiveColor ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
}
}
2024-08-16 14:37:22 +02:00
static void ComputeTripodAxisAndVisibility ( const int axisIndex , vec_t & dirAxis , vec_t & dirPlaneX , vec_t & dirPlaneY , bool & belowAxisLimit , bool & belowPlaneLimit , const bool localCoordinates = false )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
dirAxis = directionUnary [ axisIndex ] ;
dirPlaneX = directionUnary [ ( axisIndex + 1 ) % 3 ] ;
dirPlaneY = directionUnary [ ( axisIndex + 2 ) % 3 ] ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
if ( gContext . mbUsing & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) )
2017-12-31 10:50:49 +01:00
{
// when using, use stored factors so the gizmo doesn't flip when we translate
belowAxisLimit = gContext . mBelowAxisLimit [ axisIndex ] ;
belowPlaneLimit = gContext . mBelowPlaneLimit [ axisIndex ] ;
2021-07-08 16:09:40 +02:00
dirAxis * = gContext . mAxisFactor [ axisIndex ] ;
dirPlaneX * = gContext . mAxisFactor [ ( axisIndex + 1 ) % 3 ] ;
dirPlaneY * = gContext . mAxisFactor [ ( axisIndex + 2 ) % 3 ] ;
2017-12-31 10:50:49 +01:00
}
else
{
2021-07-08 16:09:40 +02:00
// new method
2024-08-16 14:37:22 +02:00
float lenDir = GetSegmentLengthClipSpace ( makeVect ( 0.f , 0.f , 0.f ) , dirAxis , localCoordinates ) ;
float lenDirMinus = GetSegmentLengthClipSpace ( makeVect ( 0.f , 0.f , 0.f ) , - dirAxis , localCoordinates ) ;
2021-07-08 16:09:40 +02:00
2024-08-16 14:37:22 +02:00
float lenDirPlaneX = GetSegmentLengthClipSpace ( makeVect ( 0.f , 0.f , 0.f ) , dirPlaneX , localCoordinates ) ;
float lenDirMinusPlaneX = GetSegmentLengthClipSpace ( makeVect ( 0.f , 0.f , 0.f ) , - dirPlaneX , localCoordinates ) ;
2021-07-08 16:09:40 +02:00
2024-08-16 14:37:22 +02:00
float lenDirPlaneY = GetSegmentLengthClipSpace ( makeVect ( 0.f , 0.f , 0.f ) , dirPlaneY , localCoordinates ) ;
float lenDirMinusPlaneY = GetSegmentLengthClipSpace ( makeVect ( 0.f , 0.f , 0.f ) , - dirPlaneY , localCoordinates ) ;
2021-07-08 16:09:40 +02:00
// For readability
bool & allowFlip = gContext . mAllowAxisFlip ;
float mulAxis = ( allowFlip & & lenDir < lenDirMinus & & fabsf ( lenDir - lenDirMinus ) > FLT_EPSILON ) ? - 1.f : 1.f ;
float mulAxisX = ( allowFlip & & lenDirPlaneX < lenDirMinusPlaneX & & fabsf ( lenDirPlaneX - lenDirMinusPlaneX ) > FLT_EPSILON ) ? - 1.f : 1.f ;
float mulAxisY = ( allowFlip & & lenDirPlaneY < lenDirMinusPlaneY & & fabsf ( lenDirPlaneY - lenDirMinusPlaneY ) > FLT_EPSILON ) ? - 1.f : 1.f ;
dirAxis * = mulAxis ;
2017-12-31 10:50:49 +01:00
dirPlaneX * = mulAxisX ;
dirPlaneY * = mulAxisY ;
2021-07-08 16:09:40 +02:00
// for axis
2024-08-16 14:37:22 +02:00
float axisLengthInClipSpace = GetSegmentLengthClipSpace ( makeVect ( 0.f , 0.f , 0.f ) , dirAxis * gContext . mScreenFactor , localCoordinates ) ;
2021-07-08 16:09:40 +02:00
float paraSurf = GetParallelogram ( makeVect ( 0.f , 0.f , 0.f ) , dirPlaneX * gContext . mScreenFactor , dirPlaneY * gContext . mScreenFactor ) ;
2024-08-16 14:37:22 +02:00
belowPlaneLimit = ( paraSurf > gContext . mAxisLimit ) ;
belowAxisLimit = ( axisLengthInClipSpace > gContext . mPlaneLimit ) ;
2017-12-31 10:50:49 +01:00
// and store values
2021-07-08 16:09:40 +02:00
gContext . mAxisFactor [ axisIndex ] = mulAxis ;
gContext . mAxisFactor [ ( axisIndex + 1 ) % 3 ] = mulAxisX ;
gContext . mAxisFactor [ ( axisIndex + 2 ) % 3 ] = mulAxisY ;
2017-12-31 10:50:49 +01:00
gContext . mBelowAxisLimit [ axisIndex ] = belowAxisLimit ;
gContext . mBelowPlaneLimit [ axisIndex ] = belowPlaneLimit ;
}
}
2021-07-08 16:09:40 +02:00
static void ComputeSnap ( float * value , float snap )
2017-12-31 10:50:49 +01:00
{
if ( snap < = FLT_EPSILON )
2021-07-08 16:09:40 +02:00
{
2017-12-31 10:50:49 +01:00
return ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
float modulo = fmodf ( * value , snap ) ;
float moduloRatio = fabsf ( modulo ) / snap ;
if ( moduloRatio < snapTension )
2021-07-08 16:09:40 +02:00
{
2017-12-31 10:50:49 +01:00
* value - = modulo ;
2021-07-08 16:09:40 +02:00
}
else if ( moduloRatio > ( 1.f - snapTension ) )
{
* value = * value - modulo + snap * ( ( * value < 0.f ) ? - 1.f : 1.f ) ;
}
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
static void ComputeSnap ( vec_t & value , const float * snap )
2017-12-31 10:50:49 +01:00
{
for ( int i = 0 ; i < 3 ; i + + )
{
ComputeSnap ( & value [ i ] , snap [ i ] ) ;
}
}
static float ComputeAngleOnPlan ( )
{
const float len = IntersectRayPlane ( gContext . mRayOrigin , gContext . mRayVector , gContext . mTranslationPlan ) ;
vec_t localPos = Normalized ( gContext . mRayOrigin + gContext . mRayVector * len - gContext . mModel . v . position ) ;
vec_t perpendicularVector ;
perpendicularVector . Cross ( gContext . mRotationVectorSource , gContext . mTranslationPlan ) ;
perpendicularVector . Normalize ( ) ;
2021-07-08 16:09:40 +02:00
float acosAngle = Clamp ( Dot ( localPos , gContext . mRotationVectorSource ) , - 1.f , 1.f ) ;
2017-12-31 10:50:49 +01:00
float angle = acosf ( acosAngle ) ;
angle * = ( Dot ( localPos , perpendicularVector ) < 0.f ) ? 1.f : - 1.f ;
return angle ;
}
2021-07-08 16:09:40 +02:00
static void DrawRotationGizmo ( OPERATION op , int type )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
if ( ! Intersects ( op , ROTATE ) )
{
return ;
}
2017-12-31 10:50:49 +01:00
ImDrawList * drawList = gContext . mDrawList ;
// colors
ImU32 colors [ 7 ] ;
ComputeColors ( colors , type , ROTATE ) ;
2021-07-08 16:09:40 +02:00
vec_t cameraToModelNormalized ;
if ( gContext . mIsOrthographic )
{
matrix_t viewInverse ;
viewInverse . Inverse ( * ( matrix_t * ) & gContext . mViewMat ) ;
2024-08-16 14:37:22 +02:00
cameraToModelNormalized = - viewInverse . v . dir ;
2021-07-08 16:09:40 +02:00
}
else
{
cameraToModelNormalized = Normalized ( gContext . mModel . v . position - gContext . mCameraEye ) ;
}
2017-12-31 10:50:49 +01:00
cameraToModelNormalized . TransformVector ( gContext . mModelInverse ) ;
2021-07-08 16:09:40 +02:00
2017-12-31 10:50:49 +01:00
gContext . mRadiusSquareCenter = screenRotateSize * gContext . mHeight ;
2021-07-08 16:09:40 +02:00
bool hasRSC = Intersects ( op , ROTATE_SCREEN ) ;
2017-12-31 10:50:49 +01:00
for ( int axis = 0 ; axis < 3 ; axis + + )
{
2021-07-08 16:09:40 +02:00
if ( ! Intersects ( op , static_cast < OPERATION > ( ROTATE_Z > > axis ) ) )
{
continue ;
}
2024-08-16 14:37:22 +02:00
const bool usingAxis = ( gContext . mbUsing & & type = = MT_ROTATE_Z - axis ) ;
const int circleMul = ( hasRSC & & ! usingAxis ) ? 1 : 2 ;
ImVec2 * circlePos = ( ImVec2 * ) alloca ( sizeof ( ImVec2 ) * ( circleMul * halfCircleSegmentCount + 1 ) ) ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
float angleStart = atan2f ( cameraToModelNormalized [ ( 4 - axis ) % 3 ] , cameraToModelNormalized [ ( 3 - axis ) % 3 ] ) + ZPI * 0.5f ;
for ( int i = 0 ; i < circleMul * halfCircleSegmentCount + 1 ; i + + )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
float ng = angleStart + ( float ) circleMul * ZPI * ( ( float ) i / ( float ) ( circleMul * halfCircleSegmentCount ) ) ;
2017-12-31 10:50:49 +01:00
vec_t axisPos = makeVect ( cosf ( ng ) , sinf ( ng ) , 0.f ) ;
2024-08-16 14:37:22 +02:00
vec_t pos = makeVect ( axisPos [ axis ] , axisPos [ ( axis + 1 ) % 3 ] , axisPos [ ( axis + 2 ) % 3 ] ) * gContext . mScreenFactor * rotationDisplayFactor ;
2017-12-31 10:50:49 +01:00
circlePos [ i ] = worldToPos ( pos , gContext . mMVP ) ;
}
2024-08-16 14:37:22 +02:00
if ( ! gContext . mbUsing | | usingAxis )
{
drawList - > AddPolyline ( circlePos , circleMul * halfCircleSegmentCount + 1 , colors [ 3 - axis ] , false , gContext . mStyle . RotationLineThickness ) ;
}
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
float radiusAxis = sqrtf ( ( ImLengthSqr ( worldToPos ( gContext . mModel . v . position , gContext . mViewProjection ) - circlePos [ 0 ] ) ) ) ;
if ( radiusAxis > gContext . mRadiusSquareCenter )
{
gContext . mRadiusSquareCenter = radiusAxis ;
}
}
2024-08-16 14:37:22 +02:00
if ( hasRSC & & ( ! gContext . mbUsing | | type = = MT_ROTATE_SCREEN ) )
2021-07-08 16:09:40 +02:00
{
2024-08-16 14:37:22 +02:00
drawList - > AddCircle ( worldToPos ( gContext . mModel . v . position , gContext . mViewProjection ) , gContext . mRadiusSquareCenter , colors [ 0 ] , 64 , gContext . mStyle . RotationOuterLineThickness ) ;
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
if ( gContext . mbUsing & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) & & IsRotateType ( type ) )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
ImVec2 circlePos [ halfCircleSegmentCount + 1 ] ;
2017-12-31 10:50:49 +01:00
circlePos [ 0 ] = worldToPos ( gContext . mModel . v . position , gContext . mViewProjection ) ;
2024-08-16 14:37:22 +02:00
for ( unsigned int i = 1 ; i < halfCircleSegmentCount + 1 ; i + + )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
float ng = gContext . mRotationAngle * ( ( float ) ( i - 1 ) / ( float ) ( halfCircleSegmentCount - 1 ) ) ;
2017-12-31 10:50:49 +01:00
matrix_t rotateVectorMatrix ;
rotateVectorMatrix . RotationAxis ( gContext . mTranslationPlan , ng ) ;
vec_t pos ;
pos . TransformPoint ( gContext . mRotationVectorSource , rotateVectorMatrix ) ;
2024-08-16 14:37:22 +02:00
pos * = gContext . mScreenFactor * rotationDisplayFactor ;
2017-12-31 10:50:49 +01:00
circlePos [ i ] = worldToPos ( pos + gContext . mModel . v . position , gContext . mViewProjection ) ;
}
2024-08-16 14:37:22 +02:00
drawList - > AddConvexPolyFilled ( circlePos , halfCircleSegmentCount + 1 , GetColorU32 ( ROTATION_USING_FILL ) ) ;
drawList - > AddPolyline ( circlePos , halfCircleSegmentCount + 1 , GetColorU32 ( ROTATION_USING_BORDER ) , true , gContext . mStyle . RotationLineThickness ) ;
2017-12-31 10:50:49 +01:00
ImVec2 destinationPosOnScreen = circlePos [ 1 ] ;
char tmps [ 512 ] ;
2021-07-08 16:09:40 +02:00
ImFormatString ( tmps , sizeof ( tmps ) , rotationInfoMask [ type - MT_ROTATE_X ] , ( gContext . mRotationAngle / ZPI ) * 180.f , gContext . mRotationAngle ) ;
2024-08-16 14:37:22 +02:00
drawList - > AddText ( ImVec2 ( destinationPosOnScreen . x + 15 , destinationPosOnScreen . y + 15 ) , GetColorU32 ( TEXT_SHADOW ) , tmps ) ;
drawList - > AddText ( ImVec2 ( destinationPosOnScreen . x + 14 , destinationPosOnScreen . y + 14 ) , GetColorU32 ( TEXT ) , tmps ) ;
2017-12-31 10:50:49 +01:00
}
}
static void DrawHatchedAxis ( const vec_t & axis )
{
2024-08-16 14:37:22 +02:00
if ( gContext . mStyle . HatchedAxisLineThickness < = 0.0f )
{
return ;
}
2017-12-31 10:50:49 +01:00
for ( int j = 1 ; j < 10 ; j + + )
{
ImVec2 baseSSpace2 = worldToPos ( axis * 0.05f * ( float ) ( j * 2 ) * gContext . mScreenFactor , gContext . mMVP ) ;
ImVec2 worldDirSSpace2 = worldToPos ( axis * 0.05f * ( float ) ( j * 2 + 1 ) * gContext . mScreenFactor , gContext . mMVP ) ;
2024-08-16 14:37:22 +02:00
gContext . mDrawList - > AddLine ( baseSSpace2 , worldDirSSpace2 , GetColorU32 ( HATCHED_AXIS_LINES ) , gContext . mStyle . HatchedAxisLineThickness ) ;
2017-12-31 10:50:49 +01:00
}
}
2021-07-08 16:09:40 +02:00
static void DrawScaleGizmo ( OPERATION op , int type )
2017-12-31 10:50:49 +01:00
{
ImDrawList * drawList = gContext . mDrawList ;
2021-07-08 16:09:40 +02:00
if ( ! Intersects ( op , SCALE ) )
{
return ;
}
2017-12-31 10:50:49 +01:00
// colors
ImU32 colors [ 7 ] ;
ComputeColors ( colors , type , SCALE ) ;
// draw
vec_t scaleDisplay = { 1.f , 1.f , 1.f , 1.f } ;
2021-07-08 16:09:40 +02:00
if ( gContext . mbUsing & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) )
{
2017-12-31 10:50:49 +01:00
scaleDisplay = gContext . mScale ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
2024-08-16 14:37:22 +02:00
for ( int i = 0 ; i < 3 ; i + + )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
if ( ! Intersects ( op , static_cast < OPERATION > ( SCALE_X < < i ) ) )
{
continue ;
}
2024-08-16 14:37:22 +02:00
const bool usingAxis = ( gContext . mbUsing & & type = = MT_SCALE_X + i ) ;
if ( ! gContext . mbUsing | | usingAxis )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
vec_t dirPlaneX , dirPlaneY , dirAxis ;
bool belowAxisLimit , belowPlaneLimit ;
ComputeTripodAxisAndVisibility ( i , dirAxis , dirPlaneX , dirPlaneY , belowAxisLimit , belowPlaneLimit , true ) ;
2017-12-31 10:50:49 +01:00
2024-08-16 14:37:22 +02:00
// draw axis
if ( belowAxisLimit )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
bool hasTranslateOnAxis = Contains ( op , static_cast < OPERATION > ( TRANSLATE_X < < i ) ) ;
float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f ;
ImVec2 baseSSpace = worldToPos ( dirAxis * 0.1f * gContext . mScreenFactor , gContext . mMVP ) ;
ImVec2 worldDirSSpaceNoScale = worldToPos ( dirAxis * markerScale * gContext . mScreenFactor , gContext . mMVP ) ;
ImVec2 worldDirSSpace = worldToPos ( ( dirAxis * markerScale * scaleDisplay [ i ] ) * gContext . mScreenFactor , gContext . mMVP ) ;
2021-07-08 16:09:40 +02:00
2024-08-16 14:37:22 +02:00
if ( gContext . mbUsing & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) )
{
ImU32 scaleLineColor = GetColorU32 ( SCALE_LINE ) ;
drawList - > AddLine ( baseSSpace , worldDirSSpaceNoScale , scaleLineColor , gContext . mStyle . ScaleLineThickness ) ;
drawList - > AddCircleFilled ( worldDirSSpaceNoScale , gContext . mStyle . ScaleLineCircleSize , scaleLineColor ) ;
}
if ( ! hasTranslateOnAxis | | gContext . mbUsing )
{
drawList - > AddLine ( baseSSpace , worldDirSSpace , colors [ i + 1 ] , gContext . mStyle . ScaleLineThickness ) ;
}
drawList - > AddCircleFilled ( worldDirSSpace , gContext . mStyle . ScaleLineCircleSize , colors [ i + 1 ] ) ;
if ( gContext . mAxisFactor [ i ] < 0.f )
{
DrawHatchedAxis ( dirAxis * scaleDisplay [ i ] ) ;
}
2017-12-31 10:50:49 +01:00
}
2024-08-16 14:37:22 +02:00
}
}
// draw screen cirle
drawList - > AddCircleFilled ( gContext . mScreenSquareCenter , gContext . mStyle . CenterCircleSize , colors [ 0 ] , 32 ) ;
if ( gContext . mbUsing & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) & & IsScaleType ( type ) )
{
//ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
ImVec2 destinationPosOnScreen = worldToPos ( gContext . mModel . v . position , gContext . mViewProjection ) ;
/*vec_t dif(destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y);
dif . Normalize ( ) ;
dif * = 5.f ;
drawList - > AddCircle ( sourcePosOnScreen , 6.f , translationLineColor ) ;
drawList - > AddCircle ( destinationPosOnScreen , 6.f , translationLineColor ) ;
drawList - > AddLine ( ImVec2 ( sourcePosOnScreen . x + dif . x , sourcePosOnScreen . y + dif . y ) , ImVec2 ( destinationPosOnScreen . x - dif . x , destinationPosOnScreen . y - dif . y ) , translationLineColor , 2.f ) ;
*/
char tmps [ 512 ] ;
//vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;
int componentInfoIndex = ( type - MT_SCALE_X ) * 3 ;
ImFormatString ( tmps , sizeof ( tmps ) , scaleInfoMask [ type - MT_SCALE_X ] , scaleDisplay [ translationInfoIndex [ componentInfoIndex ] ] ) ;
drawList - > AddText ( ImVec2 ( destinationPosOnScreen . x + 15 , destinationPosOnScreen . y + 15 ) , GetColorU32 ( TEXT_SHADOW ) , tmps ) ;
drawList - > AddText ( ImVec2 ( destinationPosOnScreen . x + 14 , destinationPosOnScreen . y + 14 ) , GetColorU32 ( TEXT ) , tmps ) ;
}
}
static void DrawScaleUniveralGizmo ( OPERATION op , int type )
{
ImDrawList * drawList = gContext . mDrawList ;
if ( ! Intersects ( op , SCALEU ) )
{
return ;
}
// colors
ImU32 colors [ 7 ] ;
ComputeColors ( colors , type , SCALEU ) ;
// draw
vec_t scaleDisplay = { 1.f , 1.f , 1.f , 1.f } ;
if ( gContext . mbUsing & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) )
{
scaleDisplay = gContext . mScale ;
}
2017-12-31 10:50:49 +01:00
2024-08-16 14:37:22 +02:00
for ( int i = 0 ; i < 3 ; i + + )
{
if ( ! Intersects ( op , static_cast < OPERATION > ( SCALE_XU < < i ) ) )
{
continue ;
}
const bool usingAxis = ( gContext . mbUsing & & type = = MT_SCALE_X + i ) ;
if ( ! gContext . mbUsing | | usingAxis )
{
vec_t dirPlaneX , dirPlaneY , dirAxis ;
bool belowAxisLimit , belowPlaneLimit ;
ComputeTripodAxisAndVisibility ( i , dirAxis , dirPlaneX , dirPlaneY , belowAxisLimit , belowPlaneLimit , true ) ;
// draw axis
if ( belowAxisLimit )
2021-07-08 16:09:40 +02:00
{
2024-08-16 14:37:22 +02:00
bool hasTranslateOnAxis = Contains ( op , static_cast < OPERATION > ( TRANSLATE_X < < i ) ) ;
float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f ;
//ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal);
//ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP);
ImVec2 worldDirSSpace = worldToPos ( ( dirAxis * markerScale * scaleDisplay [ i ] ) * gContext . mScreenFactor , gContext . mMVPLocal ) ;
#if 0
if ( gContext . mbUsing & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) )
{
drawList - > AddLine ( baseSSpace , worldDirSSpaceNoScale , IM_COL32 ( 0x40 , 0x40 , 0x40 , 0xFF ) , 3.f ) ;
drawList - > AddCircleFilled ( worldDirSSpaceNoScale , 6.f , IM_COL32 ( 0x40 , 0x40 , 0x40 , 0xFF ) ) ;
}
/*
if ( ! hasTranslateOnAxis | | gContext . mbUsing )
{
drawList - > AddLine ( baseSSpace , worldDirSSpace , colors [ i + 1 ] , 3.f ) ;
}
*/
# endif
drawList - > AddCircleFilled ( worldDirSSpace , 12.f , colors [ i + 1 ] ) ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
}
}
// draw screen cirle
2024-08-16 14:37:22 +02:00
drawList - > AddCircle ( gContext . mScreenSquareCenter , 20.f , colors [ 0 ] , 32 , gContext . mStyle . CenterCircleSize ) ;
2021-07-08 16:09:40 +02:00
if ( gContext . mbUsing & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) & & IsScaleType ( type ) )
2017-12-31 10:50:49 +01:00
{
//ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
ImVec2 destinationPosOnScreen = worldToPos ( gContext . mModel . v . position , gContext . mViewProjection ) ;
/*vec_t dif(destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y);
dif . Normalize ( ) ;
dif * = 5.f ;
drawList - > AddCircle ( sourcePosOnScreen , 6.f , translationLineColor ) ;
drawList - > AddCircle ( destinationPosOnScreen , 6.f , translationLineColor ) ;
drawList - > AddLine ( ImVec2 ( sourcePosOnScreen . x + dif . x , sourcePosOnScreen . y + dif . y ) , ImVec2 ( destinationPosOnScreen . x - dif . x , destinationPosOnScreen . y - dif . y ) , translationLineColor , 2.f ) ;
*/
char tmps [ 512 ] ;
//vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;
2021-07-08 16:09:40 +02:00
int componentInfoIndex = ( type - MT_SCALE_X ) * 3 ;
ImFormatString ( tmps , sizeof ( tmps ) , scaleInfoMask [ type - MT_SCALE_X ] , scaleDisplay [ translationInfoIndex [ componentInfoIndex ] ] ) ;
2024-08-16 14:37:22 +02:00
drawList - > AddText ( ImVec2 ( destinationPosOnScreen . x + 15 , destinationPosOnScreen . y + 15 ) , GetColorU32 ( TEXT_SHADOW ) , tmps ) ;
drawList - > AddText ( ImVec2 ( destinationPosOnScreen . x + 14 , destinationPosOnScreen . y + 14 ) , GetColorU32 ( TEXT ) , tmps ) ;
2017-12-31 10:50:49 +01:00
}
}
2021-07-08 16:09:40 +02:00
static void DrawTranslationGizmo ( OPERATION op , int type )
2017-12-31 10:50:49 +01:00
{
ImDrawList * drawList = gContext . mDrawList ;
if ( ! drawList )
2021-07-08 16:09:40 +02:00
{
return ;
}
if ( ! Intersects ( op , TRANSLATE ) )
{
return ;
}
2017-12-31 10:50:49 +01:00
// colors
ImU32 colors [ 7 ] ;
ComputeColors ( colors , type , TRANSLATE ) ;
const ImVec2 origin = worldToPos ( gContext . mModel . v . position , gContext . mViewProjection ) ;
2021-07-08 16:09:40 +02:00
2017-12-31 10:50:49 +01:00
// draw
bool belowAxisLimit = false ;
bool belowPlaneLimit = false ;
2024-08-16 14:37:22 +02:00
for ( int i = 0 ; i < 3 ; + + i )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
vec_t dirPlaneX , dirPlaneY , dirAxis ;
ComputeTripodAxisAndVisibility ( i , dirAxis , dirPlaneX , dirPlaneY , belowAxisLimit , belowPlaneLimit ) ;
2024-08-16 14:37:22 +02:00
if ( ! gContext . mbUsing | | ( gContext . mbUsing & & type = = MT_MOVE_X + i ) )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
// draw axis
if ( belowAxisLimit & & Intersects ( op , static_cast < OPERATION > ( TRANSLATE_X < < i ) ) )
{
ImVec2 baseSSpace = worldToPos ( dirAxis * 0.1f * gContext . mScreenFactor , gContext . mMVP ) ;
ImVec2 worldDirSSpace = worldToPos ( dirAxis * gContext . mScreenFactor , gContext . mMVP ) ;
2017-12-31 10:50:49 +01:00
2024-08-16 14:37:22 +02:00
drawList - > AddLine ( baseSSpace , worldDirSSpace , colors [ i + 1 ] , gContext . mStyle . TranslationLineThickness ) ;
2017-12-31 10:50:49 +01:00
2024-08-16 14:37:22 +02:00
// Arrow head begin
ImVec2 dir ( origin - worldDirSSpace ) ;
2017-12-31 10:50:49 +01:00
2024-08-16 14:37:22 +02:00
float d = sqrtf ( ImLengthSqr ( dir ) ) ;
dir / = d ; // Normalize
dir * = gContext . mStyle . TranslationLineArrowSize ;
2017-12-31 10:50:49 +01:00
2024-08-16 14:37:22 +02:00
ImVec2 ortogonalDir ( dir . y , - dir . x ) ; // Perpendicular vector
ImVec2 a ( worldDirSSpace + dir ) ;
drawList - > AddTriangleFilled ( worldDirSSpace - dir , a + ortogonalDir , a - ortogonalDir , colors [ i + 1 ] ) ;
// Arrow head end
2017-12-31 10:50:49 +01:00
2024-08-16 14:37:22 +02:00
if ( gContext . mAxisFactor [ i ] < 0.f )
{
DrawHatchedAxis ( dirAxis ) ;
}
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
}
// draw plane
2024-08-16 14:37:22 +02:00
if ( ! gContext . mbUsing | | ( gContext . mbUsing & & type = = MT_MOVE_YZ + i ) )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
if ( belowPlaneLimit & & Contains ( op , TRANSLATE_PLANS [ i ] ) )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
ImVec2 screenQuadPts [ 4 ] ;
for ( int j = 0 ; j < 4 ; + + j )
{
vec_t cornerWorldPos = ( dirPlaneX * quadUV [ j * 2 ] + dirPlaneY * quadUV [ j * 2 + 1 ] ) * gContext . mScreenFactor ;
screenQuadPts [ j ] = worldToPos ( cornerWorldPos , gContext . mMVP ) ;
}
drawList - > AddPolyline ( screenQuadPts , 4 , GetColorU32 ( DIRECTION_X + i ) , true , 1.0f ) ;
drawList - > AddConvexPolyFilled ( screenQuadPts , 4 , colors [ i + 4 ] ) ;
2017-12-31 10:50:49 +01:00
}
}
}
2024-08-16 14:37:22 +02:00
drawList - > AddCircleFilled ( gContext . mScreenSquareCenter , gContext . mStyle . CenterCircleSize , colors [ 0 ] , 32 ) ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
if ( gContext . mbUsing & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) & & IsTranslateType ( type ) )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
ImU32 translationLineColor = GetColorU32 ( TRANSLATION_LINE ) ;
2017-12-31 10:50:49 +01:00
ImVec2 sourcePosOnScreen = worldToPos ( gContext . mMatrixOrigin , gContext . mViewProjection ) ;
ImVec2 destinationPosOnScreen = worldToPos ( gContext . mModel . v . position , gContext . mViewProjection ) ;
vec_t dif = { destinationPosOnScreen . x - sourcePosOnScreen . x , destinationPosOnScreen . y - sourcePosOnScreen . y , 0.f , 0.f } ;
dif . Normalize ( ) ;
dif * = 5.f ;
drawList - > AddCircle ( sourcePosOnScreen , 6.f , translationLineColor ) ;
drawList - > AddCircle ( destinationPosOnScreen , 6.f , translationLineColor ) ;
drawList - > AddLine ( ImVec2 ( sourcePosOnScreen . x + dif . x , sourcePosOnScreen . y + dif . y ) , ImVec2 ( destinationPosOnScreen . x - dif . x , destinationPosOnScreen . y - dif . y ) , translationLineColor , 2.f ) ;
char tmps [ 512 ] ;
vec_t deltaInfo = gContext . mModel . v . position - gContext . mMatrixOrigin ;
2021-07-08 16:09:40 +02:00
int componentInfoIndex = ( type - MT_MOVE_X ) * 3 ;
ImFormatString ( tmps , sizeof ( tmps ) , translationInfoMask [ type - MT_MOVE_X ] , deltaInfo [ translationInfoIndex [ componentInfoIndex ] ] , deltaInfo [ translationInfoIndex [ componentInfoIndex + 1 ] ] , deltaInfo [ translationInfoIndex [ componentInfoIndex + 2 ] ] ) ;
2024-08-16 14:37:22 +02:00
drawList - > AddText ( ImVec2 ( destinationPosOnScreen . x + 15 , destinationPosOnScreen . y + 15 ) , GetColorU32 ( TEXT_SHADOW ) , tmps ) ;
drawList - > AddText ( ImVec2 ( destinationPosOnScreen . x + 14 , destinationPosOnScreen . y + 14 ) , GetColorU32 ( TEXT ) , tmps ) ;
2017-12-31 10:50:49 +01:00
}
}
static bool CanActivate ( )
{
if ( ImGui : : IsMouseClicked ( 0 ) & & ! ImGui : : IsAnyItemHovered ( ) & & ! ImGui : : IsAnyItemActive ( ) )
2021-07-08 16:09:40 +02:00
{
2017-12-31 10:50:49 +01:00
return true ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
return false ;
}
2021-07-08 16:09:40 +02:00
static void HandleAndDrawLocalBounds ( const float * bounds , matrix_t * matrix , const float * snapValues , OPERATION operation )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
ImDrawList * drawList = gContext . mDrawList ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
// compute best projection axis
vec_t axesWorldDirections [ 3 ] ;
vec_t bestAxisWorldDirection = { 0.0f , 0.0f , 0.0f , 0.0f } ;
int axes [ 3 ] ;
unsigned int numAxes = 1 ;
axes [ 0 ] = gContext . mBoundsBestAxis ;
int bestAxis = axes [ 0 ] ;
if ( ! gContext . mbUsingBounds )
{
numAxes = 0 ;
float bestDot = 0.f ;
2024-08-16 14:37:22 +02:00
for ( int i = 0 ; i < 3 ; i + + )
2021-07-08 16:09:40 +02:00
{
vec_t dirPlaneNormalWorld ;
dirPlaneNormalWorld . TransformVector ( directionUnary [ i ] , gContext . mModelSource ) ;
dirPlaneNormalWorld . Normalize ( ) ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
float dt = fabsf ( Dot ( Normalized ( gContext . mCameraEye - gContext . mModelSource . v . position ) , dirPlaneNormalWorld ) ) ;
if ( dt > = bestDot )
{
bestDot = dt ;
bestAxis = i ;
bestAxisWorldDirection = dirPlaneNormalWorld ;
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
if ( dt > = 0.1f )
{
axes [ numAxes ] = i ;
axesWorldDirections [ numAxes ] = dirPlaneNormalWorld ;
+ + numAxes ;
}
}
}
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
if ( numAxes = = 0 )
{
axes [ 0 ] = bestAxis ;
axesWorldDirections [ 0 ] = bestAxisWorldDirection ;
numAxes = 1 ;
}
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
else if ( bestAxis ! = axes [ 0 ] )
{
unsigned int bestIndex = 0 ;
for ( unsigned int i = 0 ; i < numAxes ; i + + )
{
if ( axes [ i ] = = bestAxis )
{
bestIndex = i ;
break ;
}
}
int tempAxis = axes [ 0 ] ;
axes [ 0 ] = axes [ bestIndex ] ;
axes [ bestIndex ] = tempAxis ;
vec_t tempDirection = axesWorldDirections [ 0 ] ;
axesWorldDirections [ 0 ] = axesWorldDirections [ bestIndex ] ;
axesWorldDirections [ bestIndex ] = tempDirection ;
}
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
for ( unsigned int axisIndex = 0 ; axisIndex < numAxes ; + + axisIndex )
{
bestAxis = axes [ axisIndex ] ;
bestAxisWorldDirection = axesWorldDirections [ axisIndex ] ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
// corners
vec_t aabb [ 4 ] ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
int secondAxis = ( bestAxis + 1 ) % 3 ;
int thirdAxis = ( bestAxis + 2 ) % 3 ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
for ( int i = 0 ; i < 4 ; i + + )
{
aabb [ i ] [ 3 ] = aabb [ i ] [ bestAxis ] = 0.f ;
aabb [ i ] [ secondAxis ] = bounds [ secondAxis + 3 * ( i > > 1 ) ] ;
aabb [ i ] [ thirdAxis ] = bounds [ thirdAxis + 3 * ( ( i > > 1 ) ^ ( i & 1 ) ) ] ;
}
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
// draw bounds
unsigned int anchorAlpha = gContext . mbEnable ? IM_COL32_BLACK : IM_COL32 ( 0 , 0 , 0 , 0x80 ) ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
matrix_t boundsMVP = gContext . mModelSource * gContext . mViewProjection ;
for ( int i = 0 ; i < 4 ; i + + )
{
ImVec2 worldBound1 = worldToPos ( aabb [ i ] , boundsMVP ) ;
ImVec2 worldBound2 = worldToPos ( aabb [ ( i + 1 ) % 4 ] , boundsMVP ) ;
if ( ! IsInContextRect ( worldBound1 ) | | ! IsInContextRect ( worldBound2 ) )
{
continue ;
}
float boundDistance = sqrtf ( ImLengthSqr ( worldBound1 - worldBound2 ) ) ;
int stepCount = ( int ) ( boundDistance / 10.f ) ;
stepCount = min ( stepCount , 1000 ) ;
for ( int j = 0 ; j < stepCount ; j + + )
{
2024-08-16 14:37:22 +02:00
float stepLength = 1.f / ( float ) stepCount ;
2021-07-08 16:09:40 +02:00
float t1 = ( float ) j * stepLength ;
float t2 = ( float ) j * stepLength + stepLength * 0.5f ;
ImVec2 worldBoundSS1 = ImLerp ( worldBound1 , worldBound2 , ImVec2 ( t1 , t1 ) ) ;
ImVec2 worldBoundSS2 = ImLerp ( worldBound1 , worldBound2 , ImVec2 ( t2 , t2 ) ) ;
//drawList->AddLine(worldBoundSS1, worldBoundSS2, IM_COL32(0, 0, 0, 0) + anchorAlpha, 3.f);
drawList - > AddLine ( worldBoundSS1 , worldBoundSS2 , IM_COL32 ( 0xAA , 0xAA , 0xAA , 0 ) + anchorAlpha , 2.f ) ;
}
vec_t midPoint = ( aabb [ i ] + aabb [ ( i + 1 ) % 4 ] ) * 0.5f ;
ImVec2 midBound = worldToPos ( midPoint , boundsMVP ) ;
static const float AnchorBigRadius = 8.f ;
static const float AnchorSmallRadius = 6.f ;
bool overBigAnchor = ImLengthSqr ( worldBound1 - io . MousePos ) < = ( AnchorBigRadius * AnchorBigRadius ) ;
bool overSmallAnchor = ImLengthSqr ( midBound - io . MousePos ) < = ( AnchorBigRadius * AnchorBigRadius ) ;
int type = MT_NONE ;
vec_t gizmoHitProportion ;
if ( Intersects ( operation , TRANSLATE ) )
{
type = GetMoveType ( operation , & gizmoHitProportion ) ;
}
if ( Intersects ( operation , ROTATE ) & & type = = MT_NONE )
{
type = GetRotateType ( operation ) ;
}
if ( Intersects ( operation , SCALE ) & & type = = MT_NONE )
{
type = GetScaleType ( operation ) ;
}
if ( type ! = MT_NONE )
{
overBigAnchor = false ;
overSmallAnchor = false ;
}
2024-08-16 14:37:22 +02:00
ImU32 selectionColor = GetColorU32 ( SELECTION ) ;
2021-07-08 16:09:40 +02:00
unsigned int bigAnchorColor = overBigAnchor ? selectionColor : ( IM_COL32 ( 0xAA , 0xAA , 0xAA , 0 ) + anchorAlpha ) ;
unsigned int smallAnchorColor = overSmallAnchor ? selectionColor : ( IM_COL32 ( 0xAA , 0xAA , 0xAA , 0 ) + anchorAlpha ) ;
drawList - > AddCircleFilled ( worldBound1 , AnchorBigRadius , IM_COL32_BLACK ) ;
drawList - > AddCircleFilled ( worldBound1 , AnchorBigRadius - 1.2f , bigAnchorColor ) ;
drawList - > AddCircleFilled ( midBound , AnchorSmallRadius , IM_COL32_BLACK ) ;
drawList - > AddCircleFilled ( midBound , AnchorSmallRadius - 1.2f , smallAnchorColor ) ;
int oppositeIndex = ( i + 2 ) % 4 ;
// big anchor on corners
if ( ! gContext . mbUsingBounds & & gContext . mbEnable & & overBigAnchor & & CanActivate ( ) )
{
gContext . mBoundsPivot . TransformPoint ( aabb [ ( i + 2 ) % 4 ] , gContext . mModelSource ) ;
gContext . mBoundsAnchor . TransformPoint ( aabb [ i ] , gContext . mModelSource ) ;
gContext . mBoundsPlan = BuildPlan ( gContext . mBoundsAnchor , bestAxisWorldDirection ) ;
gContext . mBoundsBestAxis = bestAxis ;
gContext . mBoundsAxis [ 0 ] = secondAxis ;
gContext . mBoundsAxis [ 1 ] = thirdAxis ;
gContext . mBoundsLocalPivot . Set ( 0.f ) ;
gContext . mBoundsLocalPivot [ secondAxis ] = aabb [ oppositeIndex ] [ secondAxis ] ;
gContext . mBoundsLocalPivot [ thirdAxis ] = aabb [ oppositeIndex ] [ thirdAxis ] ;
gContext . mbUsingBounds = true ;
gContext . mEditingID = gContext . mActualID ;
gContext . mBoundsMatrix = gContext . mModelSource ;
}
// small anchor on middle of segment
if ( ! gContext . mbUsingBounds & & gContext . mbEnable & & overSmallAnchor & & CanActivate ( ) )
{
vec_t midPointOpposite = ( aabb [ ( i + 2 ) % 4 ] + aabb [ ( i + 3 ) % 4 ] ) * 0.5f ;
gContext . mBoundsPivot . TransformPoint ( midPointOpposite , gContext . mModelSource ) ;
gContext . mBoundsAnchor . TransformPoint ( midPoint , gContext . mModelSource ) ;
gContext . mBoundsPlan = BuildPlan ( gContext . mBoundsAnchor , bestAxisWorldDirection ) ;
gContext . mBoundsBestAxis = bestAxis ;
int indices [ ] = { secondAxis , thirdAxis } ;
gContext . mBoundsAxis [ 0 ] = indices [ i % 2 ] ;
gContext . mBoundsAxis [ 1 ] = - 1 ;
gContext . mBoundsLocalPivot . Set ( 0.f ) ;
gContext . mBoundsLocalPivot [ gContext . mBoundsAxis [ 0 ] ] = aabb [ oppositeIndex ] [ indices [ i % 2 ] ] ; // bounds[gContext.mBoundsAxis[0]] * (((i + 1) & 2) ? 1.f : -1.f);
gContext . mbUsingBounds = true ;
gContext . mEditingID = gContext . mActualID ;
gContext . mBoundsMatrix = gContext . mModelSource ;
}
}
if ( gContext . mbUsingBounds & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) )
{
matrix_t scale ;
scale . SetToIdentity ( ) ;
// compute projected mouse position on plan
const float len = IntersectRayPlane ( gContext . mRayOrigin , gContext . mRayVector , gContext . mBoundsPlan ) ;
vec_t newPos = gContext . mRayOrigin + gContext . mRayVector * len ;
// compute a reference and delta vectors base on mouse move
vec_t deltaVector = ( newPos - gContext . mBoundsPivot ) . Abs ( ) ;
vec_t referenceVector = ( gContext . mBoundsAnchor - gContext . mBoundsPivot ) . Abs ( ) ;
// for 1 or 2 axes, compute a ratio that's used for scale and snap it based on resulting length
for ( int i = 0 ; i < 2 ; i + + )
{
int axisIndex1 = gContext . mBoundsAxis [ i ] ;
if ( axisIndex1 = = - 1 )
{
continue ;
}
float ratioAxis = 1.f ;
vec_t axisDir = gContext . mBoundsMatrix . component [ axisIndex1 ] . Abs ( ) ;
float dtAxis = axisDir . Dot ( referenceVector ) ;
float boundSize = bounds [ axisIndex1 + 3 ] - bounds [ axisIndex1 ] ;
if ( dtAxis > FLT_EPSILON )
{
ratioAxis = axisDir . Dot ( deltaVector ) / dtAxis ;
}
if ( snapValues )
{
float length = boundSize * ratioAxis ;
ComputeSnap ( & length , snapValues [ axisIndex1 ] ) ;
if ( boundSize > FLT_EPSILON )
{
ratioAxis = length / boundSize ;
}
}
scale . component [ axisIndex1 ] * = ratioAxis ;
}
// transform matrix
matrix_t preScale , postScale ;
preScale . Translation ( - gContext . mBoundsLocalPivot ) ;
postScale . Translation ( gContext . mBoundsLocalPivot ) ;
matrix_t res = preScale * scale * postScale * gContext . mBoundsMatrix ;
* matrix = res ;
// info text
char tmps [ 512 ] ;
ImVec2 destinationPosOnScreen = worldToPos ( gContext . mModel . v . position , gContext . mViewProjection ) ;
2024-08-16 14:37:22 +02:00
ImFormatString ( tmps , sizeof ( tmps ) , " X: %.2f Y: %.2f Z: %.2f "
2021-07-08 16:09:40 +02:00
, ( bounds [ 3 ] - bounds [ 0 ] ) * gContext . mBoundsMatrix . component [ 0 ] . Length ( ) * scale . component [ 0 ] . Length ( )
, ( bounds [ 4 ] - bounds [ 1 ] ) * gContext . mBoundsMatrix . component [ 1 ] . Length ( ) * scale . component [ 1 ] . Length ( )
, ( bounds [ 5 ] - bounds [ 2 ] ) * gContext . mBoundsMatrix . component [ 2 ] . Length ( ) * scale . component [ 2 ] . Length ( )
) ;
2024-08-16 14:37:22 +02:00
drawList - > AddText ( ImVec2 ( destinationPosOnScreen . x + 15 , destinationPosOnScreen . y + 15 ) , GetColorU32 ( TEXT_SHADOW ) , tmps ) ;
drawList - > AddText ( ImVec2 ( destinationPosOnScreen . x + 14 , destinationPosOnScreen . y + 14 ) , GetColorU32 ( TEXT ) , tmps ) ;
2021-07-08 16:09:40 +02:00
}
if ( ! io . MouseDown [ 0 ] ) {
gContext . mbUsingBounds = false ;
gContext . mEditingID = - 1 ;
}
if ( gContext . mbUsingBounds )
{
break ;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
static int GetScaleType ( OPERATION op )
{
2024-08-16 14:37:22 +02:00
if ( gContext . mbUsing )
{
return MT_NONE ;
}
2021-07-08 16:09:40 +02:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
int type = MT_NONE ;
// screen
if ( io . MousePos . x > = gContext . mScreenSquareMin . x & & io . MousePos . x < = gContext . mScreenSquareMax . x & &
io . MousePos . y > = gContext . mScreenSquareMin . y & & io . MousePos . y < = gContext . mScreenSquareMax . y & &
Contains ( op , SCALE ) )
{
type = MT_SCALE_XYZ ;
}
// compute
2024-08-16 14:37:22 +02:00
for ( int i = 0 ; i < 3 & & type = = MT_NONE ; i + + )
2021-07-08 16:09:40 +02:00
{
if ( ! Intersects ( op , static_cast < OPERATION > ( SCALE_X < < i ) ) )
{
continue ;
}
vec_t dirPlaneX , dirPlaneY , dirAxis ;
bool belowAxisLimit , belowPlaneLimit ;
2024-08-16 14:37:22 +02:00
ComputeTripodAxisAndVisibility ( i , dirAxis , dirPlaneX , dirPlaneY , belowAxisLimit , belowPlaneLimit , true ) ;
dirAxis . TransformVector ( gContext . mModelLocal ) ;
dirPlaneX . TransformVector ( gContext . mModelLocal ) ;
dirPlaneY . TransformVector ( gContext . mModelLocal ) ;
2021-07-08 16:09:40 +02:00
2024-08-16 14:37:22 +02:00
const float len = IntersectRayPlane ( gContext . mRayOrigin , gContext . mRayVector , BuildPlan ( gContext . mModelLocal . v . position , dirAxis ) ) ;
2021-07-08 16:09:40 +02:00
vec_t posOnPlan = gContext . mRayOrigin + gContext . mRayVector * len ;
const float startOffset = Contains ( op , static_cast < OPERATION > ( TRANSLATE_X < < i ) ) ? 1.0f : 0.1f ;
const float endOffset = Contains ( op , static_cast < OPERATION > ( TRANSLATE_X < < i ) ) ? 1.4f : 1.0f ;
const ImVec2 posOnPlanScreen = worldToPos ( posOnPlan , gContext . mViewProjection ) ;
2024-08-16 14:37:22 +02:00
const ImVec2 axisStartOnScreen = worldToPos ( gContext . mModelLocal . v . position + dirAxis * gContext . mScreenFactor * startOffset , gContext . mViewProjection ) ;
const ImVec2 axisEndOnScreen = worldToPos ( gContext . mModelLocal . v . position + dirAxis * gContext . mScreenFactor * endOffset , gContext . mViewProjection ) ;
2021-07-08 16:09:40 +02:00
vec_t closestPointOnAxis = PointOnSegment ( makeVect ( posOnPlanScreen ) , makeVect ( axisStartOnScreen ) , makeVect ( axisEndOnScreen ) ) ;
if ( ( closestPointOnAxis - makeVect ( posOnPlanScreen ) ) . Length ( ) < 12.f ) // pixel size
{
type = MT_SCALE_X + i ;
}
2017-12-31 10:50:49 +01:00
}
2024-08-16 14:37:22 +02:00
// universal
vec_t deltaScreen = { io . MousePos . x - gContext . mScreenSquareCenter . x , io . MousePos . y - gContext . mScreenSquareCenter . y , 0.f , 0.f } ;
float dist = deltaScreen . Length ( ) ;
if ( Contains ( op , SCALEU ) & & dist > = 17.0f & & dist < 23.0f )
{
type = MT_SCALE_XYZ ;
}
for ( int i = 0 ; i < 3 & & type = = MT_NONE ; i + + )
{
if ( ! Intersects ( op , static_cast < OPERATION > ( SCALE_XU < < i ) ) )
{
continue ;
}
vec_t dirPlaneX , dirPlaneY , dirAxis ;
bool belowAxisLimit , belowPlaneLimit ;
ComputeTripodAxisAndVisibility ( i , dirAxis , dirPlaneX , dirPlaneY , belowAxisLimit , belowPlaneLimit , true ) ;
// draw axis
if ( belowAxisLimit )
{
bool hasTranslateOnAxis = Contains ( op , static_cast < OPERATION > ( TRANSLATE_X < < i ) ) ;
float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f ;
//ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal);
//ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP);
ImVec2 worldDirSSpace = worldToPos ( ( dirAxis * markerScale ) * gContext . mScreenFactor , gContext . mMVPLocal ) ;
float distance = sqrtf ( ImLengthSqr ( worldDirSSpace - io . MousePos ) ) ;
if ( distance < 12.f )
{
type = MT_SCALE_X + i ;
}
}
}
2017-12-31 10:50:49 +01:00
return type ;
}
2021-07-08 16:09:40 +02:00
static int GetRotateType ( OPERATION op )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
if ( gContext . mbUsing )
{
return MT_NONE ;
}
2017-12-31 10:50:49 +01:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2021-07-08 16:09:40 +02:00
int type = MT_NONE ;
2017-12-31 10:50:49 +01:00
vec_t deltaScreen = { io . MousePos . x - gContext . mScreenSquareCenter . x , io . MousePos . y - gContext . mScreenSquareCenter . y , 0.f , 0.f } ;
float dist = deltaScreen . Length ( ) ;
2024-08-16 14:37:22 +02:00
if ( Intersects ( op , ROTATE_SCREEN ) & & dist > = ( gContext . mRadiusSquareCenter - 4.0f ) & & dist < ( gContext . mRadiusSquareCenter + 4.0f ) )
2021-07-08 16:09:40 +02:00
{
type = MT_ROTATE_SCREEN ;
}
const vec_t planNormals [ ] = { gContext . mModel . v . right , gContext . mModel . v . up , gContext . mModel . v . dir } ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
vec_t modelViewPos ;
modelViewPos . TransformPoint ( gContext . mModel . v . position , gContext . mViewMat ) ;
2017-12-31 10:50:49 +01:00
2024-08-16 14:37:22 +02:00
for ( int i = 0 ; i < 3 & & type = = MT_NONE ; i + + )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
if ( ! Intersects ( op , static_cast < OPERATION > ( ROTATE_X < < i ) ) )
{
continue ;
}
2017-12-31 10:50:49 +01:00
// pickup plan
vec_t pickupPlan = BuildPlan ( gContext . mModel . v . position , planNormals [ i ] ) ;
const float len = IntersectRayPlane ( gContext . mRayOrigin , gContext . mRayVector , pickupPlan ) ;
2021-07-08 16:09:40 +02:00
const vec_t intersectWorldPos = gContext . mRayOrigin + gContext . mRayVector * len ;
vec_t intersectViewPos ;
intersectViewPos . TransformPoint ( intersectWorldPos , gContext . mViewMat ) ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
if ( ImAbs ( modelViewPos . z ) - ImAbs ( intersectViewPos . z ) < - FLT_EPSILON )
{
2017-12-31 10:50:49 +01:00
continue ;
2021-07-08 16:09:40 +02:00
}
const vec_t localPos = intersectWorldPos - gContext . mModel . v . position ;
vec_t idealPosOnCircle = Normalized ( localPos ) ;
idealPosOnCircle . TransformVector ( gContext . mModelInverse ) ;
2024-08-16 14:37:22 +02:00
const ImVec2 idealPosOnCircleScreen = worldToPos ( idealPosOnCircle * rotationDisplayFactor * gContext . mScreenFactor , gContext . mMVP ) ;
2021-07-08 16:09:40 +02:00
//gContext.mDrawList->AddCircle(idealPosOnCircleScreen, 5.f, IM_COL32_WHITE);
const ImVec2 distanceOnScreen = idealPosOnCircleScreen - io . MousePos ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
const float distance = makeVect ( distanceOnScreen ) . Length ( ) ;
if ( distance < 8.f ) // pixel size
{
type = MT_ROTATE_X + i ;
}
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
2017-12-31 10:50:49 +01:00
return type ;
}
2021-07-08 16:09:40 +02:00
static int GetMoveType ( OPERATION op , vec_t * gizmoHitProportion )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
if ( ! Intersects ( op , TRANSLATE ) | | gContext . mbUsing | | ! gContext . mbMouseOver )
2021-07-08 16:09:40 +02:00
{
return MT_NONE ;
}
2017-12-31 10:50:49 +01:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2021-07-08 16:09:40 +02:00
int type = MT_NONE ;
2017-12-31 10:50:49 +01:00
// screen
if ( io . MousePos . x > = gContext . mScreenSquareMin . x & & io . MousePos . x < = gContext . mScreenSquareMax . x & &
2021-07-08 16:09:40 +02:00
io . MousePos . y > = gContext . mScreenSquareMin . y & & io . MousePos . y < = gContext . mScreenSquareMax . y & &
Contains ( op , TRANSLATE ) )
{
type = MT_MOVE_SCREEN ;
}
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
const vec_t screenCoord = makeVect ( io . MousePos - ImVec2 ( gContext . mX , gContext . mY ) ) ;
2017-12-31 10:50:49 +01:00
// compute
2024-08-16 14:37:22 +02:00
for ( int i = 0 ; i < 3 & & type = = MT_NONE ; i + + )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
vec_t dirPlaneX , dirPlaneY , dirAxis ;
2017-12-31 10:50:49 +01:00
bool belowAxisLimit , belowPlaneLimit ;
2021-07-08 16:09:40 +02:00
ComputeTripodAxisAndVisibility ( i , dirAxis , dirPlaneX , dirPlaneY , belowAxisLimit , belowPlaneLimit ) ;
dirAxis . TransformVector ( gContext . mModel ) ;
2017-12-31 10:50:49 +01:00
dirPlaneX . TransformVector ( gContext . mModel ) ;
dirPlaneY . TransformVector ( gContext . mModel ) ;
2021-07-08 16:09:40 +02:00
const float len = IntersectRayPlane ( gContext . mRayOrigin , gContext . mRayVector , BuildPlan ( gContext . mModel . v . position , dirAxis ) ) ;
2017-12-31 10:50:49 +01:00
vec_t posOnPlan = gContext . mRayOrigin + gContext . mRayVector * len ;
2021-07-08 16:09:40 +02:00
const ImVec2 axisStartOnScreen = worldToPos ( gContext . mModel . v . position + dirAxis * gContext . mScreenFactor * 0.1f , gContext . mViewProjection ) - ImVec2 ( gContext . mX , gContext . mY ) ;
const ImVec2 axisEndOnScreen = worldToPos ( gContext . mModel . v . position + dirAxis * gContext . mScreenFactor , gContext . mViewProjection ) - ImVec2 ( gContext . mX , gContext . mY ) ;
vec_t closestPointOnAxis = PointOnSegment ( screenCoord , makeVect ( axisStartOnScreen ) , makeVect ( axisEndOnScreen ) ) ;
if ( ( closestPointOnAxis - screenCoord ) . Length ( ) < 12.f & & Intersects ( op , static_cast < OPERATION > ( TRANSLATE_X < < i ) ) ) // pixel size
{
type = MT_MOVE_X + i ;
}
2017-12-31 10:50:49 +01:00
const float dx = dirPlaneX . Dot3 ( ( posOnPlan - gContext . mModel . v . position ) * ( 1.f / gContext . mScreenFactor ) ) ;
const float dy = dirPlaneY . Dot3 ( ( posOnPlan - gContext . mModel . v . position ) * ( 1.f / gContext . mScreenFactor ) ) ;
2021-07-08 16:09:40 +02:00
if ( belowPlaneLimit & & dx > = quadUV [ 0 ] & & dx < = quadUV [ 4 ] & & dy > = quadUV [ 1 ] & & dy < = quadUV [ 3 ] & & Contains ( op , TRANSLATE_PLANS [ i ] ) )
{
type = MT_MOVE_YZ + i ;
}
2017-12-31 10:50:49 +01:00
if ( gizmoHitProportion )
2021-07-08 16:09:40 +02:00
{
2017-12-31 10:50:49 +01:00
* gizmoHitProportion = makeVect ( dx , dy , 0.f ) ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
}
return type ;
}
2021-07-08 16:09:40 +02:00
static bool HandleTranslation ( float * matrix , float * deltaMatrix , OPERATION op , int & type , const float * snap )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
if ( ! Intersects ( op , TRANSLATE ) | | type ! = MT_NONE )
{
return false ;
}
2024-08-16 14:37:22 +02:00
const ImGuiIO & io = ImGui : : GetIO ( ) ;
const bool applyRotationLocaly = gContext . mMode = = LOCAL | | type = = MT_MOVE_SCREEN ;
2021-07-08 16:09:40 +02:00
bool modified = false ;
2017-12-31 10:50:49 +01:00
// move
2021-07-08 16:09:40 +02:00
if ( gContext . mbUsing & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) & & IsTranslateType ( gContext . mCurrentOperation ) )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
# if IMGUI_VERSION_NUM >= 18723
ImGui : : SetNextFrameWantCaptureMouse ( true ) ;
# else
2017-12-31 10:50:49 +01:00
ImGui : : CaptureMouseFromApp ( ) ;
2024-08-16 14:37:22 +02:00
# endif
const float signedLength = IntersectRayPlane ( gContext . mRayOrigin , gContext . mRayVector , gContext . mTranslationPlan ) ;
const float len = fabsf ( signedLength ) ; // near plan
const vec_t newPos = gContext . mRayOrigin + gContext . mRayVector * len ;
2017-12-31 10:50:49 +01:00
// compute delta
2024-08-16 14:37:22 +02:00
const vec_t newOrigin = newPos - gContext . mRelativeOrigin * gContext . mScreenFactor ;
2017-12-31 10:50:49 +01:00
vec_t delta = newOrigin - gContext . mModel . v . position ;
2021-07-08 16:09:40 +02:00
2017-12-31 10:50:49 +01:00
// 1 axis constraint
2021-07-08 16:09:40 +02:00
if ( gContext . mCurrentOperation > = MT_MOVE_X & & gContext . mCurrentOperation < = MT_MOVE_Z )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
const int axisIndex = gContext . mCurrentOperation - MT_MOVE_X ;
2017-12-31 10:50:49 +01:00
const vec_t & axisValue = * ( vec_t * ) & gContext . mModel . m [ axisIndex ] ;
2024-08-16 14:37:22 +02:00
const float lengthOnAxis = Dot ( axisValue , delta ) ;
2017-12-31 10:50:49 +01:00
delta = axisValue * lengthOnAxis ;
}
// snap
if ( snap )
{
vec_t cumulativeDelta = gContext . mModel . v . position + delta - gContext . mMatrixOrigin ;
if ( applyRotationLocaly )
{
matrix_t modelSourceNormalized = gContext . mModelSource ;
modelSourceNormalized . OrthoNormalize ( ) ;
matrix_t modelSourceNormalizedInverse ;
modelSourceNormalizedInverse . Inverse ( modelSourceNormalized ) ;
cumulativeDelta . TransformVector ( modelSourceNormalizedInverse ) ;
ComputeSnap ( cumulativeDelta , snap ) ;
cumulativeDelta . TransformVector ( modelSourceNormalized ) ;
}
else
{
ComputeSnap ( cumulativeDelta , snap ) ;
}
delta = gContext . mMatrixOrigin + cumulativeDelta - gContext . mModel . v . position ;
}
2021-07-08 16:09:40 +02:00
if ( delta ! = gContext . mTranslationLastDelta )
{
modified = true ;
}
gContext . mTranslationLastDelta = delta ;
2017-12-31 10:50:49 +01:00
// compute matrix & delta
matrix_t deltaMatrixTranslation ;
deltaMatrixTranslation . Translation ( delta ) ;
if ( deltaMatrix )
2021-07-08 16:09:40 +02:00
{
2017-12-31 10:50:49 +01:00
memcpy ( deltaMatrix , deltaMatrixTranslation . m16 , sizeof ( float ) * 16 ) ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
2024-08-16 14:37:22 +02:00
const matrix_t res = gContext . mModelSource * deltaMatrixTranslation ;
2017-12-31 10:50:49 +01:00
* ( matrix_t * ) matrix = res ;
if ( ! io . MouseDown [ 0 ] )
2021-07-08 16:09:40 +02:00
{
2017-12-31 10:50:49 +01:00
gContext . mbUsing = false ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
type = gContext . mCurrentOperation ;
}
else
{
// find new possible way to move
vec_t gizmoHitProportion ;
2021-07-08 16:09:40 +02:00
type = GetMoveType ( op , & gizmoHitProportion ) ;
if ( type ! = MT_NONE )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
# if IMGUI_VERSION_NUM >= 18723
ImGui : : SetNextFrameWantCaptureMouse ( true ) ;
# else
2017-12-31 10:50:49 +01:00
ImGui : : CaptureMouseFromApp ( ) ;
2024-08-16 14:37:22 +02:00
# endif
2021-07-08 16:09:40 +02:00
}
if ( CanActivate ( ) & & type ! = MT_NONE )
{
2017-12-31 10:50:49 +01:00
gContext . mbUsing = true ;
2021-07-08 16:09:40 +02:00
gContext . mEditingID = gContext . mActualID ;
2017-12-31 10:50:49 +01:00
gContext . mCurrentOperation = type ;
2021-07-08 16:09:40 +02:00
vec_t movePlanNormal [ ] = { gContext . mModel . v . right , gContext . mModel . v . up , gContext . mModel . v . dir ,
gContext . mModel . v . right , gContext . mModel . v . up , gContext . mModel . v . dir ,
- gContext . mCameraDir } ;
vec_t cameraToModelNormalized = Normalized ( gContext . mModel . v . position - gContext . mCameraEye ) ;
for ( unsigned int i = 0 ; i < 3 ; i + + )
{
vec_t orthoVector = Cross ( movePlanNormal [ i ] , cameraToModelNormalized ) ;
movePlanNormal [ i ] . Cross ( orthoVector ) ;
movePlanNormal [ i ] . Normalize ( ) ;
}
2017-12-31 10:50:49 +01:00
// pickup plan
2021-07-08 16:09:40 +02:00
gContext . mTranslationPlan = BuildPlan ( gContext . mModel . v . position , movePlanNormal [ type - MT_MOVE_X ] ) ;
2017-12-31 10:50:49 +01:00
const float len = IntersectRayPlane ( gContext . mRayOrigin , gContext . mRayVector , gContext . mTranslationPlan ) ;
gContext . mTranslationPlanOrigin = gContext . mRayOrigin + gContext . mRayVector * len ;
gContext . mMatrixOrigin = gContext . mModel . v . position ;
gContext . mRelativeOrigin = ( gContext . mTranslationPlanOrigin - gContext . mModel . v . position ) * ( 1.f / gContext . mScreenFactor ) ;
}
}
2021-07-08 16:09:40 +02:00
return modified ;
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
static bool HandleScale ( float * matrix , float * deltaMatrix , OPERATION op , int & type , const float * snap )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
if ( ( ! Intersects ( op , SCALE ) & & ! Intersects ( op , SCALEU ) ) | | type ! = MT_NONE | | ! gContext . mbMouseOver )
2021-07-08 16:09:40 +02:00
{
return false ;
}
2017-12-31 10:50:49 +01:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2021-07-08 16:09:40 +02:00
bool modified = false ;
2017-12-31 10:50:49 +01:00
if ( ! gContext . mbUsing )
{
// find new possible way to scale
2021-07-08 16:09:40 +02:00
type = GetScaleType ( op ) ;
if ( type ! = MT_NONE )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
# if IMGUI_VERSION_NUM >= 18723
ImGui : : SetNextFrameWantCaptureMouse ( true ) ;
# else
2017-12-31 10:50:49 +01:00
ImGui : : CaptureMouseFromApp ( ) ;
2024-08-16 14:37:22 +02:00
# endif
2021-07-08 16:09:40 +02:00
}
if ( CanActivate ( ) & & type ! = MT_NONE )
{
2017-12-31 10:50:49 +01:00
gContext . mbUsing = true ;
2021-07-08 16:09:40 +02:00
gContext . mEditingID = gContext . mActualID ;
2017-12-31 10:50:49 +01:00
gContext . mCurrentOperation = type ;
const vec_t movePlanNormal [ ] = { gContext . mModel . v . up , gContext . mModel . v . dir , gContext . mModel . v . right , gContext . mModel . v . dir , gContext . mModel . v . up , gContext . mModel . v . right , - gContext . mCameraDir } ;
// pickup plan
2021-07-08 16:09:40 +02:00
gContext . mTranslationPlan = BuildPlan ( gContext . mModel . v . position , movePlanNormal [ type - MT_SCALE_X ] ) ;
2017-12-31 10:50:49 +01:00
const float len = IntersectRayPlane ( gContext . mRayOrigin , gContext . mRayVector , gContext . mTranslationPlan ) ;
gContext . mTranslationPlanOrigin = gContext . mRayOrigin + gContext . mRayVector * len ;
gContext . mMatrixOrigin = gContext . mModel . v . position ;
gContext . mScale . Set ( 1.f , 1.f , 1.f ) ;
gContext . mRelativeOrigin = ( gContext . mTranslationPlanOrigin - gContext . mModel . v . position ) * ( 1.f / gContext . mScreenFactor ) ;
gContext . mScaleValueOrigin = makeVect ( gContext . mModelSource . v . right . Length ( ) , gContext . mModelSource . v . up . Length ( ) , gContext . mModelSource . v . dir . Length ( ) ) ;
gContext . mSaveMousePosx = io . MousePos . x ;
}
}
// scale
2021-07-08 16:09:40 +02:00
if ( gContext . mbUsing & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) & & IsScaleType ( gContext . mCurrentOperation ) )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
# if IMGUI_VERSION_NUM >= 18723
ImGui : : SetNextFrameWantCaptureMouse ( true ) ;
# else
2017-12-31 10:50:49 +01:00
ImGui : : CaptureMouseFromApp ( ) ;
2024-08-16 14:37:22 +02:00
# endif
2017-12-31 10:50:49 +01:00
const float len = IntersectRayPlane ( gContext . mRayOrigin , gContext . mRayVector , gContext . mTranslationPlan ) ;
vec_t newPos = gContext . mRayOrigin + gContext . mRayVector * len ;
vec_t newOrigin = newPos - gContext . mRelativeOrigin * gContext . mScreenFactor ;
2024-08-16 14:37:22 +02:00
vec_t delta = newOrigin - gContext . mModelLocal . v . position ;
2021-07-08 16:09:40 +02:00
2017-12-31 10:50:49 +01:00
// 1 axis constraint
2021-07-08 16:09:40 +02:00
if ( gContext . mCurrentOperation > = MT_SCALE_X & & gContext . mCurrentOperation < = MT_SCALE_Z )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
int axisIndex = gContext . mCurrentOperation - MT_SCALE_X ;
2024-08-16 14:37:22 +02:00
const vec_t & axisValue = * ( vec_t * ) & gContext . mModelLocal . m [ axisIndex ] ;
2017-12-31 10:50:49 +01:00
float lengthOnAxis = Dot ( axisValue , delta ) ;
delta = axisValue * lengthOnAxis ;
2024-08-16 14:37:22 +02:00
vec_t baseVector = gContext . mTranslationPlanOrigin - gContext . mModelLocal . v . position ;
2017-12-31 10:50:49 +01:00
float ratio = Dot ( axisValue , baseVector + delta ) / Dot ( axisValue , baseVector ) ;
2021-07-08 16:09:40 +02:00
2017-12-31 10:50:49 +01:00
gContext . mScale [ axisIndex ] = max ( ratio , 0.001f ) ;
}
else
2021-07-08 16:09:40 +02:00
{
float scaleDelta = ( io . MousePos . x - gContext . mSaveMousePosx ) * 0.01f ;
2017-12-31 10:50:49 +01:00
gContext . mScale . Set ( max ( 1.f + scaleDelta , 0.001f ) ) ;
}
// snap
if ( snap )
{
float scaleSnap [ ] = { snap [ 0 ] , snap [ 0 ] , snap [ 0 ] } ;
ComputeSnap ( gContext . mScale , scaleSnap ) ;
}
// no 0 allowed
2021-07-08 16:09:40 +02:00
for ( int i = 0 ; i < 3 ; i + + )
2017-12-31 10:50:49 +01:00
gContext . mScale [ i ] = max ( gContext . mScale [ i ] , 0.001f ) ;
2021-07-08 16:09:40 +02:00
if ( gContext . mScaleLast ! = gContext . mScale )
{
modified = true ;
}
gContext . mScaleLast = gContext . mScale ;
2017-12-31 10:50:49 +01:00
// compute matrix & delta
matrix_t deltaMatrixScale ;
deltaMatrixScale . Scale ( gContext . mScale * gContext . mScaleValueOrigin ) ;
2021-07-08 16:09:40 +02:00
2024-08-16 14:37:22 +02:00
matrix_t res = deltaMatrixScale * gContext . mModelLocal ;
2017-12-31 10:50:49 +01:00
* ( matrix_t * ) matrix = res ;
2021-07-08 16:09:40 +02:00
2017-12-31 10:50:49 +01:00
if ( deltaMatrix )
{
2021-07-08 16:09:40 +02:00
vec_t deltaScale = gContext . mScale * gContext . mScaleValueOrigin ;
vec_t originalScaleDivider ;
originalScaleDivider . x = 1 / gContext . mModelScaleOrigin . x ;
originalScaleDivider . y = 1 / gContext . mModelScaleOrigin . y ;
originalScaleDivider . z = 1 / gContext . mModelScaleOrigin . z ;
deltaScale = deltaScale * originalScaleDivider ;
deltaMatrixScale . Scale ( deltaScale ) ;
2017-12-31 10:50:49 +01:00
memcpy ( deltaMatrix , deltaMatrixScale . m16 , sizeof ( float ) * 16 ) ;
}
if ( ! io . MouseDown [ 0 ] )
2021-07-08 16:09:40 +02:00
{
2017-12-31 10:50:49 +01:00
gContext . mbUsing = false ;
2021-07-08 16:09:40 +02:00
gContext . mScale . Set ( 1.f , 1.f , 1.f ) ;
}
2017-12-31 10:50:49 +01:00
type = gContext . mCurrentOperation ;
}
2021-07-08 16:09:40 +02:00
return modified ;
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
static bool HandleRotation ( float * matrix , float * deltaMatrix , OPERATION op , int & type , const float * snap )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
if ( ! Intersects ( op , ROTATE ) | | type ! = MT_NONE | | ! gContext . mbMouseOver )
2021-07-08 16:09:40 +02:00
{
return false ;
}
2017-12-31 10:50:49 +01:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
bool applyRotationLocaly = gContext . mMode = = LOCAL ;
2021-07-08 16:09:40 +02:00
bool modified = false ;
2017-12-31 10:50:49 +01:00
if ( ! gContext . mbUsing )
{
2021-07-08 16:09:40 +02:00
type = GetRotateType ( op ) ;
if ( type ! = MT_NONE )
{
2024-08-16 14:37:22 +02:00
# if IMGUI_VERSION_NUM >= 18723
ImGui : : SetNextFrameWantCaptureMouse ( true ) ;
# else
2021-07-08 16:09:40 +02:00
ImGui : : CaptureMouseFromApp ( ) ;
2024-08-16 14:37:22 +02:00
# endif
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
if ( type = = MT_ROTATE_SCREEN )
2017-12-31 10:50:49 +01:00
{
applyRotationLocaly = true ;
}
2021-07-08 16:09:40 +02:00
if ( CanActivate ( ) & & type ! = MT_NONE )
2017-12-31 10:50:49 +01:00
{
gContext . mbUsing = true ;
2021-07-08 16:09:40 +02:00
gContext . mEditingID = gContext . mActualID ;
2017-12-31 10:50:49 +01:00
gContext . mCurrentOperation = type ;
const vec_t rotatePlanNormal [ ] = { gContext . mModel . v . right , gContext . mModel . v . up , gContext . mModel . v . dir , - gContext . mCameraDir } ;
// pickup plan
if ( applyRotationLocaly )
{
2021-07-08 16:09:40 +02:00
gContext . mTranslationPlan = BuildPlan ( gContext . mModel . v . position , rotatePlanNormal [ type - MT_ROTATE_X ] ) ;
2017-12-31 10:50:49 +01:00
}
else
{
2021-07-08 16:09:40 +02:00
gContext . mTranslationPlan = BuildPlan ( gContext . mModelSource . v . position , directionUnary [ type - MT_ROTATE_X ] ) ;
2017-12-31 10:50:49 +01:00
}
const float len = IntersectRayPlane ( gContext . mRayOrigin , gContext . mRayVector , gContext . mTranslationPlan ) ;
vec_t localPos = gContext . mRayOrigin + gContext . mRayVector * len - gContext . mModel . v . position ;
gContext . mRotationVectorSource = Normalized ( localPos ) ;
gContext . mRotationAngleOrigin = ComputeAngleOnPlan ( ) ;
}
}
// rotation
2021-07-08 16:09:40 +02:00
if ( gContext . mbUsing & & ( gContext . mActualID = = - 1 | | gContext . mActualID = = gContext . mEditingID ) & & IsRotateType ( gContext . mCurrentOperation ) )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
# if IMGUI_VERSION_NUM >= 18723
ImGui : : SetNextFrameWantCaptureMouse ( true ) ;
# else
2017-12-31 10:50:49 +01:00
ImGui : : CaptureMouseFromApp ( ) ;
2024-08-16 14:37:22 +02:00
# endif
2017-12-31 10:50:49 +01:00
gContext . mRotationAngle = ComputeAngleOnPlan ( ) ;
if ( snap )
{
float snapInRadian = snap [ 0 ] * DEG2RAD ;
ComputeSnap ( & gContext . mRotationAngle , snapInRadian ) ;
}
vec_t rotationAxisLocalSpace ;
2021-07-08 16:09:40 +02:00
2017-12-31 10:50:49 +01:00
rotationAxisLocalSpace . TransformVector ( makeVect ( gContext . mTranslationPlan . x , gContext . mTranslationPlan . y , gContext . mTranslationPlan . z , 0.f ) , gContext . mModelInverse ) ;
rotationAxisLocalSpace . Normalize ( ) ;
matrix_t deltaRotation ;
deltaRotation . RotationAxis ( rotationAxisLocalSpace , gContext . mRotationAngle - gContext . mRotationAngleOrigin ) ;
2021-07-08 16:09:40 +02:00
if ( gContext . mRotationAngle ! = gContext . mRotationAngleOrigin )
{
modified = true ;
}
2017-12-31 10:50:49 +01:00
gContext . mRotationAngleOrigin = gContext . mRotationAngle ;
matrix_t scaleOrigin ;
scaleOrigin . Scale ( gContext . mModelScaleOrigin ) ;
2021-07-08 16:09:40 +02:00
2017-12-31 10:50:49 +01:00
if ( applyRotationLocaly )
{
2024-08-16 14:37:22 +02:00
* ( matrix_t * ) matrix = scaleOrigin * deltaRotation * gContext . mModelLocal ;
2017-12-31 10:50:49 +01:00
}
else
{
matrix_t res = gContext . mModelSource ;
res . v . position . Set ( 0.f ) ;
* ( matrix_t * ) matrix = res * deltaRotation ;
( ( matrix_t * ) matrix ) - > v . position = gContext . mModelSource . v . position ;
}
if ( deltaMatrix )
{
* ( matrix_t * ) deltaMatrix = gContext . mModelInverse * deltaRotation * gContext . mModel ;
}
if ( ! io . MouseDown [ 0 ] )
2021-07-08 16:09:40 +02:00
{
2017-12-31 10:50:49 +01:00
gContext . mbUsing = false ;
2021-07-08 16:09:40 +02:00
gContext . mEditingID = - 1 ;
}
2017-12-31 10:50:49 +01:00
type = gContext . mCurrentOperation ;
}
2021-07-08 16:09:40 +02:00
return modified ;
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
void DecomposeMatrixToComponents ( const float * matrix , float * translation , float * rotation , float * scale )
2017-12-31 10:50:49 +01:00
{
matrix_t mat = * ( matrix_t * ) matrix ;
scale [ 0 ] = mat . v . right . Length ( ) ;
scale [ 1 ] = mat . v . up . Length ( ) ;
2021-07-08 16:09:40 +02:00
scale [ 2 ] = mat . v . dir . Length ( ) ;
2017-12-31 10:50:49 +01:00
mat . OrthoNormalize ( ) ;
rotation [ 0 ] = RAD2DEG * atan2f ( mat . m [ 1 ] [ 2 ] , mat . m [ 2 ] [ 2 ] ) ;
2021-07-08 16:09:40 +02:00
rotation [ 1 ] = RAD2DEG * atan2f ( - mat . m [ 0 ] [ 2 ] , sqrtf ( mat . m [ 1 ] [ 2 ] * mat . m [ 1 ] [ 2 ] + mat . m [ 2 ] [ 2 ] * mat . m [ 2 ] [ 2 ] ) ) ;
2017-12-31 10:50:49 +01:00
rotation [ 2 ] = RAD2DEG * atan2f ( mat . m [ 0 ] [ 1 ] , mat . m [ 0 ] [ 0 ] ) ;
translation [ 0 ] = mat . v . position . x ;
translation [ 1 ] = mat . v . position . y ;
translation [ 2 ] = mat . v . position . z ;
}
2021-07-08 16:09:40 +02:00
void RecomposeMatrixFromComponents ( const float * translation , const float * rotation , const float * scale , float * matrix )
2017-12-31 10:50:49 +01:00
{
matrix_t & mat = * ( matrix_t * ) matrix ;
matrix_t rot [ 3 ] ;
2021-07-08 16:09:40 +02:00
for ( int i = 0 ; i < 3 ; i + + )
{
2017-12-31 10:50:49 +01:00
rot [ i ] . RotationAxis ( directionUnary [ i ] , rotation [ i ] * DEG2RAD ) ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
mat = rot [ 0 ] * rot [ 1 ] * rot [ 2 ] ;
float validScale [ 3 ] ;
for ( int i = 0 ; i < 3 ; i + + )
{
if ( fabsf ( scale [ i ] ) < FLT_EPSILON )
2021-07-08 16:09:40 +02:00
{
2017-12-31 10:50:49 +01:00
validScale [ i ] = 0.001f ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
else
2021-07-08 16:09:40 +02:00
{
2017-12-31 10:50:49 +01:00
validScale [ i ] = scale [ i ] ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
}
mat . v . right * = validScale [ 0 ] ;
mat . v . up * = validScale [ 1 ] ;
mat . v . dir * = validScale [ 2 ] ;
mat . v . position . Set ( translation [ 0 ] , translation [ 1 ] , translation [ 2 ] , 1.f ) ;
}
2021-07-08 16:09:40 +02:00
void SetID ( int id )
{
gContext . mActualID = id ;
}
void AllowAxisFlip ( bool value )
{
gContext . mAllowAxisFlip = value ;
}
2024-08-16 14:37:22 +02:00
void SetAxisLimit ( float value )
{
gContext . mAxisLimit = value ;
}
void SetPlaneLimit ( float value )
{
gContext . mPlaneLimit = value ;
}
2021-07-08 16:09:40 +02:00
bool Manipulate ( const float * view , const float * projection , OPERATION operation , MODE mode , float * matrix , float * deltaMatrix , const float * snap , const float * localBounds , const float * boundsSnap )
2017-12-31 10:50:49 +01:00
{
2024-08-16 14:37:22 +02:00
// Scale is always local or matrix will be skewed when applying world scale or oriented matrix
ComputeContext ( view , projection , matrix , ( operation & SCALE ) ? LOCAL : mode ) ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
// set delta to identity
2017-12-31 10:50:49 +01:00
if ( deltaMatrix )
2021-07-08 16:09:40 +02:00
{
2017-12-31 10:50:49 +01:00
( ( matrix_t * ) deltaMatrix ) - > SetToIdentity ( ) ;
2021-07-08 16:09:40 +02:00
}
2017-12-31 10:50:49 +01:00
// behind camera
vec_t camSpacePosition ;
camSpacePosition . TransformPoint ( makeVect ( 0.f , 0.f , 0.f ) , gContext . mMVP ) ;
2024-08-16 14:37:22 +02:00
if ( ! gContext . mIsOrthographic & & camSpacePosition . z < 0.001f & & ! gContext . mbUsing )
2021-07-08 16:09:40 +02:00
{
return false ;
}
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
// --
int type = MT_NONE ;
bool manipulated = false ;
2017-12-31 10:50:49 +01:00
if ( gContext . mbEnable )
{
2021-07-08 16:09:40 +02:00
if ( ! gContext . mbUsingBounds )
{
manipulated = HandleTranslation ( matrix , deltaMatrix , operation , type , snap ) | |
HandleScale ( matrix , deltaMatrix , operation , type , snap ) | |
HandleRotation ( matrix , deltaMatrix , operation , type , snap ) ;
}
2017-12-31 10:50:49 +01:00
}
if ( localBounds & & ! gContext . mbUsing )
2021-07-08 16:09:40 +02:00
{
HandleAndDrawLocalBounds ( localBounds , ( matrix_t * ) matrix , boundsSnap , operation ) ;
}
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
gContext . mOperation = operation ;
2017-12-31 10:50:49 +01:00
if ( ! gContext . mbUsingBounds )
{
2021-07-08 16:09:40 +02:00
DrawRotationGizmo ( operation , type ) ;
DrawTranslationGizmo ( operation , type ) ;
DrawScaleGizmo ( operation , type ) ;
2024-08-16 14:37:22 +02:00
DrawScaleUniveralGizmo ( operation , type ) ;
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
return manipulated ;
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
void SetGizmoSizeClipSpace ( float value )
{
gContext . mGizmoSizeClipSpace = value ;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void ComputeFrustumPlanes ( vec_t * frustum , const float * clip )
{
frustum [ 0 ] . x = clip [ 3 ] - clip [ 0 ] ;
frustum [ 0 ] . y = clip [ 7 ] - clip [ 4 ] ;
frustum [ 0 ] . z = clip [ 11 ] - clip [ 8 ] ;
frustum [ 0 ] . w = clip [ 15 ] - clip [ 12 ] ;
frustum [ 1 ] . x = clip [ 3 ] + clip [ 0 ] ;
frustum [ 1 ] . y = clip [ 7 ] + clip [ 4 ] ;
frustum [ 1 ] . z = clip [ 11 ] + clip [ 8 ] ;
frustum [ 1 ] . w = clip [ 15 ] + clip [ 12 ] ;
frustum [ 2 ] . x = clip [ 3 ] + clip [ 1 ] ;
frustum [ 2 ] . y = clip [ 7 ] + clip [ 5 ] ;
frustum [ 2 ] . z = clip [ 11 ] + clip [ 9 ] ;
frustum [ 2 ] . w = clip [ 15 ] + clip [ 13 ] ;
frustum [ 3 ] . x = clip [ 3 ] - clip [ 1 ] ;
frustum [ 3 ] . y = clip [ 7 ] - clip [ 5 ] ;
frustum [ 3 ] . z = clip [ 11 ] - clip [ 9 ] ;
frustum [ 3 ] . w = clip [ 15 ] - clip [ 13 ] ;
frustum [ 4 ] . x = clip [ 3 ] - clip [ 2 ] ;
frustum [ 4 ] . y = clip [ 7 ] - clip [ 6 ] ;
frustum [ 4 ] . z = clip [ 11 ] - clip [ 10 ] ;
frustum [ 4 ] . w = clip [ 15 ] - clip [ 14 ] ;
frustum [ 5 ] . x = clip [ 3 ] + clip [ 2 ] ;
frustum [ 5 ] . y = clip [ 7 ] + clip [ 6 ] ;
frustum [ 5 ] . z = clip [ 11 ] + clip [ 10 ] ;
frustum [ 5 ] . w = clip [ 15 ] + clip [ 14 ] ;
for ( int i = 0 ; i < 6 ; i + + )
{
frustum [ i ] . Normalize ( ) ;
}
}
void DrawCubes ( const float * view , const float * projection , const float * matrices , int matrixCount )
2017-12-31 10:50:49 +01:00
{
matrix_t viewInverse ;
viewInverse . Inverse ( * ( matrix_t * ) view ) ;
2021-07-08 16:09:40 +02:00
struct CubeFace
{
float z ;
ImVec2 faceCoordsScreen [ 4 ] ;
ImU32 color ;
} ;
CubeFace * faces = ( CubeFace * ) _malloca ( sizeof ( CubeFace ) * matrixCount * 6 ) ;
if ( ! faces )
{
return ;
}
vec_t frustum [ 6 ] ;
matrix_t viewProjection = * ( matrix_t * ) view * * ( matrix_t * ) projection ;
ComputeFrustumPlanes ( frustum , viewProjection . m16 ) ;
int cubeFaceCount = 0 ;
for ( int cube = 0 ; cube < matrixCount ; cube + + )
{
const float * matrix = & matrices [ cube * 16 ] ;
matrix_t res = * ( matrix_t * ) matrix * * ( matrix_t * ) view * * ( matrix_t * ) projection ;
for ( int iFace = 0 ; iFace < 6 ; iFace + + )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
const int normalIndex = ( iFace % 3 ) ;
const int perpXIndex = ( normalIndex + 1 ) % 3 ;
const int perpYIndex = ( normalIndex + 2 ) % 3 ;
const float invert = ( iFace > 2 ) ? - 1.f : 1.f ;
const vec_t faceCoords [ 4 ] = { directionUnary [ normalIndex ] + directionUnary [ perpXIndex ] + directionUnary [ perpYIndex ] ,
directionUnary [ normalIndex ] + directionUnary [ perpXIndex ] - directionUnary [ perpYIndex ] ,
directionUnary [ normalIndex ] - directionUnary [ perpXIndex ] - directionUnary [ perpYIndex ] ,
directionUnary [ normalIndex ] - directionUnary [ perpXIndex ] + directionUnary [ perpYIndex ] ,
} ;
// clipping
/*
bool skipFace = false ;
for ( unsigned int iCoord = 0 ; iCoord < 4 ; iCoord + + )
2017-12-31 10:50:49 +01:00
{
2021-07-08 16:09:40 +02:00
vec_t camSpacePosition ;
camSpacePosition . TransformPoint ( faceCoords [ iCoord ] * 0.5f * invert , res ) ;
if ( camSpacePosition . z < 0.001f )
{
skipFace = true ;
break ;
}
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
if ( skipFace )
{
continue ;
}
*/
vec_t centerPosition , centerPositionVP ;
centerPosition . TransformPoint ( directionUnary [ normalIndex ] * 0.5f * invert , * ( matrix_t * ) matrix ) ;
centerPositionVP . TransformPoint ( directionUnary [ normalIndex ] * 0.5f * invert , res ) ;
bool inFrustum = true ;
for ( int iFrustum = 0 ; iFrustum < 6 ; iFrustum + + )
{
float dist = DistanceToPlane ( centerPosition , frustum [ iFrustum ] ) ;
if ( dist < 0.f )
{
inFrustum = false ;
break ;
}
}
if ( ! inFrustum )
{
continue ;
}
CubeFace & cubeFace = faces [ cubeFaceCount ] ;
// 3D->2D
//ImVec2 faceCoordsScreen[4];
for ( unsigned int iCoord = 0 ; iCoord < 4 ; iCoord + + )
{
cubeFace . faceCoordsScreen [ iCoord ] = worldToPos ( faceCoords [ iCoord ] * 0.5f * invert , res ) ;
}
2024-08-16 14:37:22 +02:00
ImU32 directionColor = GetColorU32 ( DIRECTION_X + normalIndex ) ;
cubeFace . color = directionColor | IM_COL32 ( 0x80 , 0x80 , 0x80 , 0 ) ;
2021-07-08 16:09:40 +02:00
cubeFace . z = centerPositionVP . z / centerPositionVP . w ;
cubeFaceCount + + ;
2017-12-31 10:50:49 +01:00
}
2021-07-08 16:09:40 +02:00
}
qsort ( faces , cubeFaceCount , sizeof ( CubeFace ) , [ ] ( void const * _a , void const * _b ) {
CubeFace * a = ( CubeFace * ) _a ;
CubeFace * b = ( CubeFace * ) _b ;
if ( a - > z < b - > z )
{
return 1 ;
}
return - 1 ;
} ) ;
// draw face with lighter color
for ( int iFace = 0 ; iFace < cubeFaceCount ; iFace + + )
{
const CubeFace & cubeFace = faces [ iFace ] ;
gContext . mDrawList - > AddConvexPolyFilled ( cubeFace . faceCoordsScreen , 4 , cubeFace . color ) ;
}
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
_freea ( faces ) ;
}
void DrawGrid ( const float * view , const float * projection , const float * matrix , const float gridSize )
{
matrix_t viewProjection = * ( matrix_t * ) view * * ( matrix_t * ) projection ;
vec_t frustum [ 6 ] ;
ComputeFrustumPlanes ( frustum , viewProjection . m16 ) ;
matrix_t res = * ( matrix_t * ) matrix * viewProjection ;
for ( float f = - gridSize ; f < = gridSize ; f + = 1.f )
{
for ( int dir = 0 ; dir < 2 ; dir + + )
{
vec_t ptA = makeVect ( dir ? - gridSize : f , 0.f , dir ? f : - gridSize ) ;
vec_t ptB = makeVect ( dir ? gridSize : f , 0.f , dir ? f : gridSize ) ;
bool visible = true ;
for ( int i = 0 ; i < 6 ; i + + )
{
float dA = DistanceToPlane ( ptA , frustum [ i ] ) ;
float dB = DistanceToPlane ( ptB , frustum [ i ] ) ;
if ( dA < 0.f & & dB < 0.f )
{
visible = false ;
break ;
}
if ( dA > 0.f & & dB > 0.f )
{
continue ;
}
if ( dA < 0.f )
{
float len = fabsf ( dA - dB ) ;
float t = fabsf ( dA ) / len ;
ptA . Lerp ( ptB , t ) ;
}
if ( dB < 0.f )
{
float len = fabsf ( dB - dA ) ;
float t = fabsf ( dB ) / len ;
ptB . Lerp ( ptA , t ) ;
}
}
if ( visible )
{
ImU32 col = IM_COL32 ( 0x80 , 0x80 , 0x80 , 0xFF ) ;
col = ( fmodf ( fabsf ( f ) , 10.f ) < FLT_EPSILON ) ? IM_COL32 ( 0x90 , 0x90 , 0x90 , 0xFF ) : col ;
col = ( fabsf ( f ) < FLT_EPSILON ) ? IM_COL32 ( 0x40 , 0x40 , 0x40 , 0xFF ) : col ;
2017-12-31 10:50:49 +01:00
2021-07-08 16:09:40 +02:00
float thickness = 1.f ;
thickness = ( fmodf ( fabsf ( f ) , 10.f ) < FLT_EPSILON ) ? 1.5f : thickness ;
thickness = ( fabsf ( f ) < FLT_EPSILON ) ? 2.3f : thickness ;
gContext . mDrawList - > AddLine ( worldToPos ( ptA , res ) , worldToPos ( ptB , res ) , col , thickness ) ;
}
}
2017-12-31 10:50:49 +01:00
}
}
2024-08-16 14:37:22 +02:00
void ViewManipulate ( float * view , const float * projection , OPERATION operation , MODE mode , float * matrix , float length , ImVec2 position , ImVec2 size , ImU32 backgroundColor )
{
// Scale is always local or matrix will be skewed when applying world scale or oriented matrix
ComputeContext ( view , projection , matrix , ( operation & SCALE ) ? LOCAL : mode ) ;
ViewManipulate ( view , length , position , size , backgroundColor ) ;
}
2021-07-08 16:09:40 +02:00
void ViewManipulate ( float * view , float length , ImVec2 position , ImVec2 size , ImU32 backgroundColor )
{
static bool isDraging = false ;
static bool isClicking = false ;
static bool isInside = false ;
static vec_t interpolationUp ;
static vec_t interpolationDir ;
static int interpolationFrames = 0 ;
const vec_t referenceUp = makeVect ( 0.f , 1.f , 0.f ) ;
matrix_t svgView , svgProjection ;
svgView = gContext . mViewMat ;
svgProjection = gContext . mProjectionMat ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
gContext . mDrawList - > AddRectFilled ( position , position + size , backgroundColor ) ;
matrix_t viewInverse ;
viewInverse . Inverse ( * ( matrix_t * ) view ) ;
const vec_t camTarget = viewInverse . v . position - viewInverse . v . dir * length ;
// view/projection matrices
const float distance = 3.f ;
matrix_t cubeProjection , cubeView ;
float fov = acosf ( distance / ( sqrtf ( distance * distance + 3.f ) ) ) * RAD2DEG ;
Perspective ( fov / sqrtf ( 2.f ) , size . x / size . y , 0.01f , 1000.f , cubeProjection . m16 ) ;
vec_t dir = makeVect ( viewInverse . m [ 2 ] [ 0 ] , viewInverse . m [ 2 ] [ 1 ] , viewInverse . m [ 2 ] [ 2 ] ) ;
vec_t up = makeVect ( viewInverse . m [ 1 ] [ 0 ] , viewInverse . m [ 1 ] [ 1 ] , viewInverse . m [ 1 ] [ 2 ] ) ;
vec_t eye = dir * distance ;
vec_t zero = makeVect ( 0.f , 0.f ) ;
LookAt ( & eye . x , & zero . x , & up . x , cubeView . m16 ) ;
// set context
gContext . mViewMat = cubeView ;
gContext . mProjectionMat = cubeProjection ;
ComputeCameraRay ( gContext . mRayOrigin , gContext . mRayVector , position , size ) ;
const matrix_t res = cubeView * cubeProjection ;
// panels
static const ImVec2 panelPosition [ 9 ] = { ImVec2 ( 0.75f , 0.75f ) , ImVec2 ( 0.25f , 0.75f ) , ImVec2 ( 0.f , 0.75f ) ,
ImVec2 ( 0.75f , 0.25f ) , ImVec2 ( 0.25f , 0.25f ) , ImVec2 ( 0.f , 0.25f ) ,
ImVec2 ( 0.75f , 0.f ) , ImVec2 ( 0.25f , 0.f ) , ImVec2 ( 0.f , 0.f ) } ;
static const ImVec2 panelSize [ 9 ] = { ImVec2 ( 0.25f , 0.25f ) , ImVec2 ( 0.5f , 0.25f ) , ImVec2 ( 0.25f , 0.25f ) ,
ImVec2 ( 0.25f , 0.5f ) , ImVec2 ( 0.5f , 0.5f ) , ImVec2 ( 0.25f , 0.5f ) ,
ImVec2 ( 0.25f , 0.25f ) , ImVec2 ( 0.5f , 0.25f ) , ImVec2 ( 0.25f , 0.25f ) } ;
// tag faces
bool boxes [ 27 ] { } ;
2024-08-16 14:37:22 +02:00
static int overBox = - 1 ;
2021-07-08 16:09:40 +02:00
for ( int iPass = 0 ; iPass < 2 ; iPass + + )
{
for ( int iFace = 0 ; iFace < 6 ; iFace + + )
{
const int normalIndex = ( iFace % 3 ) ;
const int perpXIndex = ( normalIndex + 1 ) % 3 ;
const int perpYIndex = ( normalIndex + 2 ) % 3 ;
const float invert = ( iFace > 2 ) ? - 1.f : 1.f ;
const vec_t indexVectorX = directionUnary [ perpXIndex ] * invert ;
const vec_t indexVectorY = directionUnary [ perpYIndex ] * invert ;
const vec_t boxOrigin = directionUnary [ normalIndex ] * - invert - indexVectorX - indexVectorY ;
// plan local space
const vec_t n = directionUnary [ normalIndex ] * invert ;
vec_t viewSpaceNormal = n ;
vec_t viewSpacePoint = n * 0.5f ;
viewSpaceNormal . TransformVector ( cubeView ) ;
viewSpaceNormal . Normalize ( ) ;
viewSpacePoint . TransformPoint ( cubeView ) ;
const vec_t viewSpaceFacePlan = BuildPlan ( viewSpacePoint , viewSpaceNormal ) ;
// back face culling
if ( viewSpaceFacePlan . w > 0.f )
{
continue ;
}
const vec_t facePlan = BuildPlan ( n * 0.5f , n ) ;
const float len = IntersectRayPlane ( gContext . mRayOrigin , gContext . mRayVector , facePlan ) ;
vec_t posOnPlan = gContext . mRayOrigin + gContext . mRayVector * len - ( n * 0.5f ) ;
float localx = Dot ( directionUnary [ perpXIndex ] , posOnPlan ) * invert + 0.5f ;
float localy = Dot ( directionUnary [ perpYIndex ] , posOnPlan ) * invert + 0.5f ;
// panels
const vec_t dx = directionUnary [ perpXIndex ] ;
const vec_t dy = directionUnary [ perpYIndex ] ;
const vec_t origin = directionUnary [ normalIndex ] - dx - dy ;
for ( int iPanel = 0 ; iPanel < 9 ; iPanel + + )
{
vec_t boxCoord = boxOrigin + indexVectorX * float ( iPanel % 3 ) + indexVectorY * float ( iPanel / 3 ) + makeVect ( 1.f , 1.f , 1.f ) ;
const ImVec2 p = panelPosition [ iPanel ] * 2.f ;
const ImVec2 s = panelSize [ iPanel ] * 2.f ;
ImVec2 faceCoordsScreen [ 4 ] ;
vec_t panelPos [ 4 ] = { dx * p . x + dy * p . y ,
dx * p . x + dy * ( p . y + s . y ) ,
dx * ( p . x + s . x ) + dy * ( p . y + s . y ) ,
dx * ( p . x + s . x ) + dy * p . y } ;
for ( unsigned int iCoord = 0 ; iCoord < 4 ; iCoord + + )
{
faceCoordsScreen [ iCoord ] = worldToPos ( ( panelPos [ iCoord ] + origin ) * 0.5f * invert , res , position , size ) ;
}
const ImVec2 panelCorners [ 2 ] = { panelPosition [ iPanel ] , panelPosition [ iPanel ] + panelSize [ iPanel ] } ;
2024-08-16 14:37:22 +02:00
bool insidePanel = localx > panelCorners [ 0 ] . x & & localx < panelCorners [ 1 ] . x & & localy > panelCorners [ 0 ] . y & & localy < panelCorners [ 1 ] . y ;
2021-07-08 16:09:40 +02:00
int boxCoordInt = int ( boxCoord . x * 9.f + boxCoord . y * 3.f + boxCoord . z ) ;
2024-08-16 14:37:22 +02:00
IM_ASSERT ( boxCoordInt < 27 ) ;
boxes [ boxCoordInt ] | = insidePanel & & ( ! isDraging ) & & gContext . mbMouseOver ;
2021-07-08 16:09:40 +02:00
// draw face with lighter color
if ( iPass )
{
2024-08-16 14:37:22 +02:00
ImU32 directionColor = GetColorU32 ( DIRECTION_X + normalIndex ) ;
gContext . mDrawList - > AddConvexPolyFilled ( faceCoordsScreen , 4 , ( directionColor | IM_COL32 ( 0x80 , 0x80 , 0x80 , 0x80 ) ) | ( isInside ? IM_COL32 ( 0x08 , 0x08 , 0x08 , 0 ) : 0 ) ) ;
2021-07-08 16:09:40 +02:00
if ( boxes [ boxCoordInt ] )
{
gContext . mDrawList - > AddConvexPolyFilled ( faceCoordsScreen , 4 , IM_COL32 ( 0xF0 , 0xA0 , 0x60 , 0x80 ) ) ;
2024-08-16 14:37:22 +02:00
if ( io . MouseDown [ 0 ] & & ! isClicking & & ! isDraging & & GImGui - > ActiveId = = 0 ) {
overBox = boxCoordInt ;
2021-07-08 16:09:40 +02:00
isClicking = true ;
2024-08-16 14:37:22 +02:00
isDraging = true ;
2021-07-08 16:09:40 +02:00
}
}
}
}
}
}
if ( interpolationFrames )
{
interpolationFrames - - ;
vec_t newDir = viewInverse . v . dir ;
newDir . Lerp ( interpolationDir , 0.2f ) ;
newDir . Normalize ( ) ;
vec_t newUp = viewInverse . v . up ;
newUp . Lerp ( interpolationUp , 0.3f ) ;
newUp . Normalize ( ) ;
newUp = interpolationUp ;
vec_t newEye = camTarget + newDir * length ;
LookAt ( & newEye . x , & camTarget . x , & newUp . x , view ) ;
}
2024-08-16 14:37:22 +02:00
isInside = gContext . mbMouseOver & & ImRect ( position , position + size ) . Contains ( io . MousePos ) ;
2021-07-08 16:09:40 +02:00
2024-08-16 14:37:22 +02:00
if ( io . MouseDown [ 0 ] & & ( fabsf ( io . MouseDelta [ 0 ] ) | | fabsf ( io . MouseDelta [ 1 ] ) ) & & isClicking )
2021-07-08 16:09:40 +02:00
{
isClicking = false ;
}
2024-08-16 14:37:22 +02:00
if ( ! io . MouseDown [ 0 ] )
2021-07-08 16:09:40 +02:00
{
2024-08-16 14:37:22 +02:00
if ( isClicking )
{
// apply new view direction
int cx = overBox / 9 ;
int cy = ( overBox - cx * 9 ) / 3 ;
int cz = overBox % 3 ;
interpolationDir = makeVect ( 1.f - ( float ) cx , 1.f - ( float ) cy , 1.f - ( float ) cz ) ;
interpolationDir . Normalize ( ) ;
if ( fabsf ( Dot ( interpolationDir , referenceUp ) ) > 1.0f - 0.01f )
{
vec_t right = viewInverse . v . right ;
if ( fabsf ( right . x ) > fabsf ( right . z ) )
{
right . z = 0.f ;
}
else
{
right . x = 0.f ;
}
right . Normalize ( ) ;
interpolationUp = Cross ( interpolationDir , right ) ;
interpolationUp . Normalize ( ) ;
}
else
{
interpolationUp = referenceUp ;
}
interpolationFrames = 40 ;
}
isClicking = false ;
2021-07-08 16:09:40 +02:00
isDraging = false ;
}
2024-08-16 14:37:22 +02:00
2021-07-08 16:09:40 +02:00
if ( isDraging )
{
matrix_t rx , ry , roll ;
rx . RotationAxis ( referenceUp , - io . MouseDelta . x * 0.01f ) ;
ry . RotationAxis ( viewInverse . v . right , - io . MouseDelta . y * 0.01f ) ;
roll = rx * ry ;
vec_t newDir = viewInverse . v . dir ;
newDir . TransformVector ( roll ) ;
newDir . Normalize ( ) ;
// clamp
vec_t planDir = Cross ( viewInverse . v . right , referenceUp ) ;
planDir . y = 0.f ;
planDir . Normalize ( ) ;
float dt = Dot ( planDir , newDir ) ;
if ( dt < 0.0f )
{
newDir + = planDir * dt ;
newDir . Normalize ( ) ;
}
vec_t newEye = camTarget + newDir * length ;
LookAt ( & newEye . x , & camTarget . x , & referenceUp . x , view ) ;
}
// restore view/projection because it was used to compute ray
ComputeContext ( svgView . m16 , svgProjection . m16 , gContext . mModelSource . m16 , gContext . mMode ) ;
}
} ;