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 (GtkWidget *widget, gpointer data)
66 parent = gtk_widget_get_toplevel (widget);
67 loop = (int*)gtk_object_get_data (GTK_OBJECT (parent), "loop");
68 ret = (int*)gtk_object_get_data (GTK_OBJECT (parent), "ret");
71 *ret = gpointer_to_int (data);
74 static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data)
78 gtk_widget_hide (widget);
79 loop = (int*)gtk_object_get_data (GTK_OBJECT (widget), "loop");
85 int DoMessageBox (const char* lpText, const char* lpCaption, guint32 uType)
87 GtkWidget *window, *w, *vbox, *hbox;
88 int mode = (uType & MB_TYPEMASK), ret, loop = 1;
90 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
91 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
92 GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);
93 gtk_signal_connect (GTK_OBJECT (window), "destroy",
94 GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);
95 gtk_window_set_title (GTK_WINDOW (window), lpCaption);
96 gtk_container_border_width (GTK_CONTAINER (window), 10);
97 gtk_object_set_data (GTK_OBJECT (window), "loop", &loop);
98 gtk_object_set_data (GTK_OBJECT (window), "ret", &ret);
99 gtk_widget_realize (window);
101 vbox = gtk_vbox_new (FALSE, 10);
102 gtk_container_add (GTK_CONTAINER (window), vbox);
103 gtk_widget_show (vbox);
105 w = gtk_label_new (lpText);
106 gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);
107 gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT);
110 w = gtk_hseparator_new ();
111 gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);
114 hbox = gtk_hbox_new (FALSE, 10);
115 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2);
116 gtk_widget_show (hbox);
120 w = gtk_button_new_with_label ("Ok");
121 gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
122 gtk_signal_connect (GTK_OBJECT (w), "clicked",
123 GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));
124 GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
125 gtk_widget_grab_default (w);
129 else if (mode == MB_OKCANCEL)
131 w = gtk_button_new_with_label ("Ok");
132 gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
133 gtk_signal_connect (GTK_OBJECT (w), "clicked",
134 GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));
135 GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
136 gtk_widget_grab_default (w);
139 w = gtk_button_new_with_label ("Cancel");
140 gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
141 gtk_signal_connect (GTK_OBJECT (w), "clicked",
142 GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));
146 else if (mode == MB_YESNOCANCEL)
148 w = gtk_button_new_with_label ("Yes");
149 gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
150 gtk_signal_connect (GTK_OBJECT (w), "clicked",
151 GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES));
152 GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
153 gtk_widget_grab_default (w);
156 w = gtk_button_new_with_label ("No");
157 gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
158 gtk_signal_connect (GTK_OBJECT (w), "clicked",
159 GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO));
162 w = gtk_button_new_with_label ("Cancel");
163 gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
164 gtk_signal_connect (GTK_OBJECT (w), "clicked",
165 GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));
169 else /* if (mode == MB_YESNO) */
171 w = gtk_button_new_with_label ("Yes");
172 gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
173 gtk_signal_connect (GTK_OBJECT (w), "clicked",
174 GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES));
175 GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
176 gtk_widget_grab_default (w);
179 w = gtk_button_new_with_label ("No");
180 gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
181 gtk_signal_connect (GTK_OBJECT (w), "clicked",
182 GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO));
187 gtk_widget_show (window);
188 gtk_grab_add (window);
191 gtk_main_iteration ();
193 gtk_grab_remove (window);
194 gtk_widget_destroy (window);
199 // End of rip from TexTool.cpp
201 // =============================================================================
202 // Ripped from cmdlib.cpp
209 void ExtractFilePath (const char *path, char *dest)
213 src = path + strlen(path) - 1;
216 // back up until a \ or the start
218 while (src != path && *(src-1) != '/' && *(src-1) != '\\')
221 memcpy (dest, path, src-path);
225 void ExtractFileName (const char *path, char *dest)
229 src = path + strlen(path) - 1;
232 // back up until a \ or the start
234 while (src != path && *(src-1) != '/'
235 && *(src-1) != '\\' )
245 void ConvertDOSToUnixName( char *dst, const char *src )
258 // End of rip from cmdlib.cpp
260 // =============================================================================
261 // Actual Plugin Code
263 // get the wad name from the shader name (or an actual wadname) and add to a list of wad names making
264 // sure we don't add duplicates.
266 GSList *AddToWadList(GSList *wadlist, const char *shadername, const char *wad)
268 char tmpstr[QER_MAX_NAMELEN];
270 if (!shadername && !wad) return wadlist;
274 if (strcmp(shadername,"color") == 0)
276 ExtractFilePath(shadername,tmpstr);
277 // Sys_Printf("checking: %s\n",shadername);
279 int l = strlen(tmpstr) - 1;
281 if (tmpstr[l] == '/' || tmpstr[l] == '\\')
285 Sys_Printf("WARNING: Unknown wad file for shader %s\n",shadername);
289 ExtractFileName(tmpstr,tmpstr);
291 wadname = (char *)malloc(strlen(tmpstr) + 5);
292 sprintf(wadname,"%s.wad",tmpstr);
299 for (GSList *l = wadlist; l != NULL ; l = l->next)
301 if (string_equal_nocase((char *)l->data,wadname))
308 Sys_Printf("Adding Wad File to WAD list: %s (reason: ",wadname);
310 Sys_Printf("see shader \"%s\")\n", shadername);
312 Sys_Printf("already in WAD key. )\n");
313 return ( g_slist_append (wadlist, wadname ) );
316 void UpdateWadKeyPair( void )
320 char wads[2048]; // change to CString usage ?
325 GSList *wadlist = NULL;
328 char cleanwadname[QER_MAX_NAMELEN];
329 const char *actualwad;
332 pEntity = (entity_t *)g_FuncTable.m_pfnGetEntityHandle(0); // get the worldspawn ent
334 Sys_Printf("Searching for in-use wad files...\n");
335 for(pEpair = pEntity->epairs; pEpair != NULL; pEpair = pEpair->next)
337 if (string_equal_nocase(pEpair->key,"wad"))
339 strcpy(wads,pEpair->value);
340 ConvertDOSToUnixName(wads,wads);
342 // ok, we got the list of ; delimited wads, now split it into a GSList that contains
343 // just the wad names themselves.
351 *p2 = 0; // swap the ; with a null terminator
353 if (strchr(p1,'/') || strchr(p1,'\\'))
355 ExtractFileName(p1,cleanwadname);
356 wadlist = AddToWadList (wadlist, NULL, cleanwadname);
360 wadlist = AddToWadList (wadlist, NULL, p1);
363 p1 = p2+1; // point back to the remainder of the string
365 p1 = NULL; // make it so we exit the loop.
369 // ok, now we have a list of wads in GSList.
370 // now we need to add any new wadfiles (with their paths) to this list
371 // so scan all brushes and see what wads are in use
372 // FIXME: scan brushes only in the region ?
374 break; // we don't need to process any more key/pairs.
378 nb = g_FuncTable.m_pfnAllocateActiveBrushHandles();
379 for( i = 0; i < nb; i++ )
381 b = (brush_t *)g_FuncTable.m_pfnGetActiveBrushHandle(i);
382 if (b->patchBrush) // patches in halflife ?
384 wadlist = AddToWadList(wadlist, b->pPatch->pShader->getName(),NULL);
387 for (f=b->brush_faces ; f ; f=f->next)
389 wadlist = AddToWadList(wadlist, f->pShader->getName(),NULL);
393 g_FuncTable.m_pfnReleaseActiveBrushHandles();
395 nb = g_FuncTable.m_pfnAllocateSelectedBrushHandles();
396 for( i = 0; i < nb; i++ )
398 b = (brush_t *)g_FuncTable.m_pfnGetSelectedBrushHandle(i);
399 if (b->patchBrush) // patches in halflife ?
401 wadlist = AddToWadList(wadlist, b->pPatch->pShader->getName(),NULL);
404 for (f=b->brush_faces ; f ; f=f->next)
406 wadlist = AddToWadList(wadlist, f->pShader->getName(),NULL);
410 g_FuncTable.m_pfnReleaseSelectedBrushHandles();
412 // Now we have a complete list of wadnames (without paths) so we just have to turn this
413 // back to a ; delimited list.
418 if (string_equal_nocase((char *)wadlist->data,"common-hydra.wad"))
420 Sys_Printf("Skipping radiant-supplied wad file %s\n",(char *)wadlist->data);
427 actualwad = vfsGetFullPath((char *)wadlist->data);
431 strcat(wads, actualwad);
435 Sys_Printf("WARNING: could not locate wad file %s\n",(char *)wadlist->data);
436 strcat(wads, (char *)wadlist->data);
440 free (wadlist->data);
441 wadlist = g_slist_remove (wadlist, wadlist->data);
444 // store the wad list back in the worldspawn.
447 //free(pEpair->value);
448 //pEpair->value = strdup(wads);
449 SetKeyValue(pEntity, "wad", wads);
454 // =============================================================================
455 // PLUGIN INTERFACE STUFF
458 const char *PLUGIN_NAME = "Q3 Texture Tools";
460 // commands in the menu
461 const char *PLUGIN_COMMANDS = "About...;Create/Update WAD keypair";
463 const char *PLUGIN_ABOUT = "HydraToolz for GTKRadiant\n\n"
466 extern "C" void* WINAPI QERPlug_GetFuncTable ()
471 const char* QERPlug_Init (void* hApp, void *pWidget)
473 GtkWidget* pMainWidget = static_cast<GtkWidget*>(pWidget);
475 g_pMainWnd = pMainWidget;
476 memset(&g_FuncTable, 0, sizeof(_QERFuncTable_1));
477 g_FuncTable.m_nSize = sizeof(_QERFuncTable_1);
478 return "HydraToolz for GTKRadiant"; // do we need this ? hmmm
481 const char* QERPlug_GetName()
483 return (char*)PLUGIN_NAME;
486 const char* QERPlug_GetCommandList()
488 return PLUGIN_COMMANDS;
491 extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush)
493 if(!strcmp(p, "Create/Update WAD keypair"))
495 else if(!strcmp(p, "About..."))
496 g_FuncTable.m_pfnMessageBox((GtkWidget*)NULL, PLUGIN_ABOUT, "About", eMB_OK);
499 // =============================================================================
502 CSynapseServer* g_pSynapseServer = NULL;
503 CSynapseClientHydraToolz g_SynapseClient;
505 extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer)
507 if (strcmp(version, SYNAPSE_VERSION))
509 Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version);
512 g_pSynapseServer = pServer;
513 g_pSynapseServer->IncRef();
514 Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf());
516 g_SynapseClient.AddAPI(PLUGIN_MAJOR, "HydraToolz", sizeof(_QERPluginTable));
517 g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable);
518 g_SynapseClient.AddAPI(VFS_MAJOR, "wad", sizeof(g_FileSystemTable), SYN_REQUIRE, &g_FileSystemTable);
519 g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable);
520 return &g_SynapseClient;
523 bool CSynapseClientHydraToolz::RequestAPI(APIDescriptor_t *pAPI)
525 if (!strcmp(pAPI->major_name, PLUGIN_MAJOR))
527 _QERPluginTable *pTable = static_cast<_QERPluginTable*>(pAPI->mpTable);
528 pTable->m_pfnQERPlug_Init = QERPlug_Init;
529 pTable->m_pfnQERPlug_GetName = QERPlug_GetName;
530 pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList;
531 pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch;
535 Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo());
539 const char* CSynapseClientHydraToolz::GetInfo()
541 return "HydraToolz plugin built " __DATE__ " " RADIANT_VERSION;