]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - plugins/textool/TexTool.cpp
propagate from internal tree
[xonotic/netradiant.git] / plugins / textool / TexTool.cpp
index ee4a7ea3d925b2d46ddf547e92dffd2e0f19509f..eb519033e1061166787f2973f97379d543514e53 100644 (file)
-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*/\r
-\r
-//-----------------------------------------------------------------------------\r
-//\r
-// DESCRIPTION:\r
-// main plugin implementation\r
-// texturing tools for Radiant\r
-//\r
-\r
-#include "StdAfx.h"\r
-\r
-static void dialog_button_callback (GtkWidget *widget, gpointer data)\r
-{\r
-  GtkWidget *parent;\r
-  int *loop, *ret;\r
\r
-  parent = gtk_widget_get_toplevel (widget);\r
-  loop = (int*)g_object_get_data (G_OBJECT (parent), "loop");\r
-  ret = (int*)g_object_get_data (G_OBJECT (parent), "ret");\r
\r
-  *loop = 0;\r
-  *ret = (int)data;\r
-}\r
\r
-static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data)\r
-{\r
-  int *loop;\r
\r
-  gtk_widget_hide (widget);\r
-  loop = (int*)g_object_get_data (G_OBJECT (widget), "loop");\r
-  *loop = 0;\r
-\r
-  return TRUE;\r
-}\r
-\r
-int DoMessageBox (const char* lpText, const char* lpCaption, guint32 uType)\r
-{\r
-  GtkWidget *window, *w, *vbox, *hbox;\r
-  int mode = (uType & MB_TYPEMASK), ret, loop = 1;\r
\r
-  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);\r
-  gtk_signal_connect (GTK_OBJECT (window), "delete_event",\r
-                      GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);\r
-  gtk_signal_connect (GTK_OBJECT (window), "destroy",\r
-                      GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);\r
-  gtk_window_set_title (GTK_WINDOW (window), lpCaption);\r
-  gtk_container_border_width (GTK_CONTAINER (window), 10);\r
-  g_object_set_data (G_OBJECT (window), "loop", &loop);\r
-  g_object_set_data (G_OBJECT (window), "ret", &ret);\r
-  gtk_widget_realize (window);\r
\r
-  vbox = gtk_vbox_new (FALSE, 10);\r
-  gtk_container_add (GTK_CONTAINER (window), vbox);\r
-  gtk_widget_show (vbox);\r
\r
-  w = gtk_label_new (lpText);\r
-  gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);\r
-  gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT);\r
-  gtk_widget_show (w);\r
\r
-  w = gtk_hseparator_new ();\r
-  gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);\r
-  gtk_widget_show (w);\r
\r
-  hbox = gtk_hbox_new (FALSE, 10);\r
-  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2);\r
-  gtk_widget_show (hbox);\r
\r
-  if (mode == MB_OK)\r
-  {\r
-    w = gtk_button_new_with_label ("Ok");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));\r
-    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);\r
-    gtk_widget_grab_default (w);\r
-    gtk_widget_show (w);\r
-    ret = IDOK;\r
-  }\r
-  else if (mode ==  MB_OKCANCEL)\r
-  {\r
-    w = gtk_button_new_with_label ("Ok");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));\r
-    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);\r
-    gtk_widget_grab_default (w);\r
-    gtk_widget_show (w);\r
\r
-    w = gtk_button_new_with_label ("Cancel");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));\r
-    gtk_widget_show (w);\r
-    ret = IDCANCEL;\r
-  }\r
-  else if (mode == MB_YESNOCANCEL)\r
-  {\r
-    w = gtk_button_new_with_label ("Yes");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES));\r
-    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);\r
-    gtk_widget_grab_default (w);\r
-    gtk_widget_show (w);\r
\r
-    w = gtk_button_new_with_label ("No");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO));\r
-    gtk_widget_show (w);\r
\r
-    w = gtk_button_new_with_label ("Cancel");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));\r
-    gtk_widget_show (w);\r
-    ret = IDCANCEL;\r
-  }\r
-  else /* if (mode == MB_YESNO) */\r
-  {\r
-    w = gtk_button_new_with_label ("Yes");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES));\r
-    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);\r
-    gtk_widget_grab_default (w);\r
-    gtk_widget_show (w);\r
\r
-    w = gtk_button_new_with_label ("No");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO));\r
-    gtk_widget_show (w);\r
-    ret = IDNO;\r
-  }\r
\r
-  gtk_widget_show (window);\r
-  gtk_grab_add (window);\r
\r
-  while (loop)\r
-    gtk_main_iteration ();\r
\r
-  gtk_grab_remove (window);\r
-  gtk_widget_destroy (window);\r
\r
-  return ret;\r
-}\r
-\r
-// Radiant function table\r
-_QERFuncTable_1 g_FuncTable;\r
-\r
-// plugin name\r
-const char *PLUGIN_NAME = "Q3 Texture Tools";\r
-\r
-// commands in the menu\r
-const char *PLUGIN_COMMANDS = "About...;Go...";\r
-\r
-// cast to GtkWidget*\r
-void *g_pMainWnd;\r
-IWindow *g_pToolWnd = NULL; // handle to the window\r
-CWindowListener g_Listen;\r
-\r
-// plugin interfaces ---------------------------\r
-bool                   g_bQglInitDone = false;\r
-_QERQglTable           g_QglTable;\r
-bool                   g_bSelectedFaceInitDone = false;\r
-_QERSelectedFaceTable  g_SelectedFaceTable;\r
-bool            g_bUITable = false;\r
-_QERUITable     g_UITable;\r
-\r
-// selected face -------------------------------\r
-// we use this one to commit / read with Radiant\r
-_QERFaceData                   g_SelectedFaceData;\r
-// g_pSelectedFaceWindings gets allocated with MAX_POINTS_ON_WINDING at plugin startup ( QERPlug_Init )\r
-winding_t                              *g_pSelectedFaceWinding = NULL;\r
-const float                            g_ViewportRatio = 1.2f;\r
-// usefull class to manage the 2D view\r
-C2DView                                        g_2DView;\r
-// control points to move the polygon\r
-CControlPointsManagerBFace     g_ControlPointsBFace;\r
-// tells if a face is selected and we have something to render in the TexWindow\r
-bool                                   g_bTexViewReady = false;\r
-// data for texture work\r
-int                                            g_NumPoints;\r
-CtrlPts_t                              g_WorkWinding;\r
-// reference _QERFaceData we use on Cancel, and for Commit\r
-_QERFaceData                   g_CancelFaceData;\r
-\r
-// patches -------------------------------------\r
-bool                                   g_bPatch = false;\r
-//++timo we use this one to grab selected patchMesh_t\r
-// FIXME: update when there's a real interface to read/write patches\r
-bool                                   g_bSurfaceTableInitDone = false;\r
-_QERAppSurfaceTable            g_SurfaceTable;\r
-CControlPointsManagerPatch     g_ControlPointsPatch;\r
-// data for texture work\r
-patchMesh_t*                   g_pPatch;\r
-// we only use ctrl[][].st in this one\r
-patchMesh_t                            g_WorkPatch;\r
-// copy of initial g_pPatch for Cancel situation\r
-patchMesh_t                            g_CancelPatch;\r
-\r
-// ---------------------------------------------\r
-// holds the manager we are currently using\r
-CControlPointsManager  *g_pManager = NULL;\r
-\r
-// ---------------------------------------------\r
-// globals flags for user preferences\r
-//++timo TODO: this should be retrieved from the Editor's .INI prefs in a dedicated interface\r
-// update camera view during manipulation ?\r
-bool                                   g_bPrefsUpdateCameraView = true;\r
-\r
-// misc ----------------------------------------\r
-bool                                   g_bHelp = false;\r
-//++timo FIXME: used to close the plugin window if InitTexView fails\r
-// it's dirty, only use is to prevent infinite loop in DialogProc\r
-bool                                   g_bClosing = false;\r
-\r
-const char *PLUGIN_ABOUT = "Texture Tools for Radiant\n\n"\r
-                           "Gtk port by Leonardo Zide (leo@lokigames.com)\n"\r
-                           "Original version by Timothee \"TTimo\" Besset (timo@qeradiant.com)";\r
-\r
-extern "C" void* WINAPI QERPlug_GetFuncTable ()\r
-{\r
-  return &g_FuncTable;\r
-}\r
-\r
-const char* QERPlug_Init (void* hApp, void *pWidget)\r
-{\r
-  int size;\r
-  GtkWidget* pMainWidget = static_cast<GtkWidget*>(pWidget);\r
-\r
-  g_pMainWnd = pMainWidget;\r
-  memset(&g_FuncTable, 0, sizeof(_QERFuncTable_1));\r
-  g_FuncTable.m_nSize = sizeof(_QERFuncTable_1);\r
-  size = (int)((winding_t *)0)->points[MAX_POINTS_ON_WINDING];\r
-  g_pSelectedFaceWinding = (winding_t *)malloc( size );\r
-  memset( g_pSelectedFaceWinding, 0, size );\r
-  return "Texture tools for Radiant";\r
-}\r
-\r
-const char* QERPlug_GetName()\r
-{\r
-  return (char*)PLUGIN_NAME;\r
-}\r
-\r
-const char* QERPlug_GetCommandList()\r
-{\r
-  return PLUGIN_COMMANDS;\r
-}\r
-\r
-char *TranslateString (char *buf)\r
-{\r
-  static       char    buf2[32768];\r
-  int          i, l;\r
-  char *out;\r
-\r
-  l = strlen(buf);\r
-  out = buf2;\r
-  for (i=0 ; i<l ; i++)\r
-  {\r
-    if (buf[i] == '\n')\r
-    {\r
-      *out++ = '\r';\r
-      *out++ = '\n';\r
-    }\r
-    else\r
-      *out++ = buf[i];\r
-  }\r
-  *out++ = 0;\r
-\r
-  return buf2;\r
-}\r
-\r
-// called by InitTexView to fit the view against the bounding box of control points\r
-void FitView (IWindow* hwndDlg, int TexSize[2])\r
-{\r
-  // apply a ratio to get the area we'll draw\r
-  g_2DView.m_Center[0] = 0.5f * ( g_2DView.m_Mins[0] + g_2DView.m_Maxs[0] );\r
-  g_2DView.m_Center[1] = 0.5f * ( g_2DView.m_Mins[1] + g_2DView.m_Maxs[1] );\r
-  g_2DView.m_Mins[0] = g_2DView.m_Center[0] + g_ViewportRatio*( g_2DView.m_Mins[0] - g_2DView.m_Center[0] );\r
-  g_2DView.m_Mins[1] = g_2DView.m_Center[1] + g_ViewportRatio*( g_2DView.m_Mins[1] - g_2DView.m_Center[1] );\r
-  g_2DView.m_Maxs[0] = g_2DView.m_Center[0] + g_ViewportRatio*( g_2DView.m_Maxs[0] - g_2DView.m_Center[0] );\r
-  g_2DView.m_Maxs[1] = g_2DView.m_Center[1] + g_ViewportRatio*( g_2DView.m_Maxs[1] - g_2DView.m_Center[1] );\r
-\r
-  g_2DView.m_rect.left = 0;\r
-  g_2DView.m_rect.top = 0;\r
-  g_2DView.m_rect.bottom = hwndDlg->getHeight();\r
-  g_2DView.m_rect.right = hwndDlg->getWidth();\r
-\r
-  // we need to draw this area, now compute a bigger area so the texture scale is the same along X and Y\r
-  // compute box shape in XY space, let's say X <-> S we'll get a ratio for Y: \r
-  if (!g_bPatch)\r
-  {\r
-    g_SelectedFaceTable.m_pfnGetTextureSize( 0, TexSize );\r
-  }\r
-  else\r
-  {\r
-    TexSize[0] = g_pPatch->d_texture->width;\r
-    TexSize[1] = g_pPatch->d_texture->height;\r
-  }\r
-  // we want a texture with the same X / Y ratio\r
-  // compute XY space / window size ratio\r
-  float SSize = (float)fabs( g_2DView.m_Maxs[0] - g_2DView.m_Mins[0] );\r
-  float TSize = (float)fabs( g_2DView.m_Maxs[1] - g_2DView.m_Mins[1] );\r
-  float XSize = TexSize[0] * SSize;\r
-  float YSize = TexSize[1] * TSize;\r
-  float RatioX = XSize / (float)abs( g_2DView.m_rect.left - g_2DView.m_rect.right );\r
-  float RatioY = YSize / (float)abs( g_2DView.m_rect.top - g_2DView.m_rect.bottom );\r
-  if ( RatioX > RatioY )\r
-  {\r
-    YSize = (float)abs( g_2DView.m_rect.top - g_2DView.m_rect.bottom ) * RatioX;\r
-    TSize = YSize / (float)TexSize[1];\r
-  }\r
-  else\r
-  {\r
-    XSize = (float)abs( g_2DView.m_rect.left - g_2DView.m_rect.right ) * RatioY;\r
-    SSize = XSize / (float)TexSize[0];\r
-  }\r
-  g_2DView.m_Mins[0] = g_2DView.m_Center[0] - 0.5f * SSize;\r
-  g_2DView.m_Maxs[0] = g_2DView.m_Center[0] + 0.5f * SSize;\r
-  g_2DView.m_Mins[1] = g_2DView.m_Center[1] - 0.5f * TSize;\r
-  g_2DView.m_Maxs[1] = g_2DView.m_Center[1] + 0.5f * TSize;\r
-}\r
-\r
-// call this one each time we need to re-init\r
-//++timo TODO: re-init objects state, g_2DView and g_ControlPointsManager\r
-void InitTexView( IWindow* hwndDlg )\r
-{\r
-  // size of the texture we are working on\r
-  int TexSize[2];\r
-  g_bTexViewReady = false;\r
-  if (g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 0)\r
-  {\r
-    g_SelectedFaceTable.m_pfnGetFaceInfo( 0, &g_SelectedFaceData, g_pSelectedFaceWinding );\r
-    g_bPatch = false;\r
-    int i;\r
-    // we have something selected\r
-    // setup: compute BBox for the winding ( in ST space )\r
-    //++timo FIXME: move this in a C2DView member ? used as well for patches\r
-    g_2DView.m_Mins[0] = +9999.0f; g_2DView.m_Mins[1] = +9999.0f;\r
-    g_2DView.m_Maxs[0] = -9999.0f; g_2DView.m_Maxs[1] = -9999.0f;\r
-    for ( i=0; i<g_pSelectedFaceWinding->numpoints; i++ )\r
-    {\r
-      if ( g_pSelectedFaceWinding->points[i][3] < g_2DView.m_Mins[0] )\r
-        g_2DView.m_Mins[0] = g_pSelectedFaceWinding->points[i][3];\r
-      if ( g_pSelectedFaceWinding->points[i][3] > g_2DView.m_Maxs[0] )\r
-        g_2DView.m_Maxs[0] = g_pSelectedFaceWinding->points[i][3];\r
-      if ( g_pSelectedFaceWinding->points[i][4] < g_2DView.m_Mins[1] )\r
-        g_2DView.m_Mins[1] = g_pSelectedFaceWinding->points[i][4];\r
-      if ( g_pSelectedFaceWinding->points[i][4] > g_2DView.m_Maxs[1] )\r
-        g_2DView.m_Maxs[1] = g_pSelectedFaceWinding->points[i][4];\r
-    }\r
-    // NOTE: FitView will read and init TexSize\r
-    FitView( hwndDlg, TexSize );\r
-    // now init the work tables\r
-    g_NumPoints = g_pSelectedFaceWinding->numpoints;\r
-    for ( i=0; i<g_NumPoints; i++ )\r
-    {\r
-      g_WorkWinding.data[i][0] = g_pSelectedFaceWinding->points[i][3];\r
-      g_WorkWinding.data[i][1] = g_pSelectedFaceWinding->points[i][4];\r
-    }\r
-    g_ControlPointsBFace.Init( g_NumPoints, &g_WorkWinding, &g_2DView, TexSize, &g_SelectedFaceData, &g_QglTable );\r
-    // init snap-to-grid\r
-    float fTexStep[2];\r
-    fTexStep[0] = 1.0f / float(TexSize[0]);\r
-    fTexStep[1] = 1.0f / float(TexSize[1]);\r
-    g_2DView.SetGrid( fTexStep[0], fTexStep[1] );\r
-    g_pManager = &g_ControlPointsBFace;\r
-    // prepare the "Cancel" data\r
-    memcpy( &g_CancelFaceData, &g_SelectedFaceData, sizeof(_QERFaceData) );\r
-    // we are done\r
-    g_bTexViewReady = true;\r
-  }\r
-  else if ( g_SurfaceTable.m_pfnAnyPatchesSelected())\r
-  {\r
-    g_pPatch = g_SurfaceTable.m_pfnGetSelectedPatch();\r
-    g_bPatch = true;\r
-    int i,j;\r
-    // compute BBox for all patch points\r
-    g_2DView.m_Mins[0] = +9999.0f; g_2DView.m_Mins[1] = +9999.0f;\r
-    g_2DView.m_Maxs[0] = -9999.0f; g_2DView.m_Maxs[1] = -9999.0f;\r
-    for ( i=0; i<g_pPatch->width; i++ )\r
-    {\r
-      for ( j=0; j<g_pPatch->height; j++ )\r
-      {\r
-        if ( g_pPatch->ctrl[i][j].st[0] < g_2DView.m_Mins[0] )\r
-          g_2DView.m_Mins[0] = g_pPatch->ctrl[i][j].st[0];\r
-        if ( g_pPatch->ctrl[i][j].st[0] > g_2DView.m_Maxs[0] )\r
-          g_2DView.m_Maxs[0] = g_pPatch->ctrl[i][j].st[0];\r
-        if ( g_pPatch->ctrl[i][j].st[1] < g_2DView.m_Mins[1] )\r
-          g_2DView.m_Mins[1] = g_pPatch->ctrl[i][j].st[1];\r
-        if ( g_pPatch->ctrl[i][j].st[1] > g_2DView.m_Maxs[1] )\r
-          g_2DView.m_Maxs[1] = g_pPatch->ctrl[i][j].st[1];\r
-      }\r
-    }\r
-    FitView( hwndDlg, TexSize);\r
-    // init the work tables\r
-    g_WorkPatch = *g_pPatch;\r
-    g_ControlPointsPatch.Init( &g_WorkPatch, &g_2DView, &g_QglTable, g_pPatch );\r
-    // init snap-to-grid\r
-    float fTexStep[2];\r
-    fTexStep[0] = 1.0f / float(TexSize[0]);\r
-    fTexStep[1] = 1.0f / float(TexSize[1]);\r
-    g_2DView.SetGrid( fTexStep[0], fTexStep[1] );\r
-    g_pManager = &g_ControlPointsPatch;\r
-    // prepare the "cancel" data\r
-    g_CancelPatch = *g_pPatch;\r
-    // we are done\r
-    g_bTexViewReady = true;\r
-  }\r
-}\r
-\r
-void Textool_Validate()\r
-{\r
-  // validate current situation into the main view\r
-  g_pManager->Commit( );\r
-  // for a brush face we have an aditionnal step\r
-  if (!g_bPatch)\r
-  {\r
-    // tell Radiant to update (will also send update windows messages )\r
-    g_SelectedFaceTable.m_pfnSetFaceInfo( 0, &g_SelectedFaceData );\r
-  }\r
-  else\r
-  {\r
-    // ask to rebuild the patch display data\r
-    g_pPatch->bDirty = true;\r
-    // send a repaint to the camera window as well\r
-    g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );\r
-  }\r
-  // we'll need to update after that as well:\r
-  g_bTexViewReady = false;\r
-  // send a repaint message\r
-  g_pToolWnd->Redraw ();\r
-}\r
-\r
-void Textool_Cancel()\r
-{\r
-  if (!g_bPatch)\r
-  {\r
-    // tell Radiant to update (will also send update windows messages )\r
-    g_SelectedFaceTable.m_pfnSetFaceInfo( 0, &g_CancelFaceData );\r
-  }\r
-  else\r
-  {\r
-    *g_pPatch = g_CancelPatch;\r
-    g_pPatch->bDirty = true;\r
-    g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );\r
-  }\r
-  // do not call destroy, decref it\r
-  g_pToolWnd->DecRef();\r
-  g_pToolWnd = NULL;\r
-}\r
-\r
-static void DoExpose ()\r
-{\r
-  int i,j;\r
-\r
-  g_2DView.PreparePaint();\r
-  g_QglTable.m_pfn_qglColor3f(1, 1, 1);\r
-  // draw the texture background\r
-  g_QglTable.m_pfn_qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );\r
-  if (!g_bPatch)\r
-  {\r
-    g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, g_SelectedFaceTable.m_pfnGetTextureNumber(0) );\r
-  }\r
-  else\r
-  {\r
-    g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, g_pPatch->d_texture->texture_number );\r
-  }\r
-\r
-  g_QglTable.m_pfn_qglEnable( GL_TEXTURE_2D );\r
-  g_QglTable.m_pfn_qglBegin( GL_QUADS );\r
-  g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Mins[0], g_2DView.m_Mins[1] );\r
-  g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Mins[0], g_2DView.m_Mins[1] );\r
-  g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Maxs[0], g_2DView.m_Mins[1] );\r
-  g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Maxs[0], g_2DView.m_Mins[1] );\r
-  g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Maxs[0], g_2DView.m_Maxs[1] );\r
-  g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Maxs[0], g_2DView.m_Maxs[1] );\r
-  g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Mins[0], g_2DView.m_Maxs[1] );\r
-  g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Mins[0], g_2DView.m_Maxs[1] );\r
-  g_QglTable.m_pfn_qglEnd();\r
-  g_QglTable.m_pfn_qglDisable( GL_TEXTURE_2D );\r
-\r
-  if (!g_bPatch)\r
-  {\r
-    g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP );\r
-    for ( i=0; i<g_NumPoints; i++ )\r
-    {\r
-      g_QglTable.m_pfn_qglVertex2f( g_WorkWinding.data[i][0], g_WorkWinding.data[i][1] );\r
-    }\r
-    g_QglTable.m_pfn_qglEnd();\r
-  }\r
-  else\r
-  {\r
-    g_QglTable.m_pfn_qglBegin( GL_LINES );\r
-    for ( i=0; i<g_pPatch->width; i++ )\r
-      for ( j=0; j<g_pPatch->height; j++ )\r
-      {\r
-       if ( i < g_pPatch->width-1 )\r
-       {\r
-         g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j].st[0], g_WorkPatch.ctrl[i][j].st[1] );\r
-         g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i+1][j].st[0], g_WorkPatch.ctrl[i+1][j].st[1] );\r
-       }\r
-\r
-       if ( j < g_pPatch->height-1 )\r
-       {\r
-         g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j].st[0], g_WorkPatch.ctrl[i][j].st[1] );\r
-         g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j+1].st[0], g_WorkPatch.ctrl[i][j+1].st[1] );\r
-       }\r
-      }\r
-    g_QglTable.m_pfn_qglEnd();\r
-  }\r
-\r
-  // let the control points manager render\r
-  g_pManager->Render( );\r
-}\r
-\r
-static bool CanProcess ()\r
-{\r
-  if (!g_bTexViewReady && !g_bClosing)\r
-  {\r
-    InitTexView (g_pToolWnd);\r
-\r
-    if (!g_bTexViewReady)\r
-    {\r
-      g_bClosing = true;\r
-      DoMessageBox ("You must have brush primitives activated in your project settings and\n"\r
-                    "have a patch or a single face selected to use the TexTool plugin.\n"\r
-                    "See plugins/TexToolHelp for documentation.", "TexTool plugin", MB_ICONERROR | MB_OK);\r
-      // decref, this will destroy\r
-      g_pToolWnd->DecRef();\r
-      g_pToolWnd = NULL;\r
-      return 0;\r
-    }\r
-    else\r
-      g_bClosing = false;\r
-  }\r
-  else if (!g_bTexViewReady && g_bClosing)\r
-  {\r
-    return 0;\r
-  }\r
-\r
-  return 1;\r
-}\r
-\r
-#if 0\r
-static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data)\r
-{\r
-  if (CanProcess ())\r
-  {\r
-    switch (event->button)\r
-    {\r
-    case 1:\r
-      g_pManager->OnLButtonDown (event->x, event->y); break;\r
-    case 3:\r
-      g_2DView.OnRButtonDown (event->x, event->y); break;\r
-    }\r
-  }\r
-}\r
-\r
-static void button_release (GtkWidget *widget, GdkEventButton *event, gpointer data)\r
-{\r
-  if (CanProcess ())\r
-  {\r
-    switch (event->button)\r
-    {\r
-    case 1:\r
-      g_pManager->OnLButtonUp (event->x, event->y); break;\r
-    case 3:\r
-      g_2DView.OnRButtonUp (event->x, event->y); break;\r
-    }\r
-  }\r
-}\r
-\r
-static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data)\r
-{\r
-  if (CanProcess ())\r
-  {\r
-    if (g_2DView.OnMouseMove (event->x, event->y))\r
-      return;\r
-\r
-    if (g_pManager->OnMouseMove (event->x, event->y))\r
-      return;\r
-  }\r
-}\r
-\r
-static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data)\r
-{\r
-  if (event->count > 0)\r
-    return TRUE;\r
-\r
-  if (!CanProcess ())\r
-    return TRUE;\r
-\r
-  if (g_bTexViewReady)\r
-  {\r
-    g_2DView.m_rect.bottom = widget->allocation.height;\r
-    g_2DView.m_rect.right = widget->allocation.width;\r
-\r
-    if (!g_QglTable.m_pfn_glwidget_make_current (g_pToolWidget))\r
-    {\r
-      Sys_Printf("TexTool: glMakeCurrent failed\n");\r
-      return TRUE;\r
-    }\r
-\r
-    DoExpose ();\r
-\r
-    g_QglTable.m_pfn_glwidget_swap_buffers (g_pToolWidget);\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-static gint keypress (GtkWidget* widget, GdkEventKey* event, gpointer data)\r
-{\r
-  unsigned int code = gdk_keyval_to_upper(event->keyval);\r
-\r
-  if (code == GDK_Escape)\r
-  {\r
-    gtk_widget_destroy (g_pToolWnd);\r
-    g_pToolWnd = NULL;\r
-    return TRUE;\r
-  }\r
-\r
-  if (CanProcess ())\r
-  {\r
-    if (g_2DView.OnKeyDown (code))\r
-      return FALSE;\r
-\r
-    if (code == GDK_Return)\r
-    {\r
-      Textool_Validate();\r
-      return FALSE;\r
-    }\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-static gint close (GtkWidget *widget, GdkEvent* event, gpointer data)\r
-{\r
-  gtk_widget_destroy (widget);\r
-  g_pToolWnd = NULL;\r
-\r
-  return TRUE;\r
-}\r
-\r
-static GtkWidget* CreateOpenGLWidget ()\r
-{\r
-  g_pToolWidget = g_QglTable.m_pfn_glwidget_new (FALSE, g_QglTable.m_pfn_GetQeglobalsGLWidget ());\r
-\r
-  gtk_widget_set_events (g_pToolWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK |\r
-                        GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);\r
-\r
-  // Connect signal handlers\r
-  gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL);\r
-  gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "motion_notify_event",\r
-                     GTK_SIGNAL_FUNC (motion), NULL);\r
-  gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "button_press_event",\r
-                     GTK_SIGNAL_FUNC (button_press), NULL);\r
-  gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "button_release_event",\r
-                     GTK_SIGNAL_FUNC (button_release), NULL);\r
-\r
-  gtk_signal_connect (GTK_OBJECT (g_pToolWnd), "delete_event", GTK_SIGNAL_FUNC (close), NULL);\r
-  gtk_signal_connect (GTK_OBJECT (g_pToolWnd), "key_press_event",\r
-                     GTK_SIGNAL_FUNC (keypress), NULL);\r
-\r
-  return g_pToolWidget;\r
-}\r
-#endif\r
-\r
-#if 0\r
-static void DoPaint ()\r
-{\r
-  if (!CanProcess ())\r
-    return;\r
-  \r
-  if (g_bTexViewReady)\r
-  {\r
-    g_2DView.m_rect.bottom = g_pToolWnd->getHeight();\r
-    g_2DView.m_rect.right = g_pToolWnd->getWidth();\r
-    \r
-    // set GL_PROJECTION\r
-    g_2DView.PreparePaint();\r
-    // render the objects\r
-    // the master is not rendered the same way, draw over a unified texture background\r
-    g_2DView.TextureBackground(g_DrawObjects[0].pObject->getTextureNumber());\r
-    if (g_nDrawObjects >= 1)\r
-    {\r
-      int i;\r
-      for (i=1;i<g_nDrawObjects;i++)\r
-      {\r
-        // we use a first step to the GL_MODELVIEW for the master object\r
-        // GL_MODELVIEW will be altered in RenderAuxiliary too\r
-        g_DrawObjects[0].pObject->PrepareModelView(g_DrawObjects[i].pTopo);\r
-        g_DrawObjects[i].pObject->RenderAuxiliary();\r
-      }\r
-    }\r
-    // draw the polygon outline and control points\r
-    g_DrawObjects[0].pObject->PrepareModelView(NULL);\r
-    g_DrawObjects[0].pObject->RenderUI();\r
-  }\r
-}\r
-#endif\r
-\r
-bool CWindowListener::OnLButtonDown(guint32 nFlags, double x, double y)\r
-{\r
-  if (CanProcess())\r
-  {\r
-    g_pManager->OnLButtonDown((int)x, (int)y);\r
-    return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-bool CWindowListener::OnRButtonDown(guint32 nFlags, double x, double y)\r
-{\r
-  if (CanProcess())\r
-  {\r
-    g_2DView.OnRButtonDown ((int)x, (int)y);\r
-    return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-bool CWindowListener::OnLButtonUp(guint32 nFlags, double x, double y)\r
-{\r
-  if (CanProcess())\r
-  {\r
-    g_pManager->OnLButtonUp((int)x, (int)y);\r
-    return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-bool CWindowListener::OnRButtonUp(guint32 nFlags, double x, double y)\r
-{\r
-  if (CanProcess())\r
-  {\r
-    g_2DView.OnRButtonUp ((int)x, (int)y);\r
-    return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-bool CWindowListener::OnMouseMove(guint32 nFlags, double x, double y)\r
-{\r
-  if (CanProcess ())\r
-  {\r
-    if (g_2DView.OnMouseMove ((int)x, (int)y))\r
-      return true;\r
-\r
-    g_pManager->OnMouseMove((int)x, (int)y);\r
-    return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-// the widget is closing\r
-void CWindowListener::Close()\r
-{\r
-  g_pToolWnd = NULL;\r
-}\r
-\r
-bool CWindowListener::Paint()\r
-{\r
-  if (!CanProcess ())\r
-    return false;\r
-\r
-  if (g_bTexViewReady)\r
-    DoExpose();\r
-\r
-  return true;\r
-}\r
-\r
-bool CWindowListener::OnKeyPressed(char *s)\r
-{\r
-  if (!strcmp(s,"Escape"))\r
-  {\r
-    Textool_Cancel();\r
-    return TRUE;\r
-  }\r
-  if (CanProcess ())\r
-  {\r
-    if (g_2DView.OnKeyDown (s))\r
-      return TRUE;\r
-\r
-    if (!strcmp(s,"Return"))\r
-    {\r
-      Textool_Validate();\r
-      return TRUE;\r
-    }\r
-  }\r
-  return FALSE;\r
-}\r
-\r
-extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush)\r
-{\r
-  #if 0\r
-  // if it's the first call, perhaps we need some additional init steps\r
-  if (!g_bQglInitDone)\r
-  {\r
-    g_QglTable.m_nSize = sizeof(_QERQglTable);\r
-    if ( g_FuncTable.m_pfnRequestInterface( QERQglTable_GUID, static_cast<LPVOID>(&g_QglTable) ) )\r
-    {\r
-      g_bQglInitDone = true;\r
-    }\r
-    else\r
-    {\r
-      Sys_Printf("TexTool plugin: _QERQglTable interface request failed\n");\r
-      return;\r
-    }\r
-  }\r
-\r
-  if (!g_bSelectedFaceInitDone)\r
-  {\r
-    g_SelectedFaceTable.m_nSize = sizeof(_QERSelectedFaceTable);\r
-    if (g_FuncTable.m_pfnRequestInterface (QERSelectedFaceTable_GUID,\r
-                                          static_cast<LPVOID>(&g_SelectedFaceTable)))\r
-    {\r
-      g_bSelectedFaceInitDone = true;\r
-    }\r
-    else\r
-    {\r
-      Sys_Printf("TexTool plugin: _QERSelectedFaceTable interface request failed\n");\r
-      return;\r
-    }\r
-  }\r
-\r
-  if (!g_bSurfaceTableInitDone)\r
-  {\r
-    g_SurfaceTable.m_nSize = sizeof(_QERAppSurfaceTable);\r
-    if ( g_FuncTable.m_pfnRequestInterface( QERAppSurfaceTable_GUID, static_cast<LPVOID>(&g_SurfaceTable) ) )\r
-    {\r
-      g_bSurfaceTableInitDone = true;\r
-    }\r
-    else\r
-    {\r
-      Sys_Printf("TexTool plugin: _QERAppSurfaceTable interface request failed\n");\r
-      return;\r
-    }\r
-  }\r
-\r
-  if (!g_bUITable)\r
-  {\r
-    g_UITable.m_nSize = sizeof(_QERUITable);\r
-    if ( g_FuncTable.m_pfnRequestInterface( QERUI_GUID, static_cast<LPVOID>(&g_UITable) ) )\r
-    {\r
-      g_bUITable = true;\r
-    }\r
-    else\r
-    {\r
-      Sys_Printf("TexTool plugin: _QERUITable interface request failed\n");\r
-      return;\r
-    }\r
-  }\r
-  #endif\r
-\r
-  if (!strcmp(p, "About..."))\r
-  {\r
-    DoMessageBox (PLUGIN_ABOUT, "About ...", MB_OK );\r
-  }\r
-  else if (!strcmp(p, "Go..."))\r
-  {\r
-    if (!g_pToolWnd)\r
-    {\r
-      g_pToolWnd = g_UITable.m_pfnCreateGLWindow();\r
-      g_pToolWnd->setSizeParm(300,300);\r
-      g_pToolWnd->setName("TexTool");\r
-      // g_Listener is a static class, we need to bump the refCount to avoid premature release problems\r
-      g_Listen.IncRef();\r
-      // setListener will incRef on the listener too\r
-      g_pToolWnd->setListener(&g_Listen);\r
-      if (!g_pToolWnd->Show())\r
-      {\r
-        DoMessageBox ("Error creating texture tools window!", "TexTool plugin", MB_ICONERROR | MB_OK);\r
-        return;\r
-      }\r
-    }\r
-    \r
-    g_bTexViewReady = false;\r
-    g_bClosing = false;\r
-  }\r
-  else if (!strcmp(p, "Help..."))\r
-  {\r
-    if (!g_bHelp)\r
-      DoMessageBox ("Select a brush face (ctrl+shift+left mouse) or a patch, and hit Go...\n"\r
-                   "See tutorials for more", "TexTool plugin", MB_OK );\r
-    else\r
-      DoMessageBox ("Are you kidding me ?", "TexTool plugin", MB_OK );\r
-    g_bHelp = true;\r
-  }\r
-}\r
-\r
-// =============================================================================\r
-// SYNAPSE\r
-\r
-CSynapseServer* g_pSynapseServer = NULL;\r
-CSynapseClientTexTool g_SynapseClient;\r
-\r
-#if __GNUC__ >= 4\r
-#pragma GCC visibility push(default)\r
-#endif\r
-extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( const char *version, CSynapseServer *pServer ) {\r
-#if __GNUC__ >= 4\r
-#pragma GCC visibility pop\r
-#endif\r
-  if (strcmp(version, SYNAPSE_VERSION))\r
-  {\r
-    Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version);\r
-    return NULL;\r
-  }\r
-  g_pSynapseServer = pServer;\r
-  g_pSynapseServer->IncRef();\r
-  Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf());\r
-  \r
-  g_SynapseClient.AddAPI(PLUGIN_MAJOR, "textool", sizeof(_QERPluginTable));  \r
-  g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable);\r
-  g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(g_QglTable), SYN_REQUIRE, &g_QglTable);\r
-  g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(g_SelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable);\r
-  \r
-  return &g_SynapseClient;\r
-}\r
-\r
-bool CSynapseClientTexTool::RequestAPI(APIDescriptor_t *pAPI)\r
-{\r
-  if (!strcmp(pAPI->major_name, PLUGIN_MAJOR))\r
-  {\r
-    _QERPluginTable *pTable = static_cast<_QERPluginTable*>(pAPI->mpTable);\r
-    pTable->m_pfnQERPlug_Init = QERPlug_Init;\r
-    pTable->m_pfnQERPlug_GetName = QERPlug_GetName;\r
-    pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList;\r
-    pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch;\r
-    return true;\r
-  }\r
-\r
-  Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo());\r
-  return false;\r
-}\r
-\r
-#include "version.h"\r
-\r
-const char* CSynapseClientTexTool::GetInfo()\r
-{\r
-  return "Texture Tools plugin built " __DATE__ " " RADIANT_VERSION;\r
-}\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+//-----------------------------------------------------------------------------
+//
+// DESCRIPTION:
+// main plugin implementation
+// texturing tools for Radiant
+//
+
+#include "StdAfx.h"
+
+static void dialog_button_callback (GtkWidget *widget, gpointer data)
+{
+  GtkWidget *parent;
+  int *loop, *ret;
+  parent = gtk_widget_get_toplevel (widget);
+  loop = (int*)g_object_get_data (G_OBJECT (parent), "loop");
+  ret = (int*)g_object_get_data (G_OBJECT (parent), "ret");
+  *loop = 0;
+  *ret = (int)data;
+}
+static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data)
+{
+  int *loop;
+  gtk_widget_hide (widget);
+  loop = (int*)g_object_get_data (G_OBJECT (widget), "loop");
+  *loop = 0;
+
+  return TRUE;
+}
+
+int DoMessageBox (const char* lpText, const char* lpCaption, guint32 uType)
+{
+  GtkWidget *window, *w, *vbox, *hbox;
+  int mode = (uType & MB_TYPEMASK), ret, loop = 1;
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                      GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                      GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);
+  gtk_window_set_title (GTK_WINDOW (window), lpCaption);
+  gtk_container_border_width (GTK_CONTAINER (window), 10);
+  g_object_set_data (G_OBJECT (window), "loop", &loop);
+  g_object_set_data (G_OBJECT (window), "ret", &ret);
+  gtk_widget_realize (window);
+  vbox = gtk_vbox_new (FALSE, 10);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+  gtk_widget_show (vbox);
+  w = gtk_label_new (lpText);
+  gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);
+  gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT);
+  gtk_widget_show (w);
+  w = gtk_hseparator_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);
+  gtk_widget_show (w);
+  hbox = gtk_hbox_new (FALSE, 10);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2);
+  gtk_widget_show (hbox);
+  if (mode == MB_OK)
+  {
+    w = gtk_button_new_with_label ("Ok");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));
+    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default (w);
+    gtk_widget_show (w);
+    ret = IDOK;
+  }
+  else if (mode ==  MB_OKCANCEL)
+  {
+    w = gtk_button_new_with_label ("Ok");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));
+    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default (w);
+    gtk_widget_show (w);
+    w = gtk_button_new_with_label ("Cancel");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));
+    gtk_widget_show (w);
+    ret = IDCANCEL;
+  }
+  else if (mode == MB_YESNOCANCEL)
+  {
+    w = gtk_button_new_with_label ("Yes");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES));
+    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default (w);
+    gtk_widget_show (w);
+    w = gtk_button_new_with_label ("No");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO));
+    gtk_widget_show (w);
+    w = gtk_button_new_with_label ("Cancel");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));
+    gtk_widget_show (w);
+    ret = IDCANCEL;
+  }
+  else /* if (mode == MB_YESNO) */
+  {
+    w = gtk_button_new_with_label ("Yes");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES));
+    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default (w);
+    gtk_widget_show (w);
+    w = gtk_button_new_with_label ("No");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO));
+    gtk_widget_show (w);
+    ret = IDNO;
+  }
+  gtk_widget_show (window);
+  gtk_grab_add (window);
+  while (loop)
+    gtk_main_iteration ();
+  gtk_grab_remove (window);
+  gtk_widget_destroy (window);
+  return ret;
+}
+
+// Radiant function table
+_QERFuncTable_1 g_FuncTable;
+
+// plugin name
+const char *PLUGIN_NAME = "Q3 Texture Tools";
+
+// commands in the menu
+const char *PLUGIN_COMMANDS = "About...;Go...";
+
+// cast to GtkWidget*
+void *g_pMainWnd;
+IWindow *g_pToolWnd = NULL; // handle to the window
+CWindowListener g_Listen;
+
+// plugin interfaces ---------------------------
+bool                   g_bQglInitDone = false;
+_QERQglTable           g_QglTable;
+bool                   g_bSelectedFaceInitDone = false;
+_QERSelectedFaceTable  g_SelectedFaceTable;
+bool            g_bUITable = false;
+_QERUITable     g_UITable;
+
+// selected face -------------------------------
+// we use this one to commit / read with Radiant
+_QERFaceData                   g_SelectedFaceData;
+// g_pSelectedFaceWindings gets allocated with MAX_POINTS_ON_WINDING at plugin startup ( QERPlug_Init )
+winding_t                              *g_pSelectedFaceWinding = NULL;
+const float                            g_ViewportRatio = 1.2f;
+// usefull class to manage the 2D view
+C2DView                                        g_2DView;
+// control points to move the polygon
+CControlPointsManagerBFace     g_ControlPointsBFace;
+// tells if a face is selected and we have something to render in the TexWindow
+bool                                   g_bTexViewReady = false;
+// data for texture work
+int                                            g_NumPoints;
+CtrlPts_t                              g_WorkWinding;
+// reference _QERFaceData we use on Cancel, and for Commit
+_QERFaceData                   g_CancelFaceData;
+
+// patches -------------------------------------
+bool                                   g_bPatch = false;
+//++timo we use this one to grab selected patchMesh_t
+// FIXME: update when there's a real interface to read/write patches
+bool                                   g_bSurfaceTableInitDone = false;
+_QERAppSurfaceTable            g_SurfaceTable;
+CControlPointsManagerPatch     g_ControlPointsPatch;
+// data for texture work
+patchMesh_t*                   g_pPatch;
+// we only use ctrl[][].st in this one
+patchMesh_t                            g_WorkPatch;
+// copy of initial g_pPatch for Cancel situation
+patchMesh_t                            g_CancelPatch;
+
+// ---------------------------------------------
+// holds the manager we are currently using
+CControlPointsManager  *g_pManager = NULL;
+
+// ---------------------------------------------
+// globals flags for user preferences
+//++timo TODO: this should be retrieved from the Editor's .INI prefs in a dedicated interface
+// update camera view during manipulation ?
+bool                                   g_bPrefsUpdateCameraView = true;
+
+// misc ----------------------------------------
+bool                                   g_bHelp = false;
+//++timo FIXME: used to close the plugin window if InitTexView fails
+// it's dirty, only use is to prevent infinite loop in DialogProc
+bool                                   g_bClosing = false;
+
+const char *PLUGIN_ABOUT = "Texture Tools for Radiant\n\n"
+                           "Gtk port by Leonardo Zide (leo@lokigames.com)\n"
+                           "Original version by Timothee \"TTimo\" Besset (timo@qeradiant.com)";
+
+extern "C" void* WINAPI QERPlug_GetFuncTable ()
+{
+  return &g_FuncTable;
+}
+
+const char* QERPlug_Init (void* hApp, void *pWidget)
+{
+  int size;
+  GtkWidget* pMainWidget = static_cast<GtkWidget*>(pWidget);
+
+  g_pMainWnd = pMainWidget;
+  memset(&g_FuncTable, 0, sizeof(_QERFuncTable_1));
+  g_FuncTable.m_nSize = sizeof(_QERFuncTable_1);
+  size = (int)((winding_t *)0)->points[MAX_POINTS_ON_WINDING];
+  g_pSelectedFaceWinding = (winding_t *)malloc( size );
+  memset( g_pSelectedFaceWinding, 0, size );
+  return "Texture tools for Radiant";
+}
+
+const char* QERPlug_GetName()
+{
+  return (char*)PLUGIN_NAME;
+}
+
+const char* QERPlug_GetCommandList()
+{
+  return PLUGIN_COMMANDS;
+}
+
+char *TranslateString (char *buf)
+{
+  static       char    buf2[32768];
+  int          i, l;
+  char *out;
+
+  l = strlen(buf);
+  out = buf2;
+  for (i=0 ; i<l ; i++)
+  {
+    if (buf[i] == '\n')
+    {
+      *out++ = '\r';
+      *out++ = '\n';
+    }
+    else
+      *out++ = buf[i];
+  }
+  *out++ = 0;
+
+  return buf2;
+}
+
+// called by InitTexView to fit the view against the bounding box of control points
+void FitView (IWindow* hwndDlg, int TexSize[2])
+{
+  // apply a ratio to get the area we'll draw
+  g_2DView.m_Center[0] = 0.5f * ( g_2DView.m_Mins[0] + g_2DView.m_Maxs[0] );
+  g_2DView.m_Center[1] = 0.5f * ( g_2DView.m_Mins[1] + g_2DView.m_Maxs[1] );
+  g_2DView.m_Mins[0] = g_2DView.m_Center[0] + g_ViewportRatio*( g_2DView.m_Mins[0] - g_2DView.m_Center[0] );
+  g_2DView.m_Mins[1] = g_2DView.m_Center[1] + g_ViewportRatio*( g_2DView.m_Mins[1] - g_2DView.m_Center[1] );
+  g_2DView.m_Maxs[0] = g_2DView.m_Center[0] + g_ViewportRatio*( g_2DView.m_Maxs[0] - g_2DView.m_Center[0] );
+  g_2DView.m_Maxs[1] = g_2DView.m_Center[1] + g_ViewportRatio*( g_2DView.m_Maxs[1] - g_2DView.m_Center[1] );
+
+  g_2DView.m_rect.left = 0;
+  g_2DView.m_rect.top = 0;
+  g_2DView.m_rect.bottom = hwndDlg->getHeight();
+  g_2DView.m_rect.right = hwndDlg->getWidth();
+
+  // we need to draw this area, now compute a bigger area so the texture scale is the same along X and Y
+  // compute box shape in XY space, let's say X <-> S we'll get a ratio for Y: 
+  if (!g_bPatch)
+  {
+    g_SelectedFaceTable.m_pfnGetTextureSize( 0, TexSize );
+  }
+  else
+  {
+    TexSize[0] = g_pPatch->d_texture->width;
+    TexSize[1] = g_pPatch->d_texture->height;
+  }
+  // we want a texture with the same X / Y ratio
+  // compute XY space / window size ratio
+  float SSize = (float)fabs( g_2DView.m_Maxs[0] - g_2DView.m_Mins[0] );
+  float TSize = (float)fabs( g_2DView.m_Maxs[1] - g_2DView.m_Mins[1] );
+  float XSize = TexSize[0] * SSize;
+  float YSize = TexSize[1] * TSize;
+  float RatioX = XSize / (float)abs( g_2DView.m_rect.left - g_2DView.m_rect.right );
+  float RatioY = YSize / (float)abs( g_2DView.m_rect.top - g_2DView.m_rect.bottom );
+  if ( RatioX > RatioY )
+  {
+    YSize = (float)abs( g_2DView.m_rect.top - g_2DView.m_rect.bottom ) * RatioX;
+    TSize = YSize / (float)TexSize[1];
+  }
+  else
+  {
+    XSize = (float)abs( g_2DView.m_rect.left - g_2DView.m_rect.right ) * RatioY;
+    SSize = XSize / (float)TexSize[0];
+  }
+  g_2DView.m_Mins[0] = g_2DView.m_Center[0] - 0.5f * SSize;
+  g_2DView.m_Maxs[0] = g_2DView.m_Center[0] + 0.5f * SSize;
+  g_2DView.m_Mins[1] = g_2DView.m_Center[1] - 0.5f * TSize;
+  g_2DView.m_Maxs[1] = g_2DView.m_Center[1] + 0.5f * TSize;
+}
+
+// call this one each time we need to re-init
+//++timo TODO: re-init objects state, g_2DView and g_ControlPointsManager
+void InitTexView( IWindow* hwndDlg )
+{
+  // size of the texture we are working on
+  int TexSize[2];
+  g_bTexViewReady = false;
+  if (g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 0)
+  {
+    g_SelectedFaceTable.m_pfnGetFaceInfo( 0, &g_SelectedFaceData, g_pSelectedFaceWinding );
+    g_bPatch = false;
+    int i;
+    // we have something selected
+    // setup: compute BBox for the winding ( in ST space )
+    //++timo FIXME: move this in a C2DView member ? used as well for patches
+    g_2DView.m_Mins[0] = +9999.0f; g_2DView.m_Mins[1] = +9999.0f;
+    g_2DView.m_Maxs[0] = -9999.0f; g_2DView.m_Maxs[1] = -9999.0f;
+    for ( i=0; i<g_pSelectedFaceWinding->numpoints; i++ )
+    {
+      if ( g_pSelectedFaceWinding->points[i][3] < g_2DView.m_Mins[0] )
+        g_2DView.m_Mins[0] = g_pSelectedFaceWinding->points[i][3];
+      if ( g_pSelectedFaceWinding->points[i][3] > g_2DView.m_Maxs[0] )
+        g_2DView.m_Maxs[0] = g_pSelectedFaceWinding->points[i][3];
+      if ( g_pSelectedFaceWinding->points[i][4] < g_2DView.m_Mins[1] )
+        g_2DView.m_Mins[1] = g_pSelectedFaceWinding->points[i][4];
+      if ( g_pSelectedFaceWinding->points[i][4] > g_2DView.m_Maxs[1] )
+        g_2DView.m_Maxs[1] = g_pSelectedFaceWinding->points[i][4];
+    }
+    // NOTE: FitView will read and init TexSize
+    FitView( hwndDlg, TexSize );
+    // now init the work tables
+    g_NumPoints = g_pSelectedFaceWinding->numpoints;
+    for ( i=0; i<g_NumPoints; i++ )
+    {
+      g_WorkWinding.data[i][0] = g_pSelectedFaceWinding->points[i][3];
+      g_WorkWinding.data[i][1] = g_pSelectedFaceWinding->points[i][4];
+    }
+    g_ControlPointsBFace.Init( g_NumPoints, &g_WorkWinding, &g_2DView, TexSize, &g_SelectedFaceData, &g_QglTable );
+    // init snap-to-grid
+    float fTexStep[2];
+    fTexStep[0] = 1.0f / float(TexSize[0]);
+    fTexStep[1] = 1.0f / float(TexSize[1]);
+    g_2DView.SetGrid( fTexStep[0], fTexStep[1] );
+    g_pManager = &g_ControlPointsBFace;
+    // prepare the "Cancel" data
+    memcpy( &g_CancelFaceData, &g_SelectedFaceData, sizeof(_QERFaceData) );
+    // we are done
+    g_bTexViewReady = true;
+  }
+  else if ( g_SurfaceTable.m_pfnAnyPatchesSelected())
+  {
+    g_pPatch = g_SurfaceTable.m_pfnGetSelectedPatch();
+    g_bPatch = true;
+    int i,j;
+    // compute BBox for all patch points
+    g_2DView.m_Mins[0] = +9999.0f; g_2DView.m_Mins[1] = +9999.0f;
+    g_2DView.m_Maxs[0] = -9999.0f; g_2DView.m_Maxs[1] = -9999.0f;
+    for ( i=0; i<g_pPatch->width; i++ )
+    {
+      for ( j=0; j<g_pPatch->height; j++ )
+      {
+        if ( g_pPatch->ctrl[i][j].st[0] < g_2DView.m_Mins[0] )
+          g_2DView.m_Mins[0] = g_pPatch->ctrl[i][j].st[0];
+        if ( g_pPatch->ctrl[i][j].st[0] > g_2DView.m_Maxs[0] )
+          g_2DView.m_Maxs[0] = g_pPatch->ctrl[i][j].st[0];
+        if ( g_pPatch->ctrl[i][j].st[1] < g_2DView.m_Mins[1] )
+          g_2DView.m_Mins[1] = g_pPatch->ctrl[i][j].st[1];
+        if ( g_pPatch->ctrl[i][j].st[1] > g_2DView.m_Maxs[1] )
+          g_2DView.m_Maxs[1] = g_pPatch->ctrl[i][j].st[1];
+      }
+    }
+    FitView( hwndDlg, TexSize);
+    // init the work tables
+    g_WorkPatch = *g_pPatch;
+    g_ControlPointsPatch.Init( &g_WorkPatch, &g_2DView, &g_QglTable, g_pPatch );
+    // init snap-to-grid
+    float fTexStep[2];
+    fTexStep[0] = 1.0f / float(TexSize[0]);
+    fTexStep[1] = 1.0f / float(TexSize[1]);
+    g_2DView.SetGrid( fTexStep[0], fTexStep[1] );
+    g_pManager = &g_ControlPointsPatch;
+    // prepare the "cancel" data
+    g_CancelPatch = *g_pPatch;
+    // we are done
+    g_bTexViewReady = true;
+  }
+}
+
+void Textool_Validate()
+{
+  // validate current situation into the main view
+  g_pManager->Commit( );
+  // for a brush face we have an aditionnal step
+  if (!g_bPatch)
+  {
+    // tell Radiant to update (will also send update windows messages )
+    g_SelectedFaceTable.m_pfnSetFaceInfo( 0, &g_SelectedFaceData );
+  }
+  else
+  {
+    // ask to rebuild the patch display data
+    g_pPatch->bDirty = true;
+    // send a repaint to the camera window as well
+    g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );
+  }
+  // we'll need to update after that as well:
+  g_bTexViewReady = false;
+  // send a repaint message
+  g_pToolWnd->Redraw ();
+}
+
+void Textool_Cancel()
+{
+  if (!g_bPatch)
+  {
+    // tell Radiant to update (will also send update windows messages )
+    g_SelectedFaceTable.m_pfnSetFaceInfo( 0, &g_CancelFaceData );
+  }
+  else
+  {
+    *g_pPatch = g_CancelPatch;
+    g_pPatch->bDirty = true;
+    g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );
+  }
+  // do not call destroy, decref it
+  g_pToolWnd->DecRef();
+  g_pToolWnd = NULL;
+}
+
+static void DoExpose ()
+{
+  int i,j;
+
+  g_2DView.PreparePaint();
+  g_QglTable.m_pfn_qglColor3f(1, 1, 1);
+  // draw the texture background
+  g_QglTable.m_pfn_qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+  if (!g_bPatch)
+  {
+    g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, g_SelectedFaceTable.m_pfnGetTextureNumber(0) );
+  }
+  else
+  {
+    g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, g_pPatch->d_texture->texture_number );
+  }
+
+  g_QglTable.m_pfn_qglEnable( GL_TEXTURE_2D );
+  g_QglTable.m_pfn_qglBegin( GL_QUADS );
+  g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Mins[0], g_2DView.m_Mins[1] );
+  g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Mins[0], g_2DView.m_Mins[1] );
+  g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Maxs[0], g_2DView.m_Mins[1] );
+  g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Maxs[0], g_2DView.m_Mins[1] );
+  g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Maxs[0], g_2DView.m_Maxs[1] );
+  g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Maxs[0], g_2DView.m_Maxs[1] );
+  g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Mins[0], g_2DView.m_Maxs[1] );
+  g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Mins[0], g_2DView.m_Maxs[1] );
+  g_QglTable.m_pfn_qglEnd();
+  g_QglTable.m_pfn_qglDisable( GL_TEXTURE_2D );
+
+  if (!g_bPatch)
+  {
+    g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP );
+    for ( i=0; i<g_NumPoints; i++ )
+    {
+      g_QglTable.m_pfn_qglVertex2f( g_WorkWinding.data[i][0], g_WorkWinding.data[i][1] );
+    }
+    g_QglTable.m_pfn_qglEnd();
+  }
+  else
+  {
+    g_QglTable.m_pfn_qglBegin( GL_LINES );
+    for ( i=0; i<g_pPatch->width; i++ )
+      for ( j=0; j<g_pPatch->height; j++ )
+      {
+       if ( i < g_pPatch->width-1 )
+       {
+         g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j].st[0], g_WorkPatch.ctrl[i][j].st[1] );
+         g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i+1][j].st[0], g_WorkPatch.ctrl[i+1][j].st[1] );
+       }
+
+       if ( j < g_pPatch->height-1 )
+       {
+         g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j].st[0], g_WorkPatch.ctrl[i][j].st[1] );
+         g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j+1].st[0], g_WorkPatch.ctrl[i][j+1].st[1] );
+       }
+      }
+    g_QglTable.m_pfn_qglEnd();
+  }
+
+  // let the control points manager render
+  g_pManager->Render( );
+}
+
+static bool CanProcess ()
+{
+  if (!g_bTexViewReady && !g_bClosing)
+  {
+    InitTexView (g_pToolWnd);
+
+    if (!g_bTexViewReady)
+    {
+      g_bClosing = true;
+      DoMessageBox ("You must have brush primitives activated in your project settings and\n"
+                    "have a patch or a single face selected to use the TexTool plugin.\n"
+                    "See plugins/TexToolHelp for documentation.", "TexTool plugin", MB_ICONERROR | MB_OK);
+      // decref, this will destroy
+      g_pToolWnd->DecRef();
+      g_pToolWnd = NULL;
+      return 0;
+    }
+    else
+      g_bClosing = false;
+  }
+  else if (!g_bTexViewReady && g_bClosing)
+  {
+    return 0;
+  }
+
+  return 1;
+}
+
+#if 0
+static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+  if (CanProcess ())
+  {
+    switch (event->button)
+    {
+    case 1:
+      g_pManager->OnLButtonDown (event->x, event->y); break;
+    case 3:
+      g_2DView.OnRButtonDown (event->x, event->y); break;
+    }
+  }
+}
+
+static void button_release (GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+  if (CanProcess ())
+  {
+    switch (event->button)
+    {
+    case 1:
+      g_pManager->OnLButtonUp (event->x, event->y); break;
+    case 3:
+      g_2DView.OnRButtonUp (event->x, event->y); break;
+    }
+  }
+}
+
+static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data)
+{
+  if (CanProcess ())
+  {
+    if (g_2DView.OnMouseMove (event->x, event->y))
+      return;
+
+    if (g_pManager->OnMouseMove (event->x, event->y))
+      return;
+  }
+}
+
+static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data)
+{
+  if (event->count > 0)
+    return TRUE;
+
+  if (!CanProcess ())
+    return TRUE;
+
+  if (g_bTexViewReady)
+  {
+    g_2DView.m_rect.bottom = widget->allocation.height;
+    g_2DView.m_rect.right = widget->allocation.width;
+
+    if (!g_QglTable.m_pfn_glwidget_make_current (g_pToolWidget))
+    {
+      Sys_Printf("TexTool: glMakeCurrent failed\n");
+      return TRUE;
+    }
+
+    DoExpose ();
+
+    g_QglTable.m_pfn_glwidget_swap_buffers (g_pToolWidget);
+  }
+
+  return TRUE;
+}
+
+static gint keypress (GtkWidget* widget, GdkEventKey* event, gpointer data)
+{
+  unsigned int code = gdk_keyval_to_upper(event->keyval);
+
+  if (code == GDK_Escape)
+  {
+    gtk_widget_destroy (g_pToolWnd);
+    g_pToolWnd = NULL;
+    return TRUE;
+  }
+
+  if (CanProcess ())
+  {
+    if (g_2DView.OnKeyDown (code))
+      return FALSE;
+
+    if (code == GDK_Return)
+    {
+      Textool_Validate();
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+static gint close (GtkWidget *widget, GdkEvent* event, gpointer data)
+{
+  gtk_widget_destroy (widget);
+  g_pToolWnd = NULL;
+
+  return TRUE;
+}
+
+static GtkWidget* CreateOpenGLWidget ()
+{
+  g_pToolWidget = g_QglTable.m_pfn_glwidget_new (FALSE, g_QglTable.m_pfn_GetQeglobalsGLWidget ());
+
+  gtk_widget_set_events (g_pToolWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK |
+                        GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
+
+  // Connect signal handlers
+  gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL);
+  gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "motion_notify_event",
+                     GTK_SIGNAL_FUNC (motion), NULL);
+  gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "button_press_event",
+                     GTK_SIGNAL_FUNC (button_press), NULL);
+  gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "button_release_event",
+                     GTK_SIGNAL_FUNC (button_release), NULL);
+
+  gtk_signal_connect (GTK_OBJECT (g_pToolWnd), "delete_event", GTK_SIGNAL_FUNC (close), NULL);
+  gtk_signal_connect (GTK_OBJECT (g_pToolWnd), "key_press_event",
+                     GTK_SIGNAL_FUNC (keypress), NULL);
+
+  return g_pToolWidget;
+}
+#endif
+
+#if 0
+static void DoPaint ()
+{
+  if (!CanProcess ())
+    return;
+  
+  if (g_bTexViewReady)
+  {
+    g_2DView.m_rect.bottom = g_pToolWnd->getHeight();
+    g_2DView.m_rect.right = g_pToolWnd->getWidth();
+    
+    // set GL_PROJECTION
+    g_2DView.PreparePaint();
+    // render the objects
+    // the master is not rendered the same way, draw over a unified texture background
+    g_2DView.TextureBackground(g_DrawObjects[0].pObject->getTextureNumber());
+    if (g_nDrawObjects >= 1)
+    {
+      int i;
+      for (i=1;i<g_nDrawObjects;i++)
+      {
+        // we use a first step to the GL_MODELVIEW for the master object
+        // GL_MODELVIEW will be altered in RenderAuxiliary too
+        g_DrawObjects[0].pObject->PrepareModelView(g_DrawObjects[i].pTopo);
+        g_DrawObjects[i].pObject->RenderAuxiliary();
+      }
+    }
+    // draw the polygon outline and control points
+    g_DrawObjects[0].pObject->PrepareModelView(NULL);
+    g_DrawObjects[0].pObject->RenderUI();
+  }
+}
+#endif
+
+bool CWindowListener::OnLButtonDown(guint32 nFlags, double x, double y)
+{
+  if (CanProcess())
+  {
+    g_pManager->OnLButtonDown((int)x, (int)y);
+    return true;
+  }
+  return false;
+}
+
+bool CWindowListener::OnRButtonDown(guint32 nFlags, double x, double y)
+{
+  if (CanProcess())
+  {
+    g_2DView.OnRButtonDown ((int)x, (int)y);
+    return true;
+  }
+  return false;
+}
+
+bool CWindowListener::OnLButtonUp(guint32 nFlags, double x, double y)
+{
+  if (CanProcess())
+  {
+    g_pManager->OnLButtonUp((int)x, (int)y);
+    return true;
+  }
+  return false;
+}
+
+bool CWindowListener::OnRButtonUp(guint32 nFlags, double x, double y)
+{
+  if (CanProcess())
+  {
+    g_2DView.OnRButtonUp ((int)x, (int)y);
+    return true;
+  }
+  return false;
+}
+
+bool CWindowListener::OnMouseMove(guint32 nFlags, double x, double y)
+{
+  if (CanProcess ())
+  {
+    if (g_2DView.OnMouseMove ((int)x, (int)y))
+      return true;
+
+    g_pManager->OnMouseMove((int)x, (int)y);
+    return true;
+  }
+  return false;
+}
+
+// the widget is closing
+void CWindowListener::Close()
+{
+  g_pToolWnd = NULL;
+}
+
+bool CWindowListener::Paint()
+{
+  if (!CanProcess ())
+    return false;
+
+  if (g_bTexViewReady)
+    DoExpose();
+
+  return true;
+}
+
+bool CWindowListener::OnKeyPressed(char *s)
+{
+  if (!strcmp(s,"Escape"))
+  {
+    Textool_Cancel();
+    return TRUE;
+  }
+  if (CanProcess ())
+  {
+    if (g_2DView.OnKeyDown (s))
+      return TRUE;
+
+    if (!strcmp(s,"Return"))
+    {
+      Textool_Validate();
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush)
+{
+  #if 0
+  // if it's the first call, perhaps we need some additional init steps
+  if (!g_bQglInitDone)
+  {
+    g_QglTable.m_nSize = sizeof(_QERQglTable);
+    if ( g_FuncTable.m_pfnRequestInterface( QERQglTable_GUID, static_cast<LPVOID>(&g_QglTable) ) )
+    {
+      g_bQglInitDone = true;
+    }
+    else
+    {
+      Sys_Printf("TexTool plugin: _QERQglTable interface request failed\n");
+      return;
+    }
+  }
+
+  if (!g_bSelectedFaceInitDone)
+  {
+    g_SelectedFaceTable.m_nSize = sizeof(_QERSelectedFaceTable);
+    if (g_FuncTable.m_pfnRequestInterface (QERSelectedFaceTable_GUID,
+                                          static_cast<LPVOID>(&g_SelectedFaceTable)))
+    {
+      g_bSelectedFaceInitDone = true;
+    }
+    else
+    {
+      Sys_Printf("TexTool plugin: _QERSelectedFaceTable interface request failed\n");
+      return;
+    }
+  }
+
+  if (!g_bSurfaceTableInitDone)
+  {
+    g_SurfaceTable.m_nSize = sizeof(_QERAppSurfaceTable);
+    if ( g_FuncTable.m_pfnRequestInterface( QERAppSurfaceTable_GUID, static_cast<LPVOID>(&g_SurfaceTable) ) )
+    {
+      g_bSurfaceTableInitDone = true;
+    }
+    else
+    {
+      Sys_Printf("TexTool plugin: _QERAppSurfaceTable interface request failed\n");
+      return;
+    }
+  }
+
+  if (!g_bUITable)
+  {
+    g_UITable.m_nSize = sizeof(_QERUITable);
+    if ( g_FuncTable.m_pfnRequestInterface( QERUI_GUID, static_cast<LPVOID>(&g_UITable) ) )
+    {
+      g_bUITable = true;
+    }
+    else
+    {
+      Sys_Printf("TexTool plugin: _QERUITable interface request failed\n");
+      return;
+    }
+  }
+  #endif
+
+  if (!strcmp(p, "About..."))
+  {
+    DoMessageBox (PLUGIN_ABOUT, "About ...", MB_OK );
+  }
+  else if (!strcmp(p, "Go..."))
+  {
+    if (!g_pToolWnd)
+    {
+      g_pToolWnd = g_UITable.m_pfnCreateGLWindow();
+      g_pToolWnd->setSizeParm(300,300);
+      g_pToolWnd->setName("TexTool");
+      // g_Listener is a static class, we need to bump the refCount to avoid premature release problems
+      g_Listen.IncRef();
+      // setListener will incRef on the listener too
+      g_pToolWnd->setListener(&g_Listen);
+      if (!g_pToolWnd->Show())
+      {
+        DoMessageBox ("Error creating texture tools window!", "TexTool plugin", MB_ICONERROR | MB_OK);
+        return;
+      }
+    }
+    
+    g_bTexViewReady = false;
+    g_bClosing = false;
+  }
+  else if (!strcmp(p, "Help..."))
+  {
+    if (!g_bHelp)
+      DoMessageBox ("Select a brush face (ctrl+shift+left mouse) or a patch, and hit Go...\n"
+                   "See tutorials for more", "TexTool plugin", MB_OK );
+    else
+      DoMessageBox ("Are you kidding me ?", "TexTool plugin", MB_OK );
+    g_bHelp = true;
+  }
+}
+
+// =============================================================================
+// SYNAPSE
+
+CSynapseServer* g_pSynapseServer = NULL;
+CSynapseClientTexTool g_SynapseClient;
+
+#if __GNUC__ >= 4
+#pragma GCC visibility push(default)
+#endif
+extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( const char *version, CSynapseServer *pServer ) {
+#if __GNUC__ >= 4
+#pragma GCC visibility pop
+#endif
+  if (strcmp(version, SYNAPSE_VERSION))
+  {
+    Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version);
+    return NULL;
+  }
+  g_pSynapseServer = pServer;
+  g_pSynapseServer->IncRef();
+  Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf());
+  
+  g_SynapseClient.AddAPI(PLUGIN_MAJOR, "textool", sizeof(_QERPluginTable));  
+  g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable);
+  g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(g_QglTable), SYN_REQUIRE, &g_QglTable);
+  g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(g_SelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable);
+  
+  return &g_SynapseClient;
+}
+
+bool CSynapseClientTexTool::RequestAPI(APIDescriptor_t *pAPI)
+{
+  if (!strcmp(pAPI->major_name, PLUGIN_MAJOR))
+  {
+    _QERPluginTable *pTable = static_cast<_QERPluginTable*>(pAPI->mpTable);
+    pTable->m_pfnQERPlug_Init = QERPlug_Init;
+    pTable->m_pfnQERPlug_GetName = QERPlug_GetName;
+    pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList;
+    pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch;
+    return true;
+  }
+
+  Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo());
+  return false;
+}
+
+#include "version.h"
+
+const char* CSynapseClientTexTool::GetInfo()
+{
+  return "Texture Tools plugin built " __DATE__ " " RADIANT_VERSION;
+}