some updates to the Linux build system - obtained a core binary and all required...
[xonotic/netradiant.git] / plugins / model / plugin.cpp
1 \r
2 /*\r
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
4 For a list of contributors, see the accompanying CONTRIBUTORS file.\r
5 \r
6 This file is part of GtkRadiant.\r
7 \r
8 GtkRadiant is free software; you can redistribute it and/or modify\r
9 it under the terms of the GNU General Public License as published by\r
10 the Free Software Foundation; either version 2 of the License, or\r
11 (at your option) any later version.\r
12 \r
13 GtkRadiant is distributed in the hope that it will be useful,\r
14 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16 GNU General Public License for more details.\r
17 \r
18 You should have received a copy of the GNU General Public License\r
19 along with GtkRadiant; if not, write to the Free Software\r
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
21 */\r
22 \r
23 #include "plugin.h"\r
24 \r
25 #if 0 // stop using windowing systems in plugins - put the text in SynapseClient::GetInfo\r
26 // =============================================================================\r
27 // Utility functions\r
28 static void dialog_button_callback (GtkWidget *widget, gpointer data)\r
29 {\r
30         GtkWidget *parent;\r
31         int *loop, *ret;\r
32  \r
33         parent = gtk_widget_get_toplevel (widget);\r
34         loop = (int*)g_object_get_data (G_OBJECT (parent), "loop");\r
35         ret = (int*)g_object_get_data (G_OBJECT (parent), "ret");\r
36  \r
37         *loop = 0;\r
38         *ret = (int)data;\r
39 }\r
40 \r
41 static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data)\r
42 {\r
43         int *loop;\r
44  \r
45         gtk_widget_hide (widget);\r
46         loop = (int*)g_object_get_data (G_OBJECT (widget), "loop");\r
47         *loop = 0;\r
48 \r
49         return TRUE;\r
50 }\r
51 \r
52 int DoAboutBox( GtkWidget *parent )\r
53 {\r
54         GtkWidget *window, *w, *text, *vbox, *hbox, *hbox2, *frame;\r
55         GdkPixmap *pixmap;\r
56         GdkBitmap *mask;\r
57         GtkStyle *style;\r
58         int ret, loop = 1;\r
59         char buf[2048];\r
60   const picoModule_t **modules, *pm;\r
61  \r
62         window = gtk_window_new (GTK_WINDOW_TOPLEVEL);\r
63         gtk_signal_connect (GTK_OBJECT (window), "delete_event",\r
64                       GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);\r
65         gtk_signal_connect (GTK_OBJECT (window), "destroy",\r
66                       GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);\r
67         gtk_window_set_title (GTK_WINDOW (window), "About...");\r
68         gtk_container_border_width (GTK_CONTAINER (window), 10);\r
69         g_object_set_data (G_OBJECT (window), "loop", &loop);\r
70         g_object_set_data (G_OBJECT (window), "ret", &ret);\r
71         gtk_widget_realize (window);\r
72 \r
73         if (parent != NULL)\r
74                 gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent));\r
75 \r
76   vbox = gtk_vbox_new (FALSE, 10);\r
77   gtk_container_add (GTK_CONTAINER (window), vbox);\r
78         gtk_widget_show (vbox);\r
79 \r
80         style = gtk_widget_get_style(window);\r
81 \r
82   hbox2 = gtk_hbox_new (FALSE, 10);\r
83   gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 2);\r
84         gtk_widget_show (hbox2);\r
85 \r
86   frame = gtk_frame_new (NULL);\r
87   gtk_box_pack_start (GTK_BOX (hbox2), frame, FALSE, FALSE, 2);\r
88   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);\r
89   gtk_widget_show (frame);\r
90 \r
91         if( g_FuncTable.m_pfnLoadBitmap( "picomodel.bmp", (void **)&pixmap, (void **)&mask ) ) {\r
92                 w = gtk_pixmap_new (pixmap, mask);\r
93     gtk_container_add (GTK_CONTAINER (frame), w);\r
94                 gtk_widget_show (w);\r
95         }\r
96 \r
97         w = gtk_label_new ("Model Module v1.0 for GtkRadiant\nby Arnout van Meer (rr2do2@splashdamage.com)\n\nBased on the MD3Model Module by SPoG\nPicoModel Library Copyright (c) 2002, Randy Reddig & seaw0lf" );\r
98         gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);\r
99         gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT);\r
100         gtk_widget_show (w);\r
101 \r
102   w = gtk_scrolled_window_new(NULL, NULL);\r
103   gtk_box_pack_start(GTK_BOX(vbox), w, TRUE, TRUE, 2);\r
104   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);\r
105   gtk_widget_show(w);\r
106 \r
107   text = gtk_text_new(NULL, NULL);\r
108   gtk_text_set_editable(GTK_TEXT(text), FALSE);\r
109   gtk_container_add(GTK_CONTAINER(w), text);\r
110 \r
111   strcpy( buf, "#Supported Model Formats:\n" );\r
112   gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, buf, -1);\r
113 \r
114   for( modules = PicoModuleList( NULL ); *modules != NULL; modules++ )\r
115   {\r
116     pm = *modules;\r
117 \r
118     if( pm == NULL)\r
119                         break;\r
120 \r
121     sprintf( buf, "\n%s, version %s, (c) %s", pm->displayName, pm->version, pm->copyright );\r
122     gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, buf, -1);\r
123   }\r
124 \r
125   gtk_text_set_word_wrap(GTK_TEXT(text), FALSE);\r
126   gtk_widget_show(text);\r
127 \r
128   gtk_text_set_point(GTK_TEXT(text), 0);\r
129   gtk_text_forward_delete(GTK_TEXT(text), 1);\r
130 \r
131         w = gtk_hseparator_new ();\r
132         gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);\r
133         gtk_widget_show (w);\r
134  \r
135         hbox = gtk_hbox_new (FALSE, 10);\r
136         gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2);\r
137         gtk_widget_show (hbox);\r
138  \r
139         w = gtk_button_new_with_label ("Ok");\r
140         gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
141         gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
142                         GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));\r
143         GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);\r
144         gtk_widget_grab_default (w);\r
145         gtk_widget_show (w);\r
146         ret = IDOK;\r
147  \r
148         gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);\r
149         gtk_widget_show (window);\r
150         gtk_grab_add (window);\r
151  \r
152         while (loop)\r
153                 gtk_main_iteration ();\r
154  \r
155         gtk_grab_remove (window);\r
156         gtk_widget_destroy (window);\r
157  \r
158         return ret;\r
159 }\r
160 #endif\r
161 \r
162 // toolbar implementation\r
163 \r
164 class CFlushReloadSelectedToolbarButton : public IToolbarButton\r
165 {\r
166 public:\r
167   virtual const char* getImage() const\r
168   {\r
169     return "model_reload_entity.bmp";\r
170   }\r
171   virtual const char* getText() const\r
172   {\r
173     return "Reload";\r
174   }\r
175   virtual const char* getTooltip() const\r
176   {\r
177     return "Flush & Reload Selected Model";\r
178   }\r
179   virtual void activate() const\r
180   {\r
181     DoFlushReloadSelected();\r
182   }\r
183   virtual EType getType() const\r
184   {\r
185     return eButton;\r
186   }\r
187 };\r
188 \r
189 CFlushReloadSelectedToolbarButton g_flushreloadselected;\r
190 \r
191 unsigned int ToolbarButtonCount()\r
192 {\r
193   return 1;\r
194 }\r
195 \r
196 const IToolbarButton* GetToolbarButton(unsigned int index)\r
197 {\r
198   return &g_flushreloadselected;\r
199 }\r
200 \r
201 // =============================================================================\r
202 // Pico utility functions\r
203 \r
204 #include "picomodel.h"\r
205 \r
206 void PicoPrintFunc( int level, const char *str )\r
207 {\r
208         if( str == NULL )\r
209                 return;\r
210         switch( level )\r
211         {\r
212                 case PICO_NORMAL:\r
213                         Sys_Printf( "%s\n", str );\r
214                         break;\r
215                 \r
216                 case PICO_VERBOSE:\r
217                         Sys_FPrintf( SYS_VRB, "%s\n", str );\r
218                         break;\r
219                 \r
220                 case PICO_WARNING:\r
221                         Sys_Printf( "WARNING: %s\n", str );\r
222                         break;\r
223                 \r
224                 case PICO_ERROR:\r
225                         Sys_FPrintf( SYS_VRB, "ERROR: %s\n", str );\r
226                         break;\r
227                 \r
228                 case PICO_FATAL:\r
229       Sys_Printf( "ERROR: %s\n", str );\r
230                         break;\r
231         }\r
232 }\r
233 \r
234 void PicoLoadFileFunc( char *name, byte **buffer, int *bufSize )\r
235 {\r
236         *bufSize = vfsLoadFile( (const char*) name, (void**) buffer, 0 );\r
237 }\r
238 \r
239 void PicoFreeFileFunc( void* file )\r
240 {\r
241         vfsFreeFile(file);\r
242 }\r
243 \r
244 static void initialise()\r
245 {\r
246         PicoInit();\r
247         PicoSetMallocFunc( malloc );\r
248         PicoSetFreeFunc( free );\r
249         PicoSetPrintFunc( PicoPrintFunc );\r
250         PicoSetLoadFileFunc( PicoLoadFileFunc );\r
251         PicoSetFreeFileFunc( PicoFreeFileFunc );\r
252 }\r
253 \r
254 static void add_model_apis(CSynapseClient& client)\r
255 {\r
256   const picoModule_t** modules = PicoModuleList( NULL );\r
257   while(*modules != NULL)\r
258   {\r
259     const picoModule_t* module = *modules++;\r
260     if(module->canload && module->load)\r
261       for(unsigned int j = 0; module->defaultExts[j] != NULL; j++)\r
262         client.AddAPI(MODEL_MAJOR, module->defaultExts[j], sizeof(_QERPlugModelTable));\r
263   }   \r
264 }\r
265 \r
266 static bool model_is_supported(const char* extension)\r
267 {\r
268   const picoModule_t** modules = PicoModuleList( NULL );\r
269   while(*modules != NULL)\r
270   {\r
271     const picoModule_t* module = *modules++;\r
272     if(module->canload && module->load)\r
273       for(unsigned int j = 0; module->defaultExts[j] != NULL; j++)\r
274         if(strcmp(extension, module->defaultExts[j]) == 0)\r
275           return true;\r
276   }\r
277   return false;\r
278 }\r
279 \r
280 void init_filetypes()\r
281 {\r
282   const picoModule_t **modules = PicoModuleList(NULL);\r
283   while(*modules != NULL)\r
284   {\r
285     const picoModule_t* module = *modules++;\r
286     if(module->canload && module->load)\r
287     {\r
288       for(char*const* ext = module->defaultExts; *ext != NULL; ++ext)\r
289       {\r
290         char buf[16];\r
291         buf[0] = '*';\r
292         buf[1] = '.';\r
293         strcpy(buf+2, *ext);\r
294         GetFileTypeRegistry()->addType(MODEL_MAJOR, filetype_t(module->displayName, buf));\r
295       }\r
296     }\r
297   }\r
298 }\r
299 \r
300 // plugin implementation\r
301 \r
302 static const char *PLUGIN_NAME = "Model loading module";\r
303 static const char *PLUGIN_COMMANDS = "Flush & Reload Models,Flush & Reload Selected";\r
304 static const char *PLUGIN_ABOUT = "Model loading module";\r
305 \r
306 extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget)\r
307 {\r
308   init_filetypes();\r
309   return (char *) PLUGIN_NAME;\r
310 }\r
311 \r
312 extern "C" const char* QERPlug_GetName ()\r
313 {\r
314   return (char *) PLUGIN_NAME;\r
315 }\r
316 \r
317 extern "C" const char* QERPlug_GetCommandList ()\r
318 {\r
319   return (char *) PLUGIN_COMMANDS;\r
320 }\r
321 \r
322 extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush)\r
323 {\r
324   if( !strcmp( p, "Flush & Reload Selected" ) )\r
325     DoFlushReloadSelected();\r
326   else if( !strcmp( p, "Flush & Reload Models" ) )\r
327     DoFlushReloadAll();\r
328 }\r
329 \r
330 \r
331 void DoFlushReloadSelected() {\r
332 }\r
333 \r
334 void DoFlushReloadAll() {\r
335   GetModelCache()->RefreshAll();\r
336 }\r
337 \r
338 // =============================================================================\r
339 \r
340 // function tables\r
341 _QERFuncTable_1 g_FuncTable;\r
342 _QERQglTable g_QglTable;\r
343 _QERShadersTable g_ShadersTable;\r
344 _QERFileSystemTable g_FileSystemTable;\r
345 \r
346 // =============================================================================\r
347 // SYNAPSE\r
348 \r
349 CSynapseServer* g_pSynapseServer = NULL;\r
350 CSynapseClientModel g_SynapseClient;\r
351 \r
352 static const XMLConfigEntry_t entries[] = \r
353   { { SHADERS_MAJOR, SYN_REQUIRE, sizeof(g_ShadersTable), &g_ShadersTable }, \r
354     { VFS_MAJOR, SYN_REQUIRE, sizeof(g_FileSystemTable), &g_FileSystemTable },\r
355     { NULL, SYN_UNKNOWN, 0, NULL } };\r
356 \r
357 #if __GNUC__ >= 4\r
358 #pragma GCC visibility push(default)\r
359 #endif\r
360 extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( const char *version, CSynapseServer *pServer ) {\r
361 #if __GNUC__ >= 4\r
362 #pragma GCC visibility pop\r
363 #endif\r
364   if (strcmp(version, SYNAPSE_VERSION))\r
365   {\r
366     Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version);\r
367     return NULL;\r
368   }\r
369   g_pSynapseServer = pServer;\r
370   g_pSynapseServer->IncRef();\r
371   Set_Syn_Printf( g_pSynapseServer->Get_Syn_Printf() );\r
372 \r
373   initialise();\r
374   \r
375   add_model_apis(g_SynapseClient);\r
376   g_SynapseClient.AddAPI(TOOLBAR_MAJOR, "model", sizeof(_QERPlugToolbarTable));\r
377   g_SynapseClient.AddAPI(PLUGIN_MAJOR, "model", sizeof(_QERPluginTable));\r
378 \r
379   g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable);\r
380   g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(g_QglTable), SYN_REQUIRE, &g_QglTable);\r
381 \r
382   if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) {\r
383     return NULL;\r
384   }\r
385   \r
386   return &g_SynapseClient;\r
387 }\r
388 \r
389 bool CSynapseClientModel::RequestAPI(APIDescriptor_t *pAPI)\r
390 {\r
391   if (!strcmp(pAPI->major_name, MODEL_MAJOR))\r
392   {\r
393     _QERPlugModelTable* pTable= static_cast<_QERPlugModelTable*>(pAPI->mpTable);\r
394 \r
395     if (model_is_supported(pAPI->minor_name))\r
396     {\r
397       pTable->m_pfnLoadModel = &LoadModel;\r
398       return true;\r
399     }\r
400   }\r
401   else if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR))\r
402   {\r
403     _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable);\r
404 \r
405     pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount;\r
406     pTable->m_pfnGetToolbarButton = &GetToolbarButton;\r
407     return true;\r
408   }\r
409   else if (!strcmp(pAPI->major_name, PLUGIN_MAJOR))\r
410   {\r
411     _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable);\r
412 \r
413     pTable->m_pfnQERPlug_Init = QERPlug_Init;\r
414     pTable->m_pfnQERPlug_GetName = QERPlug_GetName;\r
415     pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList;\r
416     pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch;\r
417     return true;\r
418   }\r
419 \r
420   Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo());\r
421   return false;\r
422 }\r
423 \r
424 #include "version.h"\r
425 \r
426 const char* CSynapseClientModel::GetInfo()\r
427 {\r
428   return "picomodel loader module built " __DATE__ " " RADIANT_VERSION;\r
429 }\r
430 \r
431 const char* CSynapseClientModel::GetName()\r
432 {\r
433   return "model";\r
434 }\r