2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 // Leonardo Zide (leo@lokigames.com)
28 #include "surfacedialog.h"
30 #include "debugging/debugging.h"
33 #include "iscenegraph.h"
36 #include "iselection.h"
38 #include <gtk/gtkhbox.h>
39 #include <gtk/gtkvbox.h>
40 #include <gtk/gtkframe.h>
41 #include <gtk/gtklabel.h>
42 #include <gtk/gtktable.h>
43 #include <gtk/gtkbutton.h>
44 #include <gtk/gtkspinbutton.h>
45 #include <gdk/gdkkeysyms.h>
46 #include <gtk/gtkcheckbutton.h> //Shamus: For Textool
48 #include "signal/isignal.h"
49 #include "generic/object.h"
50 #include "math/vector.h"
51 #include "texturelib.h"
52 #include "shaderlib.h"
55 #include "gtkutil/idledraw.h"
56 #include "gtkutil/dialog.h"
57 #include "gtkutil/entry.h"
58 #include "gtkutil/nonmodal.h"
59 #include "gtkutil/pointer.h"
60 #include "gtkutil/glwidget.h" //Shamus: For Textool
61 #include "gtkutil/button.h"
64 #include "patchmanip.h"
65 #include "brushmanip.h"
66 #include "patchdialog.h"
67 #include "preferences.h"
68 #include "brush_primit.h"
70 #include "mainframe.h"
73 #include "brush.h" //Shamus: for Textool
76 #include "stream/stringstream.h"
78 #include "textureentry.h"
80 //NOTE: Proper functioning of Textool currently requires that the "#if 1" lines in
81 // brush_primit.h be changed to "#if 0". add/removeScale screws this up ATM. :-)
82 // Plus, Radiant seems to work just fine without that stuff. ;-)
84 #define TEXTOOL_ENABLED 0
91 //Shamus: Textool function prototypes
92 gboolean size_allocate( GtkWidget *, GtkAllocation *, gpointer );
93 gboolean expose( GtkWidget *, GdkEventExpose *, gpointer );
94 gboolean button_press( GtkWidget *, GdkEventButton *, gpointer );
95 gboolean button_release( GtkWidget *, GdkEventButton *, gpointer );
96 gboolean motion( GtkWidget *, GdkEventMotion *, gpointer );
97 void flipX( GtkToggleButton *, gpointer );
98 void flipY( GtkToggleButton *, gpointer );
100 //End Textool function prototypes
102 //Shamus: Textool globals
103 GtkWidget * g_textoolWin;
104 //End Textool globals
107 gtk_widget_queue_draw( g_textoolWin );
114 inline void spin_button_set_step( GtkSpinButton* spin, gfloat step ){
116 gtk_spin_button_get_adjustment( spin )->step_increment = step;
118 GValue gvalue = GValue_default();
119 g_value_init( &gvalue, G_TYPE_DOUBLE );
120 g_value_set_double( &gvalue, step );
121 g_object_set( G_OBJECT( gtk_spin_button_get_adjustment( spin ) ), "step-increment", &gvalue, NULL );
129 GtkSpinButton* m_spin;
131 Increment( float& f ) : m_f( f ), m_spin( 0 ), m_entry( 0 ){
134 entry_set_float( m_entry, m_f );
136 typedef MemberCaller<Increment, &Increment::cancel> CancelCaller;
138 m_f = static_cast<float>( entry_get_float( m_entry ) );
139 spin_button_set_step( m_spin, m_f );
141 typedef MemberCaller<Increment, &Increment::apply> ApplyCaller;
144 void SurfaceInspector_GridChange();
146 class SurfaceInspector : public Dialog
148 GtkWindow* BuildDialog();
150 NonModalEntry m_textureEntry;
151 NonModalSpinner m_hshiftSpinner;
152 NonModalEntry m_hshiftEntry;
153 NonModalSpinner m_vshiftSpinner;
154 NonModalEntry m_vshiftEntry;
155 NonModalSpinner m_hscaleSpinner;
156 NonModalEntry m_hscaleEntry;
157 NonModalSpinner m_vscaleSpinner;
158 NonModalEntry m_vscaleEntry;
159 NonModalSpinner m_rotateSpinner;
160 NonModalEntry m_rotateEntry;
164 GtkCheckButton* m_surfaceFlags[32];
165 GtkCheckButton* m_contentFlags[32];
167 NonModalEntry m_valueEntry;
168 GtkEntry* m_valueEntryWidget;
170 WindowPositionTracker m_positionTracker;
171 WindowPositionTrackerImportStringCaller m_importPosition;
172 WindowPositionTrackerExportStringCaller m_exportPosition;
175 float m_fitHorizontal;
178 Increment m_hshiftIncrement;
179 Increment m_vshiftIncrement;
180 Increment m_hscaleIncrement;
181 Increment m_vscaleIncrement;
182 Increment m_rotateIncrement;
186 m_textureEntry( ApplyShaderCaller( *this ), UpdateCaller( *this ) ),
187 m_hshiftSpinner( ApplyTexdefCaller( *this ), UpdateCaller( *this ) ),
188 m_hshiftEntry( Increment::ApplyCaller( m_hshiftIncrement ), Increment::CancelCaller( m_hshiftIncrement ) ),
189 m_vshiftSpinner( ApplyTexdefCaller( *this ), UpdateCaller( *this ) ),
190 m_vshiftEntry( Increment::ApplyCaller( m_vshiftIncrement ), Increment::CancelCaller( m_vshiftIncrement ) ),
191 m_hscaleSpinner( ApplyTexdefCaller( *this ), UpdateCaller( *this ) ),
192 m_hscaleEntry( Increment::ApplyCaller( m_hscaleIncrement ), Increment::CancelCaller( m_hscaleIncrement ) ),
193 m_vscaleSpinner( ApplyTexdefCaller( *this ), UpdateCaller( *this ) ),
194 m_vscaleEntry( Increment::ApplyCaller( m_vscaleIncrement ), Increment::CancelCaller( m_vscaleIncrement ) ),
195 m_rotateSpinner( ApplyTexdefCaller( *this ), UpdateCaller( *this ) ),
196 m_rotateEntry( Increment::ApplyCaller( m_rotateIncrement ), Increment::CancelCaller( m_rotateIncrement ) ),
197 m_idleDraw( UpdateCaller( *this ) ),
198 m_valueEntry( ApplyFlagsCaller( *this ), UpdateCaller( *this ) ),
199 m_importPosition( m_positionTracker ),
200 m_exportPosition( m_positionTracker ),
201 m_hshiftIncrement( g_si_globals.shift[0] ),
202 m_vshiftIncrement( g_si_globals.shift[1] ),
203 m_hscaleIncrement( g_si_globals.scale[0] ),
204 m_vscaleIncrement( g_si_globals.scale[1] ),
205 m_rotateIncrement( g_si_globals.rotate ){
208 m_positionTracker.setPosition( c_default_window_pos );
211 void constructWindow( GtkWindow* main_window ){
212 m_parent = main_window;
214 AddGridChangeCallback( FreeCaller<SurfaceInspector_GridChange>() );
216 void destroyWindow(){
219 bool visible() const {
220 return GTK_WIDGET_VISIBLE( const_cast<GtkWindow*>( GetWidget() ) );
224 m_idleDraw.queueDraw();
229 typedef MemberCaller<SurfaceInspector, &SurfaceInspector::Update> UpdateCaller;
231 typedef MemberCaller<SurfaceInspector, &SurfaceInspector::ApplyShader> ApplyShaderCaller;
233 typedef MemberCaller<SurfaceInspector, &SurfaceInspector::ApplyTexdef> ApplyTexdefCaller;
235 typedef MemberCaller<SurfaceInspector, &SurfaceInspector::ApplyFlags> ApplyFlagsCaller;
240 SurfaceInspector* g_SurfaceInspector;
242 inline SurfaceInspector& getSurfaceInspector(){
243 ASSERT_NOTNULL( g_SurfaceInspector );
244 return *g_SurfaceInspector;
248 void SurfaceInspector_constructWindow( GtkWindow* main_window ){
249 getSurfaceInspector().constructWindow( main_window );
251 void SurfaceInspector_destroyWindow(){
252 getSurfaceInspector().destroyWindow();
255 void SurfaceInspector_queueDraw(){
256 getSurfaceInspector().queueDraw();
261 CopiedString g_selectedShader;
262 TextureProjection g_selectedTexdef;
263 ContentsFlagsValue g_selectedFlags;
264 size_t g_selectedShaderSize[2];
267 void SurfaceInspector_SetSelectedShader( const char* shader ){
268 g_selectedShader = shader;
269 SurfaceInspector_queueDraw();
272 void SurfaceInspector_SetSelectedTexdef( const TextureProjection& projection ){
273 g_selectedTexdef = projection;
274 SurfaceInspector_queueDraw();
277 void SurfaceInspector_SetSelectedFlags( const ContentsFlagsValue& flags ){
278 g_selectedFlags = flags;
279 SurfaceInspector_queueDraw();
282 static bool s_texture_selection_dirty = false;
284 void SurfaceInspector_updateSelection(){
285 s_texture_selection_dirty = true;
286 SurfaceInspector_queueDraw();
289 if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES ) {
290 TexTool::queueDraw();
291 //globalOutputStream() << "textool texture changed..\n";
296 void SurfaceInspector_SelectionChanged( const Selectable& selectable ){
297 SurfaceInspector_updateSelection();
300 void SurfaceInspector_SetCurrent_FromSelected(){
301 if ( s_texture_selection_dirty == true ) {
302 s_texture_selection_dirty = false;
303 if ( !g_SelectedFaceInstances.empty() ) {
304 TextureProjection projection;
305 //This *may* be the point before it fucks up... Let's see!
306 //Yep, there was a call to removeScale in there...
307 Scene_BrushGetTexdef_Component_Selected( GlobalSceneGraph(), projection );
309 SurfaceInspector_SetSelectedTexdef( projection );
311 Scene_BrushGetShaderSize_Component_Selected( GlobalSceneGraph(), g_selectedShaderSize[0], g_selectedShaderSize[1] );
312 g_selectedTexdef.m_brushprimit_texdef.coords[0][2] = float_mod( g_selectedTexdef.m_brushprimit_texdef.coords[0][2], (float)g_selectedShaderSize[0] );
313 g_selectedTexdef.m_brushprimit_texdef.coords[1][2] = float_mod( g_selectedTexdef.m_brushprimit_texdef.coords[1][2], (float)g_selectedShaderSize[1] );
316 Scene_BrushGetShader_Component_Selected( GlobalSceneGraph(), name );
317 if ( string_not_empty( name.c_str() ) ) {
318 SurfaceInspector_SetSelectedShader( name.c_str() );
321 ContentsFlagsValue flags;
322 Scene_BrushGetFlags_Component_Selected( GlobalSceneGraph(), flags );
323 SurfaceInspector_SetSelectedFlags( flags );
327 TextureProjection projection;
328 Scene_BrushGetTexdef_Selected( GlobalSceneGraph(), projection );
329 SurfaceInspector_SetSelectedTexdef( projection );
332 Scene_BrushGetShader_Selected( GlobalSceneGraph(), name );
333 if ( string_empty( name.c_str() ) ) {
334 Scene_PatchGetShader_Selected( GlobalSceneGraph(), name );
336 if ( string_not_empty( name.c_str() ) ) {
337 SurfaceInspector_SetSelectedShader( name.c_str() );
340 ContentsFlagsValue flags( 0, 0, 0, false );
341 Scene_BrushGetFlags_Selected( GlobalSceneGraph(), flags );
342 SurfaceInspector_SetSelectedFlags( flags );
347 const char* SurfaceInspector_GetSelectedShader(){
348 SurfaceInspector_SetCurrent_FromSelected();
349 return g_selectedShader.c_str();
352 const TextureProjection& SurfaceInspector_GetSelectedTexdef(){
353 SurfaceInspector_SetCurrent_FromSelected();
354 return g_selectedTexdef;
357 const ContentsFlagsValue& SurfaceInspector_GetSelectedFlags(){
358 SurfaceInspector_SetCurrent_FromSelected();
359 return g_selectedFlags;
365 ===================================================
369 ===================================================
372 si_globals_t g_si_globals;
375 // make the shift increments match the grid settings
376 // the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size
377 // this depends on a scale value if you have selected a particular texture on which you want it to work:
378 // we move the textures in pixels, not world units. (i.e. increment values are in pixel)
379 // depending on the texture scale it doesn't take the same amount of pixels to move of GetGridSize()
380 // increment * scale = gridsize
381 // hscale and vscale are optional parameters, if they are zero they will be set to the default scale
382 // NOTE: the default scale depends if you are using BP mode or regular.
383 // For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f
385 void DoSnapTToGrid( float hscale, float vscale ){
386 g_si_globals.shift[0] = static_cast<float>( float_to_integer( static_cast<float>( GetGridSize() ) / hscale ) );
387 g_si_globals.shift[1] = static_cast<float>( float_to_integer( static_cast<float>( GetGridSize() ) / vscale ) );
388 getSurfaceInspector().queueDraw();
391 void SurfaceInspector_GridChange(){
392 if ( g_si_globals.m_bSnapTToGrid ) {
393 DoSnapTToGrid( Texdef_getDefaultTextureScale(), Texdef_getDefaultTextureScale() );
397 // make the shift increments match the grid settings
398 // the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size
399 // this depends on the current texture scale used?
400 // we move the textures in pixels, not world units. (i.e. increment values are in pixel)
401 // depending on the texture scale it doesn't take the same amount of pixels to move of GetGridSize()
402 // increment * scale = gridsize
403 static void OnBtnMatchGrid( GtkWidget *widget, gpointer data ){
404 float hscale, vscale;
405 hscale = static_cast<float>( gtk_spin_button_get_value_as_float( getSurfaceInspector().m_hscaleIncrement.m_spin ) );
406 vscale = static_cast<float>( gtk_spin_button_get_value_as_float( getSurfaceInspector().m_vscaleIncrement.m_spin ) );
408 if ( hscale == 0.0f || vscale == 0.0f ) {
409 globalOutputStream() << "ERROR: unexpected scale == 0.0f\n";
413 DoSnapTToGrid( hscale, vscale );
416 // DoSurface will always try to show the surface inspector
417 // or update it because something new has been selected
418 // Shamus: It does get called when the SI is hidden, but not when you select something new. ;-)
419 void DoSurface( void ){
420 if ( getSurfaceInspector().GetWidget() == 0 ) {
421 getSurfaceInspector().Create();
424 getSurfaceInspector().Update();
425 getSurfaceInspector().importData();
426 getSurfaceInspector().ShowDlg();
429 void SurfaceInspector_toggleShown(){
430 if ( getSurfaceInspector().visible() ) {
431 getSurfaceInspector().HideDlg();
439 void SurfaceInspector_FitTexture(){
440 UndoableCommand undo( "textureAutoFit" );
441 Select_FitTexture( getSurfaceInspector().m_fitHorizontal, getSurfaceInspector().m_fitVertical );
444 void SurfaceInspector_FitTextureW(){
445 UndoableCommand undo( "textureAutoFitW" );
446 Select_FitTextureW( getSurfaceInspector().m_fitHorizontal, getSurfaceInspector().m_fitVertical );
449 void SurfaceInspector_FitTextureH(){
450 UndoableCommand undo( "textureAutoFitH" );
451 Select_FitTextureH( getSurfaceInspector().m_fitHorizontal, getSurfaceInspector().m_fitVertical );
454 static void OnBtnPatchdetails( GtkWidget *widget, gpointer data ){
455 Scene_PatchCapTexture_Selected( GlobalSceneGraph() );
458 static void OnBtnPatchnatural( GtkWidget *widget, gpointer data ){
459 Scene_PatchNaturalTexture_Selected( GlobalSceneGraph() );
462 static void OnBtnPatchreset( GtkWidget *widget, gpointer data ){
465 if ( DoTextureLayout( &fx, &fy ) == eIDOK ) {
466 Scene_PatchTileTexture_Selected( GlobalSceneGraph(), fx, fy );
470 static void OnBtnPatchFit( GtkWidget *widget, gpointer data ){
471 Scene_PatchTileTexture_Selected( GlobalSceneGraph(), 1, 1 );
474 static void OnBtnAxial( GtkWidget *widget, gpointer data ){
475 //globalOutputStream() << "--> [OnBtnAxial]...\n";
476 UndoableCommand undo( "textureDefault" );
477 TextureProjection projection;
478 //globalOutputStream() << " TexDef_Construct_Default()...\n";
479 TexDef_Construct_Default( projection );
480 //globalOutputStream() << " Select_SetTexdef()...\n";
485 if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES ) {
486 // Scale up texture width/height if in BP mode...
487 //NOTE: This may not be correct any more! :-P
488 if ( !g_SelectedFaceInstances.empty() ) {
489 Face & face = g_SelectedFaceInstances.last().getFace();
490 float x = face.getShader().m_state->getTexture().width;
491 float y = face.getShader().m_state->getTexture().height;
492 projection.m_brushprimit_texdef.coords[0][0] /= x;
493 projection.m_brushprimit_texdef.coords[0][1] /= y;
494 projection.m_brushprimit_texdef.coords[1][0] /= x;
495 projection.m_brushprimit_texdef.coords[1][1] /= y;
500 Select_SetTexdef( projection );
503 static void OnBtnFaceFit( GtkWidget *widget, gpointer data ){
504 getSurfaceInspector().exportData();
505 SurfaceInspector_FitTexture();
508 static void OnBtnFaceFitW( GtkWidget *widget, gpointer data ){
509 getSurfaceInspector().exportData();
510 SurfaceInspector_FitTextureW();
513 static void OnBtnFaceFitH( GtkWidget *widget, gpointer data ){
514 getSurfaceInspector().exportData();
515 SurfaceInspector_FitTextureH();
520 typedef const char* FlagName;
522 const FlagName surfaceflagNamesDefault[32] = {
557 const FlagName contentflagNamesDefault[32] = {
592 const char* getSurfaceFlagName( std::size_t bit ){
593 const char* value = g_pGameDescription->getKeyValue( surfaceflagNamesDefault[bit] );
594 if ( string_empty( value ) ) {
595 return surfaceflagNamesDefault[bit];
600 const char* getContentFlagName( std::size_t bit ){
601 const char* value = g_pGameDescription->getKeyValue( contentflagNamesDefault[bit] );
602 if ( string_empty( value ) ) {
603 return contentflagNamesDefault[bit];
609 // =============================================================================
610 // SurfaceInspector class
612 guint togglebutton_connect_toggled( GtkToggleButton* button, const Callback& callback ){
613 return g_signal_connect_swapped( G_OBJECT( button ), "toggled", G_CALLBACK( callback.getThunk() ), callback.getEnvironment() );
616 GtkWindow* SurfaceInspector::BuildDialog(){
617 GtkWindow* window = create_floating_window( "Surface Inspector", m_parent );
619 m_positionTracker.connect( window );
621 global_accel_connect_window( window );
623 window_connect_focus_in_clear_focus_widget( window );
627 // replaced by only the vbox:
628 GtkWidget* vbox = gtk_vbox_new( FALSE, 5 );
629 gtk_widget_show( vbox );
630 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( vbox ) );
631 gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
634 GtkWidget* hbox2 = gtk_hbox_new( FALSE, 5 );
635 gtk_widget_show( hbox2 );
636 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox2 ), FALSE, FALSE, 0 );
639 GtkWidget* label = gtk_label_new( "Texture" );
640 gtk_widget_show( label );
641 gtk_box_pack_start( GTK_BOX( hbox2 ), label, FALSE, TRUE, 0 );
644 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
645 gtk_widget_show( GTK_WIDGET( entry ) );
646 gtk_box_pack_start( GTK_BOX( hbox2 ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
648 m_textureEntry.connect( entry );
649 GlobalTextureEntryCompletion::instance().connect( entry );
655 GtkWidget* table = gtk_table_new( 6, 4, FALSE );
656 gtk_widget_show( table );
657 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( table ), FALSE, FALSE, 0 );
658 gtk_table_set_row_spacings( GTK_TABLE( table ), 5 );
659 gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
661 GtkWidget* label = gtk_label_new( "Horizontal shift" );
662 gtk_widget_show( label );
663 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
664 gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1,
665 (GtkAttachOptions) ( GTK_FILL ),
666 (GtkAttachOptions) ( 0 ), 0, 0 );
669 GtkSpinButton* spin = GTK_SPIN_BUTTON( gtk_spin_button_new( GTK_ADJUSTMENT( gtk_adjustment_new( 0, -8192, 8192, 2, 8, 0 ) ), 0, 2 ) );
670 m_hshiftIncrement.m_spin = spin;
671 m_hshiftSpinner.connect( spin );
672 gtk_widget_show( GTK_WIDGET( spin ) );
673 gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( spin ), 1, 2, 0, 1,
674 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
675 (GtkAttachOptions) ( 0 ), 0, 0 );
676 gtk_widget_set_usize( GTK_WIDGET( spin ), 60, -2 );
679 GtkWidget* label = gtk_label_new( "Step" );
680 gtk_widget_show( label );
681 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
682 gtk_table_attach( GTK_TABLE( table ), label, 2, 3, 0, 1,
683 (GtkAttachOptions) ( GTK_FILL ),
684 (GtkAttachOptions) ( 0 ), 0, 0 );
687 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
688 gtk_widget_show( GTK_WIDGET( entry ) );
689 gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( entry ), 3, 4, 0, 1,
690 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
691 (GtkAttachOptions) ( 0 ), 0, 0 );
692 gtk_widget_set_usize( GTK_WIDGET( entry ), 50, -2 );
693 m_hshiftIncrement.m_entry = entry;
694 m_hshiftEntry.connect( entry );
697 GtkWidget* label = gtk_label_new( "Vertical shift" );
698 gtk_widget_show( label );
699 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
700 gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 1, 2,
701 (GtkAttachOptions) ( GTK_FILL ),
702 (GtkAttachOptions) ( 0 ), 0, 0 );
705 GtkSpinButton* spin = GTK_SPIN_BUTTON( gtk_spin_button_new( GTK_ADJUSTMENT( gtk_adjustment_new( 0, -8192, 8192, 2, 8, 0 ) ), 0, 2 ) );
706 m_vshiftIncrement.m_spin = spin;
707 m_vshiftSpinner.connect( spin );
708 gtk_widget_show( GTK_WIDGET( spin ) );
709 gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( spin ), 1, 2, 1, 2,
710 (GtkAttachOptions) ( GTK_FILL ),
711 (GtkAttachOptions) ( 0 ), 0, 0 );
712 gtk_widget_set_usize( GTK_WIDGET( spin ), 60, -2 );
715 GtkWidget* label = gtk_label_new( "Step" );
716 gtk_widget_show( label );
717 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
718 gtk_table_attach( GTK_TABLE( table ), label, 2, 3, 1, 2,
719 (GtkAttachOptions) ( GTK_FILL ),
720 (GtkAttachOptions) ( 0 ), 0, 0 );
723 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
724 gtk_widget_show( GTK_WIDGET( entry ) );
725 gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( entry ), 3, 4, 1, 2,
726 (GtkAttachOptions) ( GTK_FILL ),
727 (GtkAttachOptions) ( 0 ), 0, 0 );
728 gtk_widget_set_usize( GTK_WIDGET( entry ), 50, -2 );
729 m_vshiftIncrement.m_entry = entry;
730 m_vshiftEntry.connect( entry );
733 GtkWidget* label = gtk_label_new( "Horizontal stretch" );
734 gtk_widget_show( label );
735 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
736 gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 2, 3,
737 (GtkAttachOptions) ( GTK_FILL ),
738 (GtkAttachOptions) ( 0 ), 0, 0 );
741 GtkSpinButton* spin = GTK_SPIN_BUTTON( gtk_spin_button_new( GTK_ADJUSTMENT( gtk_adjustment_new( 0, -8192, 8192, 2, 8, 0 ) ), 0, 5 ) );
742 m_hscaleIncrement.m_spin = spin;
743 m_hscaleSpinner.connect( spin );
744 gtk_widget_show( GTK_WIDGET( spin ) );
745 gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( spin ), 1, 2, 2, 3,
746 (GtkAttachOptions) ( GTK_FILL ),
747 (GtkAttachOptions) ( 0 ), 0, 0 );
748 gtk_widget_set_usize( GTK_WIDGET( spin ), 60, -2 );
751 GtkWidget* label = gtk_label_new( "Step" );
752 gtk_widget_show( label );
753 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
754 gtk_table_attach( GTK_TABLE( table ), label, 2, 3, 2, 3,
755 (GtkAttachOptions) ( GTK_FILL ),
756 (GtkAttachOptions) ( 0 ), 2, 3 );
759 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
760 gtk_widget_show( GTK_WIDGET( entry ) );
761 gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( entry ), 3, 4, 2, 3,
762 (GtkAttachOptions) ( GTK_FILL ),
763 (GtkAttachOptions) ( 0 ), 2, 3 );
764 gtk_widget_set_usize( GTK_WIDGET( entry ), 50, -2 );
765 m_hscaleIncrement.m_entry = entry;
766 m_hscaleEntry.connect( entry );
769 GtkWidget* label = gtk_label_new( "Vertical stretch" );
770 gtk_widget_show( label );
771 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
772 gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 3, 4,
773 (GtkAttachOptions) ( GTK_FILL ),
774 (GtkAttachOptions) ( 0 ), 0, 0 );
777 GtkSpinButton* spin = GTK_SPIN_BUTTON( gtk_spin_button_new( GTK_ADJUSTMENT( gtk_adjustment_new( 0, -8192, 8192, 2, 8, 0 ) ), 0, 5 ) );
778 m_vscaleIncrement.m_spin = spin;
779 m_vscaleSpinner.connect( spin );
780 gtk_widget_show( GTK_WIDGET( spin ) );
781 gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( spin ), 1, 2, 3, 4,
782 (GtkAttachOptions) ( GTK_FILL ),
783 (GtkAttachOptions) ( 0 ), 0, 0 );
784 gtk_widget_set_usize( GTK_WIDGET( spin ), 60, -2 );
787 GtkWidget* label = gtk_label_new( "Step" );
788 gtk_widget_show( label );
789 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
790 gtk_table_attach( GTK_TABLE( table ), label, 2, 3, 3, 4,
791 (GtkAttachOptions) ( GTK_FILL ),
792 (GtkAttachOptions) ( 0 ), 0, 0 );
795 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
796 gtk_widget_show( GTK_WIDGET( entry ) );
797 gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( entry ), 3, 4, 3, 4,
798 (GtkAttachOptions) ( GTK_FILL ),
799 (GtkAttachOptions) ( 0 ), 0, 0 );
800 gtk_widget_set_usize( GTK_WIDGET( entry ), 50, -2 );
801 m_vscaleIncrement.m_entry = entry;
802 m_vscaleEntry.connect( entry );
805 GtkWidget* label = gtk_label_new( "Rotate" );
806 gtk_widget_show( label );
807 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
808 gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 4, 5,
809 (GtkAttachOptions) ( GTK_FILL ),
810 (GtkAttachOptions) ( 0 ), 0, 0 );
813 GtkSpinButton* spin = GTK_SPIN_BUTTON( gtk_spin_button_new( GTK_ADJUSTMENT( gtk_adjustment_new( 0, -8192, 8192, 2, 8, 0 ) ), 0, 2 ) );
814 m_rotateIncrement.m_spin = spin;
815 m_rotateSpinner.connect( spin );
816 gtk_widget_show( GTK_WIDGET( spin ) );
817 gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( spin ), 1, 2, 4, 5,
818 (GtkAttachOptions) ( GTK_FILL ),
819 (GtkAttachOptions) ( 0 ), 0, 0 );
820 gtk_widget_set_usize( GTK_WIDGET( spin ), 60, -2 );
821 gtk_spin_button_set_wrap( spin, TRUE );
824 GtkWidget* label = gtk_label_new( "Step" );
825 gtk_widget_show( label );
826 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0 );
827 gtk_table_attach( GTK_TABLE( table ), label, 2, 3, 4, 5,
828 (GtkAttachOptions) ( GTK_FILL ),
829 (GtkAttachOptions) ( 0 ), 0, 0 );
832 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
833 gtk_widget_show( GTK_WIDGET( entry ) );
834 gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( entry ), 3, 4, 4, 5,
835 (GtkAttachOptions) ( GTK_FILL ),
836 (GtkAttachOptions) ( 0 ), 0, 0 );
837 gtk_widget_set_usize( GTK_WIDGET( entry ), 50, -2 );
838 m_rotateIncrement.m_entry = entry;
839 m_rotateEntry.connect( entry );
843 GtkWidget* button = gtk_button_new_with_label( "Match Grid" );
844 gtk_widget_show( button );
845 gtk_table_attach( GTK_TABLE( table ), button, 2, 4, 5, 6,
846 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
847 (GtkAttachOptions) ( 0 ), 0, 0 );
848 g_signal_connect( G_OBJECT( button ), "clicked", G_CALLBACK( OnBtnMatchGrid ), 0 );
853 GtkWidget* frame = gtk_frame_new( "Texturing" );
854 gtk_widget_show( frame );
855 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
857 GtkWidget* table = gtk_table_new( 4, 4, FALSE );
858 gtk_widget_show( table );
859 gtk_container_add( GTK_CONTAINER( frame ), table );
860 gtk_table_set_row_spacings( GTK_TABLE( table ), 5 );
861 gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
862 gtk_container_set_border_width( GTK_CONTAINER( table ), 5 );
864 GtkWidget* label = gtk_label_new( "Brush" );
865 gtk_widget_show( label );
866 gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1,
867 (GtkAttachOptions) ( GTK_FILL ),
868 (GtkAttachOptions) ( 0 ), 0, 0 );
871 GtkWidget* label = gtk_label_new( "Patch" );
872 gtk_widget_show( label );
873 gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 2, 3,
874 (GtkAttachOptions) ( GTK_FILL ),
875 (GtkAttachOptions) ( 0 ), 0, 0 );
878 GtkWidget* button = gtk_button_new_with_label( "Width" );
879 gtk_widget_show( button );
880 gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 0, 1,
881 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
882 (GtkAttachOptions) ( 0 ), 0, 0 );
883 g_signal_connect( G_OBJECT( button ), "clicked",
884 G_CALLBACK( OnBtnFaceFitW ), 0 );
885 gtk_widget_set_usize( button, 60, -2 );
888 GtkWidget* button = gtk_button_new_with_label( "Height" );
889 gtk_widget_show( button );
890 gtk_table_attach( GTK_TABLE( table ), button, 3, 4, 0, 1,
891 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
892 (GtkAttachOptions) ( 0 ), 0, 0 );
893 g_signal_connect( G_OBJECT( button ), "clicked",
894 G_CALLBACK( OnBtnFaceFitH ), 0 );
895 gtk_widget_set_usize( button, 60, -2 );
898 GtkWidget* button = gtk_button_new_with_label( "Axial" );
899 gtk_widget_show( button );
900 gtk_table_attach( GTK_TABLE( table ), button, 0, 1, 1, 2,
901 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
902 (GtkAttachOptions) ( 0 ), 0, 0 );
903 g_signal_connect( G_OBJECT( button ), "clicked",
904 G_CALLBACK( OnBtnAxial ), 0 );
905 gtk_widget_set_usize( button, 60, -2 );
908 GtkWidget* button = gtk_button_new_with_label( "Fit" );
909 gtk_widget_show( button );
910 gtk_table_attach( GTK_TABLE( table ), button, 1, 2, 1, 2,
911 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
912 (GtkAttachOptions) ( 0 ), 0, 0 );
913 g_signal_connect( G_OBJECT( button ), "clicked",
914 G_CALLBACK( OnBtnFaceFit ), 0 );
915 gtk_widget_set_usize( button, 60, -2 );
918 GtkWidget* button = gtk_button_new_with_label( "CAP" );
919 gtk_widget_show( button );
920 gtk_table_attach( GTK_TABLE( table ), button, 0, 1, 3, 4,
921 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
922 (GtkAttachOptions) ( 0 ), 0, 0 );
923 g_signal_connect( G_OBJECT( button ), "clicked",
924 G_CALLBACK( OnBtnPatchdetails ), 0 );
925 gtk_widget_set_usize( button, 60, -2 );
928 GtkWidget* button = gtk_button_new_with_label( "Set..." );
929 gtk_widget_show( button );
930 gtk_table_attach( GTK_TABLE( table ), button, 1, 2, 3, 4,
931 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
932 (GtkAttachOptions) ( 0 ), 0, 0 );
933 g_signal_connect( G_OBJECT( button ), "clicked",
934 G_CALLBACK( OnBtnPatchreset ), 0 );
935 gtk_widget_set_usize( button, 60, -2 );
938 GtkWidget* button = gtk_button_new_with_label( "Natural" );
939 gtk_widget_show( button );
940 gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 3, 4,
941 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
942 (GtkAttachOptions) ( 0 ), 0, 0 );
943 g_signal_connect( G_OBJECT( button ), "clicked",
944 G_CALLBACK( OnBtnPatchnatural ), 0 );
945 gtk_widget_set_usize( button, 60, -2 );
948 GtkWidget* button = gtk_button_new_with_label( "Fit" );
949 gtk_widget_show( button );
950 gtk_table_attach( GTK_TABLE( table ), button, 3, 4, 3, 4,
951 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
952 (GtkAttachOptions) ( 0 ), 0, 0 );
953 g_signal_connect( G_OBJECT( button ), "clicked",
954 G_CALLBACK( OnBtnPatchFit ), 0 );
955 gtk_widget_set_usize( button, 60, -2 );
958 GtkWidget* spin = gtk_spin_button_new( GTK_ADJUSTMENT( gtk_adjustment_new( 1, 0, 1 << 16, 1, 10, 0 ) ), 0, 6 );
959 gtk_widget_show( spin );
960 gtk_table_attach( GTK_TABLE( table ), spin, 2, 3, 1, 2,
961 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
962 (GtkAttachOptions) ( 0 ), 0, 0 );
963 gtk_widget_set_usize( spin, 60, -2 );
964 AddDialogData( *GTK_SPIN_BUTTON( spin ), m_fitHorizontal );
967 GtkWidget* spin = gtk_spin_button_new( GTK_ADJUSTMENT( gtk_adjustment_new( 1, 0, 1 << 16, 1, 10, 0 ) ), 0, 6 );
968 gtk_widget_show( spin );
969 gtk_table_attach( GTK_TABLE( table ), spin, 3, 4, 1, 2,
970 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
971 (GtkAttachOptions) ( 0 ), 0, 0 );
972 gtk_widget_set_usize( spin, 60, -2 );
973 AddDialogData( *GTK_SPIN_BUTTON( spin ), m_fitVertical );
977 if ( !string_empty( g_pGameDescription->getKeyValue( "si_flags" ) ) ) {
979 GtkFrame* frame = GTK_FRAME( gtk_frame_new( "Surface Flags" ) );
980 gtk_widget_show( GTK_WIDGET( frame ) );
981 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), TRUE, TRUE, 0 );
983 GtkVBox* vbox3 = GTK_VBOX( gtk_vbox_new( FALSE, 4 ) );
984 //gtk_container_set_border_width(GTK_CONTAINER(vbox3), 4);
985 gtk_widget_show( GTK_WIDGET( vbox3 ) );
986 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( vbox3 ) );
988 GtkTable* table = GTK_TABLE( gtk_table_new( 8, 4, FALSE ) );
989 gtk_widget_show( GTK_WIDGET( table ) );
990 gtk_box_pack_start( GTK_BOX( vbox3 ), GTK_WIDGET( table ), TRUE, TRUE, 0 );
991 gtk_table_set_row_spacings( table, 0 );
992 gtk_table_set_col_spacings( table, 0 );
994 GtkCheckButton** p = m_surfaceFlags;
996 for ( int c = 0; c != 4; ++c )
998 for ( int r = 0; r != 8; ++r )
1000 GtkCheckButton* check = GTK_CHECK_BUTTON( gtk_check_button_new_with_label( getSurfaceFlagName( c * 8 + r ) ) );
1001 gtk_widget_show( GTK_WIDGET( check ) );
1002 gtk_table_attach( table, GTK_WIDGET( check ), c, c + 1, r, r + 1,
1003 (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ),
1004 (GtkAttachOptions)( 0 ), 0, 0 );
1006 guint handler_id = togglebutton_connect_toggled( GTK_TOGGLE_BUTTON( check ), ApplyFlagsCaller( *this ) );
1007 g_object_set_data( G_OBJECT( check ), "handler", gint_to_pointer( handler_id ) );
1014 GtkFrame* frame = GTK_FRAME( gtk_frame_new( "Content Flags" ) );
1015 gtk_widget_show( GTK_WIDGET( frame ) );
1016 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), TRUE, TRUE, 0 );
1018 GtkVBox* vbox3 = GTK_VBOX( gtk_vbox_new( FALSE, 4 ) );
1019 //gtk_container_set_border_width(GTK_CONTAINER(vbox3), 4);
1020 gtk_widget_show( GTK_WIDGET( vbox3 ) );
1021 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( vbox3 ) );
1024 GtkTable* table = GTK_TABLE( gtk_table_new( 8, 4, FALSE ) );
1025 gtk_widget_show( GTK_WIDGET( table ) );
1026 gtk_box_pack_start( GTK_BOX( vbox3 ), GTK_WIDGET( table ), TRUE, TRUE, 0 );
1027 gtk_table_set_row_spacings( table, 0 );
1028 gtk_table_set_col_spacings( table, 0 );
1030 GtkCheckButton** p = m_contentFlags;
1032 for ( int c = 0; c != 4; ++c )
1034 for ( int r = 0; r != 8; ++r )
1036 GtkCheckButton* check = GTK_CHECK_BUTTON( gtk_check_button_new_with_label( getContentFlagName( c * 8 + r ) ) );
1037 gtk_widget_show( GTK_WIDGET( check ) );
1038 gtk_table_attach( table, GTK_WIDGET( check ), c, c + 1, r, r + 1,
1039 (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ),
1040 (GtkAttachOptions)( 0 ), 0, 0 );
1042 guint handler_id = togglebutton_connect_toggled( GTK_TOGGLE_BUTTON( check ), ApplyFlagsCaller( *this ) );
1043 g_object_set_data( G_OBJECT( check ), "handler", gint_to_pointer( handler_id ) );
1047 // not allowed to modify detail flag using Surface Inspector
1048 gtk_widget_set_sensitive( GTK_WIDGET( m_contentFlags[BRUSH_DETAIL_FLAG] ), FALSE );
1053 GtkFrame* frame = GTK_FRAME( gtk_frame_new( "Value" ) );
1054 gtk_widget_show( GTK_WIDGET( frame ) );
1055 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), TRUE, TRUE, 0 );
1057 GtkVBox* vbox3 = GTK_VBOX( gtk_vbox_new( FALSE, 4 ) );
1058 gtk_container_set_border_width( GTK_CONTAINER( vbox3 ), 4 );
1059 gtk_widget_show( GTK_WIDGET( vbox3 ) );
1060 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( vbox3 ) );
1063 GtkEntry* entry = GTK_ENTRY( gtk_entry_new() );
1064 gtk_widget_show( GTK_WIDGET( entry ) );
1065 gtk_box_pack_start( GTK_BOX( vbox3 ), GTK_WIDGET( entry ), TRUE, TRUE, 0 );
1066 m_valueEntryWidget = entry;
1067 m_valueEntry.connect( entry );
1074 if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES ) {
1075 // Shamus: Textool goodies...
1076 GtkWidget * frame = gtk_frame_new( "Textool" );
1077 gtk_widget_show( frame );
1078 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
1080 //Prolly should make this a member or global var, so the SI can draw on it...
1081 TexTool::g_textoolWin = glwidget_new( FALSE );
1082 // --> Dunno, but this stuff may be necessary... (Looks like it!)
1083 gtk_widget_ref( TexTool::g_textoolWin );
1084 gtk_widget_set_events( TexTool::g_textoolWin, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK );
1085 GTK_WIDGET_SET_FLAGS( TexTool::g_textoolWin, GTK_CAN_FOCUS );
1087 gtk_widget_show( TexTool::g_textoolWin );
1088 gtk_widget_set_usize( TexTool::g_textoolWin, -1, 240 ); //Yeah!
1089 gtk_container_add( GTK_CONTAINER( frame ), TexTool::g_textoolWin );
1091 g_signal_connect( G_OBJECT( TexTool::g_textoolWin ), "size_allocate", G_CALLBACK( TexTool::size_allocate ), NULL );
1092 g_signal_connect( G_OBJECT( TexTool::g_textoolWin ), "expose_event", G_CALLBACK( TexTool::expose ), NULL );
1093 g_signal_connect( G_OBJECT( TexTool::g_textoolWin ), "button_press_event", G_CALLBACK( TexTool::button_press ), NULL );
1094 g_signal_connect( G_OBJECT( TexTool::g_textoolWin ), "button_release_event", G_CALLBACK( TexTool::button_release ), NULL );
1095 g_signal_connect( G_OBJECT( TexTool::g_textoolWin ), "motion_notify_event", G_CALLBACK( TexTool::motion ), NULL );
1098 GtkWidget * hbox = gtk_hbox_new( FALSE, 5 );
1099 gtk_widget_show( hbox );
1100 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( hbox ), FALSE, FALSE, 0 );
1101 // Checkboxes go here... (Flip X/Y)
1102 GtkWidget * flipX = gtk_check_button_new_with_label( "Flip X axis" );
1103 GtkWidget * flipY = gtk_check_button_new_with_label( "Flip Y axis" );
1104 gtk_widget_show( flipX );
1105 gtk_widget_show( flipY );
1106 gtk_box_pack_start( GTK_BOX( hbox ), flipX, FALSE, FALSE, 0 );
1107 gtk_box_pack_start( GTK_BOX( hbox ), flipY, FALSE, FALSE, 0 );
1109 //Instead of this, we probably need to create a vbox to put into the frame, then the
1110 //window, then the hbox. !!! FIX !!!
1111 // gtk_container_add(GTK_CONTAINER(frame), hbox);
1113 //Hmm. Do we really need g_object_set_data? Mebbe not... And we don't! :-)
1114 // g_object_set_data(G_OBJECT(flipX), "handler", gint_to_pointer(g_signal_connect(G_OBJECT(flipX), "toggled", G_CALLBACK(TexTool::flipX), 0)));
1115 // g_object_set_data(G_OBJECT(flipY), "handler", gint_to_pointer(g_signal_connect(G_OBJECT(flipY), "toggled", G_CALLBACK(TexTool::flipY), 0)));
1117 g_signal_connect( G_OBJECT( flipX ), "toggled", G_CALLBACK( TexTool::flipX ), NULL );
1118 g_signal_connect( G_OBJECT( flipY ), "toggled", G_CALLBACK( TexTool::flipY ), NULL );
1131 Set the fields to the current texdef (i.e. map/texdef -> dialog widgets)
1132 if faces selected (instead of brushes) -> will read this face texdef, else current texdef
1133 if only patches selected, will read the patch texdef
1137 void spin_button_set_value_no_signal( GtkSpinButton* spin, gdouble value ){
1138 guint handler_id = gpointer_to_int( g_object_get_data( G_OBJECT( spin ), "handler" ) );
1139 g_signal_handler_block( G_OBJECT( gtk_spin_button_get_adjustment( spin ) ), handler_id );
1140 gtk_spin_button_set_value( spin, value );
1141 g_signal_handler_unblock( G_OBJECT( gtk_spin_button_get_adjustment( spin ) ), handler_id );
1144 void spin_button_set_step_increment( GtkSpinButton* spin, gdouble value ){
1145 GtkAdjustment* adjust = gtk_spin_button_get_adjustment( spin );
1146 adjust->step_increment = value;
1149 void SurfaceInspector::Update(){
1150 const char * name = SurfaceInspector_GetSelectedShader();
1152 if ( shader_is_texture( name ) ) {
1153 gtk_entry_set_text( m_texture, shader_get_textureName( name ) );
1157 gtk_entry_set_text( m_texture, "" );
1160 texdef_t shiftScaleRotate;
1161 //Shamus: This is where we get into trouble--the BP code tries to convert to a "faked"
1162 //shift, rotate & scale values from the brush face, which seems to screw up for some reason.
1164 /*globalOutputStream() << "--> SI::Update. About to do ShiftScaleRotate_fromFace()...\n";
1165 SurfaceInspector_GetSelectedBPTexdef();
1166 globalOutputStream() << "BP: (" << g_selectedBrushPrimitTexdef.coords[0][0] << ", " << g_selectedBrushPrimitTexdef.coords[0][1] << ")("
1167 << g_selectedBrushPrimitTexdef.coords[1][0] << ", " << g_selectedBrushPrimitTexdef.coords[1][1] << ")("
1168 << g_selectedBrushPrimitTexdef.coords[0][2] << ", " << g_selectedBrushPrimitTexdef.coords[1][2] << ") SurfaceInspector::Update\n";//*/
1169 //Ok, it's screwed up *before* we get here...
1170 ShiftScaleRotate_fromFace( shiftScaleRotate, SurfaceInspector_GetSelectedTexdef() );
1172 // normalize again to hide the ridiculously high scale values that get created when using texlock
1173 shiftScaleRotate.shift[0] = float_mod( shiftScaleRotate.shift[0], (float)g_selectedShaderSize[0] );
1174 shiftScaleRotate.shift[1] = float_mod( shiftScaleRotate.shift[1], (float)g_selectedShaderSize[1] );
1177 spin_button_set_value_no_signal( m_hshiftIncrement.m_spin, shiftScaleRotate.shift[0] );
1178 spin_button_set_step_increment( m_hshiftIncrement.m_spin, g_si_globals.shift[0] );
1179 entry_set_float( m_hshiftIncrement.m_entry, g_si_globals.shift[0] );
1183 spin_button_set_value_no_signal( m_vshiftIncrement.m_spin, shiftScaleRotate.shift[1] );
1184 spin_button_set_step_increment( m_vshiftIncrement.m_spin, g_si_globals.shift[1] );
1185 entry_set_float( m_vshiftIncrement.m_entry, g_si_globals.shift[1] );
1189 spin_button_set_value_no_signal( m_hscaleIncrement.m_spin, shiftScaleRotate.scale[0] );
1190 spin_button_set_step_increment( m_hscaleIncrement.m_spin, g_si_globals.scale[0] );
1191 entry_set_float( m_hscaleIncrement.m_entry, g_si_globals.scale[0] );
1195 spin_button_set_value_no_signal( m_vscaleIncrement.m_spin, shiftScaleRotate.scale[1] );
1196 spin_button_set_step_increment( m_vscaleIncrement.m_spin, g_si_globals.scale[1] );
1197 entry_set_float( m_vscaleIncrement.m_entry, g_si_globals.scale[1] );
1201 spin_button_set_value_no_signal( m_rotateIncrement.m_spin, shiftScaleRotate.rotate );
1202 spin_button_set_step_increment( m_rotateIncrement.m_spin, g_si_globals.rotate );
1203 entry_set_float( m_rotateIncrement.m_entry, g_si_globals.rotate );
1206 if ( !string_empty( g_pGameDescription->getKeyValue( "si_flags" ) ) ) {
1207 ContentsFlagsValue flags( SurfaceInspector_GetSelectedFlags() );
1209 entry_set_int( m_valueEntryWidget, flags.m_value );
1211 for ( GtkCheckButton** p = m_surfaceFlags; p != m_surfaceFlags + 32; ++p )
1213 toggle_button_set_active_no_signal( GTK_TOGGLE_BUTTON( *p ), flags.m_surfaceFlags & ( 1 << ( p - m_surfaceFlags ) ) );
1216 for ( GtkCheckButton** p = m_contentFlags; p != m_contentFlags + 32; ++p )
1218 toggle_button_set_active_no_signal( GTK_TOGGLE_BUTTON( *p ), flags.m_contentFlags & ( 1 << ( p - m_contentFlags ) ) );
1227 Reads the fields to get the current texdef (i.e. widgets -> MAP)
1228 in brush primitive mode, grab the fake shift scale rot and compute a new texture matrix
1231 void SurfaceInspector::ApplyShader(){
1232 StringOutputStream name( 256 );
1233 name << GlobalTexturePrefix_get() << gtk_entry_get_text( m_texture );
1235 // TTimo: detect and refuse invalid texture names (at least the ones with spaces)
1236 if ( !texdef_name_valid( name.c_str() ) ) {
1237 globalErrorStream() << "invalid texture name '" << name.c_str() << "'\n";
1238 SurfaceInspector_queueDraw();
1242 UndoableCommand undo( "textureNameSetSelected" );
1243 Select_SetShader( name.c_str() );
1246 void SurfaceInspector::ApplyTexdef(){
1247 texdef_t shiftScaleRotate;
1249 shiftScaleRotate.shift[0] = static_cast<float>( gtk_spin_button_get_value_as_float( m_hshiftIncrement.m_spin ) );
1250 shiftScaleRotate.shift[1] = static_cast<float>( gtk_spin_button_get_value_as_float( m_vshiftIncrement.m_spin ) );
1251 shiftScaleRotate.scale[0] = static_cast<float>( gtk_spin_button_get_value_as_float( m_hscaleIncrement.m_spin ) );
1252 shiftScaleRotate.scale[1] = static_cast<float>( gtk_spin_button_get_value_as_float( m_vscaleIncrement.m_spin ) );
1253 shiftScaleRotate.rotate = static_cast<float>( gtk_spin_button_get_value_as_float( m_rotateIncrement.m_spin ) );
1255 TextureProjection projection;
1256 //Shamus: This is the other place that screws up, it seems, since it doesn't seem to do the
1257 //conversion from the face (I think) and so bogus values end up in the thing... !!! FIX !!!
1258 //This is actually OK. :-P
1259 ShiftScaleRotate_toFace( shiftScaleRotate, projection );
1261 UndoableCommand undo( "textureProjectionSetSelected" );
1262 Select_SetTexdef( projection );
1265 void SurfaceInspector::ApplyFlags(){
1266 unsigned int surfaceflags = 0;
1267 for ( GtkCheckButton** p = m_surfaceFlags; p != m_surfaceFlags + 32; ++p )
1269 if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( *p ) ) ) {
1270 surfaceflags |= ( 1 << ( p - m_surfaceFlags ) );
1274 unsigned int contentflags = 0;
1275 for ( GtkCheckButton** p = m_contentFlags; p != m_contentFlags + 32; ++p )
1277 if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( *p ) ) ) {
1278 contentflags |= ( 1 << ( p - m_contentFlags ) );
1282 int value = entry_get_int( m_valueEntryWidget );
1284 UndoableCommand undo( "flagsSetSelected" );
1285 Select_SetFlags( ContentsFlagsValue( surfaceflags, contentflags, value, true ) );
1289 void Face_getTexture( Face& face, CopiedString& shader, TextureProjection& projection, ContentsFlagsValue& flags ){
1290 shader = face.GetShader();
1291 face.GetTexdef( projection );
1292 flags = face.getShader().m_flags;
1294 typedef Function4<Face&, CopiedString&, TextureProjection&, ContentsFlagsValue&, void, Face_getTexture> FaceGetTexture;
1296 void Face_setTexture( Face& face, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags ){
1297 face.SetShader( shader );
1298 face.SetTexdef( projection );
1299 face.SetFlags( flags );
1301 typedef Function4<Face&, const char*, const TextureProjection&, const ContentsFlagsValue&, void, Face_setTexture> FaceSetTexture;
1304 void Patch_getTexture( Patch& patch, CopiedString& shader, TextureProjection& projection, ContentsFlagsValue& flags ){
1305 shader = patch.GetShader();
1306 projection = TextureProjection( texdef_t(), brushprimit_texdef_t(), Vector3( 0, 0, 0 ), Vector3( 0, 0, 0 ) );
1307 flags = ContentsFlagsValue( 0, 0, 0, false );
1309 typedef Function4<Patch&, CopiedString&, TextureProjection&, ContentsFlagsValue&, void, Patch_getTexture> PatchGetTexture;
1311 void Patch_setTexture( Patch& patch, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags ){
1312 patch.SetShader( shader );
1314 typedef Function4<Patch&, const char*, const TextureProjection&, const ContentsFlagsValue&, void, Patch_setTexture> PatchSetTexture;
1317 typedef Callback3<CopiedString&, TextureProjection&, ContentsFlagsValue&> GetTextureCallback;
1318 typedef Callback3<const char*, const TextureProjection&, const ContentsFlagsValue&> SetTextureCallback;
1322 GetTextureCallback getTexture;
1323 SetTextureCallback setTexture;
1327 void Face_getClosest( Face& face, SelectionTest& test, SelectionIntersection& bestIntersection, Texturable& texturable ){
1328 SelectionIntersection intersection;
1329 face.testSelect( test, intersection );
1330 if ( intersection.valid()
1331 && SelectionIntersection_closer( intersection, bestIntersection ) ) {
1332 bestIntersection = intersection;
1333 texturable.setTexture = makeCallback3( FaceSetTexture(), face );
1334 texturable.getTexture = makeCallback3( FaceGetTexture(), face );
1339 class OccludeSelector : public Selector
1341 SelectionIntersection& m_bestIntersection;
1344 OccludeSelector( SelectionIntersection& bestIntersection, bool& occluded ) : m_bestIntersection( bestIntersection ), m_occluded( occluded ){
1347 void pushSelectable( Selectable& selectable ){
1349 void popSelectable(){
1351 void addIntersection( const SelectionIntersection& intersection ){
1352 if ( SelectionIntersection_closer( intersection, m_bestIntersection ) ) {
1353 m_bestIntersection = intersection;
1359 class BrushGetClosestFaceVisibleWalker : public scene::Graph::Walker
1361 SelectionTest& m_test;
1362 Texturable& m_texturable;
1363 mutable SelectionIntersection m_bestIntersection;
1365 BrushGetClosestFaceVisibleWalker( SelectionTest& test, Texturable& texturable ) : m_test( test ), m_texturable( texturable ){
1367 bool pre( const scene::Path& path, scene::Instance& instance ) const {
1368 if ( path.top().get().visible() ) {
1369 BrushInstance* brush = Instance_getBrush( instance );
1371 m_test.BeginMesh( brush->localToWorld() );
1373 for ( Brush::const_iterator i = brush->getBrush().begin(); i != brush->getBrush().end(); ++i )
1375 Face_getClosest( *( *i ), m_test, m_bestIntersection, m_texturable );
1380 SelectionTestable* selectionTestable = Instance_getSelectionTestable( instance );
1381 if ( selectionTestable ) {
1383 OccludeSelector selector( m_bestIntersection, occluded );
1384 selectionTestable->testSelect( selector, m_test );
1386 Patch* patch = Node_getPatch( path.top() );
1388 m_texturable.setTexture = makeCallback3( PatchSetTexture(), *patch );
1389 m_texturable.getTexture = makeCallback3( PatchGetTexture(), *patch );
1393 m_texturable = Texturable();
1403 Texturable Scene_getClosestTexturable( scene::Graph& graph, SelectionTest& test ){
1404 Texturable texturable;
1405 graph.traverse( BrushGetClosestFaceVisibleWalker( test, texturable ) );
1409 bool Scene_getClosestTexture( scene::Graph& graph, SelectionTest& test, CopiedString& shader, TextureProjection& projection, ContentsFlagsValue& flags ){
1410 Texturable texturable = Scene_getClosestTexturable( graph, test );
1411 if ( texturable.getTexture != GetTextureCallback() ) {
1412 texturable.getTexture( shader, projection, flags );
1418 void Scene_setClosestTexture( scene::Graph& graph, SelectionTest& test, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags ){
1419 Texturable texturable = Scene_getClosestTexturable( graph, test );
1420 if ( texturable.setTexture != SetTextureCallback() ) {
1421 texturable.setTexture( shader, projection, flags );
1429 TextureProjection m_projection;
1430 ContentsFlagsValue m_flags;
1433 FaceTexture g_faceTextureClipboard;
1435 void FaceTextureClipboard_setDefault(){
1436 g_faceTextureClipboard.m_flags = ContentsFlagsValue( 0, 0, 0, false );
1437 TexDef_Construct_Default( g_faceTextureClipboard.m_projection );
1440 void TextureClipboard_textureSelected( const char* shader ){
1441 FaceTextureClipboard_setDefault();
1444 class TextureBrowser;
1445 extern TextureBrowser g_TextureBrowser;
1446 void TextureBrowser_SetSelectedShader( TextureBrowser& textureBrowser, const char* shader );
1447 const char* TextureBrowser_GetSelectedShader( TextureBrowser& textureBrowser );
1449 void Scene_copyClosestTexture( SelectionTest& test ){
1450 CopiedString shader;
1451 if ( Scene_getClosestTexture( GlobalSceneGraph(), test, shader, g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_flags ) ) {
1452 TextureBrowser_SetSelectedShader( g_TextureBrowser, shader.c_str() );
1456 void Scene_applyClosestTexture( SelectionTest& test ){
1457 UndoableCommand command( "facePaintTexture" );
1459 Scene_setClosestTexture( GlobalSceneGraph(), test, TextureBrowser_GetSelectedShader( g_TextureBrowser ), g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_flags );
1461 SceneChangeNotify();
1468 void SelectedFaces_copyTexture(){
1469 if ( !g_SelectedFaceInstances.empty() ) {
1470 Face& face = g_SelectedFaceInstances.last().getFace();
1471 face.GetTexdef( g_faceTextureClipboard.m_projection );
1472 g_faceTextureClipboard.m_flags = face.getShader().m_flags;
1474 TextureBrowser_SetSelectedShader( g_TextureBrowser, face.getShader().getShader() );
1478 void FaceInstance_pasteTexture( FaceInstance& faceInstance ){
1479 faceInstance.getFace().SetTexdef( g_faceTextureClipboard.m_projection );
1480 faceInstance.getFace().SetShader( TextureBrowser_GetSelectedShader( g_TextureBrowser ) );
1481 faceInstance.getFace().SetFlags( g_faceTextureClipboard.m_flags );
1482 SceneChangeNotify();
1485 bool SelectedFaces_empty(){
1486 return g_SelectedFaceInstances.empty();
1489 void SelectedFaces_pasteTexture(){
1490 UndoableCommand command( "facePasteTexture" );
1491 g_SelectedFaceInstances.foreach( FaceInstance_pasteTexture );
1496 void SurfaceInspector_constructPreferences( PreferencesPage& page ){
1497 page.appendCheckBox( "", "Surface Inspector Increments Match Grid", g_si_globals.m_bSnapTToGrid );
1499 void SurfaceInspector_constructPage( PreferenceGroup& group ){
1500 PreferencesPage page( group.createPage( "Surface Inspector", "Surface Inspector Preferences" ) );
1501 SurfaceInspector_constructPreferences( page );
1503 void SurfaceInspector_registerPreferencesPage(){
1504 PreferencesDialog_addSettingsPage( FreeCaller1<PreferenceGroup&, SurfaceInspector_constructPage>() );
1507 void SurfaceInspector_registerCommands(){
1508 GlobalCommands_insert( "FitTexture", FreeCaller<SurfaceInspector_FitTexture>(), Accelerator( 'F', (GdkModifierType)GDK_CONTROL_MASK ) );
1509 GlobalCommands_insert( "SurfaceInspector", FreeCaller<SurfaceInspector_toggleShown>(), Accelerator( 'S' ) );
1511 GlobalCommands_insert( "FaceCopyTexture", FreeCaller<SelectedFaces_copyTexture>() );
1512 GlobalCommands_insert( "FacePasteTexture", FreeCaller<SelectedFaces_pasteTexture>() );
1516 #include "preferencesystem.h"
1519 void SurfaceInspector_Construct(){
1520 g_SurfaceInspector = new SurfaceInspector;
1522 SurfaceInspector_registerCommands();
1524 FaceTextureClipboard_setDefault();
1526 GlobalPreferenceSystem().registerPreference( "SurfaceWnd", getSurfaceInspector().m_importPosition, getSurfaceInspector().m_exportPosition );
1527 GlobalPreferenceSystem().registerPreference( "SI_SurfaceTexdef_Scale1", FloatImportStringCaller( g_si_globals.scale[0] ), FloatExportStringCaller( g_si_globals.scale[0] ) );
1528 GlobalPreferenceSystem().registerPreference( "SI_SurfaceTexdef_Scale2", FloatImportStringCaller( g_si_globals.scale[1] ), FloatExportStringCaller( g_si_globals.scale[1] ) );
1529 GlobalPreferenceSystem().registerPreference( "SI_SurfaceTexdef_Shift1", FloatImportStringCaller( g_si_globals.shift[0] ), FloatExportStringCaller( g_si_globals.shift[0] ) );
1530 GlobalPreferenceSystem().registerPreference( "SI_SurfaceTexdef_Shift2", FloatImportStringCaller( g_si_globals.shift[1] ), FloatExportStringCaller( g_si_globals.shift[1] ) );
1531 GlobalPreferenceSystem().registerPreference( "SI_SurfaceTexdef_Rotate", FloatImportStringCaller( g_si_globals.rotate ), FloatExportStringCaller( g_si_globals.rotate ) );
1532 GlobalPreferenceSystem().registerPreference( "SnapTToGrid", BoolImportStringCaller( g_si_globals.m_bSnapTToGrid ), BoolExportStringCaller( g_si_globals.m_bSnapTToGrid ) );
1534 typedef FreeCaller1<const Selectable&, SurfaceInspector_SelectionChanged> SurfaceInspectorSelectionChangedCaller;
1535 GlobalSelectionSystem().addSelectionChangeCallback( SurfaceInspectorSelectionChangedCaller() );
1536 typedef FreeCaller<SurfaceInspector_updateSelection> SurfaceInspectorUpdateSelectionCaller;
1537 Brush_addTextureChangedCallback( SurfaceInspectorUpdateSelectionCaller() );
1538 Patch_addTextureChangedCallback( SurfaceInspectorUpdateSelectionCaller() );
1540 SurfaceInspector_registerPreferencesPage();
1542 void SurfaceInspector_Destroy(){
1543 delete g_SurfaceInspector;
1550 namespace TexTool { // namespace hides these symbols from other object-files
1552 //Shamus: Textool functions, including GTK+ callbacks
1555 //NOTE: Black screen when TT first comes up is caused by an uninitialized Extent... !!! FIX !!!
1556 // But... You can see down below that it *is* initialized! WTF?
1559 float minX, minY, maxX, maxY;
1560 float width( void ) { return fabs( maxX - minX ); }
1561 float height( void ) { return fabs( maxY - minY ); }
1564 //This seems to control the texture scale... (Yep! ;-)
1565 Extent extents = { -2.0f, -2.0f, +2.0f, +2.0f };
1566 brushprimit_texdef_t tm; // Texture transform matrix
1567 Vector2 pts[c_brush_maxFaces];
1571 Vector2 textureSize;
1573 #define VP_PADDING 1.2
1574 #define PI 3.14159265358979
1575 bool lButtonDown = false;
1576 bool rButtonDown = false;
1579 bool haveAnchor = false;
1580 brushprimit_texdef_t currentBP;
1581 brushprimit_texdef_t origBP; // Original brush primitive (before we muck it up)
1582 float controlRadius = 5.0f;
1583 float rotationAngle = 0.0f;
1584 float rotationAngle2 = 0.0f;
1585 float oldRotationAngle;
1586 Vector2 rotationPoint;
1587 bool translatingX = false; // Widget state variables
1588 bool translatingY = false;
1589 bool scalingX = false;
1590 bool scalingY = false;
1591 bool rotating = false;
1592 bool resizingX = false; // Not sure what this means... :-/
1593 bool resizingY = false;
1594 float origAngle, origScaleX, origScaleY;
1598 // Function prototypes (move up to top later...)
1600 void DrawCircularArc( Vector2 ctr, float startAngle, float endAngle, float radius );
1603 void CopyPointsFromSelectedFace( void ){
1604 // Make sure that there's a face and winding to get!
1606 if ( g_SelectedFaceInstances.empty() ) {
1611 Face & face = g_SelectedFaceInstances.last().getFace();
1612 textureNum = face.getShader().m_state->getTexture().texture_number;
1613 textureSize.x() = face.getShader().m_state->getTexture().width;
1614 textureSize.y() = face.getShader().m_state->getTexture().height;
1615 //globalOutputStream() << "--> Texture #" << textureNum << ": " << textureSize.x() << " x " << textureSize.y() << "...\n";
1617 currentBP = SurfaceInspector_GetSelectedTexdef().m_brushprimit_texdef;
1619 face.EmitTextureCoordinates();
1620 Winding & w = face.getWinding();
1623 for ( Winding::const_iterator i = w.begin(); i != w.end(); i++ )
1625 //globalOutputStream() << (*i).texcoord.x() << " " << (*i).texcoord.y() << ", ";
1626 pts[count].x() = ( *i ).texcoord.x();
1627 pts[count].y() = ( *i ).texcoord.y();
1633 //globalOutputStream() << " ..copied points\n";
1636 brushprimit_texdef_t bp;
1637 //This approach is probably wrongheaded and just not right anyway. So, !!! FIX !!! [DONE]
1638 void CommitChanges( void ){
1639 texdef_t t; // Throwaway, since this is BP only
1641 bp.coords[0][0] = tm.coords[0][0] * origBP.coords[0][0] + tm.coords[0][1] * origBP.coords[1][0];
1642 bp.coords[0][1] = tm.coords[0][0] * origBP.coords[0][1] + tm.coords[0][1] * origBP.coords[1][1];
1643 bp.coords[0][2] = tm.coords[0][0] * origBP.coords[0][2] + tm.coords[0][1] * origBP.coords[1][2] + tm.coords[0][2];
1644 //Ok, this works for translation...
1645 // bp.coords[0][2] = tm.coords[0][0] * origBP.coords[0][2] + tm.coords[0][1] * origBP.coords[1][2] + tm.coords[0][2] * textureSize.x();
1646 bp.coords[1][0] = tm.coords[1][0] * origBP.coords[0][0] + tm.coords[1][1] * origBP.coords[1][0];
1647 bp.coords[1][1] = tm.coords[1][0] * origBP.coords[0][1] + tm.coords[1][1] * origBP.coords[1][1];
1648 bp.coords[1][2] = tm.coords[1][0] * origBP.coords[0][2] + tm.coords[1][1] * origBP.coords[1][2] + tm.coords[1][2];
1649 // bp.coords[1][2] = tm.coords[1][0] * origBP.coords[0][2] + tm.coords[1][1] * origBP.coords[1][2] + tm.coords[1][2] * textureSize.y();
1651 //This doesn't work: g_brush_texture_changed();
1653 //Note: We should only set an undo *after* the button has been released... !!! FIX !!!
1654 //Definitely *should* have an undo, though!
1655 // UndoableCommand undo("textureProjectionSetSelected");
1656 Select_SetTexdef( TextureProjection( t, bp, Vector3( 0, 0, 0 ), Vector3( 0, 0, 0 ) ) );
1657 //This is working, but for some reason the translate is causing the rest of the SI
1658 //widgets to yield bad readings... !!! FIX !!!
1659 //I.e., click on textool window, translate face wireframe, then controls go crazy. Dunno why.
1660 //It's because there were some uncommented out add/removeScale functions in brush.h and a
1661 //removeScale in brushmanip.cpp... :-/
1662 //Translate isn't working at all now... :-(
1663 //It's because we need to multiply in some scaling factor (prolly the texture width/height)
1667 void UpdateControlPoints( void ){
1670 // Init texture transform matrix
1672 tm.coords[0][0] = 1.0f; tm.coords[0][1] = 0.0f; tm.coords[0][2] = 0.0f;
1673 tm.coords[1][0] = 0.0f; tm.coords[1][1] = 1.0f; tm.coords[1][2] = 0.0f;
1678 For shifting we have:
1681 The code that should provide reasonable defaults, but doesn't for some reason:
1682 It's scaling the BP by 128 for some reason, between the time it's created and the
1683 time we get back to the SI widgets:
1685 static void OnBtnAxial(GtkWidget *widget, gpointer data)
1687 UndoableCommand undo("textureDefault");
1688 TextureProjection projection;
1689 TexDef_Construct_Default(projection);
1690 Select_SetTexdef(projection);
1693 Select_SetTexdef() calls Scene_BrushSetTexdef_Component_Selected(GlobalSceneGraph(), projection)
1694 which is in brushmanip.h: This eventually calls
1695 Texdef_Assign(m_texdef, texdef, m_brushprimit_texdef, brushprimit_texdef) in class Face...
1696 which just copies from brushpr to m_brushpr...
1699 //Small problem with this thing: It's scaled to the texture which is all screwed up... !!! FIX !!! [DONE]
1700 //Prolly should separate out the grid drawing so that we can draw it behind the polygon.
1701 const float gridWidth = 1.3f; // Let's try an absolute height... WORKS!!!
1702 // NOTE that 2.0 is the height of the viewport. Dunno why... Should make collision
1703 // detection easier...
1704 const float gridRadius = gridWidth * 0.5f;
1706 typedef const float WidgetColor[3];
1707 const WidgetColor widgetColor[10] = {
1708 { 1.0000f, 0.2000f, 0.0000f }, // Red
1709 { 0.9137f, 0.9765f, 0.4980f }, // Yellow
1710 { 0.0000f, 0.6000f, 0.3216f }, // Green
1711 { 0.6157f, 0.7726f, 0.8196f }, // Cyan
1712 { 0.4980f, 0.5000f, 0.4716f }, // Grey
1715 { 1.0000f, 0.6000f, 0.4000f }, // Light Red
1716 { 1.0000f, 1.0000f, 0.8980f }, // Light Yellow
1717 { 0.4000f, 1.0000f, 0.7216f }, // Light Green
1718 { 1.0000f, 1.0000f, 1.0000f }, // Light Cyan
1719 { 0.8980f, 0.9000f, 0.8716f } // Light Grey
1723 #define COLOR_YELLOW 1
1724 #define COLOR_GREEN 2
1725 #define COLOR_CYAN 3
1726 #define COLOR_GREY 4
1727 #define COLOR_LT_RED 5
1728 #define COLOR_LT_YELLOW 6
1729 #define COLOR_LT_GREEN 7
1730 #define COLOR_LT_CYAN 8
1731 #define COLOR_LT_GREY 9
1733 void DrawControlWidgets( void ){
1734 //Note that the grid should go *behind* the face outline... !!! FIX !!!
1736 float xStart = center.x() - ( gridWidth / 2.0f );
1737 float yStart = center.y() - ( gridWidth / 2.0f );
1738 float xScale = ( extents.height() / extents.width() ) * ( textureSize.y() / textureSize.x() );
1741 //Small problem with this approach: Changing the center point in the TX code doesn't seem to
1742 //change anything here--prolly because we load a new identity matrix. A couple of ways to fix
1743 //this would be to get rid of that code, or change the center to a new point by taking into
1744 //account the transforms that we toss with the new identity matrix. Dunno which is better.
1746 glScalef( xScale, 1.0, 1.0 ); // Will that square it up? Yup.
1747 glRotatef( static_cast<float>( radians_to_degrees( atan2( -currentBP.coords[0][1], currentBP.coords[0][0] ) ) ), 0.0, 0.0, -1.0 );
1748 glTranslatef( -center.x(), -center.y(), 0.0 );
1751 glColor3fv( translatingX && translatingY ? widgetColor[COLOR_LT_YELLOW] : widgetColor[COLOR_YELLOW] );
1752 glBegin( GL_LINE_LOOP );
1753 DrawCircularArc( center, 0, 2.0f * PI, gridRadius * 0.16 );
1758 glBegin( GL_LINES );
1759 glColor3fv( translatingY && !translatingX ? widgetColor[COLOR_LT_GREEN] : widgetColor[COLOR_GREEN] );
1760 glVertex2f( center.x(), center.y() + ( gridRadius * 0.16 ) );
1761 glVertex2f( center.x(), center.y() + ( gridRadius * 1.00 ) );
1762 glColor3fv( translatingX && !translatingY ? widgetColor[COLOR_LT_RED] : widgetColor[COLOR_RED] );
1763 glVertex2f( center.x() + ( gridRadius * 0.16 ), center.y() );
1764 glVertex2f( center.x() + ( gridRadius * 1.00 ), center.y() );
1768 glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
1769 glBegin( GL_TRIANGLES );
1770 glColor3fv( translatingY && !translatingX ? widgetColor[COLOR_LT_GREEN] : widgetColor[COLOR_GREEN] );
1771 glVertex2f( center.x(), center.y() + ( gridRadius * 1.10 ) );
1772 glVertex2f( center.x() + ( gridRadius * 0.06 ), center.y() + ( gridRadius * 0.94 ) );
1773 glVertex2f( center.x() - ( gridRadius * 0.06 ), center.y() + ( gridRadius * 0.94 ) );
1774 glColor3fv( translatingX && !translatingY ? widgetColor[COLOR_LT_RED] : widgetColor[COLOR_RED] );
1775 glVertex2f( center.x() + ( gridRadius * 1.10 ), center.y() );
1776 glVertex2f( center.x() + ( gridRadius * 0.94 ), center.y() + ( gridRadius * 0.06 ) );
1777 glVertex2f( center.x() + ( gridRadius * 0.94 ), center.y() - ( gridRadius * 0.06 ) );
1781 glBegin( GL_LINE_STRIP );
1782 glColor3fv( rotating ? widgetColor[COLOR_LT_CYAN] : widgetColor[COLOR_CYAN] );
1783 DrawCircularArc( center, 0.03f * PI, 0.47f * PI, gridRadius * 0.90 );
1787 glColor3fv( scalingY && !scalingX ? widgetColor[COLOR_LT_GREEN] : widgetColor[COLOR_GREEN] );
1788 glBegin( GL_LINES );
1789 glVertex2f( center.x() + ( gridRadius * 0.20 ), center.y() + ( gridRadius * 1.50 ) );
1790 glVertex2f( center.x() - ( gridRadius * 0.20 ), center.y() + ( gridRadius * 1.50 ) );
1792 glBegin( GL_LINE_LOOP );
1793 glVertex2f( center.x() + ( gridRadius * 0.10 ), center.y() + ( gridRadius * 1.40 ) );
1794 glVertex2f( center.x() - ( gridRadius * 0.10 ), center.y() + ( gridRadius * 1.40 ) );
1795 glVertex2f( center.x() - ( gridRadius * 0.10 ), center.y() + ( gridRadius * 1.20 ) );
1796 glVertex2f( center.x() + ( gridRadius * 0.10 ), center.y() + ( gridRadius * 1.20 ) );
1799 glColor3fv( scalingX && !scalingY ? widgetColor[COLOR_LT_RED] : widgetColor[COLOR_RED] );
1800 glBegin( GL_LINES );
1801 glVertex2f( center.x() + ( gridRadius * 1.50 ), center.y() + ( gridRadius * 0.20 ) );
1802 glVertex2f( center.x() + ( gridRadius * 1.50 ), center.y() - ( gridRadius * 0.20 ) );
1804 glBegin( GL_LINE_LOOP );
1805 glVertex2f( center.x() + ( gridRadius * 1.40 ), center.y() + ( gridRadius * 0.10 ) );
1806 glVertex2f( center.x() + ( gridRadius * 1.40 ), center.y() - ( gridRadius * 0.10 ) );
1807 glVertex2f( center.x() + ( gridRadius * 1.20 ), center.y() - ( gridRadius * 0.10 ) );
1808 glVertex2f( center.x() + ( gridRadius * 1.20 ), center.y() + ( gridRadius * 0.10 ) );
1811 glColor3fv( scalingX && scalingY ? widgetColor[COLOR_LT_CYAN] : widgetColor[COLOR_CYAN] );
1812 glBegin( GL_LINE_STRIP );
1813 glVertex2f( center.x() + ( gridRadius * 1.50 ), center.y() + ( gridRadius * 1.10 ) );
1814 glVertex2f( center.x() + ( gridRadius * 1.50 ), center.y() + ( gridRadius * 1.50 ) );
1815 glVertex2f( center.x() + ( gridRadius * 1.10 ), center.y() + ( gridRadius * 1.50 ) );
1817 glBegin( GL_LINE_LOOP );
1818 glVertex2f( center.x() + ( gridRadius * 1.40 ), center.y() + ( gridRadius * 1.40 ) );
1819 glVertex2f( center.x() + ( gridRadius * 1.40 ), center.y() + ( gridRadius * 1.20 ) );
1820 glVertex2f( center.x() + ( gridRadius * 1.20 ), center.y() + ( gridRadius * 1.20 ) );
1821 glVertex2f( center.x() + ( gridRadius * 1.20 ), center.y() + ( gridRadius * 1.40 ) );
1827 void DrawControlPoints( void ){
1828 glColor3f( 1, 1, 1 );
1829 glBegin( GL_LINE_LOOP );
1831 for ( int i = 0; i < numPts; i++ )
1832 glVertex2f( pts[i].x(), pts[i].y() );
1837 // Note: Setup and all that jazz must be done by the caller!
1839 void DrawCircularArc( Vector2 ctr, float startAngle, float endAngle, float radius ){
1840 float stepSize = ( 2.0f * PI ) / 200.0f;
1842 for ( float angle = startAngle; angle <= endAngle; angle += stepSize )
1843 glVertex2f( ctr.x() + radius * cos( angle ), ctr.y() + radius * sin( angle ) );
1848 if ( numPts == 0 ) {
1852 // Find selected texture's extents...
1854 extents.minX = extents.maxX = pts[0].x(),
1855 extents.minY = extents.maxY = pts[0].y();
1857 for ( int i = 1; i < numPts; i++ )
1859 if ( pts[i].x() < extents.minX ) {
1860 extents.minX = pts[i].x();
1862 if ( pts[i].x() > extents.maxX ) {
1863 extents.maxX = pts[i].x();
1865 if ( pts[i].y() < extents.minY ) {
1866 extents.minY = pts[i].y();
1868 if ( pts[i].y() > extents.maxY ) {
1869 extents.maxY = pts[i].y();
1873 // Do some viewport fitting stuff...
1875 //globalOutputStream() << "--> Center: " << center.x() << ", " << center.y() << "\n";
1876 //globalOutputStream() << "--> Extents (stage 1): " << extents.minX << ", "
1877 // << extents.maxX << ", " << extents.minY << ", " << extents.maxY << "\n";
1878 // TTimo: Apply a ratio to get the area we'll draw.
1879 center.x() = 0.5f * ( extents.minX + extents.maxX ),
1880 center.y() = 0.5f * ( extents.minY + extents.maxY );
1881 extents.minX = center.x() + VP_PADDING * ( extents.minX - center.x() ),
1882 extents.minY = center.y() + VP_PADDING * ( extents.minY - center.y() ),
1883 extents.maxX = center.x() + VP_PADDING * ( extents.maxX - center.x() ),
1884 extents.maxY = center.y() + VP_PADDING * ( extents.maxY - center.y() );
1885 //globalOutputStream() << "--> Extents (stage 2): " << extents.minX << ", "
1886 // << extents.maxX << ", " << extents.minY << ", " << extents.maxY << "\n";
1888 // TTimo: We want a texture with the same X / Y ratio.
1889 // TTimo: Compute XY space / window size ratio.
1890 float SSize = extents.width(), TSize = extents.height();
1891 float ratioX = textureSize.x() * extents.width() / windowSize.x(),
1892 ratioY = textureSize.y() * extents.height() / windowSize.y();
1893 //globalOutputStream() << "--> Texture size: " << textureSize.x() << ", " << textureSize.y() << "\n";
1894 //globalOutputStream() << "--> Window size: " << windowSize.x() << ", " << windowSize.y() << "\n";
1896 if ( ratioX > ratioY ) {
1897 TSize = ( windowSize.y() * ratioX ) / textureSize.y();
1898 // TSize = extents.width() * (windowSize.y() / windowSize.x()) * (textureSize.x() / textureSize.y());
1902 SSize = ( windowSize.x() * ratioY ) / textureSize.x();
1903 // SSize = extents.height() * (windowSize.x() / windowSize.y()) * (textureSize.y() / textureSize.x());
1906 extents.minX = center.x() - 0.5f * SSize, extents.maxX = center.x() + 0.5f * SSize,
1907 extents.minY = center.y() - 0.5f * TSize, extents.maxY = center.y() + 0.5f * TSize;
1908 //globalOutputStream() << "--> Extents (stage 3): " << extents.minX << ", "
1909 // << extents.maxX << ", " << extents.minY << ", " << extents.maxY << "\n";
1912 gboolean size_allocate( GtkWidget * win, GtkAllocation * a, gpointer ){
1913 windowSize.x() = a->width;
1914 windowSize.y() = a->height;
1919 gboolean expose( GtkWidget * win, GdkEventExpose * e, gpointer ){
1920 // globalOutputStream() << "--> Textool Window was exposed!\n";
1921 // globalOutputStream() << " (window width/height: " << cc << "/" << e->area.height << ")\n";
1923 // windowSize.x() = e->area.width, windowSize.y() = e->area.height;
1924 //This needs to go elsewhere...
1927 if ( glwidget_make_current( win ) == FALSE ) {
1928 globalOutputStream() << " FAILED to make current! Oh, the agony! :-(\n";
1932 CopyPointsFromSelectedFace();
1934 if ( !lButtonDown ) {
1938 // Probably should init button/anchor states here as well...
1939 // rotationAngle = 0.0f;
1940 glClearColor( 0, 0, 0, 0 );
1941 glViewport( 0, 0, e->area.width, e->area.height );
1942 glMatrixMode( GL_PROJECTION );
1946 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
1947 glDisable( GL_DEPTH_TEST );
1948 glDisable( GL_BLEND );
1950 glOrtho( extents.minX, extents.maxX, extents.maxY, extents.minY, -1, 1 );
1952 glColor3f( 1, 1, 1 );
1953 // draw the texture background
1954 glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
1955 glBindTexture( GL_TEXTURE_2D, textureNum );
1957 glEnable( GL_TEXTURE_2D );
1958 glBegin( GL_QUADS );
1959 glTexCoord2f( extents.minX, extents.minY );
1960 glVertex2f( extents.minX, extents.minY );
1961 glTexCoord2f( extents.maxX, extents.minY );
1962 glVertex2f( extents.maxX, extents.minY );
1963 glTexCoord2f( extents.maxX, extents.maxY );
1964 glVertex2f( extents.maxX, extents.maxY );
1965 glTexCoord2f( extents.minX, extents.maxY );
1966 glVertex2f( extents.minX, extents.maxY );
1968 glDisable( GL_TEXTURE_2D );
1970 // draw the texture-space grid
1971 glColor3fv( widgetColor[COLOR_GREY] );
1972 glBegin( GL_LINES );
1974 const int gridSubdivisions = 8;
1975 const float gridExtents = 4.0f;
1977 for ( int i = 0; i < gridSubdivisions + 1; ++i )
1979 float y = i * ( gridExtents / float(gridSubdivisions) );
1980 float x = i * ( gridExtents / float(gridSubdivisions) );
1982 glVertex2f( gridExtents, y );
1984 glVertex2f( x, gridExtents );
1989 DrawControlPoints();
1990 DrawControlWidgets();
1992 // reset the current texture
1993 // glBindTexture(GL_TEXTURE_2D, 0);
1995 glwidget_swap_buffers( win );
2000 /*int FindSelectedPoint(int x, int y)
2002 for(int i=0; i<numPts; i++)
2004 int nx = (int)(windowSize.x() * (pts[i].x() - extents.minX) / extents.width());
2005 int ny = (int)(windowSize.y() * (pts[i].y() - extents.minY) / extents.height());
2007 if (abs(nx - x) <= 3 && abs(ny - y) <= 3)
2016 Vector2 dragPoint; // Defined in terms of window space (+x/-y)
2018 gboolean button_press( GtkWidget * win, GdkEventButton * e, gpointer ){
2019 // globalOutputStream() << "--> Textool button press...\n";
2021 if ( e->button == 1 ) {
2023 GlobalUndoSystem().start();
2027 //globalOutputStream() << "--> Original BP: [" << origBP.coords[0][0] << "][" << origBP.coords[0][1] << "][" << origBP.coords[0][2] << "]\n";
2028 //globalOutputStream() << " [" << origBP.coords[1][0] << "][" << origBP.coords[1][1] << "][" << origBP.coords[1][2] << "]\n";
2029 //float angle = atan2(origBP.coords[0][1], origBP.coords[0][0]) * 180.0f / 3.141592653589f;
2030 origAngle = ( origBP.coords[0][1] > 0 ? PI : -PI ); // Could also be -PI... !!! FIX !!! [DONE]
2032 if ( origBP.coords[0][0] != 0.0f ) {
2033 origAngle = atan( origBP.coords[0][1] / origBP.coords[0][0] );
2036 origScaleX = origBP.coords[0][0] / cos( origAngle );
2037 origScaleY = origBP.coords[1][1] / cos( origAngle );
2038 rotationAngle = origAngle;
2039 oldCenter[0] = oldCenter[1] = 0;
2041 //globalOutputStream() << "--> BP stats: ang=" << origAngle * RAD_TO_DEG << ", scale=" << origScaleX << "/" << origScaleY << "\n";
2042 //Should also set the Flip X/Y checkboxes here as well... !!! FIX !!!
2043 //Also: should reverse texture left/right up/down instead of flipping the points...
2046 //float nx = windowSize.x() * (e->x - extents.minX) / (extents.maxX - extents.minX);
2047 //float ny = windowSize.y() * (e->y - extents.minY) / (extents.maxY - extents.minY);
2049 //But I want it to scroll the texture window, not the points... !!! FIX !!!
2050 //Actually, should scroll the texture window only when mouse is down on no widgets...
2051 float nx = e->x / windowSize.x() * extents.width() + extents.minX;
2052 float ny = e->y / windowSize.y() * extents.height() + extents.minY;
2053 trans.x() = -tm.coords[0][0] * nx - tm.coords[0][1] * ny;
2054 trans.y() = -tm.coords[1][0] * nx - tm.coords[1][1] * ny;
2056 dragPoint.x() = e->x, dragPoint.y() = e->y;
2057 trans2.x() = nx, trans2.y() = ny;
2058 oldRotationAngle = rotationAngle;
2059 // oldTrans.x() = tm.coords[0][2] - nx * textureSize.x();
2060 // oldTrans.y() = tm.coords[1][2] - ny * textureSize.y();
2061 oldTrans.x() = tm.coords[0][2];
2062 oldTrans.y() = tm.coords[1][2];
2063 oldCenter.x() = center.x();
2064 oldCenter.y() = center.y();
2070 /* else if (e->button == 3)
2075 //globalOutputStream() << "(" << (haveAnchor ? "anchor" : "released") << ")\n";
2080 gboolean button_release( GtkWidget * win, GdkEventButton * e, gpointer ){
2081 // globalOutputStream() << "--> Textool button release...\n";
2083 if ( e->button == 1 ) {
2084 /* float ptx = e->x / windowSize.x() * extents.width() + extents.minX;
2085 float pty = e->y / windowSize.y() * extents.height() + extents.minY;
2087 //This prolly should go into the mouse move code...
2088 //Doesn't work correctly anyway...
2089 if (translatingX || translatingY)
2090 center.x() = ptx, center.y() = pty;//*/
2092 lButtonDown = false;
2094 if ( translatingX || translatingY ) {
2095 GlobalUndoSystem().finish( "translateTexture" );
2097 else if ( rotating ) {
2098 GlobalUndoSystem().finish( "rotateTexture" );
2100 else if ( scalingX || scalingY ) {
2101 GlobalUndoSystem().finish( "scaleTexture" );
2103 else if ( resizingX || resizingY ) {
2104 GlobalUndoSystem().finish( "resizeTexture" );
2108 GlobalUndoSystem().finish( "textoolUnknown" );
2111 rotating = translatingX = translatingY = scalingX = scalingY
2112 = resizingX = resizingY = false;
2116 else if ( e->button == 3 ) {
2117 rButtonDown = false;
2124 void C2DView::GridForWindow( float c[2], int x, int y)
2126 SpaceForWindow( c, x, y );
2129 c[0] /= m_GridStep[0];
2130 c[1] /= m_GridStep[1];
2131 c[0] = (float)floor( c[0] + 0.5f );
2132 c[1] = (float)floor( c[1] + 0.5f );
2133 c[0] *= m_GridStep[0];
2134 c[1] *= m_GridStep[1];
2136 void C2DView::SpaceForWindow( float c[2], int x, int y)
2138 c[0] = ((float)(x))/((float)(m_rect.right-m_rect.left))*(m_Maxs[0]-m_Mins[0])+m_Mins[0];
2139 c[1] = ((float)(y))/((float)(m_rect.bottom-m_rect.top))*(m_Maxs[1]-m_Mins[1])+m_Mins[1];
2142 gboolean motion( GtkWidget * win, GdkEventMotion * e, gpointer ){
2143 // globalOutputStream() << "--> Textool motion...\n";
2145 if ( lButtonDown ) {
2146 if ( translatingX || translatingY ) {
2147 float ptx = e->x / windowSize.x() * extents.width() + extents.minX;
2148 float pty = e->y / windowSize.y() * extents.height() + extents.minY;
2150 //Need to fix this to take the rotation angle into account, so that it moves along
2151 //the rotated X/Y axis...
2152 if ( translatingX ) {
2153 // tm.coords[0][2] = (trans.x() + ptx) * textureSize.x();
2154 //This works, but only when the angle is zero. !!! FIX !!! [DONE]
2155 // tm.coords[0][2] = oldCenter.x() + (ptx * textureSize.x());
2156 tm.coords[0][2] = oldTrans.x() + ( ptx - trans2.x() ) * textureSize.x();
2157 // center.x() = oldCenter.x() + (ptx - trans2.x());
2160 if ( translatingY ) {
2161 // tm.coords[1][2] = (trans.y() + pty) * textureSize.y();
2162 // tm.coords[1][2] = oldCenter.y() + (pty * textureSize.y());
2163 tm.coords[1][2] = oldTrans.y() + ( pty - trans2.y() ) * textureSize.y();
2164 // center.y() = oldCenter.y() + (pty - trans2.y());
2167 //Need to update center.x/y() so that the widget translates as well. Also, oldCenter
2168 //is badly named... Should be oldTrans or something like that... !!! FIX !!!
2169 //Changing center.x/y() here doesn't seem to change anything... :-/
2170 UpdateControlPoints();
2172 else if ( rotating ) {
2173 // Shamus: New rotate code
2174 int cx = (int)( windowSize.x() * ( center.x() - extents.minX ) / extents.width() );
2175 int cy = (int)( windowSize.y() * ( center.y() - extents.minY ) / extents.height() );
2176 Vector3 v1( dragPoint.x() - cx, dragPoint.y() - cy, 0 ), v2( e->x - cx, e->y - cy, 0 );
2178 vector3_normalise( v1 );
2179 vector3_normalise( v2 );
2180 float c = vector3_dot( v1, v2 );
2181 Vector3 cross = vector3_cross( v1, v2 );
2182 float s = vector3_length( cross );
2184 if ( cross[2] > 0 ) {
2188 // Problem with this: arcsin/cos seems to only return -90 to 90 and 0 to 180...
2189 // Can't derive angle from that!
2191 //rotationAngle = asin(s);// * 180.0f / 3.141592653589f;
2192 rotationAngle = acos( c );
2193 //rotationAngle2 = asin(s);
2194 if ( cross[2] < 0 ) {
2195 rotationAngle = -rotationAngle;
2198 //NO! DOESN'T WORK! rotationAngle -= 45.0f * DEG_TO_RAD;
2201 /*c = cos(rotationAngle - oldRotationAngle);
2202 s = sin(rotationAngle - oldRotationAngle);
2203 rotationAngle += oldRotationAngle;
2204 //c += cos(oldRotationAngle);
2205 //s += sin(oldRotationAngle);
2206 //rotationAngle += oldRotationAngle;
2209 //rotationAngle %= 2.0 * PI;//*/
2211 //This is wrong... Hmm...
2212 //It seems to shear the texture instead of rotating it... !!! FIX !!!
2213 // Now it rotates correctly. Seems TTimo was overcomplicating things here... ;-)
2215 // Seems like what needs to happen here is multiplying these rotations by tm... !!! FIX !!!
2217 // See brush_primit.cpp line 244 (Texdef_EmitTextureCoordinates()) for where texcoords come from...
2219 tm.coords[0][0] = c;
2220 tm.coords[0][1] = s;
2221 tm.coords[1][0] = -s;
2222 tm.coords[1][1] = c;
2223 //It doesn't work anymore... Dunno why...
2224 //tm.coords[0][2] = -trans.x(); // This works!!! Yeah!!!
2225 //tm.coords[1][2] = -trans.y();
2227 //tm.coords[0][2] = rotationPoint.x(); // This works, but strangely...
2228 //tm.coords[1][2] = rotationPoint.y();
2229 //tm.coords[0][2] = 0;// center.x() / 2.0f;
2230 //tm.coords[1][2] = 0;// center.y() / 2.0f;
2232 //tm.coords[0][2] = -(center.x() * textureSize.x());
2233 //tm.coords[1][2] = -(center.y() * textureSize.y());
2234 //Eh? No, but seems to be getting closer...
2235 /*float ptx = e->x / windowSize.x() * extents.width() + extents.minX;
2236 float pty = e->y / windowSize.y() * extents.height() + extents.minY;
2237 tm.coords[0][2] = -c * center.x() - s * center.y() + ptx;
2238 tm.coords[1][2] = s * center.x() - c * center.x() + pty;//*/
2239 //Kinda works, but center drifts around on non-square textures...
2240 /*tm.coords[0][2] = (-c * center.x() - s * center.y()) * textureSize.x();
2241 tm.coords[1][2] = ( s * center.x() - c * center.y()) * textureSize.y();//*/
2242 //Rotates correctly, but not around the actual center of the face's points...
2243 /*tm.coords[0][2] = -c * center.x() * textureSize.x() - s * center.y() * textureSize.y();
2244 tm.coords[1][2] = s * center.x() * textureSize.x() - c * center.y() * textureSize.y();//*/
2246 tm.coords[0][2] = ( -c * center.x() * textureSize.x() - s * center.y() * textureSize.y() ) + center.x() * textureSize.x();
2247 tm.coords[1][2] = ( s * center.x() * textureSize.x() - c * center.y() * textureSize.y() ) + center.y() * textureSize.y(); //*/
2248 //This doesn't work...
2249 //And this is the wrong place for this anyway (I'm pretty sure).
2250 /*tm.coords[0][2] += oldCenter.x();
2251 tm.coords[1][2] += oldCenter.y();//*/
2252 UpdateControlPoints(); // will cause a redraw
2257 else // Check for widget mouseovers
2260 float nx = e->x / windowSize.x() * extents.width() + extents.minX;
2261 float ny = e->y / windowSize.y() * extents.height() + extents.minY;
2262 // Translate nx/y to the "center" point...
2265 ny = -ny; // Flip Y-axis so that increasing numbers move up
2267 tran.x() = tm.coords[0][0] * nx + tm.coords[0][1] * ny;
2268 tran.y() = tm.coords[1][0] * nx + tm.coords[1][1] * ny;
2269 //This doesn't seem to generate a valid distance from the center--for some reason it
2270 //calculates a fixed number every time
2271 //Look at nx/y above: they're getting fixed there! !!! FIX !!! [DONE]
2272 float dist = sqrt( ( nx * nx ) + ( ny * ny ) );
2273 // Normalize to the 2.0 = height standard (for now)
2274 //globalOutputStream() << "--> Distance before: " << dist;
2275 dist = dist * 2.0f / extents.height();
2276 //globalOutputStream() << ". After: " << dist;
2277 tran.x() = tran.x() * 2.0f / extents.height();
2278 tran.y() = tran.y() * 2.0f / extents.height();
2279 //globalOutputStream() << ". Trans: " << tran.x() << ", " << tran.y() << "\n";
2281 //Let's try this instead...
2282 //Interesting! It seems that e->x/y are rotated
2283 //(no, they're not--the TM above is what's doing it...)
2284 nx = ( ( e->x / windowSize.y() ) * 2.0f ) - ( windowSize.x() / windowSize.y() );
2285 ny = ( ( e->y / windowSize.y() ) * 2.0f ) - ( windowSize.y() / windowSize.y() );
2287 //Cool! It works! Now just need to do rotation...
2289 rotating = translatingX = translatingY = scalingX = scalingY
2290 = resizingX = resizingY = false;
2292 if ( dist < ( gridRadius * 0.16f ) ) {
2293 translatingX = translatingY = true;
2295 else if ( dist > ( gridRadius * 0.16f ) && dist < ( gridRadius * 1.10f )
2296 && fabs( ny ) < ( gridRadius * 0.05f ) && nx > 0 ) {
2297 translatingX = true;
2299 else if ( dist > ( gridRadius * 0.16f ) && dist < ( gridRadius * 1.10f )
2300 && fabs( nx ) < ( gridRadius * 0.05f ) && ny > 0 ) {
2301 translatingY = true;
2303 // Should tighten up the angle on this, or put this test after the axis tests...
2304 else if ( tran.x() > 0 && tran.y() > 0
2305 && ( dist > ( gridRadius * 0.82f ) && dist < ( gridRadius * 0.98f ) ) ) {
2317 //It seems the fake tex coords conversion is screwing this stuff up... !!! FIX !!!
2318 //This is still wrong... Prolly need to do something with the oldScaleX/Y stuff...
2319 void flipX( GtkToggleButton *, gpointer ){
2320 // globalOutputStream() << "--> Flip X...\n";
2322 // SurfaceInspector_GetSelectedBPTexdef(); // Refresh g_selectedBrushPrimitTexdef...
2323 // tm.coords[0][0] = -tm.coords[0][0];
2324 // tm.coords[1][0] = -tm.coords[1][0];
2325 // tm.coords[0][0] = -tm.coords[0][0]; // This should be correct now...Nope.
2326 // tm.coords[1][1] = -tm.coords[1][1];
2327 tm.coords[0][0] = -tm.coords[0][0]; // This should be correct now...
2328 tm.coords[1][0] = -tm.coords[1][0];
2329 // tm.coords[2][0] = -tm.coords[2][0];//wil wok? no.
2330 UpdateControlPoints();
2333 void flipY( GtkToggleButton *, gpointer ){
2334 // globalOutputStream() << "--> Flip Y...\n";
2335 // tm.coords[0][1] = -tm.coords[0][1];
2336 // tm.coords[1][1] = -tm.coords[1][1];
2337 // tm.coords[0][1] = -tm.coords[0][1]; // This should be correct now...Nope.
2338 // tm.coords[1][0] = -tm.coords[1][0];
2339 tm.coords[0][1] = -tm.coords[0][1]; // This should be correct now...
2340 tm.coords[1][1] = -tm.coords[1][1];
2341 // tm.coords[2][1] = -tm.coords[2][1];//wil wok? no.
2342 UpdateControlPoints();
2345 } // end namespace TexTool