Files
netradiant-custom/radiant/selection_mtable_scale.h
T
2026-01-03 20:27:45 +05:00

179 lines
7.1 KiB
C++

/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "selection_.h"
#include "grid.h"
class ScaleAxis : public Manipulatable
{
Vector3 m_start;
Vector3 m_axis;
Scalable& m_scalable;
Vector3 m_chosen_extent;
AABB m_bounds;
public:
ScaleAxis( Scalable& scalable )
: m_scalable( scalable ){
}
void Construct( const Matrix4& device2manip, const DeviceVector device_point, const AABB& bounds, const Vector3& transform_origin ) override {
m_start = point_on_axis( m_axis, device2manip, device_point );
m_chosen_extent = Vector3(
std::max( bounds.origin[0] + bounds.extents[0] - transform_origin[0], - bounds.origin[0] + bounds.extents[0] + transform_origin[0] ),
std::max( bounds.origin[1] + bounds.extents[1] - transform_origin[1], - bounds.origin[1] + bounds.extents[1] + transform_origin[1] ),
std::max( bounds.origin[2] + bounds.extents[2] - transform_origin[2], - bounds.origin[2] + bounds.extents[2] + transform_origin[2] )
);
m_bounds = bounds;
}
void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const DeviceVector device_point ) override {
//globalOutputStream() << "manip2object: " << manip2object << " device2manip: " << device2manip << " x: " << x << " y:" << y << '\n';
Vector3 current = point_on_axis( m_axis, device2manip, device_point );
Vector3 delta = vector3_subtracted( current, m_start );
delta = translation_local2object( delta, manip2object );
vector3_snap( delta, GetSnapGridSize() );
vector3_scale( delta, m_axis );
Vector3 start( vector3_snapped( m_start, GetSnapGridSize() != 0 ? GetSnapGridSize() : 1e-3f ) );
for ( std::size_t i = 0; i < 3; ++i ){ //prevent snapping to 0 with big gridsize
if( float_snapped( m_start[i], 1e-3f ) != 0 && start[i] == 0 ){
start[i] = GetSnapGridSize();
}
}
//globalOutputStream() << "m_start: " << m_start << " start: " << start << " delta: " << delta << '\n';
/* boundless way */
Vector3 scale(
start[0] == 0 ? 1 : 1 + delta[0] / start[0],
start[1] == 0 ? 1 : 1 + delta[1] / start[1],
start[2] == 0 ? 1 : 1 + delta[2] / start[2]
);
/* try bbox way */
for( std::size_t i = 0; i < 3; ++i ){
if( m_chosen_extent[i] > 0.0625f && m_axis[i] != 0 ){ //epsilon to prevent super high scale for set of models, having really small extent, formed by origins
scale[i] = ( m_chosen_extent[i] + delta[i] ) / m_chosen_extent[i];
if( g_modifiers.ctrl() ){ // snap bbox dimension size to grid
const float snappdwidth = float_snapped( scale[i] * m_bounds.extents[i] * 2.f, GetSnapGridSize() );
scale[i] = snappdwidth / ( m_bounds.extents[i] * 2.f );
}
}
}
if( g_modifiers.shift() ){ // scale all axes equally
for( std::size_t i = 0; i < 3; ++i ){
if( m_axis[i] == 0 ){
scale[i] = vector3_dot( scale, vector3_scaled( m_axis, m_axis ) );
}
}
}
//globalOutputStream() << "scale: " << scale << '\n';
m_scalable.scale( scale );
}
void SetAxis( const Vector3& axis ){
m_axis = axis;
}
};
class ScaleFree : public Manipulatable
{
Vector3 m_start;
Vector3 m_axis;
Vector3 m_axis2;
Scalable& m_scalable;
Vector3 m_chosen_extent;
AABB m_bounds;
public:
ScaleFree( Scalable& scalable )
: m_scalable( scalable ){
}
void Construct( const Matrix4& device2manip, const DeviceVector device_point, const AABB& bounds, const Vector3& transform_origin ) override {
m_start = point_on_plane( device2manip, device_point );
m_chosen_extent = Vector3(
std::max( bounds.origin[0] + bounds.extents[0] - transform_origin[0], -( bounds.origin[0] - bounds.extents[0] - transform_origin[0] ) ),
std::max( bounds.origin[1] + bounds.extents[1] - transform_origin[1], -( bounds.origin[1] - bounds.extents[1] - transform_origin[1] ) ),
std::max( bounds.origin[2] + bounds.extents[2] - transform_origin[2], -( bounds.origin[2] - bounds.extents[2] - transform_origin[2] ) )
);
m_bounds = bounds;
}
void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const DeviceVector device_point ) override {
Vector3 current = point_on_plane( device2manip, device_point );
Vector3 delta = vector3_subtracted( current, m_start );
delta = translation_local2object( delta, manip2object );
vector3_snap( delta, GetSnapGridSize() );
if( m_axis != g_vector3_identity )
delta = vector3_scaled( delta, m_axis ) + vector3_scaled( delta, m_axis2 );
Vector3 start( vector3_snapped( m_start, GetSnapGridSize() != 0 ? GetSnapGridSize() : 1e-3f ) );
for ( std::size_t i = 0; i < 3; ++i ){ //prevent snapping to 0 with big gridsize
if( float_snapped( m_start[i], 1e-3f ) != 0 && start[i] == 0 ){
start[i] = GetSnapGridSize();
}
}
const std::size_t ignore_axis = vector3_min_abs_component_index( m_start );
if( g_modifiers.shift() )
start[ignore_axis] = 0;
Vector3 scale(
start[0] == 0 ? 1 : 1 + delta[0] / start[0],
start[1] == 0 ? 1 : 1 + delta[1] / start[1],
start[2] == 0 ? 1 : 1 + delta[2] / start[2]
);
//globalOutputStream() << "m_start: " << m_start << " start: " << start << " delta: " << delta << '\n';
for( std::size_t i = 0; i < 3; ++i ){
if( m_chosen_extent[i] > 0.0625f && start[i] != 0 ){
scale[i] = ( m_chosen_extent[i] + delta[i] ) / m_chosen_extent[i];
if( g_modifiers.ctrl() ){ // snap bbox dimension size to grid
const float snappdwidth = float_snapped( scale[i] * m_bounds.extents[i] * 2.f, GetSnapGridSize() );
scale[i] = snappdwidth / ( m_bounds.extents[i] * 2.f );
}
}
}
//globalOutputStream() << "pre snap scale: " << scale << '\n';
if( g_modifiers.shift() ){ // snap 2 axes equally
float bestscale = ignore_axis != 0 ? scale[0] : scale[1];
for( std::size_t i = ignore_axis != 0 ? 1 : 2; i < 3; ++i ){
if( ignore_axis != i && std::fabs( scale[i] ) < std::fabs( bestscale ) ){
bestscale = scale[i];
}
//globalOutputStream() << "bestscale: " << bestscale << '\n';
}
for( std::size_t i = 0; i < 3; ++i ){
if( ignore_axis != i ){
scale[i] = ( scale[i] < 0 ) ? -std::fabs( bestscale ) : fabs( bestscale );
}
}
}
//globalOutputStream() << "scale: " << scale << '\n';
m_scalable.scale( scale );
}
void SetAxes( const Vector3& axis, const Vector3& axis2 ){
m_axis = axis;
m_axis2 = axis2;
}
};