2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 HydraToolz by Dominic Clifton - Hydra (Hydra@Hydras-World.com)
48 // =============================================================================
51 _QERFuncTable_1 g_FuncTable;
52 _QERFileSystemTable g_FileSystemTable;
53 _QEREntityTable g_EntityTable;
58 // =============================================================================
59 // Ripped from TexTool.cpp
61 static void dialog_button_callback(ui::Widget widget, gpointer data)
65 auto parent = widget.window();
66 loop = (int *) gtk_object_get_data(GTK_OBJECT(parent), "loop");
67 ret = (int *) gtk_object_get_data(GTK_OBJECT(parent), "ret");
70 *ret = gpointer_to_int(data);
73 static gint dialog_delete_callback(GtkWidget *widget, GdkEvent *event, gpointer data)
77 gtk_widget_hide(widget);
78 loop = (int *) gtk_object_get_data(GTK_OBJECT(widget), "loop");
84 int DoMessageBox(const char *lpText, const char *lpCaption, guint32 uType)
87 int mode = (uType & MB_TYPEMASK), ret, loop = 1;
89 auto window = ui::Window(ui::window_type::TOP);
90 window.connect("delete_event",
91 G_CALLBACK(dialog_delete_callback), NULL);
92 window.connect("destroy",
93 G_CALLBACK(gtk_widget_destroy), NULL);
94 gtk_window_set_title(window, lpCaption);
95 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
96 gtk_object_set_data(GTK_OBJECT(window), "loop", &loop);
97 gtk_object_set_data(GTK_OBJECT(window), "ret", &ret);
98 gtk_widget_realize(window);
100 auto vbox = ui::VBox(FALSE, 10);
104 w = ui::Label(lpText);
105 vbox.pack_start(w, FALSE, FALSE, 2);
106 gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_LEFT);
109 w = gtk_hseparator_new();
110 vbox.pack_start(w, FALSE, FALSE, 2);
113 hbox = ui::HBox(FALSE, 10);
114 vbox.pack_start(hbox, FALSE, FALSE, 2);
118 w = ui::Button("Ok");
119 hbox.pack_start(w, TRUE, TRUE, 0);
121 G_CALLBACK(dialog_button_callback), GINT_TO_POINTER(IDOK));
122 gtk_widget_set_can_default(w, true);
123 gtk_widget_grab_default(w);
126 } else if (mode == MB_OKCANCEL) {
127 w = ui::Button("Ok");
128 hbox.pack_start(w, TRUE, TRUE, 0);
130 G_CALLBACK(dialog_button_callback), GINT_TO_POINTER(IDOK));
131 gtk_widget_set_can_default(w, true);
132 gtk_widget_grab_default(w);
135 w = ui::Button("Cancel");
136 hbox.pack_start(w, TRUE, TRUE, 0);
138 G_CALLBACK(dialog_button_callback), GINT_TO_POINTER(IDCANCEL));
141 } else if (mode == MB_YESNOCANCEL) {
142 w = ui::Button("Yes");
143 hbox.pack_start(w, TRUE, TRUE, 0);
145 G_CALLBACK(dialog_button_callback), GINT_TO_POINTER(IDYES));
146 gtk_widget_set_can_default(w, true);
147 gtk_widget_grab_default(w);
150 w = ui::Button("No");
151 hbox.pack_start(w, TRUE, TRUE, 0);
153 G_CALLBACK(dialog_button_callback), GINT_TO_POINTER(IDNO));
156 w = ui::Button("Cancel");
157 hbox.pack_start(w, TRUE, TRUE, 0);
159 G_CALLBACK(dialog_button_callback), GINT_TO_POINTER(IDCANCEL));
162 } else /* if (mode == MB_YESNO) */
164 w = ui::Button("Yes");
165 hbox.pack_start(w, TRUE, TRUE, 0);
167 G_CALLBACK(dialog_button_callback), GINT_TO_POINTER(IDYES));
168 gtk_widget_set_can_default(w, true);
169 gtk_widget_grab_default(w);
172 w = ui::Button("No");
173 hbox.pack_start(w, TRUE, TRUE, 0);
175 G_CALLBACK(dialog_button_callback), GINT_TO_POINTER(IDNO));
181 gtk_grab_add(window);
184 gtk_main_iteration();
187 gtk_grab_remove(window);
193 // End of rip from TexTool.cpp
195 // =============================================================================
196 // Ripped from cmdlib.cpp
203 void ExtractFilePath(const char *path, char *dest)
207 src = path + strlen(path) - 1;
210 // back up until a \ or the start
212 while (src != path && *(src - 1) != '/' && *(src - 1) != '\\') {
216 memcpy(dest, path, src - path);
217 dest[src - path] = 0;
220 void ExtractFileName(const char *path, char *dest)
224 src = path + strlen(path) - 1;
227 // back up until a \ or the start
229 while (src != path && *(src - 1) != '/'
230 && *(src - 1) != '\\') {
240 void ConvertDOSToUnixName(char *dst, const char *src)
254 // End of rip from cmdlib.cpp
256 // =============================================================================
257 // Actual Plugin Code
259 // get the wad name from the shader name (or an actual wadname) and add to a list of wad names making
260 // sure we don't add duplicates.
262 GSList *AddToWadList(GSList *wadlist, const char *shadername, const char *wad)
264 char tmpstr[QER_MAX_NAMELEN];
266 if (!shadername && !wad) {
271 if (strcmp(shadername, "color") == 0) {
274 ExtractFilePath(shadername, tmpstr);
275 // Sys_Printf("checking: %s\n",shadername);
277 int l = strlen(tmpstr) - 1;
279 if (tmpstr[l] == '/' || tmpstr[l] == '\\') {
282 Sys_Printf("WARNING: Unknown wad file for shader %s\n", shadername);
286 ExtractFileName(tmpstr, tmpstr);
288 wadname = (char *) malloc(strlen(tmpstr) + 5);
289 sprintf(wadname, "%s.wad", tmpstr);
291 wadname = strdup(wad);
294 for (GSList *l = wadlist; l != NULL; l = l->next) {
295 if (string_equal_nocase((char *) l->data, wadname)) {
301 Sys_Printf("Adding Wad File to WAD list: %s (reason: ", wadname);
303 Sys_Printf("see shader \"%s\")\n", shadername);
305 Sys_Printf("already in WAD key. )\n");
307 return (g_slist_append(wadlist, wadname));
310 void UpdateWadKeyPair(void)
314 char wads[2048]; // change to CString usage ?
319 GSList *wadlist = NULL;
322 char cleanwadname[QER_MAX_NAMELEN];
323 const char *actualwad;
326 pEntity = (entity_t *) g_FuncTable.m_pfnGetEntityHandle(0); // get the worldspawn ent
328 Sys_Printf("Searching for in-use wad files...\n");
329 for (pEpair = pEntity->epairs; pEpair != NULL; pEpair = pEpair->next) {
330 if (string_equal_nocase(pEpair->key, "wad")) {
331 strcpy(wads, pEpair->value);
332 ConvertDOSToUnixName(wads, wads);
334 // ok, we got the list of ; delimited wads, now split it into a GSList that contains
335 // just the wad names themselves.
340 p2 = strchr(p1, ';');
342 *p2 = 0; // swap the ; with a null terminator
345 if (strchr(p1, '/') || strchr(p1, '\\')) {
346 ExtractFileName(p1, cleanwadname);
347 wadlist = AddToWadList(wadlist, NULL, cleanwadname);
349 wadlist = AddToWadList(wadlist, NULL, p1);
352 p1 = p2 + 1; // point back to the remainder of the string
354 p1 = NULL; // make it so we exit the loop.
359 // ok, now we have a list of wads in GSList.
360 // now we need to add any new wadfiles (with their paths) to this list
361 // so scan all brushes and see what wads are in use
362 // FIXME: scan brushes only in the region ?
364 break; // we don't need to process any more key/pairs.
368 nb = g_FuncTable.m_pfnAllocateActiveBrushHandles();
369 for (i = 0; i < nb; i++) {
370 b = (brush_t *) g_FuncTable.m_pfnGetActiveBrushHandle(i);
371 if (b->patchBrush) { // patches in halflife ?
372 wadlist = AddToWadList(wadlist, b->pPatch->pShader->getName(), NULL);
374 for (f = b->brush_faces; f; f = f->next) {
375 wadlist = AddToWadList(wadlist, f->pShader->getName(), NULL);
379 g_FuncTable.m_pfnReleaseActiveBrushHandles();
381 nb = g_FuncTable.m_pfnAllocateSelectedBrushHandles();
382 for (i = 0; i < nb; i++) {
383 b = (brush_t *) g_FuncTable.m_pfnGetSelectedBrushHandle(i);
384 if (b->patchBrush) { // patches in halflife ?
385 wadlist = AddToWadList(wadlist, b->pPatch->pShader->getName(), NULL);
387 for (f = b->brush_faces; f; f = f->next) {
388 wadlist = AddToWadList(wadlist, f->pShader->getName(), NULL);
392 g_FuncTable.m_pfnReleaseSelectedBrushHandles();
394 // Now we have a complete list of wadnames (without paths) so we just have to turn this
395 // back to a ; delimited list.
399 if (string_equal_nocase((char *) wadlist->data, "common-hydra.wad")) {
400 Sys_Printf("Skipping radiant-supplied wad file %s\n", (char *) wadlist->data);
406 actualwad = vfsGetFullPath((char *) wadlist->data);
409 strcat(wads, actualwad);
411 Sys_Printf("WARNING: could not locate wad file %s\n", (char *) wadlist->data);
412 strcat(wads, (char *) wadlist->data);
417 wadlist = g_slist_remove(wadlist, wadlist->data);
420 // store the wad list back in the worldspawn.
422 //free(pEpair->value);
423 //pEpair->value = strdup(wads);
424 SetKeyValue(pEntity, "wad", wads);
429 // =============================================================================
430 // PLUGIN INTERFACE STUFF
433 const char *PLUGIN_NAME = "Q3 Texture Tools";
435 // commands in the menu
436 const char *PLUGIN_COMMANDS = "About...;Create/Update WAD keypair";
438 const char *PLUGIN_ABOUT = "HydraToolz for GTKRadiant\n\n"
441 extern "C" void *WINAPI
443 QERPlug_GetFuncTable()
448 const char *QERPlug_Init(void *hApp, void *pWidget)
450 GtkWidget *pMainWidget = static_cast<GtkWidget *>( pWidget );
452 g_pMainWnd = pMainWidget;
453 memset(&g_FuncTable, 0, sizeof(_QERFuncTable_1));
454 g_FuncTable.m_nSize = sizeof(_QERFuncTable_1);
455 return "HydraToolz for GTKRadiant"; // do we need this ? hmmm
458 const char *QERPlug_GetName()
460 return (char *) PLUGIN_NAME;
463 const char *QERPlug_GetCommandList()
465 return PLUGIN_COMMANDS;
468 extern "C" void QERPlug_Dispatch(const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush)
470 if (!strcmp(p, "Create/Update WAD keypair")) {
472 } else if (!strcmp(p, "About...")) {
473 g_FuncTable.m_pfnMessageBox((GtkWidget *) NULL, PLUGIN_ABOUT, "About", eMB_OK);
477 // =============================================================================
480 CSynapseServer *g_pSynapseServer = NULL;
481 CSynapseClientHydraToolz g_SynapseClient;
483 extern "C" CSynapseClient *SYNAPSE_DLL_EXPORT
485 Synapse_EnumerateInterfaces(const char *version, CSynapseServer *pServer)
487 if (strcmp(version, SYNAPSE_VERSION)) {
488 Syn_Printf("ERROR: synapse API version mismatch: should be '"
490 "', got '%s'\n", version );
493 g_pSynapseServer = pServer;
494 g_pSynapseServer->IncRef();
495 Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf());
497 g_SynapseClient.AddAPI(PLUGIN_MAJOR, "HydraToolz", sizeof(_QERPluginTable));
498 g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable);
499 g_SynapseClient.AddAPI(VFS_MAJOR, "wad", sizeof(g_FileSystemTable), SYN_REQUIRE, &g_FileSystemTable);
500 g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable);
501 return &g_SynapseClient;
504 bool CSynapseClientHydraToolz::RequestAPI(APIDescriptor_t *pAPI)
506 if (!strcmp(pAPI->major_name, PLUGIN_MAJOR)) {
507 _QERPluginTable *pTable = static_cast<_QERPluginTable *>( pAPI->mpTable );
508 pTable->m_pfnQERPlug_Init = QERPlug_Init;
509 pTable->m_pfnQERPlug_GetName = QERPlug_GetName;
510 pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList;
511 pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch;
515 Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo());
519 const char *CSynapseClientHydraToolz::GetInfo()
521 return "HydraToolz plugin built " __DATE__ " "