TexTool.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. /*
  2. Copyright (C) 1999-2006 Id Software, Inc. and contributors.
  3. For a list of contributors, see the accompanying CONTRIBUTORS file.
  4. This file is part of GtkRadiant.
  5. GtkRadiant is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. GtkRadiant is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with GtkRadiant; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. */
  17. //-----------------------------------------------------------------------------
  18. //
  19. // DESCRIPTION:
  20. // main plugin implementation
  21. // texturing tools for Radiant
  22. //
  23. #include "StdAfx.h"
  24. static void dialog_button_callback (GtkWidget *widget, gpointer data)
  25. {
  26. GtkWidget *parent;
  27. int *loop, *ret;
  28. parent = gtk_widget_get_toplevel (widget);
  29. loop = (int*)g_object_get_data (G_OBJECT (parent), "loop");
  30. ret = (int*)g_object_get_data (G_OBJECT (parent), "ret");
  31. *loop = 0;
  32. *ret = (int)data;
  33. }
  34. static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data)
  35. {
  36. int *loop;
  37. gtk_widget_hide (widget);
  38. loop = (int*)g_object_get_data (G_OBJECT (widget), "loop");
  39. *loop = 0;
  40. return TRUE;
  41. }
  42. int DoMessageBox (const char* lpText, const char* lpCaption, guint32 uType)
  43. {
  44. GtkWidget *window, *w, *vbox, *hbox;
  45. int mode = (uType & MB_TYPEMASK), ret, loop = 1;
  46. window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  47. gtk_signal_connect (GTK_OBJECT (window), "delete_event",
  48. GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);
  49. gtk_signal_connect (GTK_OBJECT (window), "destroy",
  50. GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);
  51. gtk_window_set_title (GTK_WINDOW (window), lpCaption);
  52. gtk_container_border_width (GTK_CONTAINER (window), 10);
  53. g_object_set_data (G_OBJECT (window), "loop", &loop);
  54. g_object_set_data (G_OBJECT (window), "ret", &ret);
  55. gtk_widget_realize (window);
  56. vbox = gtk_vbox_new (FALSE, 10);
  57. gtk_container_add (GTK_CONTAINER (window), vbox);
  58. gtk_widget_show (vbox);
  59. w = gtk_label_new (lpText);
  60. gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);
  61. gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT);
  62. gtk_widget_show (w);
  63. w = gtk_hseparator_new ();
  64. gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);
  65. gtk_widget_show (w);
  66. hbox = gtk_hbox_new (FALSE, 10);
  67. gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2);
  68. gtk_widget_show (hbox);
  69. if (mode == MB_OK)
  70. {
  71. w = gtk_button_new_with_label ("Ok");
  72. gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
  73. gtk_signal_connect (GTK_OBJECT (w), "clicked",
  74. GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));
  75. GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
  76. gtk_widget_grab_default (w);
  77. gtk_widget_show (w);
  78. ret = IDOK;
  79. }
  80. else if (mode == MB_OKCANCEL)
  81. {
  82. w = gtk_button_new_with_label ("Ok");
  83. gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
  84. gtk_signal_connect (GTK_OBJECT (w), "clicked",
  85. GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));
  86. GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
  87. gtk_widget_grab_default (w);
  88. gtk_widget_show (w);
  89. w = gtk_button_new_with_label ("Cancel");
  90. gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
  91. gtk_signal_connect (GTK_OBJECT (w), "clicked",
  92. GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));
  93. gtk_widget_show (w);
  94. ret = IDCANCEL;
  95. }
  96. else if (mode == MB_YESNOCANCEL)
  97. {
  98. w = gtk_button_new_with_label ("Yes");
  99. gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
  100. gtk_signal_connect (GTK_OBJECT (w), "clicked",
  101. GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES));
  102. GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
  103. gtk_widget_grab_default (w);
  104. gtk_widget_show (w);
  105. w = gtk_button_new_with_label ("No");
  106. gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
  107. gtk_signal_connect (GTK_OBJECT (w), "clicked",
  108. GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO));
  109. gtk_widget_show (w);
  110. w = gtk_button_new_with_label ("Cancel");
  111. gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
  112. gtk_signal_connect (GTK_OBJECT (w), "clicked",
  113. GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));
  114. gtk_widget_show (w);
  115. ret = IDCANCEL;
  116. }
  117. else /* if (mode == MB_YESNO) */
  118. {
  119. w = gtk_button_new_with_label ("Yes");
  120. gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
  121. gtk_signal_connect (GTK_OBJECT (w), "clicked",
  122. GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES));
  123. GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
  124. gtk_widget_grab_default (w);
  125. gtk_widget_show (w);
  126. w = gtk_button_new_with_label ("No");
  127. gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
  128. gtk_signal_connect (GTK_OBJECT (w), "clicked",
  129. GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO));
  130. gtk_widget_show (w);
  131. ret = IDNO;
  132. }
  133. gtk_widget_show (window);
  134. gtk_grab_add (window);
  135. while (loop)
  136. gtk_main_iteration ();
  137. gtk_grab_remove (window);
  138. gtk_widget_destroy (window);
  139. return ret;
  140. }
  141. // Radiant function table
  142. _QERFuncTable_1 g_FuncTable;
  143. // plugin name
  144. const char *PLUGIN_NAME = "Q3 Texture Tools";
  145. // commands in the menu
  146. const char *PLUGIN_COMMANDS = "About...;Go...";
  147. // cast to GtkWidget*
  148. void *g_pMainWnd;
  149. IWindow *g_pToolWnd = NULL; // handle to the window
  150. CWindowListener g_Listen;
  151. // plugin interfaces ---------------------------
  152. bool g_bQglInitDone = false;
  153. OpenGLBinding g_QglTable;
  154. bool g_bSelectedFaceInitDone = false;
  155. _QERSelectedFaceTable g_SelectedFaceTable;
  156. bool g_bUITable = false;
  157. _QERUITable g_UITable;
  158. // selected face -------------------------------
  159. // we use this one to commit / read with Radiant
  160. _QERFaceData g_SelectedFaceData;
  161. // g_pSelectedFaceWindings gets allocated with MAX_POINTS_ON_WINDING at plugin startup ( QERPlug_Init )
  162. winding_t *g_pSelectedFaceWinding = NULL;
  163. const float g_ViewportRatio = 1.2f;
  164. // usefull class to manage the 2D view
  165. C2DView g_2DView;
  166. // control points to move the polygon
  167. CControlPointsManagerBFace g_ControlPointsBFace;
  168. // tells if a face is selected and we have something to render in the TexWindow
  169. bool g_bTexViewReady = false;
  170. // data for texture work
  171. int g_NumPoints;
  172. CtrlPts_t g_WorkWinding;
  173. // reference _QERFaceData we use on Cancel, and for Commit
  174. _QERFaceData g_CancelFaceData;
  175. // patches -------------------------------------
  176. bool g_bPatch = false;
  177. //++timo we use this one to grab selected patchMesh_t
  178. // FIXME: update when there's a real interface to read/write patches
  179. bool g_bSurfaceTableInitDone = false;
  180. _QERAppSurfaceTable g_SurfaceTable;
  181. CControlPointsManagerPatch g_ControlPointsPatch;
  182. // data for texture work
  183. patchMesh_t* g_pPatch;
  184. // we only use ctrl[][].st in this one
  185. patchMesh_t g_WorkPatch;
  186. // copy of initial g_pPatch for Cancel situation
  187. patchMesh_t g_CancelPatch;
  188. // ---------------------------------------------
  189. // holds the manager we are currently using
  190. CControlPointsManager *g_pManager = NULL;
  191. // ---------------------------------------------
  192. // globals flags for user preferences
  193. //++timo TODO: this should be retrieved from the Editor's .INI prefs in a dedicated interface
  194. // update camera view during manipulation ?
  195. bool g_bPrefsUpdateCameraView = true;
  196. // misc ----------------------------------------
  197. bool g_bHelp = false;
  198. //++timo FIXME: used to close the plugin window if InitTexView fails
  199. // it's dirty, only use is to prevent infinite loop in DialogProc
  200. bool g_bClosing = false;
  201. const char *PLUGIN_ABOUT = "Texture Tools for Radiant\n\n"
  202. "Gtk port by Leonardo Zide (leo@lokigames.com)\n"
  203. "Original version by Timothee \"TTimo\" Besset (timo@qeradiant.com)";
  204. extern "C" void* WINAPI QERPlug_GetFuncTable ()
  205. {
  206. return &g_FuncTable;
  207. }
  208. const char* QERPlug_Init (void* hApp, void *pWidget)
  209. {
  210. int size;
  211. GtkWidget* pMainWidget = static_cast<GtkWidget*>(pWidget);
  212. g_pMainWnd = pMainWidget;
  213. memset(&g_FuncTable, 0, sizeof(_QERFuncTable_1));
  214. g_FuncTable.m_nSize = sizeof(_QERFuncTable_1);
  215. size = (int)((winding_t *)0)->points[MAX_POINTS_ON_WINDING];
  216. g_pSelectedFaceWinding = (winding_t *)malloc( size );
  217. memset( g_pSelectedFaceWinding, 0, size );
  218. return "Texture tools for Radiant";
  219. }
  220. const char* QERPlug_GetName()
  221. {
  222. return (char*)PLUGIN_NAME;
  223. }
  224. const char* QERPlug_GetCommandList()
  225. {
  226. return PLUGIN_COMMANDS;
  227. }
  228. char *TranslateString (char *buf)
  229. {
  230. static char buf2[32768];
  231. int i, l;
  232. char *out;
  233. l = strlen(buf);
  234. out = buf2;
  235. for (i=0 ; i<l ; i++)
  236. {
  237. if (buf[i] == '\n')
  238. {
  239. *out++ = '\r';
  240. *out++ = '\n';
  241. }
  242. else
  243. *out++ = buf[i];
  244. }
  245. *out++ = 0;
  246. return buf2;
  247. }
  248. // called by InitTexView to fit the view against the bounding box of control points
  249. void FitView (IWindow* hwndDlg, int TexSize[2])
  250. {
  251. // apply a ratio to get the area we'll draw
  252. g_2DView.m_Center[0] = 0.5f * ( g_2DView.m_Mins[0] + g_2DView.m_Maxs[0] );
  253. g_2DView.m_Center[1] = 0.5f * ( g_2DView.m_Mins[1] + g_2DView.m_Maxs[1] );
  254. g_2DView.m_Mins[0] = g_2DView.m_Center[0] + g_ViewportRatio*( g_2DView.m_Mins[0] - g_2DView.m_Center[0] );
  255. g_2DView.m_Mins[1] = g_2DView.m_Center[1] + g_ViewportRatio*( g_2DView.m_Mins[1] - g_2DView.m_Center[1] );
  256. g_2DView.m_Maxs[0] = g_2DView.m_Center[0] + g_ViewportRatio*( g_2DView.m_Maxs[0] - g_2DView.m_Center[0] );
  257. g_2DView.m_Maxs[1] = g_2DView.m_Center[1] + g_ViewportRatio*( g_2DView.m_Maxs[1] - g_2DView.m_Center[1] );
  258. g_2DView.m_rect.left = 0;
  259. g_2DView.m_rect.top = 0;
  260. g_2DView.m_rect.bottom = hwndDlg->getHeight();
  261. g_2DView.m_rect.right = hwndDlg->getWidth();
  262. // we need to draw this area, now compute a bigger area so the texture scale is the same along X and Y
  263. // compute box shape in XY space, let's say X <-> S we'll get a ratio for Y:
  264. if (!g_bPatch)
  265. {
  266. g_SelectedFaceTable.m_pfnGetTextureSize( 0, TexSize );
  267. }
  268. else
  269. {
  270. TexSize[0] = g_pPatch->d_texture->width;
  271. TexSize[1] = g_pPatch->d_texture->height;
  272. }
  273. // we want a texture with the same X / Y ratio
  274. // compute XY space / window size ratio
  275. float SSize = (float)fabs( g_2DView.m_Maxs[0] - g_2DView.m_Mins[0] );
  276. float TSize = (float)fabs( g_2DView.m_Maxs[1] - g_2DView.m_Mins[1] );
  277. float XSize = TexSize[0] * SSize;
  278. float YSize = TexSize[1] * TSize;
  279. float RatioX = XSize / (float)abs( g_2DView.m_rect.left - g_2DView.m_rect.right );
  280. float RatioY = YSize / (float)abs( g_2DView.m_rect.top - g_2DView.m_rect.bottom );
  281. if ( RatioX > RatioY )
  282. {
  283. YSize = (float)abs( g_2DView.m_rect.top - g_2DView.m_rect.bottom ) * RatioX;
  284. TSize = YSize / (float)TexSize[1];
  285. }
  286. else
  287. {
  288. XSize = (float)abs( g_2DView.m_rect.left - g_2DView.m_rect.right ) * RatioY;
  289. SSize = XSize / (float)TexSize[0];
  290. }
  291. g_2DView.m_Mins[0] = g_2DView.m_Center[0] - 0.5f * SSize;
  292. g_2DView.m_Maxs[0] = g_2DView.m_Center[0] + 0.5f * SSize;
  293. g_2DView.m_Mins[1] = g_2DView.m_Center[1] - 0.5f * TSize;
  294. g_2DView.m_Maxs[1] = g_2DView.m_Center[1] + 0.5f * TSize;
  295. }
  296. // call this one each time we need to re-init
  297. //++timo TODO: re-init objects state, g_2DView and g_ControlPointsManager
  298. void InitTexView( IWindow* hwndDlg )
  299. {
  300. // size of the texture we are working on
  301. int TexSize[2];
  302. g_bTexViewReady = false;
  303. if (g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 0)
  304. {
  305. g_SelectedFaceTable.m_pfnGetFaceInfo( 0, &g_SelectedFaceData, g_pSelectedFaceWinding );
  306. g_bPatch = false;
  307. int i;
  308. // we have something selected
  309. // setup: compute BBox for the winding ( in ST space )
  310. //++timo FIXME: move this in a C2DView member ? used as well for patches
  311. g_2DView.m_Mins[0] = +9999.0f; g_2DView.m_Mins[1] = +9999.0f;
  312. g_2DView.m_Maxs[0] = -9999.0f; g_2DView.m_Maxs[1] = -9999.0f;
  313. for ( i=0; i<g_pSelectedFaceWinding->numpoints; i++ )
  314. {
  315. if ( g_pSelectedFaceWinding->points[i][3] < g_2DView.m_Mins[0] )
  316. g_2DView.m_Mins[0] = g_pSelectedFaceWinding->points[i][3];
  317. if ( g_pSelectedFaceWinding->points[i][3] > g_2DView.m_Maxs[0] )
  318. g_2DView.m_Maxs[0] = g_pSelectedFaceWinding->points[i][3];
  319. if ( g_pSelectedFaceWinding->points[i][4] < g_2DView.m_Mins[1] )
  320. g_2DView.m_Mins[1] = g_pSelectedFaceWinding->points[i][4];
  321. if ( g_pSelectedFaceWinding->points[i][4] > g_2DView.m_Maxs[1] )
  322. g_2DView.m_Maxs[1] = g_pSelectedFaceWinding->points[i][4];
  323. }
  324. // NOTE: FitView will read and init TexSize
  325. FitView( hwndDlg, TexSize );
  326. // now init the work tables
  327. g_NumPoints = g_pSelectedFaceWinding->numpoints;
  328. for ( i=0; i<g_NumPoints; i++ )
  329. {
  330. g_WorkWinding.data[i][0] = g_pSelectedFaceWinding->points[i][3];
  331. g_WorkWinding.data[i][1] = g_pSelectedFaceWinding->points[i][4];
  332. }
  333. g_ControlPointsBFace.Init( g_NumPoints, &g_WorkWinding, &g_2DView, TexSize, &g_SelectedFaceData, &g_QglTable );
  334. // init snap-to-grid
  335. float fTexStep[2];
  336. fTexStep[0] = 1.0f / float(TexSize[0]);
  337. fTexStep[1] = 1.0f / float(TexSize[1]);
  338. g_2DView.SetGrid( fTexStep[0], fTexStep[1] );
  339. g_pManager = &g_ControlPointsBFace;
  340. // prepare the "Cancel" data
  341. memcpy( &g_CancelFaceData, &g_SelectedFaceData, sizeof(_QERFaceData) );
  342. // we are done
  343. g_bTexViewReady = true;
  344. }
  345. else if ( g_SurfaceTable.m_pfnAnyPatchesSelected())
  346. {
  347. g_pPatch = g_SurfaceTable.m_pfnGetSelectedPatch();
  348. g_bPatch = true;
  349. int i,j;
  350. // compute BBox for all patch points
  351. g_2DView.m_Mins[0] = +9999.0f; g_2DView.m_Mins[1] = +9999.0f;
  352. g_2DView.m_Maxs[0] = -9999.0f; g_2DView.m_Maxs[1] = -9999.0f;
  353. for ( i=0; i<g_pPatch->width; i++ )
  354. {
  355. for ( j=0; j<g_pPatch->height; j++ )
  356. {
  357. if ( g_pPatch->ctrl[i][j].st[0] < g_2DView.m_Mins[0] )
  358. g_2DView.m_Mins[0] = g_pPatch->ctrl[i][j].st[0];
  359. if ( g_pPatch->ctrl[i][j].st[0] > g_2DView.m_Maxs[0] )
  360. g_2DView.m_Maxs[0] = g_pPatch->ctrl[i][j].st[0];
  361. if ( g_pPatch->ctrl[i][j].st[1] < g_2DView.m_Mins[1] )
  362. g_2DView.m_Mins[1] = g_pPatch->ctrl[i][j].st[1];
  363. if ( g_pPatch->ctrl[i][j].st[1] > g_2DView.m_Maxs[1] )
  364. g_2DView.m_Maxs[1] = g_pPatch->ctrl[i][j].st[1];
  365. }
  366. }
  367. FitView( hwndDlg, TexSize);
  368. // init the work tables
  369. g_WorkPatch = *g_pPatch;
  370. g_ControlPointsPatch.Init( &g_WorkPatch, &g_2DView, &g_QglTable, g_pPatch );
  371. // init snap-to-grid
  372. float fTexStep[2];
  373. fTexStep[0] = 1.0f / float(TexSize[0]);
  374. fTexStep[1] = 1.0f / float(TexSize[1]);
  375. g_2DView.SetGrid( fTexStep[0], fTexStep[1] );
  376. g_pManager = &g_ControlPointsPatch;
  377. // prepare the "cancel" data
  378. g_CancelPatch = *g_pPatch;
  379. // we are done
  380. g_bTexViewReady = true;
  381. }
  382. }
  383. void Textool_Validate()
  384. {
  385. // validate current situation into the main view
  386. g_pManager->Commit( );
  387. // for a brush face we have an aditionnal step
  388. if (!g_bPatch)
  389. {
  390. // tell Radiant to update (will also send update windows messages )
  391. g_SelectedFaceTable.m_pfnSetFaceInfo( 0, &g_SelectedFaceData );
  392. }
  393. else
  394. {
  395. // ask to rebuild the patch display data
  396. g_pPatch->bDirty = true;
  397. // send a repaint to the camera window as well
  398. g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );
  399. }
  400. // we'll need to update after that as well:
  401. g_bTexViewReady = false;
  402. // send a repaint message
  403. g_pToolWnd->Redraw ();
  404. }
  405. void Textool_Cancel()
  406. {
  407. if (!g_bPatch)
  408. {
  409. // tell Radiant to update (will also send update windows messages )
  410. g_SelectedFaceTable.m_pfnSetFaceInfo( 0, &g_CancelFaceData );
  411. }
  412. else
  413. {
  414. *g_pPatch = g_CancelPatch;
  415. g_pPatch->bDirty = true;
  416. g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA );
  417. }
  418. // do not call destroy, decref it
  419. g_pToolWnd->DecRef();
  420. g_pToolWnd = NULL;
  421. }
  422. static void DoExpose ()
  423. {
  424. int i,j;
  425. g_2DView.PreparePaint();
  426. g_QglTable.m_pfn_qglColor3f(1, 1, 1);
  427. // draw the texture background
  428. g_QglTable.m_pfn_qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
  429. if (!g_bPatch)
  430. {
  431. g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, g_SelectedFaceTable.m_pfnGetTextureNumber(0) );
  432. }
  433. else
  434. {
  435. g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, g_pPatch->d_texture->texture_number );
  436. }
  437. g_QglTable.m_pfn_qglEnable( GL_TEXTURE_2D );
  438. g_QglTable.m_pfn_qglBegin( GL_QUADS );
  439. g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Mins[0], g_2DView.m_Mins[1] );
  440. g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Mins[0], g_2DView.m_Mins[1] );
  441. g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Maxs[0], g_2DView.m_Mins[1] );
  442. g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Maxs[0], g_2DView.m_Mins[1] );
  443. g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Maxs[0], g_2DView.m_Maxs[1] );
  444. g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Maxs[0], g_2DView.m_Maxs[1] );
  445. g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Mins[0], g_2DView.m_Maxs[1] );
  446. g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Mins[0], g_2DView.m_Maxs[1] );
  447. g_QglTable.m_pfn_qglEnd();
  448. g_QglTable.m_pfn_qglDisable( GL_TEXTURE_2D );
  449. if (!g_bPatch)
  450. {
  451. g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP );
  452. for ( i=0; i<g_NumPoints; i++ )
  453. {
  454. g_QglTable.m_pfn_qglVertex2f( g_WorkWinding.data[i][0], g_WorkWinding.data[i][1] );
  455. }
  456. g_QglTable.m_pfn_qglEnd();
  457. }
  458. else
  459. {
  460. g_QglTable.m_pfn_qglBegin( GL_LINES );
  461. for ( i=0; i<g_pPatch->width; i++ )
  462. for ( j=0; j<g_pPatch->height; j++ )
  463. {
  464. if ( i < g_pPatch->width-1 )
  465. {
  466. g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j].st[0], g_WorkPatch.ctrl[i][j].st[1] );
  467. g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i+1][j].st[0], g_WorkPatch.ctrl[i+1][j].st[1] );
  468. }
  469. if ( j < g_pPatch->height-1 )
  470. {
  471. g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j].st[0], g_WorkPatch.ctrl[i][j].st[1] );
  472. g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j+1].st[0], g_WorkPatch.ctrl[i][j+1].st[1] );
  473. }
  474. }
  475. g_QglTable.m_pfn_qglEnd();
  476. }
  477. // let the control points manager render
  478. g_pManager->render( );
  479. }
  480. static bool CanProcess ()
  481. {
  482. if (!g_bTexViewReady && !g_bClosing)
  483. {
  484. InitTexView (g_pToolWnd);
  485. if (!g_bTexViewReady)
  486. {
  487. g_bClosing = true;
  488. DoMessageBox ("You must have brush primitives activated in your project settings and\n"
  489. "have a patch or a single face selected to use the TexTool plugin.\n"
  490. "See plugins/TexToolHelp for documentation.", "TexTool plugin", MB_ICONERROR | MB_OK);
  491. // decref, this will destroy
  492. g_pToolWnd->DecRef();
  493. g_pToolWnd = NULL;
  494. return 0;
  495. }
  496. else
  497. g_bClosing = false;
  498. }
  499. else if (!g_bTexViewReady && g_bClosing)
  500. {
  501. return 0;
  502. }
  503. return 1;
  504. }
  505. #if 0
  506. static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data)
  507. {
  508. if (CanProcess ())
  509. {
  510. switch (event->button)
  511. {
  512. case 1:
  513. g_pManager->OnLButtonDown (event->x, event->y); break;
  514. case 3:
  515. g_2DView.OnRButtonDown (event->x, event->y); break;
  516. }
  517. }
  518. }
  519. static void button_release (GtkWidget *widget, GdkEventButton *event, gpointer data)
  520. {
  521. if (CanProcess ())
  522. {
  523. switch (event->button)
  524. {
  525. case 1:
  526. g_pManager->OnLButtonUp (event->x, event->y); break;
  527. case 3:
  528. g_2DView.OnRButtonUp (event->x, event->y); break;
  529. }
  530. }
  531. }
  532. static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data)
  533. {
  534. if (CanProcess ())
  535. {
  536. if (g_2DView.OnMouseMove (event->x, event->y))
  537. return;
  538. if (g_pManager->OnMouseMove (event->x, event->y))
  539. return;
  540. }
  541. }
  542. static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data)
  543. {
  544. if (event->count > 0)
  545. return TRUE;
  546. if (!CanProcess ())
  547. return TRUE;
  548. if (g_bTexViewReady)
  549. {
  550. g_2DView.m_rect.bottom = widget->allocation.height;
  551. g_2DView.m_rect.right = widget->allocation.width;
  552. if (!g_QglTable.m_pfn_glwidget_make_current (g_pToolWidget))
  553. {
  554. Sys_Printf("TexTool: glMakeCurrent failed\n");
  555. return TRUE;
  556. }
  557. DoExpose ();
  558. g_QglTable.m_pfn_glwidget_swap_buffers (g_pToolWidget);
  559. }
  560. return TRUE;
  561. }
  562. static gint keypress (GtkWidget* widget, GdkEventKey* event, gpointer data)
  563. {
  564. unsigned int code = gdk_keyval_to_upper(event->keyval);
  565. if (code == GDK_Escape)
  566. {
  567. gtk_widget_destroy (g_pToolWnd);
  568. g_pToolWnd = NULL;
  569. return TRUE;
  570. }
  571. if (CanProcess ())
  572. {
  573. if (g_2DView.OnKeyDown (code))
  574. return FALSE;
  575. if (code == GDK_Return)
  576. {
  577. Textool_Validate();
  578. return FALSE;
  579. }
  580. }
  581. return TRUE;
  582. }
  583. static gint close (GtkWidget *widget, GdkEvent* event, gpointer data)
  584. {
  585. gtk_widget_destroy (widget);
  586. g_pToolWnd = NULL;
  587. return TRUE;
  588. }
  589. static GtkWidget* CreateOpenGLWidget ()
  590. {
  591. g_pToolWidget = g_QglTable.m_pfn_glwidget_new (FALSE, g_QglTable.m_pfn_GetQeglobalsGLWidget ());
  592. gtk_widget_set_events (g_pToolWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK |
  593. GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
  594. // Connect signal handlers
  595. gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL);
  596. gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "motion_notify_event",
  597. GTK_SIGNAL_FUNC (motion), NULL);
  598. gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "button_press_event",
  599. GTK_SIGNAL_FUNC (button_press), NULL);
  600. gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "button_release_event",
  601. GTK_SIGNAL_FUNC (button_release), NULL);
  602. gtk_signal_connect (GTK_OBJECT (g_pToolWnd), "delete_event", GTK_SIGNAL_FUNC (close), NULL);
  603. gtk_signal_connect (GTK_OBJECT (g_pToolWnd), "key_press_event",
  604. GTK_SIGNAL_FUNC (keypress), NULL);
  605. return g_pToolWidget;
  606. }
  607. #endif
  608. #if 0
  609. static void DoPaint ()
  610. {
  611. if (!CanProcess ())
  612. return;
  613. if (g_bTexViewReady)
  614. {
  615. g_2DView.m_rect.bottom = g_pToolWnd->getHeight();
  616. g_2DView.m_rect.right = g_pToolWnd->getWidth();
  617. // set GL_PROJECTION
  618. g_2DView.PreparePaint();
  619. // render the objects
  620. // the master is not rendered the same way, draw over a unified texture background
  621. g_2DView.TextureBackground(g_DrawObjects[0].pObject->getTextureNumber());
  622. if (g_nDrawObjects >= 1)
  623. {
  624. int i;
  625. for (i=1;i<g_nDrawObjects;i++)
  626. {
  627. // we use a first step to the GL_MODELVIEW for the master object
  628. // GL_MODELVIEW will be altered in RenderAuxiliary too
  629. g_DrawObjects[0].pObject->PrepareModelView(g_DrawObjects[i].pTopo);
  630. g_DrawObjects[i].pObject->RenderAuxiliary();
  631. }
  632. }
  633. // draw the polygon outline and control points
  634. g_DrawObjects[0].pObject->PrepareModelView(NULL);
  635. g_DrawObjects[0].pObject->RenderUI();
  636. }
  637. }
  638. #endif
  639. bool CWindowListener::OnLButtonDown(guint32 nFlags, double x, double y)
  640. {
  641. if (CanProcess())
  642. {
  643. g_pManager->OnLButtonDown((int)x, (int)y);
  644. return true;
  645. }
  646. return false;
  647. }
  648. bool CWindowListener::OnRButtonDown(guint32 nFlags, double x, double y)
  649. {
  650. if (CanProcess())
  651. {
  652. g_2DView.OnRButtonDown ((int)x, (int)y);
  653. return true;
  654. }
  655. return false;
  656. }
  657. bool CWindowListener::OnLButtonUp(guint32 nFlags, double x, double y)
  658. {
  659. if (CanProcess())
  660. {
  661. g_pManager->OnLButtonUp((int)x, (int)y);
  662. return true;
  663. }
  664. return false;
  665. }
  666. bool CWindowListener::OnRButtonUp(guint32 nFlags, double x, double y)
  667. {
  668. if (CanProcess())
  669. {
  670. g_2DView.OnRButtonUp ((int)x, (int)y);
  671. return true;
  672. }
  673. return false;
  674. }
  675. bool CWindowListener::OnMouseMove(guint32 nFlags, double x, double y)
  676. {
  677. if (CanProcess ())
  678. {
  679. if (g_2DView.OnMouseMove ((int)x, (int)y))
  680. return true;
  681. g_pManager->OnMouseMove((int)x, (int)y);
  682. return true;
  683. }
  684. return false;
  685. }
  686. // the widget is closing
  687. void CWindowListener::Close()
  688. {
  689. g_pToolWnd = NULL;
  690. }
  691. bool CWindowListener::Paint()
  692. {
  693. if (!CanProcess ())
  694. return false;
  695. if (g_bTexViewReady)
  696. DoExpose();
  697. return true;
  698. }
  699. bool CWindowListener::OnKeyPressed(char *s)
  700. {
  701. if (!strcmp(s,"Escape"))
  702. {
  703. Textool_Cancel();
  704. return TRUE;
  705. }
  706. if (CanProcess ())
  707. {
  708. if (g_2DView.OnKeyDown (s))
  709. return TRUE;
  710. if (!strcmp(s,"Return"))
  711. {
  712. Textool_Validate();
  713. return TRUE;
  714. }
  715. }
  716. return FALSE;
  717. }
  718. extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush)
  719. {
  720. #if 0
  721. // if it's the first call, perhaps we need some additional init steps
  722. if (!g_bQglInitDone)
  723. {
  724. g_QglTable.m_nSize = sizeof(OpenGLBinding);
  725. if ( g_FuncTable.m_pfnRequestInterface( QERQglTable_GUID, static_cast<LPVOID>(&g_QglTable) ) )
  726. {
  727. g_bQglInitDone = true;
  728. }
  729. else
  730. {
  731. Sys_Printf("TexTool plugin: OpenGLBinding interface request failed\n");
  732. return;
  733. }
  734. }
  735. if (!g_bSelectedFaceInitDone)
  736. {
  737. g_SelectedFaceTable.m_nSize = sizeof(_QERSelectedFaceTable);
  738. if (g_FuncTable.m_pfnRequestInterface (QERSelectedFaceTable_GUID,
  739. static_cast<LPVOID>(&g_SelectedFaceTable)))
  740. {
  741. g_bSelectedFaceInitDone = true;
  742. }
  743. else
  744. {
  745. Sys_Printf("TexTool plugin: _QERSelectedFaceTable interface request failed\n");
  746. return;
  747. }
  748. }
  749. if (!g_bSurfaceTableInitDone)
  750. {
  751. g_SurfaceTable.m_nSize = sizeof(_QERAppSurfaceTable);
  752. if ( g_FuncTable.m_pfnRequestInterface( QERAppSurfaceTable_GUID, static_cast<LPVOID>(&g_SurfaceTable) ) )
  753. {
  754. g_bSurfaceTableInitDone = true;
  755. }
  756. else
  757. {
  758. Sys_Printf("TexTool plugin: _QERAppSurfaceTable interface request failed\n");
  759. return;
  760. }
  761. }
  762. if (!g_bUITable)
  763. {
  764. g_UITable.m_nSize = sizeof(_QERUITable);
  765. if ( g_FuncTable.m_pfnRequestInterface( QERUI_GUID, static_cast<LPVOID>(&g_UITable) ) )
  766. {
  767. g_bUITable = true;
  768. }
  769. else
  770. {
  771. Sys_Printf("TexTool plugin: _QERUITable interface request failed\n");
  772. return;
  773. }
  774. }
  775. #endif
  776. if (!strcmp(p, "About..."))
  777. {
  778. DoMessageBox (PLUGIN_ABOUT, "About ...", MB_OK );
  779. }
  780. else if (!strcmp(p, "Go..."))
  781. {
  782. if (!g_pToolWnd)
  783. {
  784. g_pToolWnd = g_UITable.m_pfnCreateGLWindow();
  785. g_pToolWnd->setSizeParm(300,300);
  786. g_pToolWnd->setName("TexTool");
  787. // g_Listener is a static class, we need to bump the refCount to avoid premature release problems
  788. g_Listen.IncRef();
  789. // setListener will incRef on the listener too
  790. g_pToolWnd->setListener(&g_Listen);
  791. if (!g_pToolWnd->Show())
  792. {
  793. DoMessageBox ("Error creating texture tools window!", "TexTool plugin", MB_ICONERROR | MB_OK);
  794. return;
  795. }
  796. }
  797. g_bTexViewReady = false;
  798. g_bClosing = false;
  799. }
  800. else if (!strcmp(p, "Help..."))
  801. {
  802. if (!g_bHelp)
  803. DoMessageBox ("Select a brush face (ctrl+shift+left mouse) or a patch, and hit Go...\n"
  804. "See tutorials for more", "TexTool plugin", MB_OK );
  805. else
  806. DoMessageBox ("Are you kidding me ?", "TexTool plugin", MB_OK );
  807. g_bHelp = true;
  808. }
  809. }
  810. // =============================================================================
  811. // SYNAPSE
  812. CSynapseServer* g_pSynapseServer = NULL;
  813. CSynapseClientTexTool g_SynapseClient;
  814. extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer)
  815. {
  816. if (strcmp(version, SYNAPSE_VERSION))
  817. {
  818. Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version);
  819. return NULL;
  820. }
  821. g_pSynapseServer = pServer;
  822. g_pSynapseServer->IncRef();
  823. Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf());
  824. g_SynapseClient.AddAPI(PLUGIN_MAJOR, "textool", sizeof(_QERPluginTable));
  825. g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable);
  826. g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(g_QglTable), SYN_REQUIRE, &g_QglTable);
  827. g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(g_SelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable);
  828. return &g_SynapseClient;
  829. }
  830. bool CSynapseClientTexTool::RequestAPI(APIDescriptor_t *pAPI)
  831. {
  832. if (!strcmp(pAPI->major_name, PLUGIN_MAJOR))
  833. {
  834. _QERPluginTable *pTable = static_cast<_QERPluginTable*>(pAPI->mpTable);
  835. pTable->m_pfnQERPlug_Init = QERPlug_Init;
  836. pTable->m_pfnQERPlug_GetName = QERPlug_GetName;
  837. pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList;
  838. pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch;
  839. return true;
  840. }
  841. Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo());
  842. return false;
  843. }
  844. #include "version.h"
  845. const char* CSynapseClientTexTool::GetInfo()
  846. {
  847. return "Texture Tools plugin built " __DATE__ " " RADIANT_VERSION;
  848. }