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
108 gtk_widget_queue_draw(g_textoolWin);
115 inline void spin_button_set_step(GtkSpinButton* spin, gfloat step)
118 gtk_spin_button_get_adjustment(spin)->step_increment = step;
120 GValue gvalue = GValue_default();
121 g_value_init(&gvalue, G_TYPE_DOUBLE);
122 g_value_set_double(&gvalue, step);
123 g_object_set(G_OBJECT(gtk_spin_button_get_adjustment(spin)), "step-increment", &gvalue, NULL);
131 GtkSpinButton* m_spin;
133 Increment(float& f) : m_f(f), m_spin(0), m_entry(0)
138 entry_set_float(m_entry, m_f);
140 typedef MemberCaller<Increment, &Increment::cancel> CancelCaller;
143 m_f = static_cast<float>(entry_get_float(m_entry));
144 spin_button_set_step(m_spin, m_f);
146 typedef MemberCaller<Increment, &Increment::apply> ApplyCaller;
149 void SurfaceInspector_GridChange();
151 class SurfaceInspector : public Dialog
153 GtkWindow* BuildDialog();
155 NonModalEntry m_textureEntry;
156 NonModalSpinner m_hshiftSpinner;
157 NonModalEntry m_hshiftEntry;
158 NonModalSpinner m_vshiftSpinner;
159 NonModalEntry m_vshiftEntry;
160 NonModalSpinner m_hscaleSpinner;
161 NonModalEntry m_hscaleEntry;
162 NonModalSpinner m_vscaleSpinner;
163 NonModalEntry m_vscaleEntry;
164 NonModalSpinner m_rotateSpinner;
165 NonModalEntry m_rotateEntry;
169 GtkCheckButton* m_surfaceFlags[32];
170 GtkCheckButton* m_contentFlags[32];
172 NonModalEntry m_valueEntry;
173 GtkEntry* m_valueEntryWidget;
175 WindowPositionTracker m_positionTracker;
176 WindowPositionTrackerImportStringCaller m_importPosition;
177 WindowPositionTrackerExportStringCaller m_exportPosition;
180 float m_fitHorizontal;
183 Increment m_hshiftIncrement;
184 Increment m_vshiftIncrement;
185 Increment m_hscaleIncrement;
186 Increment m_vscaleIncrement;
187 Increment m_rotateIncrement;
191 m_textureEntry(ApplyShaderCaller(*this), UpdateCaller(*this)),
192 m_hshiftSpinner(ApplyTexdefCaller(*this), UpdateCaller(*this)),
193 m_hshiftEntry(Increment::ApplyCaller(m_hshiftIncrement), Increment::CancelCaller(m_hshiftIncrement)),
194 m_vshiftSpinner(ApplyTexdefCaller(*this), UpdateCaller(*this)),
195 m_vshiftEntry(Increment::ApplyCaller(m_vshiftIncrement), Increment::CancelCaller(m_vshiftIncrement)),
196 m_hscaleSpinner(ApplyTexdefCaller(*this), UpdateCaller(*this)),
197 m_hscaleEntry(Increment::ApplyCaller(m_hscaleIncrement), Increment::CancelCaller(m_hscaleIncrement)),
198 m_vscaleSpinner(ApplyTexdefCaller(*this), UpdateCaller(*this)),
199 m_vscaleEntry(Increment::ApplyCaller(m_vscaleIncrement), Increment::CancelCaller(m_vscaleIncrement)),
200 m_rotateSpinner(ApplyTexdefCaller(*this), UpdateCaller(*this)),
201 m_rotateEntry(Increment::ApplyCaller(m_rotateIncrement), Increment::CancelCaller(m_rotateIncrement)),
202 m_idleDraw(UpdateCaller(*this)),
203 m_valueEntry(ApplyFlagsCaller(*this), UpdateCaller(*this)),
204 m_importPosition(m_positionTracker),
205 m_exportPosition(m_positionTracker),
206 m_hshiftIncrement(g_si_globals.shift[0]),
207 m_vshiftIncrement(g_si_globals.shift[1]),
208 m_hscaleIncrement(g_si_globals.scale[0]),
209 m_vscaleIncrement(g_si_globals.scale[1]),
210 m_rotateIncrement(g_si_globals.rotate)
214 m_positionTracker.setPosition(c_default_window_pos);
217 void constructWindow(GtkWindow* main_window)
219 m_parent = main_window;
221 AddGridChangeCallback(FreeCaller<SurfaceInspector_GridChange>());
229 return GTK_WIDGET_VISIBLE(const_cast<GtkWindow*>(GetWidget()));
235 m_idleDraw.queueDraw();
240 typedef MemberCaller<SurfaceInspector, &SurfaceInspector::Update> UpdateCaller;
242 typedef MemberCaller<SurfaceInspector, &SurfaceInspector::ApplyShader> ApplyShaderCaller;
244 typedef MemberCaller<SurfaceInspector, &SurfaceInspector::ApplyTexdef> ApplyTexdefCaller;
246 typedef MemberCaller<SurfaceInspector, &SurfaceInspector::ApplyFlags> ApplyFlagsCaller;
251 SurfaceInspector* g_SurfaceInspector;
253 inline SurfaceInspector& getSurfaceInspector()
255 ASSERT_NOTNULL(g_SurfaceInspector);
256 return *g_SurfaceInspector;
260 void SurfaceInspector_constructWindow(GtkWindow* main_window)
262 getSurfaceInspector().constructWindow(main_window);
264 void SurfaceInspector_destroyWindow()
266 getSurfaceInspector().destroyWindow();
269 void SurfaceInspector_queueDraw()
271 getSurfaceInspector().queueDraw();
276 CopiedString g_selectedShader;
277 TextureProjection g_selectedTexdef;
278 ContentsFlagsValue g_selectedFlags;
279 size_t g_selectedShaderSize[2];
282 void SurfaceInspector_SetSelectedShader(const char* shader)
284 g_selectedShader = shader;
285 SurfaceInspector_queueDraw();
288 void SurfaceInspector_SetSelectedTexdef(const TextureProjection& projection)
290 g_selectedTexdef = projection;
291 SurfaceInspector_queueDraw();
294 void SurfaceInspector_SetSelectedFlags(const ContentsFlagsValue& flags)
296 g_selectedFlags = flags;
297 SurfaceInspector_queueDraw();
300 static bool s_texture_selection_dirty = false;
302 void SurfaceInspector_updateSelection()
304 s_texture_selection_dirty = true;
305 SurfaceInspector_queueDraw();
308 if (g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES)
310 TexTool::queueDraw();
311 //globalOutputStream() << "textool texture changed..\n";
316 void SurfaceInspector_SelectionChanged(const Selectable& selectable)
318 SurfaceInspector_updateSelection();
321 void SurfaceInspector_SetCurrent_FromSelected()
323 if(s_texture_selection_dirty == true)
325 s_texture_selection_dirty = false;
326 if(!g_SelectedFaceInstances.empty())
328 TextureProjection projection;
329 //This *may* be the point before it fucks up... Let's see!
330 //Yep, there was a call to removeScale in there...
331 Scene_BrushGetTexdef_Component_Selected(GlobalSceneGraph(), projection);
333 SurfaceInspector_SetSelectedTexdef(projection);
335 Scene_BrushGetShaderSize_Component_Selected(GlobalSceneGraph(), g_selectedShaderSize[0], g_selectedShaderSize[1]);
336 g_selectedTexdef.m_brushprimit_texdef.coords[0][2] = float_mod(g_selectedTexdef.m_brushprimit_texdef.coords[0][2], (float)g_selectedShaderSize[0]);
337 g_selectedTexdef.m_brushprimit_texdef.coords[1][2] = float_mod(g_selectedTexdef.m_brushprimit_texdef.coords[1][2], (float)g_selectedShaderSize[1]);
340 Scene_BrushGetShader_Component_Selected(GlobalSceneGraph(), name);
341 if(string_not_empty(name.c_str()))
343 SurfaceInspector_SetSelectedShader(name.c_str());
346 ContentsFlagsValue flags;
347 Scene_BrushGetFlags_Component_Selected(GlobalSceneGraph(), flags);
348 SurfaceInspector_SetSelectedFlags(flags);
352 TextureProjection projection;
353 Scene_BrushGetTexdef_Selected(GlobalSceneGraph(), projection);
354 SurfaceInspector_SetSelectedTexdef(projection);
357 Scene_BrushGetShader_Selected(GlobalSceneGraph(), name);
358 if(string_empty(name.c_str()))
360 Scene_PatchGetShader_Selected(GlobalSceneGraph(), name);
362 if(string_not_empty(name.c_str()))
364 SurfaceInspector_SetSelectedShader(name.c_str());
367 ContentsFlagsValue flags(0, 0, 0, false);
368 Scene_BrushGetFlags_Selected(GlobalSceneGraph(), flags);
369 SurfaceInspector_SetSelectedFlags(flags);
374 const char* SurfaceInspector_GetSelectedShader()
376 SurfaceInspector_SetCurrent_FromSelected();
377 return g_selectedShader.c_str();
380 const TextureProjection& SurfaceInspector_GetSelectedTexdef()
382 SurfaceInspector_SetCurrent_FromSelected();
383 return g_selectedTexdef;
386 const ContentsFlagsValue& SurfaceInspector_GetSelectedFlags()
388 SurfaceInspector_SetCurrent_FromSelected();
389 return g_selectedFlags;
395 ===================================================
399 ===================================================
402 si_globals_t g_si_globals;
405 // make the shift increments match the grid settings
406 // the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size
407 // this depends on a scale value if you have selected a particular texture on which you want it to work:
408 // we move the textures in pixels, not world units. (i.e. increment values are in pixel)
409 // depending on the texture scale it doesn't take the same amount of pixels to move of GetGridSize()
410 // increment * scale = gridsize
411 // hscale and vscale are optional parameters, if they are zero they will be set to the default scale
412 // NOTE: the default scale depends if you are using BP mode or regular.
413 // For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f
415 void DoSnapTToGrid(float hscale, float vscale)
417 g_si_globals.shift[0] = static_cast<float>(float_to_integer(static_cast<float>(GetGridSize()) / hscale));
418 g_si_globals.shift[1] = static_cast<float>(float_to_integer(static_cast<float>(GetGridSize()) / vscale));
419 getSurfaceInspector().queueDraw();
422 void SurfaceInspector_GridChange()
424 if (g_si_globals.m_bSnapTToGrid)
425 DoSnapTToGrid(Texdef_getDefaultTextureScale(), Texdef_getDefaultTextureScale());
428 // make the shift increments match the grid settings
429 // the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size
430 // this depends on the current texture scale used?
431 // we move the textures in pixels, not world units. (i.e. increment values are in pixel)
432 // depending on the texture scale it doesn't take the same amount of pixels to move of GetGridSize()
433 // increment * scale = gridsize
434 static void OnBtnMatchGrid(GtkWidget *widget, gpointer data)
436 float hscale, vscale;
437 hscale = static_cast<float>(gtk_spin_button_get_value_as_float(getSurfaceInspector().m_hscaleIncrement.m_spin));
438 vscale = static_cast<float>(gtk_spin_button_get_value_as_float(getSurfaceInspector().m_vscaleIncrement.m_spin));
440 if (hscale == 0.0f || vscale == 0.0f)
442 globalOutputStream() << "ERROR: unexpected scale == 0.0f\n";
446 DoSnapTToGrid (hscale, vscale);
449 // DoSurface will always try to show the surface inspector
450 // or update it because something new has been selected
451 // Shamus: It does get called when the SI is hidden, but not when you select something new. ;-)
452 void DoSurface (void)
454 if(getSurfaceInspector().GetWidget() == 0)
456 getSurfaceInspector().Create();
459 getSurfaceInspector().Update();
460 getSurfaceInspector().importData();
461 getSurfaceInspector().ShowDlg();
464 void SurfaceInspector_toggleShown()
466 if (getSurfaceInspector().visible())
468 getSurfaceInspector().HideDlg();
476 void SurfaceInspector_FitTexture()
478 UndoableCommand undo("textureAutoFit");
479 Select_FitTexture(getSurfaceInspector().m_fitHorizontal, getSurfaceInspector().m_fitVertical);
482 static void OnBtnPatchdetails(GtkWidget *widget, gpointer data)
484 Scene_PatchCapTexture_Selected(GlobalSceneGraph());
487 static void OnBtnPatchnatural(GtkWidget *widget, gpointer data)
489 Scene_PatchNaturalTexture_Selected(GlobalSceneGraph());
492 static void OnBtnPatchreset(GtkWidget *widget, gpointer data)
496 if (DoTextureLayout (&fx, &fy) == eIDOK)
498 Scene_PatchTileTexture_Selected(GlobalSceneGraph(), fx, fy);
502 static void OnBtnPatchFit(GtkWidget *widget, gpointer data)
504 Scene_PatchTileTexture_Selected(GlobalSceneGraph(), 1, 1);
507 static void OnBtnAxial(GtkWidget *widget, gpointer data)
509 //globalOutputStream() << "--> [OnBtnAxial]...\n";
510 UndoableCommand undo("textureDefault");
511 TextureProjection projection;
512 //globalOutputStream() << " TexDef_Construct_Default()...\n";
513 TexDef_Construct_Default(projection);
514 //globalOutputStream() << " Select_SetTexdef()...\n";
519 if (g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES)
521 // Scale up texture width/height if in BP mode...
522 //NOTE: This may not be correct any more! :-P
523 if (!g_SelectedFaceInstances.empty())
525 Face & face = g_SelectedFaceInstances.last().getFace();
526 float x = face.getShader().m_state->getTexture().width;
527 float y = face.getShader().m_state->getTexture().height;
528 projection.m_brushprimit_texdef.coords[0][0] /= x;
529 projection.m_brushprimit_texdef.coords[0][1] /= y;
530 projection.m_brushprimit_texdef.coords[1][0] /= x;
531 projection.m_brushprimit_texdef.coords[1][1] /= y;
536 Select_SetTexdef(projection);
539 static void OnBtnFaceFit(GtkWidget *widget, gpointer data)
541 getSurfaceInspector().exportData();
542 SurfaceInspector_FitTexture();
545 typedef const char* FlagName;
547 const FlagName surfaceflagNamesDefault[32] = {
582 const FlagName contentflagNamesDefault[32] = {
617 const char* getSurfaceFlagName(std::size_t bit)
619 const char* value = g_pGameDescription->getKeyValue(surfaceflagNamesDefault[bit]);
620 if(string_empty(value))
622 return surfaceflagNamesDefault[bit];
627 const char* getContentFlagName(std::size_t bit)
629 const char* value = g_pGameDescription->getKeyValue(contentflagNamesDefault[bit]);
630 if(string_empty(value))
632 return contentflagNamesDefault[bit];
638 // =============================================================================
639 // SurfaceInspector class
641 guint togglebutton_connect_toggled(GtkToggleButton* button, const Callback& callback)
643 return g_signal_connect_swapped(G_OBJECT(button), "toggled", G_CALLBACK(callback.getThunk()), callback.getEnvironment());
646 GtkWindow* SurfaceInspector::BuildDialog()
648 GtkWindow* window = create_floating_window("Surface Inspector", m_parent);
650 m_positionTracker.connect(window);
652 global_accel_connect_window(window);
654 window_connect_focus_in_clear_focus_widget(window);
658 // replaced by only the vbox:
659 GtkWidget* vbox = gtk_vbox_new (FALSE, 5);
660 gtk_widget_show (vbox);
661 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
662 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
665 GtkWidget* hbox2 = gtk_hbox_new (FALSE, 5);
666 gtk_widget_show (hbox2);
667 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox2), FALSE, FALSE, 0);
670 GtkWidget* label = gtk_label_new ("Texture");
671 gtk_widget_show (label);
672 gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0);
675 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
676 gtk_widget_show(GTK_WIDGET(entry));
677 gtk_box_pack_start(GTK_BOX(hbox2), GTK_WIDGET(entry), TRUE, TRUE, 0);
679 m_textureEntry.connect(entry);
680 GlobalTextureEntryCompletion::instance().connect(entry);
686 GtkWidget* table = gtk_table_new (6, 4, FALSE);
687 gtk_widget_show (table);
688 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), FALSE, FALSE, 0);
689 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
690 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
692 GtkWidget* label = gtk_label_new ("Horizontal shift");
693 gtk_widget_show (label);
694 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
695 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,
696 (GtkAttachOptions) (GTK_FILL),
697 (GtkAttachOptions) (0), 0, 0);
700 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(GTK_ADJUSTMENT(gtk_adjustment_new(0, -8192, 8192, 2, 8, 0)), 0, 2));
701 m_hshiftIncrement.m_spin = spin;
702 m_hshiftSpinner.connect(spin);
703 gtk_widget_show(GTK_WIDGET(spin));
704 gtk_table_attach (GTK_TABLE(table), GTK_WIDGET(spin), 1, 2, 0, 1,
705 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
706 (GtkAttachOptions) (0), 0, 0);
707 gtk_widget_set_usize(GTK_WIDGET(spin), 60, -2);
710 GtkWidget* label = gtk_label_new ("Step");
711 gtk_widget_show (label);
712 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
713 gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1,
714 (GtkAttachOptions) (GTK_FILL),
715 (GtkAttachOptions) (0), 0, 0);
718 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
719 gtk_widget_show(GTK_WIDGET(entry));
720 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(entry), 3, 4, 0, 1,
721 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
722 (GtkAttachOptions) (0), 0, 0);
723 gtk_widget_set_usize(GTK_WIDGET(entry), 50, -2);
724 m_hshiftIncrement.m_entry = entry;
725 m_hshiftEntry.connect(entry);
728 GtkWidget* label = gtk_label_new ("Vertical shift");
729 gtk_widget_show (label);
730 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
731 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2,
732 (GtkAttachOptions) (GTK_FILL),
733 (GtkAttachOptions) (0), 0, 0);
736 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(GTK_ADJUSTMENT(gtk_adjustment_new(0, -8192, 8192, 2, 8, 0)), 0, 2));
737 m_vshiftIncrement.m_spin = spin;
738 m_vshiftSpinner.connect(spin);
739 gtk_widget_show(GTK_WIDGET(spin));
740 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(spin), 1, 2, 1, 2,
741 (GtkAttachOptions) (GTK_FILL),
742 (GtkAttachOptions) (0), 0, 0);
743 gtk_widget_set_usize(GTK_WIDGET(spin), 60, -2);
746 GtkWidget* label = gtk_label_new ("Step");
747 gtk_widget_show (label);
748 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
749 gtk_table_attach(GTK_TABLE(table), label, 2, 3, 1, 2,
750 (GtkAttachOptions) (GTK_FILL),
751 (GtkAttachOptions) (0), 0, 0);
754 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
755 gtk_widget_show(GTK_WIDGET(entry));
756 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(entry), 3, 4, 1, 2,
757 (GtkAttachOptions) (GTK_FILL),
758 (GtkAttachOptions) (0), 0, 0);
759 gtk_widget_set_usize(GTK_WIDGET(entry), 50, -2);
760 m_vshiftIncrement.m_entry = entry;
761 m_vshiftEntry.connect(entry);
764 GtkWidget* label = gtk_label_new ("Horizontal stretch");
765 gtk_widget_show (label);
766 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
767 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3,
768 (GtkAttachOptions) (GTK_FILL),
769 (GtkAttachOptions) (0), 0, 0);
772 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(GTK_ADJUSTMENT(gtk_adjustment_new(0, -8192, 8192, 2, 8, 0)), 0, 5));
773 m_hscaleIncrement.m_spin = spin;
774 m_hscaleSpinner.connect(spin);
775 gtk_widget_show(GTK_WIDGET(spin));
776 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(spin), 1, 2, 2, 3,
777 (GtkAttachOptions) (GTK_FILL),
778 (GtkAttachOptions) (0), 0, 0);
779 gtk_widget_set_usize(GTK_WIDGET(spin), 60, -2);
782 GtkWidget* label = gtk_label_new ("Step");
783 gtk_widget_show (label);
784 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
785 gtk_table_attach(GTK_TABLE(table), label, 2, 3, 2, 3,
786 (GtkAttachOptions) (GTK_FILL),
787 (GtkAttachOptions) (0), 2, 3);
790 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
791 gtk_widget_show(GTK_WIDGET(entry));
792 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(entry), 3, 4, 2, 3,
793 (GtkAttachOptions) (GTK_FILL),
794 (GtkAttachOptions) (0), 2, 3);
795 gtk_widget_set_usize(GTK_WIDGET(entry), 50, -2);
796 m_hscaleIncrement.m_entry = entry;
797 m_hscaleEntry.connect(entry);
800 GtkWidget* label = gtk_label_new ("Vertical stretch");
801 gtk_widget_show (label);
802 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
803 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4,
804 (GtkAttachOptions) (GTK_FILL),
805 (GtkAttachOptions) (0), 0, 0);
808 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(GTK_ADJUSTMENT(gtk_adjustment_new(0, -8192, 8192, 2, 8, 0)), 0, 5));
809 m_vscaleIncrement.m_spin = spin;
810 m_vscaleSpinner.connect(spin);
811 gtk_widget_show(GTK_WIDGET(spin));
812 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(spin), 1, 2, 3, 4,
813 (GtkAttachOptions) (GTK_FILL),
814 (GtkAttachOptions) (0), 0, 0);
815 gtk_widget_set_usize(GTK_WIDGET(spin), 60, -2);
818 GtkWidget* label = gtk_label_new ("Step");
819 gtk_widget_show (label);
820 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
821 gtk_table_attach(GTK_TABLE(table), label, 2, 3, 3, 4,
822 (GtkAttachOptions) (GTK_FILL),
823 (GtkAttachOptions) (0), 0, 0);
826 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
827 gtk_widget_show(GTK_WIDGET(entry));
828 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(entry), 3, 4, 3, 4,
829 (GtkAttachOptions) (GTK_FILL),
830 (GtkAttachOptions) (0), 0, 0);
831 gtk_widget_set_usize(GTK_WIDGET(entry), 50, -2);
832 m_vscaleIncrement.m_entry = entry;
833 m_vscaleEntry.connect(entry);
836 GtkWidget* label = gtk_label_new ("Rotate");
837 gtk_widget_show (label);
838 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
839 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5,
840 (GtkAttachOptions) (GTK_FILL),
841 (GtkAttachOptions) (0), 0, 0);
844 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(GTK_ADJUSTMENT(gtk_adjustment_new(0, -8192, 8192, 2, 8, 0)), 0, 2));
845 m_rotateIncrement.m_spin = spin;
846 m_rotateSpinner.connect(spin);
847 gtk_widget_show(GTK_WIDGET(spin));
848 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(spin), 1, 2, 4, 5,
849 (GtkAttachOptions) (GTK_FILL),
850 (GtkAttachOptions) (0), 0, 0);
851 gtk_widget_set_usize(GTK_WIDGET(spin), 60, -2);
852 gtk_spin_button_set_wrap(spin, TRUE);
855 GtkWidget* label = gtk_label_new ("Step");
856 gtk_widget_show (label);
857 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
858 gtk_table_attach(GTK_TABLE(table), label, 2, 3, 4, 5,
859 (GtkAttachOptions) (GTK_FILL),
860 (GtkAttachOptions) (0), 0, 0);
863 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
864 gtk_widget_show(GTK_WIDGET(entry));
865 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(entry), 3, 4, 4, 5,
866 (GtkAttachOptions) (GTK_FILL),
867 (GtkAttachOptions) (0), 0, 0);
868 gtk_widget_set_usize(GTK_WIDGET(entry), 50, -2);
869 m_rotateIncrement.m_entry = entry;
870 m_rotateEntry.connect(entry);
874 GtkWidget* button = gtk_button_new_with_label ("Match Grid");
875 gtk_widget_show (button);
876 gtk_table_attach(GTK_TABLE(table), button, 2, 4, 5, 6,
877 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
878 (GtkAttachOptions) (0), 0, 0);
879 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(OnBtnMatchGrid), 0);
884 GtkWidget* frame = gtk_frame_new ("Texturing");
885 gtk_widget_show (frame);
886 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(frame), FALSE, FALSE, 0);
888 GtkWidget* table = gtk_table_new (4, 4, FALSE);
889 gtk_widget_show (table);
890 gtk_container_add (GTK_CONTAINER (frame), table);
891 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
892 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
893 gtk_container_set_border_width (GTK_CONTAINER (table), 5);
895 GtkWidget* label = gtk_label_new ("Brush");
896 gtk_widget_show (label);
897 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,
898 (GtkAttachOptions) (GTK_FILL),
899 (GtkAttachOptions) (0), 0, 0);
902 GtkWidget* label = gtk_label_new ("Patch");
903 gtk_widget_show (label);
904 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3,
905 (GtkAttachOptions) (GTK_FILL),
906 (GtkAttachOptions) (0), 0, 0);
909 GtkWidget* label = gtk_label_new ("Width");
910 gtk_widget_show (label);
911 gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1,
912 (GtkAttachOptions) (GTK_FILL),
913 (GtkAttachOptions) (0), 0, 0);
916 GtkWidget* label = gtk_label_new ("Height");
917 gtk_widget_show (label);
918 gtk_table_attach(GTK_TABLE(table), label, 3, 4, 0, 1,
919 (GtkAttachOptions) (GTK_FILL),
920 (GtkAttachOptions) (0), 0, 0);
923 GtkWidget* button = gtk_button_new_with_label ("Axial");
924 gtk_widget_show (button);
925 gtk_table_attach(GTK_TABLE(table), button, 0, 1, 1, 2,
926 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
927 (GtkAttachOptions) (0), 0, 0);
928 g_signal_connect(G_OBJECT(button), "clicked",
929 G_CALLBACK(OnBtnAxial), 0);
930 gtk_widget_set_usize (button, 60, -2);
933 GtkWidget* button = gtk_button_new_with_label ("Fit");
934 gtk_widget_show (button);
935 gtk_table_attach(GTK_TABLE(table), button, 1, 2, 1, 2,
936 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
937 (GtkAttachOptions) (0), 0, 0);
938 g_signal_connect(G_OBJECT(button), "clicked",
939 G_CALLBACK(OnBtnFaceFit), 0);
940 gtk_widget_set_usize (button, 60, -2);
943 GtkWidget* button = gtk_button_new_with_label ("CAP");
944 gtk_widget_show (button);
945 gtk_table_attach(GTK_TABLE(table), button, 0, 1, 3, 4,
946 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
947 (GtkAttachOptions) (0), 0, 0);
948 g_signal_connect(G_OBJECT(button), "clicked",
949 G_CALLBACK(OnBtnPatchdetails), 0);
950 gtk_widget_set_usize (button, 60, -2);
953 GtkWidget* button = gtk_button_new_with_label ("Set...");
954 gtk_widget_show (button);
955 gtk_table_attach(GTK_TABLE(table), button, 1, 2, 3, 4,
956 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
957 (GtkAttachOptions) (0), 0, 0);
958 g_signal_connect(G_OBJECT(button), "clicked",
959 G_CALLBACK(OnBtnPatchreset), 0);
960 gtk_widget_set_usize (button, 60, -2);
963 GtkWidget* button = gtk_button_new_with_label ("Natural");
964 gtk_widget_show (button);
965 gtk_table_attach(GTK_TABLE(table), button, 2, 3, 3, 4,
966 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
967 (GtkAttachOptions) (0), 0, 0);
968 g_signal_connect(G_OBJECT(button), "clicked",
969 G_CALLBACK(OnBtnPatchnatural), 0);
970 gtk_widget_set_usize (button, 60, -2);
973 GtkWidget* button = gtk_button_new_with_label ("Fit");
974 gtk_widget_show (button);
975 gtk_table_attach(GTK_TABLE(table), button, 3, 4, 3, 4,
976 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
977 (GtkAttachOptions) (0), 0, 0);
978 g_signal_connect(G_OBJECT(button), "clicked",
979 G_CALLBACK(OnBtnPatchFit), 0);
980 gtk_widget_set_usize (button, 60, -2);
983 GtkWidget* spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 0, 1 << 16, 1, 10, 0)), 0, 6);
984 gtk_widget_show (spin);
985 gtk_table_attach(GTK_TABLE(table), spin, 2, 3, 1, 2,
986 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
987 (GtkAttachOptions) (0), 0, 0);
988 gtk_widget_set_usize (spin, 60, -2);
989 AddDialogData(*GTK_SPIN_BUTTON(spin), m_fitHorizontal);
992 GtkWidget* spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 0, 1 << 16, 1, 10, 0)), 0, 6);
993 gtk_widget_show (spin);
994 gtk_table_attach(GTK_TABLE(table), spin, 3, 4, 1, 2,
995 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
996 (GtkAttachOptions) (0), 0, 0);
997 gtk_widget_set_usize (spin, 60, -2);
998 AddDialogData(*GTK_SPIN_BUTTON(spin), m_fitVertical);
1002 if(!string_empty(g_pGameDescription->getKeyValue("si_flags")))
1005 GtkFrame* frame = GTK_FRAME(gtk_frame_new("Surface Flags"));
1006 gtk_widget_show(GTK_WIDGET(frame));
1007 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(frame), TRUE, TRUE, 0);
1009 GtkVBox* vbox3 = GTK_VBOX(gtk_vbox_new(FALSE, 4));
1010 //gtk_container_set_border_width(GTK_CONTAINER(vbox3), 4);
1011 gtk_widget_show(GTK_WIDGET(vbox3));
1012 gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(vbox3));
1014 GtkTable* table = GTK_TABLE(gtk_table_new(8, 4, FALSE));
1015 gtk_widget_show(GTK_WIDGET(table));
1016 gtk_box_pack_start(GTK_BOX(vbox3), GTK_WIDGET(table), TRUE, TRUE, 0);
1017 gtk_table_set_row_spacings(table, 0);
1018 gtk_table_set_col_spacings(table, 0);
1020 GtkCheckButton** p = m_surfaceFlags;
1022 for(int c = 0; c != 4; ++c)
1024 for(int r = 0; r != 8; ++r)
1026 GtkCheckButton* check = GTK_CHECK_BUTTON(gtk_check_button_new_with_label(getSurfaceFlagName(c * 8 + r)));
1027 gtk_widget_show(GTK_WIDGET(check));
1028 gtk_table_attach(table, GTK_WIDGET(check), c, c+1, r, r+1,
1029 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
1030 (GtkAttachOptions)(0), 0, 0);
1032 guint handler_id = togglebutton_connect_toggled(GTK_TOGGLE_BUTTON(check), ApplyFlagsCaller(*this));
1033 g_object_set_data(G_OBJECT(check), "handler", gint_to_pointer(handler_id));
1040 GtkFrame* frame = GTK_FRAME(gtk_frame_new("Content Flags"));
1041 gtk_widget_show(GTK_WIDGET(frame));
1042 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(frame), TRUE, TRUE, 0);
1044 GtkVBox* vbox3 = GTK_VBOX(gtk_vbox_new(FALSE, 4));
1045 //gtk_container_set_border_width(GTK_CONTAINER(vbox3), 4);
1046 gtk_widget_show(GTK_WIDGET(vbox3));
1047 gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(vbox3));
1050 GtkTable* table = GTK_TABLE(gtk_table_new(8, 4, FALSE));
1051 gtk_widget_show(GTK_WIDGET(table));
1052 gtk_box_pack_start(GTK_BOX(vbox3), GTK_WIDGET(table), TRUE, TRUE, 0);
1053 gtk_table_set_row_spacings(table, 0);
1054 gtk_table_set_col_spacings(table, 0);
1056 GtkCheckButton** p = m_contentFlags;
1058 for(int c = 0; c != 4; ++c)
1060 for(int r = 0; r != 8; ++r)
1062 GtkCheckButton* check = GTK_CHECK_BUTTON(gtk_check_button_new_with_label(getContentFlagName(c * 8 + r)));
1063 gtk_widget_show(GTK_WIDGET(check));
1064 gtk_table_attach(table, GTK_WIDGET(check), c, c+1, r, r+1,
1065 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
1066 (GtkAttachOptions)(0), 0, 0);
1068 guint handler_id = togglebutton_connect_toggled(GTK_TOGGLE_BUTTON(check), ApplyFlagsCaller(*this));
1069 g_object_set_data(G_OBJECT(check), "handler", gint_to_pointer(handler_id));
1073 // not allowed to modify detail flag using Surface Inspector
1074 gtk_widget_set_sensitive(GTK_WIDGET(m_contentFlags[BRUSH_DETAIL_FLAG]), FALSE);
1079 GtkFrame* frame = GTK_FRAME(gtk_frame_new("Value"));
1080 gtk_widget_show(GTK_WIDGET(frame));
1081 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(frame), TRUE, TRUE, 0);
1083 GtkVBox* vbox3 = GTK_VBOX(gtk_vbox_new(FALSE, 4));
1084 gtk_container_set_border_width(GTK_CONTAINER(vbox3), 4);
1085 gtk_widget_show(GTK_WIDGET(vbox3));
1086 gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(vbox3));
1089 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
1090 gtk_widget_show(GTK_WIDGET(entry));
1091 gtk_box_pack_start(GTK_BOX(vbox3), GTK_WIDGET(entry), TRUE, TRUE, 0);
1092 m_valueEntryWidget = entry;
1093 m_valueEntry.connect(entry);
1100 if(g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES)
1101 // Shamus: Textool goodies...
1103 GtkWidget * frame = gtk_frame_new("Textool");
1104 gtk_widget_show(frame);
1105 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(frame), FALSE, FALSE, 0);
1107 //Prolly should make this a member or global var, so the SI can draw on it...
1108 TexTool::g_textoolWin = glwidget_new(FALSE);
1109 // --> Dunno, but this stuff may be necessary... (Looks like it!)
1110 gtk_widget_ref(TexTool::g_textoolWin);
1111 gtk_widget_set_events(TexTool::g_textoolWin, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
1112 GTK_WIDGET_SET_FLAGS(TexTool::g_textoolWin, GTK_CAN_FOCUS);
1114 gtk_widget_show(TexTool::g_textoolWin);
1115 gtk_widget_set_usize(TexTool::g_textoolWin, -1, 240); //Yeah!
1116 gtk_container_add(GTK_CONTAINER(frame), TexTool::g_textoolWin);
1118 g_signal_connect(G_OBJECT(TexTool::g_textoolWin), "size_allocate", G_CALLBACK(TexTool::size_allocate), NULL);
1119 g_signal_connect(G_OBJECT(TexTool::g_textoolWin), "expose_event", G_CALLBACK(TexTool::expose), NULL);
1120 g_signal_connect(G_OBJECT(TexTool::g_textoolWin), "button_press_event", G_CALLBACK(TexTool::button_press), NULL);
1121 g_signal_connect(G_OBJECT(TexTool::g_textoolWin), "button_release_event", G_CALLBACK(TexTool::button_release), NULL);
1122 g_signal_connect(G_OBJECT(TexTool::g_textoolWin), "motion_notify_event", G_CALLBACK(TexTool::motion), NULL);
1125 GtkWidget * hbox = gtk_hbox_new(FALSE, 5);
1126 gtk_widget_show(hbox);
1127 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 0);
1128 // Checkboxes go here... (Flip X/Y)
1129 GtkWidget * flipX = gtk_check_button_new_with_label("Flip X axis");
1130 GtkWidget * flipY = gtk_check_button_new_with_label("Flip Y axis");
1131 gtk_widget_show(flipX);
1132 gtk_widget_show(flipY);
1133 gtk_box_pack_start(GTK_BOX(hbox), flipX, FALSE, FALSE, 0);
1134 gtk_box_pack_start(GTK_BOX(hbox), flipY, FALSE, FALSE, 0);
1136 //Instead of this, we probably need to create a vbox to put into the frame, then the
1137 //window, then the hbox. !!! FIX !!!
1138 // gtk_container_add(GTK_CONTAINER(frame), hbox);
1140 //Hmm. Do we really need g_object_set_data? Mebbe not... And we don't! :-)
1141 // g_object_set_data(G_OBJECT(flipX), "handler", gint_to_pointer(g_signal_connect(G_OBJECT(flipX), "toggled", G_CALLBACK(TexTool::flipX), 0)));
1142 // g_object_set_data(G_OBJECT(flipY), "handler", gint_to_pointer(g_signal_connect(G_OBJECT(flipY), "toggled", G_CALLBACK(TexTool::flipY), 0)));
1144 g_signal_connect(G_OBJECT(flipX), "toggled", G_CALLBACK(TexTool::flipX), NULL);
1145 g_signal_connect(G_OBJECT(flipY), "toggled", G_CALLBACK(TexTool::flipY), NULL);
1158 Set the fields to the current texdef (i.e. map/texdef -> dialog widgets)
1159 if faces selected (instead of brushes) -> will read this face texdef, else current texdef
1160 if only patches selected, will read the patch texdef
1164 void spin_button_set_value_no_signal(GtkSpinButton* spin, gdouble value)
1166 guint handler_id = gpointer_to_int(g_object_get_data(G_OBJECT(spin), "handler"));
1167 g_signal_handler_block(G_OBJECT(gtk_spin_button_get_adjustment(spin)), handler_id);
1168 gtk_spin_button_set_value(spin, value);
1169 g_signal_handler_unblock(G_OBJECT(gtk_spin_button_get_adjustment(spin)), handler_id);
1172 void spin_button_set_step_increment(GtkSpinButton* spin, gdouble value)
1174 GtkAdjustment* adjust = gtk_spin_button_get_adjustment(spin);
1175 adjust->step_increment = value;
1178 void SurfaceInspector::Update()
1180 const char * name = SurfaceInspector_GetSelectedShader();
1182 if(shader_is_texture(name))
1184 gtk_entry_set_text(m_texture, shader_get_textureName(name));
1188 gtk_entry_set_text(m_texture, "");
1191 texdef_t shiftScaleRotate;
1192 //Shamus: This is where we get into trouble--the BP code tries to convert to a "faked"
1193 //shift, rotate & scale values from the brush face, which seems to screw up for some reason.
1195 /*globalOutputStream() << "--> SI::Update. About to do ShiftScaleRotate_fromFace()...\n";
1196 SurfaceInspector_GetSelectedBPTexdef();
1197 globalOutputStream() << "BP: (" << g_selectedBrushPrimitTexdef.coords[0][0] << ", " << g_selectedBrushPrimitTexdef.coords[0][1] << ")("
1198 << g_selectedBrushPrimitTexdef.coords[1][0] << ", " << g_selectedBrushPrimitTexdef.coords[1][1] << ")("
1199 << g_selectedBrushPrimitTexdef.coords[0][2] << ", " << g_selectedBrushPrimitTexdef.coords[1][2] << ") SurfaceInspector::Update\n";//*/
1200 //Ok, it's screwed up *before* we get here...
1201 ShiftScaleRotate_fromFace(shiftScaleRotate, SurfaceInspector_GetSelectedTexdef());
1203 // normalize again to hide the ridiculously high scale values that get created when using texlock
1204 shiftScaleRotate.shift[0] = float_mod(shiftScaleRotate.shift[0], (float)g_selectedShaderSize[0]);
1205 shiftScaleRotate.shift[1] = float_mod(shiftScaleRotate.shift[1], (float)g_selectedShaderSize[1]);
1208 spin_button_set_value_no_signal(m_hshiftIncrement.m_spin, shiftScaleRotate.shift[0]);
1209 spin_button_set_step_increment(m_hshiftIncrement.m_spin, g_si_globals.shift[0]);
1210 entry_set_float(m_hshiftIncrement.m_entry, g_si_globals.shift[0]);
1214 spin_button_set_value_no_signal(m_vshiftIncrement.m_spin, shiftScaleRotate.shift[1]);
1215 spin_button_set_step_increment(m_vshiftIncrement.m_spin, g_si_globals.shift[1]);
1216 entry_set_float(m_vshiftIncrement.m_entry, g_si_globals.shift[1]);
1220 spin_button_set_value_no_signal(m_hscaleIncrement.m_spin, shiftScaleRotate.scale[0]);
1221 spin_button_set_step_increment(m_hscaleIncrement.m_spin, g_si_globals.scale[0]);
1222 entry_set_float(m_hscaleIncrement.m_entry, g_si_globals.scale[0]);
1226 spin_button_set_value_no_signal(m_vscaleIncrement.m_spin, shiftScaleRotate.scale[1]);
1227 spin_button_set_step_increment(m_vscaleIncrement.m_spin, g_si_globals.scale[1]);
1228 entry_set_float(m_vscaleIncrement.m_entry, g_si_globals.scale[1]);
1232 spin_button_set_value_no_signal(m_rotateIncrement.m_spin, shiftScaleRotate.rotate);
1233 spin_button_set_step_increment(m_rotateIncrement.m_spin, g_si_globals.rotate);
1234 entry_set_float(m_rotateIncrement.m_entry, g_si_globals.rotate);
1237 if(!string_empty(g_pGameDescription->getKeyValue("si_flags")))
1239 ContentsFlagsValue flags(SurfaceInspector_GetSelectedFlags());
1241 entry_set_int(m_valueEntryWidget, flags.m_value);
1243 for(GtkCheckButton** p = m_surfaceFlags; p != m_surfaceFlags + 32; ++p)
1245 toggle_button_set_active_no_signal(GTK_TOGGLE_BUTTON(*p), flags.m_surfaceFlags & (1 << (p - m_surfaceFlags)));
1248 for(GtkCheckButton** p = m_contentFlags; p != m_contentFlags + 32; ++p)
1250 toggle_button_set_active_no_signal(GTK_TOGGLE_BUTTON(*p), flags.m_contentFlags & (1 << (p - m_contentFlags)));
1259 Reads the fields to get the current texdef (i.e. widgets -> MAP)
1260 in brush primitive mode, grab the fake shift scale rot and compute a new texture matrix
1263 void SurfaceInspector::ApplyShader()
1265 StringOutputStream name(256);
1266 name << GlobalTexturePrefix_get() << gtk_entry_get_text(m_texture);
1268 // TTimo: detect and refuse invalid texture names (at least the ones with spaces)
1269 if(!texdef_name_valid(name.c_str()))
1271 globalErrorStream() << "invalid texture name '" << name.c_str() << "'\n";
1272 SurfaceInspector_queueDraw();
1276 UndoableCommand undo("textureNameSetSelected");
1277 Select_SetShader(name.c_str());
1280 void SurfaceInspector::ApplyTexdef()
1282 texdef_t shiftScaleRotate;
1284 shiftScaleRotate.shift[0] = static_cast<float>(gtk_spin_button_get_value_as_float(m_hshiftIncrement.m_spin));
1285 shiftScaleRotate.shift[1] = static_cast<float>(gtk_spin_button_get_value_as_float(m_vshiftIncrement.m_spin));
1286 shiftScaleRotate.scale[0] = static_cast<float>(gtk_spin_button_get_value_as_float(m_hscaleIncrement.m_spin));
1287 shiftScaleRotate.scale[1] = static_cast<float>(gtk_spin_button_get_value_as_float(m_vscaleIncrement.m_spin));
1288 shiftScaleRotate.rotate = static_cast<float>(gtk_spin_button_get_value_as_float(m_rotateIncrement.m_spin));
1290 TextureProjection projection;
1291 //Shamus: This is the other place that screws up, it seems, since it doesn't seem to do the
1292 //conversion from the face (I think) and so bogus values end up in the thing... !!! FIX !!!
1293 //This is actually OK. :-P
1294 ShiftScaleRotate_toFace(shiftScaleRotate, projection);
1296 UndoableCommand undo("textureProjectionSetSelected");
1297 Select_SetTexdef(projection);
1300 void SurfaceInspector::ApplyFlags()
1302 unsigned int surfaceflags = 0;
1303 for(GtkCheckButton** p = m_surfaceFlags; p != m_surfaceFlags + 32; ++p)
1305 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(*p)))
1307 surfaceflags |= (1 << (p - m_surfaceFlags));
1311 unsigned int contentflags = 0;
1312 for(GtkCheckButton** p = m_contentFlags; p != m_contentFlags + 32; ++p)
1314 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(*p)))
1316 contentflags |= (1 << (p - m_contentFlags));
1320 int value = entry_get_int(m_valueEntryWidget);
1322 UndoableCommand undo("flagsSetSelected");
1323 Select_SetFlags(ContentsFlagsValue(surfaceflags, contentflags, value, true));
1327 void Face_getTexture(Face& face, CopiedString& shader, TextureProjection& projection, ContentsFlagsValue& flags)
1329 shader = face.GetShader();
1330 face.GetTexdef(projection);
1331 flags = face.getShader().m_flags;
1333 typedef Function4<Face&, CopiedString&, TextureProjection&, ContentsFlagsValue&, void, Face_getTexture> FaceGetTexture;
1335 void Face_setTexture(Face& face, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags)
1337 face.SetShader(shader);
1338 face.SetTexdef(projection);
1339 face.SetFlags(flags);
1341 typedef Function4<Face&, const char*, const TextureProjection&, const ContentsFlagsValue&, void, Face_setTexture> FaceSetTexture;
1344 void Patch_getTexture(Patch& patch, CopiedString& shader, TextureProjection& projection, ContentsFlagsValue& flags)
1346 shader = patch.GetShader();
1347 projection = TextureProjection(texdef_t(), brushprimit_texdef_t(), Vector3(0, 0, 0), Vector3(0, 0, 0));
1348 flags = ContentsFlagsValue(0, 0, 0, false);
1350 typedef Function4<Patch&, CopiedString&, TextureProjection&, ContentsFlagsValue&, void, Patch_getTexture> PatchGetTexture;
1352 void Patch_setTexture(Patch& patch, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags)
1354 patch.SetShader(shader);
1356 typedef Function4<Patch&, const char*, const TextureProjection&, const ContentsFlagsValue&, void, Patch_setTexture> PatchSetTexture;
1359 typedef Callback3<CopiedString&, TextureProjection&, ContentsFlagsValue&> GetTextureCallback;
1360 typedef Callback3<const char*, const TextureProjection&, const ContentsFlagsValue&> SetTextureCallback;
1364 GetTextureCallback getTexture;
1365 SetTextureCallback setTexture;
1369 void Face_getClosest(Face& face, SelectionTest& test, SelectionIntersection& bestIntersection, Texturable& texturable)
1371 SelectionIntersection intersection;
1372 face.testSelect(test, intersection);
1373 if(intersection.valid()
1374 && SelectionIntersection_closer(intersection, bestIntersection))
1376 bestIntersection = intersection;
1377 texturable.setTexture = makeCallback3(FaceSetTexture(), face);
1378 texturable.getTexture = makeCallback3(FaceGetTexture(), face);
1383 class OccludeSelector : public Selector
1385 SelectionIntersection& m_bestIntersection;
1388 OccludeSelector(SelectionIntersection& bestIntersection, bool& occluded) : m_bestIntersection(bestIntersection), m_occluded(occluded)
1392 void pushSelectable(Selectable& selectable)
1395 void popSelectable()
1398 void addIntersection(const SelectionIntersection& intersection)
1400 if(SelectionIntersection_closer(intersection, m_bestIntersection))
1402 m_bestIntersection = intersection;
1408 class BrushGetClosestFaceVisibleWalker : public scene::Graph::Walker
1410 SelectionTest& m_test;
1411 Texturable& m_texturable;
1412 mutable SelectionIntersection m_bestIntersection;
1414 BrushGetClosestFaceVisibleWalker(SelectionTest& test, Texturable& texturable) : m_test(test), m_texturable(texturable)
1417 bool pre(const scene::Path& path, scene::Instance& instance) const
1419 if(path.top().get().visible())
1421 BrushInstance* brush = Instance_getBrush(instance);
1424 m_test.BeginMesh(brush->localToWorld());
1426 for(Brush::const_iterator i = brush->getBrush().begin(); i != brush->getBrush().end(); ++i)
1428 Face_getClosest(*(*i), m_test, m_bestIntersection, m_texturable);
1433 SelectionTestable* selectionTestable = Instance_getSelectionTestable(instance);
1434 if(selectionTestable)
1437 OccludeSelector selector(m_bestIntersection, occluded);
1438 selectionTestable->testSelect(selector, m_test);
1441 Patch* patch = Node_getPatch(path.top());
1444 m_texturable.setTexture = makeCallback3(PatchSetTexture(), *patch);
1445 m_texturable.getTexture = makeCallback3(PatchGetTexture(), *patch);
1449 m_texturable = Texturable();
1459 Texturable Scene_getClosestTexturable(scene::Graph& graph, SelectionTest& test)
1461 Texturable texturable;
1462 graph.traverse(BrushGetClosestFaceVisibleWalker(test, texturable));
1466 bool Scene_getClosestTexture(scene::Graph& graph, SelectionTest& test, CopiedString& shader, TextureProjection& projection, ContentsFlagsValue& flags)
1468 Texturable texturable = Scene_getClosestTexturable(graph, test);
1469 if(texturable.getTexture != GetTextureCallback())
1471 texturable.getTexture(shader, projection, flags);
1477 void Scene_setClosestTexture(scene::Graph& graph, SelectionTest& test, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags)
1479 Texturable texturable = Scene_getClosestTexturable(graph, test);
1480 if(texturable.setTexture != SetTextureCallback())
1482 texturable.setTexture(shader, projection, flags);
1490 TextureProjection m_projection;
1491 ContentsFlagsValue m_flags;
1494 FaceTexture g_faceTextureClipboard;
1496 void FaceTextureClipboard_setDefault()
1498 g_faceTextureClipboard.m_flags = ContentsFlagsValue(0, 0, 0, false);
1499 TexDef_Construct_Default(g_faceTextureClipboard.m_projection);
1502 void TextureClipboard_textureSelected(const char* shader)
1504 FaceTextureClipboard_setDefault();
1507 class TextureBrowser;
1508 extern TextureBrowser g_TextureBrowser;
1509 void TextureBrowser_SetSelectedShader(TextureBrowser& textureBrowser, const char* shader);
1510 const char* TextureBrowser_GetSelectedShader(TextureBrowser& textureBrowser);
1512 void Scene_copyClosestTexture(SelectionTest& test)
1514 CopiedString shader;
1515 if(Scene_getClosestTexture(GlobalSceneGraph(), test, shader, g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_flags))
1517 TextureBrowser_SetSelectedShader(g_TextureBrowser, shader.c_str());
1521 void Scene_applyClosestTexture(SelectionTest& test)
1523 UndoableCommand command("facePaintTexture");
1525 Scene_setClosestTexture(GlobalSceneGraph(), test, TextureBrowser_GetSelectedShader(g_TextureBrowser), g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_flags);
1527 SceneChangeNotify();
1534 void SelectedFaces_copyTexture()
1536 if(!g_SelectedFaceInstances.empty())
1538 Face& face = g_SelectedFaceInstances.last().getFace();
1539 face.GetTexdef(g_faceTextureClipboard.m_projection);
1540 g_faceTextureClipboard.m_flags = face.getShader().m_flags;
1542 TextureBrowser_SetSelectedShader(g_TextureBrowser, face.getShader().getShader());
1546 void FaceInstance_pasteTexture(FaceInstance& faceInstance)
1548 faceInstance.getFace().SetTexdef(g_faceTextureClipboard.m_projection);
1549 faceInstance.getFace().SetShader(TextureBrowser_GetSelectedShader(g_TextureBrowser));
1550 faceInstance.getFace().SetFlags(g_faceTextureClipboard.m_flags);
1551 SceneChangeNotify();
1554 bool SelectedFaces_empty()
1556 return g_SelectedFaceInstances.empty();
1559 void SelectedFaces_pasteTexture()
1561 UndoableCommand command("facePasteTexture");
1562 g_SelectedFaceInstances.foreach(FaceInstance_pasteTexture);
1567 void SurfaceInspector_constructPreferences(PreferencesPage& page)
1569 page.appendCheckBox("", "Surface Inspector Increments Match Grid", g_si_globals.m_bSnapTToGrid);
1571 void SurfaceInspector_constructPage(PreferenceGroup& group)
1573 PreferencesPage page(group.createPage("Surface Inspector", "Surface Inspector Preferences"));
1574 SurfaceInspector_constructPreferences(page);
1576 void SurfaceInspector_registerPreferencesPage()
1578 PreferencesDialog_addSettingsPage(FreeCaller1<PreferenceGroup&, SurfaceInspector_constructPage>());
1581 void SurfaceInspector_registerCommands()
1583 GlobalCommands_insert("FitTexture", FreeCaller<SurfaceInspector_FitTexture>(), Accelerator('B', (GdkModifierType)GDK_SHIFT_MASK));
1584 GlobalCommands_insert("SurfaceInspector", FreeCaller<SurfaceInspector_toggleShown>(), Accelerator('S'));
1586 GlobalCommands_insert("FaceCopyTexture", FreeCaller<SelectedFaces_copyTexture>());
1587 GlobalCommands_insert("FacePasteTexture", FreeCaller<SelectedFaces_pasteTexture>());
1591 #include "preferencesystem.h"
1594 void SurfaceInspector_Construct()
1596 g_SurfaceInspector = new SurfaceInspector;
1598 SurfaceInspector_registerCommands();
1600 FaceTextureClipboard_setDefault();
1602 GlobalPreferenceSystem().registerPreference("SurfaceWnd", getSurfaceInspector().m_importPosition, getSurfaceInspector().m_exportPosition);
1603 GlobalPreferenceSystem().registerPreference("SI_SurfaceTexdef_Scale1", FloatImportStringCaller(g_si_globals.scale[0]), FloatExportStringCaller(g_si_globals.scale[0]));
1604 GlobalPreferenceSystem().registerPreference("SI_SurfaceTexdef_Scale2", FloatImportStringCaller(g_si_globals.scale[1]), FloatExportStringCaller(g_si_globals.scale[1]));
1605 GlobalPreferenceSystem().registerPreference("SI_SurfaceTexdef_Shift1", FloatImportStringCaller(g_si_globals.shift[0]), FloatExportStringCaller(g_si_globals.shift[0]));
1606 GlobalPreferenceSystem().registerPreference("SI_SurfaceTexdef_Shift2", FloatImportStringCaller(g_si_globals.shift[1]), FloatExportStringCaller(g_si_globals.shift[1]));
1607 GlobalPreferenceSystem().registerPreference("SI_SurfaceTexdef_Rotate", FloatImportStringCaller(g_si_globals.rotate), FloatExportStringCaller(g_si_globals.rotate));
1608 GlobalPreferenceSystem().registerPreference("SnapTToGrid", BoolImportStringCaller(g_si_globals.m_bSnapTToGrid), BoolExportStringCaller(g_si_globals.m_bSnapTToGrid));
1610 typedef FreeCaller1<const Selectable&, SurfaceInspector_SelectionChanged> SurfaceInspectorSelectionChangedCaller;
1611 GlobalSelectionSystem().addSelectionChangeCallback(SurfaceInspectorSelectionChangedCaller());
1612 typedef FreeCaller<SurfaceInspector_updateSelection> SurfaceInspectorUpdateSelectionCaller;
1613 Brush_addTextureChangedCallback(SurfaceInspectorUpdateSelectionCaller());
1614 Patch_addTextureChangedCallback(SurfaceInspectorUpdateSelectionCaller());
1616 SurfaceInspector_registerPreferencesPage();
1618 void SurfaceInspector_Destroy()
1620 delete g_SurfaceInspector;
1627 namespace TexTool { // namespace hides these symbols from other object-files
1629 //Shamus: Textool functions, including GTK+ callbacks
1632 //NOTE: Black screen when TT first comes up is caused by an uninitialized Extent... !!! FIX !!!
1633 // But... You can see down below that it *is* initialized! WTF?
1636 float minX, minY, maxX, maxY;
1637 float width(void) { return fabs(maxX - minX); }
1638 float height(void) { return fabs(maxY - minY); }
1641 //This seems to control the texture scale... (Yep! ;-)
1642 Extent extents = { -2.0f, -2.0f, +2.0f, +2.0f };
1643 brushprimit_texdef_t tm; // Texture transform matrix
1644 Vector2 pts[c_brush_maxFaces];
1648 Vector2 textureSize;
1650 #define VP_PADDING 1.2
1651 #define PI 3.14159265358979
1652 bool lButtonDown = false;
1653 bool rButtonDown = false;
1656 bool haveAnchor = false;
1657 brushprimit_texdef_t currentBP;
1658 brushprimit_texdef_t origBP; // Original brush primitive (before we muck it up)
1659 float controlRadius = 5.0f;
1660 float rotationAngle = 0.0f;
1661 float rotationAngle2 = 0.0f;
1662 float oldRotationAngle;
1663 Vector2 rotationPoint;
1664 bool translatingX = false; // Widget state variables
1665 bool translatingY = false;
1666 bool scalingX = false;
1667 bool scalingY = false;
1668 bool rotating = false;
1669 bool resizingX = false; // Not sure what this means... :-/
1670 bool resizingY = false;
1671 float origAngle, origScaleX, origScaleY;
1675 // Function prototypes (move up to top later...)
1677 void DrawCircularArc(Vector2 ctr, float startAngle, float endAngle, float radius);
1680 void CopyPointsFromSelectedFace(void)
1682 // Make sure that there's a face and winding to get!
1684 if (g_SelectedFaceInstances.empty())
1690 Face & face = g_SelectedFaceInstances.last().getFace();
1691 textureNum = face.getShader().m_state->getTexture().texture_number;
1692 textureSize.x() = face.getShader().m_state->getTexture().width;
1693 textureSize.y() = face.getShader().m_state->getTexture().height;
1694 //globalOutputStream() << "--> Texture #" << textureNum << ": " << textureSize.x() << " x " << textureSize.y() << "...\n";
1696 currentBP = SurfaceInspector_GetSelectedTexdef().m_brushprimit_texdef;
1698 face.EmitTextureCoordinates();
1699 Winding & w = face.getWinding();
1702 for(Winding::const_iterator i=w.begin(); i!=w.end(); i++)
1704 //globalOutputStream() << (*i).texcoord.x() << " " << (*i).texcoord.y() << ", ";
1705 pts[count].x() = (*i).texcoord.x();
1706 pts[count].y() = (*i).texcoord.y();
1712 //globalOutputStream() << " ..copied points\n";
1715 brushprimit_texdef_t bp;
1716 //This approach is probably wrongheaded and just not right anyway. So, !!! FIX !!! [DONE]
1717 void CommitChanges(void)
1719 texdef_t t; // Throwaway, since this is BP only
1721 bp.coords[0][0] = tm.coords[0][0] * origBP.coords[0][0] + tm.coords[0][1] * origBP.coords[1][0];
1722 bp.coords[0][1] = tm.coords[0][0] * origBP.coords[0][1] + tm.coords[0][1] * origBP.coords[1][1];
1723 bp.coords[0][2] = tm.coords[0][0] * origBP.coords[0][2] + tm.coords[0][1] * origBP.coords[1][2] + tm.coords[0][2];
1724 //Ok, this works for translation...
1725 // 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();
1726 bp.coords[1][0] = tm.coords[1][0] * origBP.coords[0][0] + tm.coords[1][1] * origBP.coords[1][0];
1727 bp.coords[1][1] = tm.coords[1][0] * origBP.coords[0][1] + tm.coords[1][1] * origBP.coords[1][1];
1728 bp.coords[1][2] = tm.coords[1][0] * origBP.coords[0][2] + tm.coords[1][1] * origBP.coords[1][2] + tm.coords[1][2];
1729 // 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();
1731 //This doesn't work: g_brush_texture_changed();
1733 //Note: We should only set an undo *after* the button has been released... !!! FIX !!!
1734 //Definitely *should* have an undo, though!
1735 // UndoableCommand undo("textureProjectionSetSelected");
1736 Select_SetTexdef(TextureProjection(t, bp, Vector3(0, 0, 0), Vector3(0, 0, 0)));
1737 //This is working, but for some reason the translate is causing the rest of the SI
1738 //widgets to yield bad readings... !!! FIX !!!
1739 //I.e., click on textool window, translate face wireframe, then controls go crazy. Dunno why.
1740 //It's because there were some uncommented out add/removeScale functions in brush.h and a
1741 //removeScale in brushmanip.cpp... :-/
1742 //Translate isn't working at all now... :-(
1743 //It's because we need to multiply in some scaling factor (prolly the texture width/height)
1747 void UpdateControlPoints(void)
1751 // Init texture transform matrix
1753 tm.coords[0][0] = 1.0f; tm.coords[0][1] = 0.0f; tm.coords[0][2] = 0.0f;
1754 tm.coords[1][0] = 0.0f; tm.coords[1][1] = 1.0f; tm.coords[1][2] = 0.0f;
1759 For shifting we have:
1762 The code that should provide reasonable defaults, but doesn't for some reason:
1763 It's scaling the BP by 128 for some reason, between the time it's created and the
1764 time we get back to the SI widgets:
1766 static void OnBtnAxial(GtkWidget *widget, gpointer data)
1768 UndoableCommand undo("textureDefault");
1769 TextureProjection projection;
1770 TexDef_Construct_Default(projection);
1771 Select_SetTexdef(projection);
1774 Select_SetTexdef() calls Scene_BrushSetTexdef_Component_Selected(GlobalSceneGraph(), projection)
1775 which is in brushmanip.h: This eventually calls
1776 Texdef_Assign(m_texdef, texdef, m_brushprimit_texdef, brushprimit_texdef) in class Face...
1777 which just copies from brushpr to m_brushpr...
1780 //Small problem with this thing: It's scaled to the texture which is all screwed up... !!! FIX !!! [DONE]
1781 //Prolly should separate out the grid drawing so that we can draw it behind the polygon.
1782 const float gridWidth = 1.3f;// Let's try an absolute height... WORKS!!!
1783 // NOTE that 2.0 is the height of the viewport. Dunno why... Should make collision
1784 // detection easier...
1785 const float gridRadius = gridWidth * 0.5f;
1787 typedef const float WidgetColor[3];
1788 const WidgetColor widgetColor[10] = {
1789 { 1.0000f, 0.2000f, 0.0000f }, // Red
1790 { 0.9137f, 0.9765f, 0.4980f }, // Yellow
1791 { 0.0000f, 0.6000f, 0.3216f }, // Green
1792 { 0.6157f, 0.7726f, 0.8196f }, // Cyan
1793 { 0.4980f, 0.5000f, 0.4716f }, // Grey
1796 { 1.0000f, 0.6000f, 0.4000f }, // Light Red
1797 { 1.0000f, 1.0000f, 0.8980f }, // Light Yellow
1798 { 0.4000f, 1.0000f, 0.7216f }, // Light Green
1799 { 1.0000f, 1.0000f, 1.0000f }, // Light Cyan
1800 { 0.8980f, 0.9000f, 0.8716f } // Light Grey
1804 #define COLOR_YELLOW 1
1805 #define COLOR_GREEN 2
1806 #define COLOR_CYAN 3
1807 #define COLOR_GREY 4
1808 #define COLOR_LT_RED 5
1809 #define COLOR_LT_YELLOW 6
1810 #define COLOR_LT_GREEN 7
1811 #define COLOR_LT_CYAN 8
1812 #define COLOR_LT_GREY 9
1814 void DrawControlWidgets(void)
1816 //Note that the grid should go *behind* the face outline... !!! FIX !!!
1818 float xStart = center.x() - (gridWidth / 2.0f);
1819 float yStart = center.y() - (gridWidth / 2.0f);
1820 float xScale = (extents.height() / extents.width()) * (textureSize.y() / textureSize.x());
1823 //Small problem with this approach: Changing the center point in the TX code doesn't seem to
1824 //change anything here--prolly because we load a new identity matrix. A couple of ways to fix
1825 //this would be to get rid of that code, or change the center to a new point by taking into
1826 //account the transforms that we toss with the new identity matrix. Dunno which is better.
1828 glScalef(xScale, 1.0, 1.0); // Will that square it up? Yup.
1829 glRotatef(static_cast<float>(radians_to_degrees(atan2(-currentBP.coords[0][1], currentBP.coords[0][0]))), 0.0, 0.0, -1.0);
1830 glTranslatef(-center.x(), -center.y(), 0.0);
1833 glColor3fv(translatingX && translatingY ? widgetColor[COLOR_LT_YELLOW] : widgetColor[COLOR_YELLOW]);
1834 glBegin(GL_LINE_LOOP);
1835 DrawCircularArc(center, 0, 2.0f * PI, gridRadius * 0.16);
1841 glColor3fv(translatingY && !translatingX ? widgetColor[COLOR_LT_GREEN] : widgetColor[COLOR_GREEN]);
1842 glVertex2f(center.x(), center.y() + (gridRadius * 0.16));
1843 glVertex2f(center.x(), center.y() + (gridRadius * 1.00));
1844 glColor3fv(translatingX && !translatingY ? widgetColor[COLOR_LT_RED] : widgetColor[COLOR_RED]);
1845 glVertex2f(center.x() + (gridRadius * 0.16), center.y());
1846 glVertex2f(center.x() + (gridRadius * 1.00), center.y());
1850 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1851 glBegin(GL_TRIANGLES);
1852 glColor3fv(translatingY && !translatingX ? widgetColor[COLOR_LT_GREEN] : widgetColor[COLOR_GREEN]);
1853 glVertex2f(center.x(), center.y() + (gridRadius * 1.10));
1854 glVertex2f(center.x() + (gridRadius * 0.06), center.y() + (gridRadius * 0.94));
1855 glVertex2f(center.x() - (gridRadius * 0.06), center.y() + (gridRadius * 0.94));
1856 glColor3fv(translatingX && !translatingY ? widgetColor[COLOR_LT_RED] : widgetColor[COLOR_RED]);
1857 glVertex2f(center.x() + (gridRadius * 1.10), center.y());
1858 glVertex2f(center.x() + (gridRadius * 0.94), center.y() + (gridRadius * 0.06));
1859 glVertex2f(center.x() + (gridRadius * 0.94), center.y() - (gridRadius * 0.06));
1863 glBegin(GL_LINE_STRIP);
1864 glColor3fv(rotating ? widgetColor[COLOR_LT_CYAN] : widgetColor[COLOR_CYAN]);
1865 DrawCircularArc(center, 0.03f * PI, 0.47f * PI, gridRadius * 0.90);
1869 glColor3fv(scalingY && !scalingX ? widgetColor[COLOR_LT_GREEN] : widgetColor[COLOR_GREEN]);
1871 glVertex2f(center.x() + (gridRadius * 0.20), center.y() + (gridRadius * 1.50));
1872 glVertex2f(center.x() - (gridRadius * 0.20), center.y() + (gridRadius * 1.50));
1874 glBegin(GL_LINE_LOOP);
1875 glVertex2f(center.x() + (gridRadius * 0.10), center.y() + (gridRadius * 1.40));
1876 glVertex2f(center.x() - (gridRadius * 0.10), center.y() + (gridRadius * 1.40));
1877 glVertex2f(center.x() - (gridRadius * 0.10), center.y() + (gridRadius * 1.20));
1878 glVertex2f(center.x() + (gridRadius * 0.10), center.y() + (gridRadius * 1.20));
1881 glColor3fv(scalingX && !scalingY ? widgetColor[COLOR_LT_RED] : widgetColor[COLOR_RED]);
1883 glVertex2f(center.x() + (gridRadius * 1.50), center.y() + (gridRadius * 0.20));
1884 glVertex2f(center.x() + (gridRadius * 1.50), center.y() - (gridRadius * 0.20));
1886 glBegin(GL_LINE_LOOP);
1887 glVertex2f(center.x() + (gridRadius * 1.40), center.y() + (gridRadius * 0.10));
1888 glVertex2f(center.x() + (gridRadius * 1.40), center.y() - (gridRadius * 0.10));
1889 glVertex2f(center.x() + (gridRadius * 1.20), center.y() - (gridRadius * 0.10));
1890 glVertex2f(center.x() + (gridRadius * 1.20), center.y() + (gridRadius * 0.10));
1893 glColor3fv(scalingX && scalingY ? widgetColor[COLOR_LT_CYAN] : widgetColor[COLOR_CYAN]);
1894 glBegin(GL_LINE_STRIP);
1895 glVertex2f(center.x() + (gridRadius * 1.50), center.y() + (gridRadius * 1.10));
1896 glVertex2f(center.x() + (gridRadius * 1.50), center.y() + (gridRadius * 1.50));
1897 glVertex2f(center.x() + (gridRadius * 1.10), center.y() + (gridRadius * 1.50));
1899 glBegin(GL_LINE_LOOP);
1900 glVertex2f(center.x() + (gridRadius * 1.40), center.y() + (gridRadius * 1.40));
1901 glVertex2f(center.x() + (gridRadius * 1.40), center.y() + (gridRadius * 1.20));
1902 glVertex2f(center.x() + (gridRadius * 1.20), center.y() + (gridRadius * 1.20));
1903 glVertex2f(center.x() + (gridRadius * 1.20), center.y() + (gridRadius * 1.40));
1909 void DrawControlPoints(void)
1912 glBegin(GL_LINE_LOOP);
1914 for(int i=0; i<numPts; i++)
1915 glVertex2f(pts[i].x(), pts[i].y());
1920 // Note: Setup and all that jazz must be done by the caller!
1922 void DrawCircularArc(Vector2 ctr, float startAngle, float endAngle, float radius)
1924 float stepSize = (2.0f * PI) / 200.0f;
1926 for(float angle=startAngle; angle<=endAngle; angle+=stepSize)
1927 glVertex2f(ctr.x() + radius * cos(angle), ctr.y() + radius * sin(angle));
1936 // Find selected texture's extents...
1938 extents.minX = extents.maxX = pts[0].x(),
1939 extents.minY = extents.maxY = pts[0].y();
1941 for(int i=1; i<numPts; i++)
1943 if (pts[i].x() < extents.minX)
1944 extents.minX = pts[i].x();
1945 if (pts[i].x() > extents.maxX)
1946 extents.maxX = pts[i].x();
1947 if (pts[i].y() < extents.minY)
1948 extents.minY = pts[i].y();
1949 if (pts[i].y() > extents.maxY)
1950 extents.maxY = pts[i].y();
1953 // Do some viewport fitting stuff...
1955 //globalOutputStream() << "--> Center: " << center.x() << ", " << center.y() << "\n";
1956 //globalOutputStream() << "--> Extents (stage 1): " << extents.minX << ", "
1957 // << extents.maxX << ", " << extents.minY << ", " << extents.maxY << "\n";
1958 // TTimo: Apply a ratio to get the area we'll draw.
1959 center.x() = 0.5f * (extents.minX + extents.maxX),
1960 center.y() = 0.5f * (extents.minY + extents.maxY);
1961 extents.minX = center.x() + VP_PADDING * (extents.minX - center.x()),
1962 extents.minY = center.y() + VP_PADDING * (extents.minY - center.y()),
1963 extents.maxX = center.x() + VP_PADDING * (extents.maxX - center.x()),
1964 extents.maxY = center.y() + VP_PADDING * (extents.maxY - center.y());
1965 //globalOutputStream() << "--> Extents (stage 2): " << extents.minX << ", "
1966 // << extents.maxX << ", " << extents.minY << ", " << extents.maxY << "\n";
1968 // TTimo: We want a texture with the same X / Y ratio.
1969 // TTimo: Compute XY space / window size ratio.
1970 float SSize = extents.width(), TSize = extents.height();
1971 float ratioX = textureSize.x() * extents.width() / windowSize.x(),
1972 ratioY = textureSize.y() * extents.height() / windowSize.y();
1973 //globalOutputStream() << "--> Texture size: " << textureSize.x() << ", " << textureSize.y() << "\n";
1974 //globalOutputStream() << "--> Window size: " << windowSize.x() << ", " << windowSize.y() << "\n";
1976 if (ratioX > ratioY)
1978 TSize = (windowSize.y() * ratioX) / textureSize.y();
1979 // TSize = extents.width() * (windowSize.y() / windowSize.x()) * (textureSize.x() / textureSize.y());
1983 SSize = (windowSize.x() * ratioY) / textureSize.x();
1984 // SSize = extents.height() * (windowSize.x() / windowSize.y()) * (textureSize.y() / textureSize.x());
1987 extents.minX = center.x() - 0.5f * SSize, extents.maxX = center.x() + 0.5f * SSize,
1988 extents.minY = center.y() - 0.5f * TSize, extents.maxY = center.y() + 0.5f * TSize;
1989 //globalOutputStream() << "--> Extents (stage 3): " << extents.minX << ", "
1990 // << extents.maxX << ", " << extents.minY << ", " << extents.maxY << "\n";
1993 gboolean size_allocate(GtkWidget * win, GtkAllocation * a, gpointer)
1995 windowSize.x() = a->width;
1996 windowSize.y() = a->height;
2001 gboolean expose(GtkWidget * win, GdkEventExpose * e, gpointer)
2003 // globalOutputStream() << "--> Textool Window was exposed!\n";
2004 // globalOutputStream() << " (window width/height: " << cc << "/" << e->area.height << ")\n";
2006 // windowSize.x() = e->area.width, windowSize.y() = e->area.height;
2007 //This needs to go elsewhere...
2010 if (glwidget_make_current(win) == FALSE)
2012 globalOutputStream() << " FAILED to make current! Oh, the agony! :-(\n";
2016 CopyPointsFromSelectedFace();
2023 // Probably should init button/anchor states here as well...
2024 // rotationAngle = 0.0f;
2025 glClearColor(0, 0, 0, 0);
2026 glViewport(0, 0, e->area.width, e->area.height);
2027 glMatrixMode(GL_PROJECTION);
2031 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2032 glDisable(GL_DEPTH_TEST);
2033 glDisable(GL_BLEND);
2035 glOrtho(extents.minX, extents.maxX, extents.maxY, extents.minY, -1, 1);
2038 // draw the texture background
2039 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
2040 glBindTexture(GL_TEXTURE_2D, textureNum);
2042 glEnable(GL_TEXTURE_2D);
2044 glTexCoord2f(extents.minX, extents.minY);
2045 glVertex2f(extents.minX, extents.minY);
2046 glTexCoord2f(extents.maxX, extents.minY);
2047 glVertex2f(extents.maxX, extents.minY);
2048 glTexCoord2f(extents.maxX, extents.maxY);
2049 glVertex2f(extents.maxX, extents.maxY);
2050 glTexCoord2f(extents.minX, extents.maxY);
2051 glVertex2f(extents.minX, extents.maxY);
2053 glDisable(GL_TEXTURE_2D);
2055 // draw the texture-space grid
2056 glColor3fv(widgetColor[COLOR_GREY]);
2059 const int gridSubdivisions = 8;
2060 const float gridExtents = 4.0f;
2062 for(int i = 0; i < gridSubdivisions + 1; ++i)
2064 float y = i * (gridExtents / float(gridSubdivisions));
2065 float x = i * (gridExtents / float(gridSubdivisions));
2067 glVertex2f(gridExtents, y);
2069 glVertex2f(x, gridExtents);
2074 DrawControlPoints();
2075 DrawControlWidgets();
2077 // reset the current texture
2078 // glBindTexture(GL_TEXTURE_2D, 0);
2080 glwidget_swap_buffers(win);
2085 /*int FindSelectedPoint(int x, int y)
2087 for(int i=0; i<numPts; i++)
2089 int nx = (int)(windowSize.x() * (pts[i].x() - extents.minX) / extents.width());
2090 int ny = (int)(windowSize.y() * (pts[i].y() - extents.minY) / extents.height());
2092 if (abs(nx - x) <= 3 && abs(ny - y) <= 3)
2101 Vector2 dragPoint; // Defined in terms of window space (+x/-y)
2103 gboolean button_press(GtkWidget * win, GdkEventButton * e, gpointer)
2105 // globalOutputStream() << "--> Textool button press...\n";
2110 GlobalUndoSystem().start();
2114 //globalOutputStream() << "--> Original BP: [" << origBP.coords[0][0] << "][" << origBP.coords[0][1] << "][" << origBP.coords[0][2] << "]\n";
2115 //globalOutputStream() << " [" << origBP.coords[1][0] << "][" << origBP.coords[1][1] << "][" << origBP.coords[1][2] << "]\n";
2116 //float angle = atan2(origBP.coords[0][1], origBP.coords[0][0]) * 180.0f / 3.141592653589f;
2117 origAngle = (origBP.coords[0][1] > 0 ? PI : -PI); // Could also be -PI... !!! FIX !!! [DONE]
2119 if (origBP.coords[0][0] != 0.0f)
2120 origAngle = atan(origBP.coords[0][1] / origBP.coords[0][0]);
2122 origScaleX = origBP.coords[0][0] / cos(origAngle);
2123 origScaleY = origBP.coords[1][1] / cos(origAngle);
2124 rotationAngle = origAngle;
2125 oldCenter[0] = oldCenter[1] = 0;
2127 //globalOutputStream() << "--> BP stats: ang=" << origAngle * RAD_TO_DEG << ", scale=" << origScaleX << "/" << origScaleY << "\n";
2128 //Should also set the Flip X/Y checkboxes here as well... !!! FIX !!!
2129 //Also: should reverse texture left/right up/down instead of flipping the points...
2132 //float nx = windowSize.x() * (e->x - extents.minX) / (extents.maxX - extents.minX);
2133 //float ny = windowSize.y() * (e->y - extents.minY) / (extents.maxY - extents.minY);
2135 //But I want it to scroll the texture window, not the points... !!! FIX !!!
2136 //Actually, should scroll the texture window only when mouse is down on no widgets...
2137 float nx = e->x / windowSize.x() * extents.width() + extents.minX;
2138 float ny = e->y / windowSize.y() * extents.height() + extents.minY;
2139 trans.x() = -tm.coords[0][0] * nx - tm.coords[0][1] * ny;
2140 trans.y() = -tm.coords[1][0] * nx - tm.coords[1][1] * ny;
2142 dragPoint.x() = e->x, dragPoint.y() = e->y;
2143 trans2.x() = nx, trans2.y() = ny;
2144 oldRotationAngle = rotationAngle;
2145 // oldTrans.x() = tm.coords[0][2] - nx * textureSize.x();
2146 // oldTrans.y() = tm.coords[1][2] - ny * textureSize.y();
2147 oldTrans.x() = tm.coords[0][2];
2148 oldTrans.y() = tm.coords[1][2];
2149 oldCenter.x() = center.x();
2150 oldCenter.y() = center.y();
2156 /* else if (e->button == 3)
2161 //globalOutputStream() << "(" << (haveAnchor ? "anchor" : "released") << ")\n";
2166 gboolean button_release(GtkWidget * win, GdkEventButton * e, gpointer)
2168 // globalOutputStream() << "--> Textool button release...\n";
2172 /* float ptx = e->x / windowSize.x() * extents.width() + extents.minX;
2173 float pty = e->y / windowSize.y() * extents.height() + extents.minY;
2175 //This prolly should go into the mouse move code...
2176 //Doesn't work correctly anyway...
2177 if (translatingX || translatingY)
2178 center.x() = ptx, center.y() = pty;//*/
2180 lButtonDown = false;
2182 if(translatingX || translatingY)
2184 GlobalUndoSystem().finish("translateTexture");
2188 GlobalUndoSystem().finish("rotateTexture");
2190 else if(scalingX || scalingY)
2192 GlobalUndoSystem().finish("scaleTexture");
2194 else if(resizingX || resizingY)
2196 GlobalUndoSystem().finish("resizeTexture");
2200 GlobalUndoSystem().finish("textoolUnknown");
2203 rotating = translatingX = translatingY = scalingX = scalingY
2204 = resizingX = resizingY = false;
2208 else if (e->button == 3)
2210 rButtonDown = false;
2217 void C2DView::GridForWindow( float c[2], int x, int y)
2219 SpaceForWindow( c, x, y );
2222 c[0] /= m_GridStep[0];
2223 c[1] /= m_GridStep[1];
2224 c[0] = (float)floor( c[0] + 0.5f );
2225 c[1] = (float)floor( c[1] + 0.5f );
2226 c[0] *= m_GridStep[0];
2227 c[1] *= m_GridStep[1];
2229 void C2DView::SpaceForWindow( float c[2], int x, int y)
2231 c[0] = ((float)(x))/((float)(m_rect.right-m_rect.left))*(m_Maxs[0]-m_Mins[0])+m_Mins[0];
2232 c[1] = ((float)(y))/((float)(m_rect.bottom-m_rect.top))*(m_Maxs[1]-m_Mins[1])+m_Mins[1];
2235 gboolean motion(GtkWidget * win, GdkEventMotion * e, gpointer)
2237 // globalOutputStream() << "--> Textool motion...\n";
2241 if (translatingX || translatingY)
2243 float ptx = e->x / windowSize.x() * extents.width() + extents.minX;
2244 float pty = e->y / windowSize.y() * extents.height() + extents.minY;
2246 //Need to fix this to take the rotation angle into account, so that it moves along
2247 //the rotated X/Y axis...
2250 // tm.coords[0][2] = (trans.x() + ptx) * textureSize.x();
2251 //This works, but only when the angle is zero. !!! FIX !!! [DONE]
2252 // tm.coords[0][2] = oldCenter.x() + (ptx * textureSize.x());
2253 tm.coords[0][2] = oldTrans.x() + (ptx - trans2.x()) * textureSize.x();
2254 // center.x() = oldCenter.x() + (ptx - trans2.x());
2259 // tm.coords[1][2] = (trans.y() + pty) * textureSize.y();
2260 // tm.coords[1][2] = oldCenter.y() + (pty * textureSize.y());
2261 tm.coords[1][2] = oldTrans.y() + (pty - trans2.y()) * textureSize.y();
2262 // center.y() = oldCenter.y() + (pty - trans2.y());
2265 //Need to update center.x/y() so that the widget translates as well. Also, oldCenter
2266 //is badly named... Should be oldTrans or something like that... !!! FIX !!!
2267 //Changing center.x/y() here doesn't seem to change anything... :-/
2268 UpdateControlPoints();
2272 // Shamus: New rotate code
2273 int cx = (int)(windowSize.x() * (center.x() - extents.minX) / extents.width());
2274 int cy = (int)(windowSize.y() * (center.y() - extents.minY) / extents.height());
2275 Vector3 v1(dragPoint.x() - cx, dragPoint.y() - cy, 0), v2(e->x - cx, e->y - cy, 0);
2277 vector3_normalise(v1);
2278 vector3_normalise(v2);
2279 float c = vector3_dot(v1, v2);
2280 Vector3 cross = vector3_cross(v1, v2);
2281 float s = vector3_length(cross);
2286 // Problem with this: arcsin/cos seems to only return -90 to 90 and 0 to 180...
2287 // Can't derive angle from that!
2289 //rotationAngle = asin(s);// * 180.0f / 3.141592653589f;
2290 rotationAngle = acos(c);
2291 //rotationAngle2 = asin(s);
2293 rotationAngle = -rotationAngle;
2295 //NO! DOESN'T WORK! rotationAngle -= 45.0f * DEG_TO_RAD;
2298 /*c = cos(rotationAngle - oldRotationAngle);
2299 s = sin(rotationAngle - oldRotationAngle);
2300 rotationAngle += oldRotationAngle;
2301 //c += cos(oldRotationAngle);
2302 //s += sin(oldRotationAngle);
2303 //rotationAngle += oldRotationAngle;
2306 //rotationAngle %= 2.0 * PI;//*/
2308 //This is wrong... Hmm...
2309 //It seems to shear the texture instead of rotating it... !!! FIX !!!
2310 // Now it rotates correctly. Seems TTimo was overcomplicating things here... ;-)
2312 // Seems like what needs to happen here is multiplying these rotations by tm... !!! FIX !!!
2314 // See brush_primit.cpp line 244 (Texdef_EmitTextureCoordinates()) for where texcoords come from...
2316 tm.coords[0][0] = c;
2317 tm.coords[0][1] = s;
2318 tm.coords[1][0] = -s;
2319 tm.coords[1][1] = c;
2320 //It doesn't work anymore... Dunno why...
2321 //tm.coords[0][2] = -trans.x(); // This works!!! Yeah!!!
2322 //tm.coords[1][2] = -trans.y();
2324 //tm.coords[0][2] = rotationPoint.x(); // This works, but strangely...
2325 //tm.coords[1][2] = rotationPoint.y();
2326 //tm.coords[0][2] = 0;// center.x() / 2.0f;
2327 //tm.coords[1][2] = 0;// center.y() / 2.0f;
2329 //tm.coords[0][2] = -(center.x() * textureSize.x());
2330 //tm.coords[1][2] = -(center.y() * textureSize.y());
2331 //Eh? No, but seems to be getting closer...
2332 /*float ptx = e->x / windowSize.x() * extents.width() + extents.minX;
2333 float pty = e->y / windowSize.y() * extents.height() + extents.minY;
2334 tm.coords[0][2] = -c * center.x() - s * center.y() + ptx;
2335 tm.coords[1][2] = s * center.x() - c * center.x() + pty;//*/
2336 //Kinda works, but center drifts around on non-square textures...
2337 /*tm.coords[0][2] = (-c * center.x() - s * center.y()) * textureSize.x();
2338 tm.coords[1][2] = ( s * center.x() - c * center.y()) * textureSize.y();//*/
2339 //Rotates correctly, but not around the actual center of the face's points...
2340 /*tm.coords[0][2] = -c * center.x() * textureSize.x() - s * center.y() * textureSize.y();
2341 tm.coords[1][2] = s * center.x() * textureSize.x() - c * center.y() * textureSize.y();//*/
2343 tm.coords[0][2] = (-c * center.x() * textureSize.x() - s * center.y() * textureSize.y()) + center.x() * textureSize.x();
2344 tm.coords[1][2] = ( s * center.x() * textureSize.x() - c * center.y() * textureSize.y()) + center.y() * textureSize.y();//*/
2345 //This doesn't work...
2346 //And this is the wrong place for this anyway (I'm pretty sure).
2347 /*tm.coords[0][2] += oldCenter.x();
2348 tm.coords[1][2] += oldCenter.y();//*/
2349 UpdateControlPoints(); // will cause a redraw
2354 else // Check for widget mouseovers
2357 float nx = e->x / windowSize.x() * extents.width() + extents.minX;
2358 float ny = e->y / windowSize.y() * extents.height() + extents.minY;
2359 // Translate nx/y to the "center" point...
2362 ny = -ny; // Flip Y-axis so that increasing numbers move up
2364 tran.x() = tm.coords[0][0] * nx + tm.coords[0][1] * ny;
2365 tran.y() = tm.coords[1][0] * nx + tm.coords[1][1] * ny;
2366 //This doesn't seem to generate a valid distance from the center--for some reason it
2367 //calculates a fixed number every time
2368 //Look at nx/y above: they're getting fixed there! !!! FIX !!! [DONE]
2369 float dist = sqrt((nx * nx) + (ny * ny));
2370 // Normalize to the 2.0 = height standard (for now)
2371 //globalOutputStream() << "--> Distance before: " << dist;
2372 dist = dist * 2.0f / extents.height();
2373 //globalOutputStream() << ". After: " << dist;
2374 tran.x() = tran.x() * 2.0f / extents.height();
2375 tran.y() = tran.y() * 2.0f / extents.height();
2376 //globalOutputStream() << ". Trans: " << tran.x() << ", " << tran.y() << "\n";
2378 //Let's try this instead...
2379 //Interesting! It seems that e->x/y are rotated
2380 //(no, they're not--the TM above is what's doing it...)
2381 nx = ((e->x / windowSize.y()) * 2.0f) - (windowSize.x() / windowSize.y());
2382 ny = ((e->y / windowSize.y()) * 2.0f) - (windowSize.y() / windowSize.y());
2384 //Cool! It works! Now just need to do rotation...
2386 rotating = translatingX = translatingY = scalingX = scalingY
2387 = resizingX = resizingY = false;
2389 if (dist < (gridRadius * 0.16f))
2391 translatingX = translatingY = true;
2393 else if (dist > (gridRadius * 0.16f) && dist < (gridRadius * 1.10f)
2394 && fabs(ny) < (gridRadius * 0.05f) && nx > 0)
2396 translatingX = true;
2398 else if (dist > (gridRadius * 0.16f) && dist < (gridRadius * 1.10f)
2399 && fabs(nx) < (gridRadius * 0.05f) && ny > 0)
2401 translatingY = true;
2403 // Should tighten up the angle on this, or put this test after the axis tests...
2404 else if (tran.x() > 0 && tran.y() > 0
2405 && (dist > (gridRadius * 0.82f) && dist < (gridRadius * 0.98f)))
2418 //It seems the fake tex coords conversion is screwing this stuff up... !!! FIX !!!
2419 //This is still wrong... Prolly need to do something with the oldScaleX/Y stuff...
2420 void flipX(GtkToggleButton *, gpointer)
2422 // globalOutputStream() << "--> Flip X...\n";
2424 // SurfaceInspector_GetSelectedBPTexdef(); // Refresh g_selectedBrushPrimitTexdef...
2425 // tm.coords[0][0] = -tm.coords[0][0];
2426 // tm.coords[1][0] = -tm.coords[1][0];
2427 // tm.coords[0][0] = -tm.coords[0][0]; // This should be correct now...Nope.
2428 // tm.coords[1][1] = -tm.coords[1][1];
2429 tm.coords[0][0] = -tm.coords[0][0]; // This should be correct now...
2430 tm.coords[1][0] = -tm.coords[1][0];
2431 // tm.coords[2][0] = -tm.coords[2][0];//wil wok? no.
2432 UpdateControlPoints();
2435 void flipY(GtkToggleButton *, gpointer)
2437 // globalOutputStream() << "--> Flip Y...\n";
2438 // tm.coords[0][1] = -tm.coords[0][1];
2439 // tm.coords[1][1] = -tm.coords[1][1];
2440 // tm.coords[0][1] = -tm.coords[0][1]; // This should be correct now...Nope.
2441 // tm.coords[1][0] = -tm.coords[1][0];
2442 tm.coords[0][1] = -tm.coords[0][1]; // This should be correct now...
2443 tm.coords[1][1] = -tm.coords[1][1];
2444 // tm.coords[2][1] = -tm.coords[2][1];//wil wok? no.
2445 UpdateControlPoints();
2448 } // end namespace TexTool