216 lines
6.5 KiB
C++
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 ); } );
|
|
}
|