netradiant-custom/radiant/patchdialog.cpp
2022-10-27 09:10:31 +03:00

216 lines
6.5 KiB
C++

/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.
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
*/
//
// Leonardo Zide (leo@lokigames.com)
//
#include "patchdialog.h"
#include "itexdef.h"
#include "debugging/debugging.h"
#include <QGroupBox>
#include <QHBoxLayout>
#include "gtkutil/spinbox.h"
#include "gtkutil/nonmodal.h"
#include "dialog.h"
#include "gtkdlgs.h"
#include "mainframe.h"
#include "patchmanip.h"
#include "patch.h"
class PatchFixedSubdivisions
{
public:
PatchFixedSubdivisions() : m_enabled( false ), m_x( 0 ), m_y( 0 ){
}
PatchFixedSubdivisions( bool enabled, std::size_t x, std::size_t y ) : m_enabled( enabled ), m_x( x ), m_y( y ){
}
bool m_enabled;
std::size_t m_x;
std::size_t m_y;
};
void Patch_getFixedSubdivisions( const Patch& patch, PatchFixedSubdivisions& subdivisions ){
subdivisions.m_enabled = patch.m_patchDef3;
subdivisions.m_x = patch.m_subdivisions_x;
subdivisions.m_y = patch.m_subdivisions_y;
}
const std::size_t MAX_PATCH_SUBDIVISIONS = 32;
void Patch_setFixedSubdivisions( Patch& patch, const PatchFixedSubdivisions& subdivisions ){
patch.undoSave();
patch.m_patchDef3 = subdivisions.m_enabled;
patch.m_subdivisions_x = subdivisions.m_x;
patch.m_subdivisions_y = subdivisions.m_y;
if ( patch.m_subdivisions_x == 0 ) {
patch.m_subdivisions_x = 4;
}
else if ( patch.m_subdivisions_x > MAX_PATCH_SUBDIVISIONS ) {
patch.m_subdivisions_x = MAX_PATCH_SUBDIVISIONS;
}
if ( patch.m_subdivisions_y == 0 ) {
patch.m_subdivisions_y = 4;
}
else if ( patch.m_subdivisions_y > MAX_PATCH_SUBDIVISIONS ) {
patch.m_subdivisions_y = MAX_PATCH_SUBDIVISIONS;
}
SceneChangeNotify();
Patch_textureChanged();
patch.controlPointsChanged();
}
class PatchGetFixedSubdivisions
{
PatchFixedSubdivisions& m_subdivisions;
public:
PatchGetFixedSubdivisions( PatchFixedSubdivisions& subdivisions ) : m_subdivisions( subdivisions ){
}
void operator()( Patch& patch ){
Patch_getFixedSubdivisions( patch, m_subdivisions );
SceneChangeNotify();
}
};
void Scene_PatchGetFixedSubdivisions( PatchFixedSubdivisions& subdivisions ){
#if 1
if ( GlobalSelectionSystem().countSelected() != 0 ) {
Patch* patch = Node_getPatch( GlobalSelectionSystem().ultimateSelected().path().top() );
if ( patch != 0 ) {
Patch_getFixedSubdivisions( *patch, subdivisions );
}
}
#else
Scene_forEachVisibleSelectedPatch( PatchGetFixedSubdivisions( subdivisions ) );
#endif
}
void Scene_PatchSetFixedSubdivisions( const PatchFixedSubdivisions& subdivisions ){
UndoableCommand command( "patchSetFixedSubdivisions" );
Scene_forEachVisibleSelectedPatch( [subdivisions]( Patch& patch ){ Patch_setFixedSubdivisions( patch, subdivisions ); } );
}
class Subdivisions
{
public:
QGroupBox* m_enabled;
NonModalSpinner* m_horizontal;
NonModalSpinner* m_vertical;
Subdivisions() : m_enabled( 0 ), m_horizontal( 0 ), m_vertical( 0 ){
}
void update(){
PatchFixedSubdivisions subdivisions;
Scene_PatchGetFixedSubdivisions( subdivisions );
m_enabled->setChecked( subdivisions.m_enabled );
m_horizontal->setValue( subdivisions.m_x );
m_vertical->setValue( subdivisions.m_y );
}
void cancel(){
update();
}
typedef MemberCaller<Subdivisions, &Subdivisions::cancel> CancelCaller;
void apply(){
Scene_PatchSetFixedSubdivisions(
PatchFixedSubdivisions(
m_enabled->isChecked(),
static_cast<std::size_t>( m_horizontal->value() ),
static_cast<std::size_t>( m_vertical->value() )
)
);
}
typedef MemberCaller<Subdivisions, &Subdivisions::apply> ApplyCaller;
};
static Subdivisions *g_subdivisions;
QGroupBox* patch_tesselation_create(){
g_subdivisions = new Subdivisions;
auto *frame = g_subdivisions->m_enabled = new QGroupBox( "Fixed Tesselation" );
auto *hbox = new QHBoxLayout( frame );
hbox->setContentsMargins( 0, 0, 0, 0 );
auto *hspin = g_subdivisions->m_horizontal = new NonModalSpinner( 1, MAX_PATCH_SUBDIVISIONS, 4, 0, 1 );
hspin->setCallbacks( Subdivisions::ApplyCaller( *g_subdivisions ), Subdivisions::CancelCaller( *g_subdivisions ) );
auto *wlabel = new SpinBoxLabel( "H", hspin );
hbox->addWidget( wlabel, 0, Qt::AlignmentFlag::AlignRight );
hbox->addWidget( hspin, 0, Qt::AlignmentFlag::AlignLeft );
auto *vspin = g_subdivisions->m_vertical = new NonModalSpinner( 1, MAX_PATCH_SUBDIVISIONS, 4, 0, 1 );
vspin->setCallbacks( Subdivisions::ApplyCaller( *g_subdivisions ), Subdivisions::CancelCaller( *g_subdivisions ) );
auto *hlabel = new SpinBoxLabel( "V", vspin );
hbox->addWidget( hlabel, 0, Qt::AlignmentFlag::AlignRight );
hbox->addWidget( vspin, 0, Qt::AlignmentFlag::AlignLeft );
QObject::connect( frame, &QGroupBox::toggled, [hspin, wlabel, vspin, hlabel]( bool on ){
hspin->setVisible( on );
wlabel->setVisible( on );
vspin->setVisible( on );
hlabel->setVisible( on );
} );
frame->setCheckable( true );
frame->setChecked( false );
QObject::connect( frame, &QGroupBox::clicked, Subdivisions::ApplyCaller( *g_subdivisions ) );
return frame;
}
void patch_tesselation_update(){
if( g_subdivisions != nullptr ){
g_subdivisions->update();
}
}
void Scene_PatchRotateTexture_Selected( scene::Graph& graph, float angle ){
Scene_forEachVisibleSelectedPatch( [angle]( Patch& patch ){ patch.RotateTexture( angle ); } );
}
inline float Patch_convertScale( float scale ){
if ( scale > 0 ) {
return scale;
}
if ( scale < 0 ) {
return -1 / scale;
}
return 1;
}
void Scene_PatchScaleTexture_Selected( scene::Graph& graph, float s, float t ){
Scene_forEachVisibleSelectedPatch( [s = Patch_convertScale( s ), t = Patch_convertScale( t )]( Patch& patch ){ patch.ScaleTexture( s, t ); } );
}
void Scene_PatchTranslateTexture_Selected( scene::Graph& graph, float s, float t ){
Scene_forEachVisibleSelectedPatch( [s, t]( Patch& patch ){ patch.TranslateTexture( s, t ); } );
}