]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - plugins/model/plugin.cpp
merge branch work back into trunk
[xonotic/netradiant.git] / plugins / model / plugin.cpp
index dc5da485f2e6ef9e7c2bfa0d28d46a09a060d4cd..a69ce21f910f4b883d2f32e5cfc58f6f754476af 100644 (file)
-\r
-/*\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
-#include "plugin.h"\r
-\r
-#if 0 // stop using windowing systems in plugins - put the text in SynapseClient::GetInfo\r
-// =============================================================================\r
-// Utility functions\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 DoAboutBox( GtkWidget *parent )\r
-{\r
-       GtkWidget *window, *w, *text, *vbox, *hbox, *hbox2, *frame;\r
-       GdkPixmap *pixmap;\r
-       GdkBitmap *mask;\r
-       GtkStyle *style;\r
-       int ret, loop = 1;\r
-       char buf[2048];\r
-  const picoModule_t **modules, *pm;\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), "About...");\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
-       if (parent != NULL)\r
-               gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent));\r
-\r
-  vbox = gtk_vbox_new (FALSE, 10);\r
-  gtk_container_add (GTK_CONTAINER (window), vbox);\r
-       gtk_widget_show (vbox);\r
-\r
-       style = gtk_widget_get_style(window);\r
-\r
-  hbox2 = gtk_hbox_new (FALSE, 10);\r
-  gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 2);\r
-       gtk_widget_show (hbox2);\r
-\r
-  frame = gtk_frame_new (NULL);\r
-  gtk_box_pack_start (GTK_BOX (hbox2), frame, FALSE, FALSE, 2);\r
-  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);\r
-  gtk_widget_show (frame);\r
-\r
-       if( g_FuncTable.m_pfnLoadBitmap( "picomodel.bmp", (void **)&pixmap, (void **)&mask ) ) {\r
-               w = gtk_pixmap_new (pixmap, mask);\r
-    gtk_container_add (GTK_CONTAINER (frame), w);\r
-               gtk_widget_show (w);\r
-       }\r
-\r
-       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
-       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_scrolled_window_new(NULL, NULL);\r
-  gtk_box_pack_start(GTK_BOX(vbox), w, TRUE, TRUE, 2);\r
-  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);\r
-  gtk_widget_show(w);\r
-\r
-  text = gtk_text_new(NULL, NULL);\r
-  gtk_text_set_editable(GTK_TEXT(text), FALSE);\r
-  gtk_container_add(GTK_CONTAINER(w), text);\r
-\r
-  strcpy( buf, "#Supported Model Formats:\n" );\r
-  gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, buf, -1);\r
-\r
-  for( modules = PicoModuleList( NULL ); *modules != NULL; modules++ )\r
-  {\r
-    pm = *modules;\r
-\r
-    if( pm == NULL)\r
-                       break;\r
-\r
-    sprintf( buf, "\n%s, version %s, (c) %s", pm->displayName, pm->version, pm->copyright );\r
-    gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, buf, -1);\r
-  }\r
-\r
-  gtk_text_set_word_wrap(GTK_TEXT(text), FALSE);\r
-  gtk_widget_show(text);\r
-\r
-  gtk_text_set_point(GTK_TEXT(text), 0);\r
-  gtk_text_forward_delete(GTK_TEXT(text), 1);\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
-       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
-       gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);\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
-#endif\r
-\r
-// toolbar implementation\r
-\r
-class CFlushReloadSelectedToolbarButton : public IToolbarButton\r
-{\r
-public:\r
-  virtual const char* getImage() const\r
-  {\r
-    return "model_reload_entity.bmp";\r
-  }\r
-  virtual const char* getText() const\r
-  {\r
-    return "Reload";\r
-  }\r
-  virtual const char* getTooltip() const\r
-  {\r
-    return "Flush & Reload Selected Model";\r
-  }\r
-  virtual void activate() const\r
-  {\r
-    DoFlushReloadSelected();\r
-  }\r
-  virtual EType getType() const\r
-  {\r
-    return eButton;\r
-  }\r
-};\r
-\r
-CFlushReloadSelectedToolbarButton g_flushreloadselected;\r
-\r
-unsigned int ToolbarButtonCount()\r
-{\r
-  return 1;\r
-}\r
-\r
-const IToolbarButton* GetToolbarButton(unsigned int index)\r
-{\r
-  return &g_flushreloadselected;\r
-}\r
-\r
-// =============================================================================\r
-// Pico utility functions\r
-\r
-#include "picomodel.h"\r
-\r
-void PicoPrintFunc( int level, const char *str )\r
-{\r
-       if( str == NULL )\r
-               return;\r
-       switch( level )\r
-       {\r
-               case PICO_NORMAL:\r
-                       Sys_Printf( "%s\n", str );\r
-                       break;\r
-               \r
-               case PICO_VERBOSE:\r
-                       Sys_FPrintf( SYS_VRB, "%s\n", str );\r
-                       break;\r
-               \r
-               case PICO_WARNING:\r
-                       Sys_Printf( "WARNING: %s\n", str );\r
-                       break;\r
-               \r
-               case PICO_ERROR:\r
-                       Sys_FPrintf( SYS_VRB, "ERROR: %s\n", str );\r
-                       break;\r
-               \r
-               case PICO_FATAL:\r
-      Sys_Printf( "ERROR: %s\n", str );\r
-                       break;\r
-       }\r
-}\r
-\r
-void PicoLoadFileFunc( char *name, byte **buffer, int *bufSize )\r
-{\r
-       *bufSize = vfsLoadFile( (const char*) name, (void**) buffer, 0 );\r
-}\r
-\r
-void PicoFreeFileFunc( void* file )\r
-{\r
-       vfsFreeFile(file);\r
-}\r
-\r
-static void initialise()\r
-{\r
-       PicoInit();\r
-       PicoSetMallocFunc( malloc );\r
-       PicoSetFreeFunc( free );\r
-       PicoSetPrintFunc( PicoPrintFunc );\r
-       PicoSetLoadFileFunc( PicoLoadFileFunc );\r
-       PicoSetFreeFileFunc( PicoFreeFileFunc );\r
-}\r
-\r
-static void add_model_apis(CSynapseClient& client)\r
-{\r
-  const picoModule_t** modules = PicoModuleList( NULL );\r
-  while(*modules != NULL)\r
-  {\r
-    const picoModule_t* module = *modules++;\r
-    if(module->canload && module->load)\r
-      for(unsigned int j = 0; module->defaultExts[j] != NULL; j++)\r
-        client.AddAPI(MODEL_MAJOR, module->defaultExts[j], sizeof(_QERPlugModelTable));\r
-  }   \r
-}\r
-\r
-static bool model_is_supported(const char* extension)\r
-{\r
-  const picoModule_t** modules = PicoModuleList( NULL );\r
-  while(*modules != NULL)\r
-  {\r
-    const picoModule_t* module = *modules++;\r
-    if(module->canload && module->load)\r
-      for(unsigned int j = 0; module->defaultExts[j] != NULL; j++)\r
-        if(strcmp(extension, module->defaultExts[j]) == 0)\r
-          return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-void init_filetypes()\r
-{\r
-  const picoModule_t **modules = PicoModuleList(NULL);\r
-  while(*modules != NULL)\r
-  {\r
-    const picoModule_t* module = *modules++;\r
-    if(module->canload && module->load)\r
-    {\r
-      for(char*const* ext = module->defaultExts; *ext != NULL; ++ext)\r
-      {\r
-        char buf[16];\r
-        buf[0] = '*';\r
-        buf[1] = '.';\r
-        strcpy(buf+2, *ext);\r
-        GetFileTypeRegistry()->addType(MODEL_MAJOR, filetype_t(module->displayName, buf));\r
-      }\r
-    }\r
-  }\r
-}\r
-\r
-// plugin implementation\r
-\r
-static const char *PLUGIN_NAME = "Model loading module";\r
-static const char *PLUGIN_COMMANDS = "Flush & Reload Models,Flush & Reload Selected";\r
-static const char *PLUGIN_ABOUT = "Model loading module";\r
-\r
-extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget)\r
-{\r
-  init_filetypes();\r
-  return (char *) PLUGIN_NAME;\r
-}\r
-\r
-extern "C" const char* QERPlug_GetName ()\r
-{\r
-  return (char *) PLUGIN_NAME;\r
-}\r
-\r
-extern "C" const char* QERPlug_GetCommandList ()\r
-{\r
-  return (char *) PLUGIN_COMMANDS;\r
-}\r
-\r
-extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush)\r
-{\r
-  if( !strcmp( p, "Flush & Reload Selected" ) )\r
-    DoFlushReloadSelected();\r
-  else if( !strcmp( p, "Flush & Reload Models" ) )\r
-    DoFlushReloadAll();\r
-}\r
-\r
-\r
-void DoFlushReloadSelected() {\r
-}\r
-\r
-void DoFlushReloadAll() {\r
-  GetModelCache()->RefreshAll();\r
-}\r
-\r
-// =============================================================================\r
-\r
-// function tables\r
-_QERFuncTable_1 g_FuncTable;\r
-_QERQglTable g_QglTable;\r
-_QERShadersTable g_ShadersTable;\r
-_QERFileSystemTable g_FileSystemTable;\r
-\r
-// =============================================================================\r
-// SYNAPSE\r
-\r
-CSynapseServer* g_pSynapseServer = NULL;\r
-CSynapseClientModel g_SynapseClient;\r
-\r
-static const XMLConfigEntry_t entries[] = \r
-  { { SHADERS_MAJOR, SYN_REQUIRE, sizeof(g_ShadersTable), &g_ShadersTable }, \r
-    { VFS_MAJOR, SYN_REQUIRE, sizeof(g_FileSystemTable), &g_FileSystemTable },\r
-    { NULL, SYN_UNKNOWN, 0, NULL } };\r
-\r
-extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer)\r
-{\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
-  initialise();\r
-  \r
-  add_model_apis(g_SynapseClient);\r
-  g_SynapseClient.AddAPI(TOOLBAR_MAJOR, "model", sizeof(_QERPlugToolbarTable));\r
-  g_SynapseClient.AddAPI(PLUGIN_MAJOR, "model", sizeof(_QERPluginTable));\r
-\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
-\r
-  if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) {\r
-    return NULL;\r
-  }\r
-  \r
-  return &g_SynapseClient;\r
-}\r
-\r
-bool CSynapseClientModel::RequestAPI(APIDescriptor_t *pAPI)\r
-{\r
-  if (!strcmp(pAPI->major_name, MODEL_MAJOR))\r
-  {\r
-    _QERPlugModelTable* pTable= static_cast<_QERPlugModelTable*>(pAPI->mpTable);\r
-\r
-    if (model_is_supported(pAPI->minor_name))\r
-    {\r
-      pTable->m_pfnLoadModel = &LoadModel;\r
-      return true;\r
-    }\r
-  }\r
-  else if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR))\r
-  {\r
-    _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable);\r
-\r
-    pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount;\r
-    pTable->m_pfnGetToolbarButton = &GetToolbarButton;\r
-    return true;\r
-  }\r
-  else if (!strcmp(pAPI->major_name, PLUGIN_MAJOR))\r
-  {\r
-    _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable);\r
-\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* CSynapseClientModel::GetInfo()\r
-{\r
-  return "picomodel loader module built " __DATE__ " " RADIANT_VERSION;\r
-}\r
-\r
-const char* CSynapseClientModel::GetName()\r
-{\r
-  return "model";\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
+*/
+
+#include "plugin.h"
+
+// toolbar implementation
+
+class CFlushReloadSelectedToolbarButton : public IToolbarButton
+{
+public:
+  virtual const char* getImage() const
+  {
+    return "model_reload_entity.bmp";
+  }
+  virtual const char* getText() const
+  {
+    return "Reload";
+  }
+  virtual const char* getTooltip() const
+  {
+    return "Flush & Reload Selected Model";
+  }
+  virtual void activate() const
+  {
+    DoFlushReloadSelected();
+  }
+  virtual EType getType() const
+  {
+    return eButton;
+  }
+};
+
+CFlushReloadSelectedToolbarButton g_flushreloadselected;
+
+unsigned int ToolbarButtonCount()
+{
+  return 1;
+}
+
+const IToolbarButton* GetToolbarButton(unsigned int index)
+{
+  return &g_flushreloadselected;
+}
+
+// =============================================================================
+// Pico utility functions
+
+#include "picomodel.h"
+
+void PicoPrintFunc( int level, const char *str )
+{
+       if( str == NULL )
+               return;
+       switch( level )
+       {
+               case PICO_NORMAL:
+                       Sys_Printf( "%s\n", str );
+                       break;
+               
+               case PICO_VERBOSE:
+                       Sys_FPrintf( SYS_VRB, "%s\n", str );
+                       break;
+               
+               case PICO_WARNING:
+                       Sys_Printf( "WARNING: %s\n", str );
+                       break;
+               
+               case PICO_ERROR:
+                       Sys_FPrintf( SYS_VRB, "ERROR: %s\n", str );
+                       break;
+               
+               case PICO_FATAL:
+      Sys_Printf( "ERROR: %s\n", str );
+                       break;
+       }
+}
+
+void PicoLoadFileFunc( char *name, byte **buffer, int *bufSize )
+{
+       *bufSize = vfsLoadFile( (const char*) name, (void**) buffer, 0 );
+}
+
+void PicoFreeFileFunc( void* file )
+{
+       vfsFreeFile(file);
+}
+
+static void initialise()
+{
+       PicoInit();
+       PicoSetMallocFunc( malloc );
+       PicoSetFreeFunc( free );
+       PicoSetPrintFunc( PicoPrintFunc );
+       PicoSetLoadFileFunc( PicoLoadFileFunc );
+       PicoSetFreeFileFunc( PicoFreeFileFunc );
+}
+
+static void add_model_apis(CSynapseClient& client)
+{
+  const picoModule_t** modules = PicoModuleList( NULL );
+  while(*modules != NULL)
+  {
+    const picoModule_t* module = *modules++;
+    if(module->canload && module->load)
+      for(unsigned int j = 0; module->defaultExts[j] != NULL; j++)
+        client.AddAPI(MODEL_MAJOR, module->defaultExts[j], sizeof(_QERPlugModelTable));
+  }   
+}
+
+static bool model_is_supported(const char* extension)
+{
+  const picoModule_t** modules = PicoModuleList( NULL );
+  while(*modules != NULL)
+  {
+    const picoModule_t* module = *modules++;
+    if(module->canload && module->load)
+      for(unsigned int j = 0; module->defaultExts[j] != NULL; j++)
+        if(strcmp(extension, module->defaultExts[j]) == 0)
+          return true;
+  }
+  return false;
+}
+
+void init_filetypes()
+{
+  const picoModule_t **modules = PicoModuleList(NULL);
+  while(*modules != NULL)
+  {
+    const picoModule_t* module = *modules++;
+    if(module->canload && module->load)
+    {
+      for(char*const* ext = module->defaultExts; *ext != NULL; ++ext)
+      {
+        char buf[16];
+        buf[0] = '*';
+        buf[1] = '.';
+        strcpy(buf+2, *ext);
+        GetFileTypeRegistry()->addType(MODEL_MAJOR, filetype_t(module->displayName, buf));
+      }
+    }
+  }
+}
+
+// plugin implementation
+
+static const char *PLUGIN_NAME = "Model loading module";
+static const char *PLUGIN_COMMANDS = "About;-;Flush & Reload Models;Flush & Reload Selected";
+static const char *PLUGIN_ABOUT = "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\n\nSupported models:\n";
+
+extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget)
+{
+  init_filetypes();
+  return (char *) PLUGIN_NAME;
+}
+
+extern "C" const char* QERPlug_GetName ()
+{
+  return (char *) PLUGIN_NAME;
+}
+
+extern "C" const char* QERPlug_GetCommandList ()
+{
+  return (char *) PLUGIN_COMMANDS;
+}
+
+extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush)
+{
+  if( !strcmp( p, "Flush & Reload Selected" ) )
+    DoFlushReloadSelected();
+  else if( !strcmp( p, "Flush & Reload Models" ) )
+    DoFlushReloadAll();
+  else if( !strcmp( p, "About" ) ) {
+    const picoModule_t** modules = PicoModuleList( NULL );
+    char about_buf[1024];
+    strncpy(about_buf, PLUGIN_ABOUT, sizeof(about_buf) - 1);
+    while(*modules != NULL) {
+      const picoModule_t* module = *modules++;
+      strncat(about_buf, module->displayName, sizeof(about_buf) - 1);
+      strncat(about_buf, " (", sizeof(about_buf) - 1);
+      strncat(about_buf, module->defaultExts[0], sizeof(about_buf) - 1);
+      strncat(about_buf, ")\n\t", sizeof(about_buf) - 1);
+      strncat(about_buf, module->copyright, sizeof(about_buf) - 1);
+      strncat(about_buf, "\n", sizeof(about_buf) - 1);
+    }
+    g_FuncTable.m_pfnMessageBox(NULL, about_buf, "About", MB_OK, NULL);
+  }
+}
+
+
+void DoFlushReloadSelected() {
+}
+
+void DoFlushReloadAll() {
+  GetModelCache()->RefreshAll();
+}
+
+// =============================================================================
+
+// function tables
+_QERFuncTable_1 g_FuncTable;
+_QERQglTable g_QglTable;
+_QERShadersTable g_ShadersTable;
+_QERFileSystemTable g_FileSystemTable;
+
+// =============================================================================
+// SYNAPSE
+
+CSynapseServer* g_pSynapseServer = NULL;
+CSynapseClientModel g_SynapseClient;
+
+static const XMLConfigEntry_t entries[] = 
+  { { SHADERS_MAJOR, SYN_REQUIRE, sizeof(g_ShadersTable), &g_ShadersTable }, 
+    { VFS_MAJOR, SYN_REQUIRE, sizeof(g_FileSystemTable), &g_FileSystemTable },
+    { NULL, SYN_UNKNOWN, 0, NULL } };
+
+#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() );
+
+  initialise();
+  
+  add_model_apis(g_SynapseClient);
+  g_SynapseClient.AddAPI(TOOLBAR_MAJOR, "model", sizeof(_QERPlugToolbarTable));
+  g_SynapseClient.AddAPI(PLUGIN_MAJOR, "model", 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);
+
+  if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) {
+    return NULL;
+  }
+  
+  return &g_SynapseClient;
+}
+
+bool CSynapseClientModel::RequestAPI(APIDescriptor_t *pAPI)
+{
+  if (!strcmp(pAPI->major_name, MODEL_MAJOR))
+  {
+    _QERPlugModelTable* pTable= static_cast<_QERPlugModelTable*>(pAPI->mpTable);
+
+    if (model_is_supported(pAPI->minor_name))
+    {
+      pTable->m_pfnLoadModel = &LoadModel;
+      return true;
+    }
+  }
+  else if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR))
+  {
+    _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable);
+
+    pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount;
+    pTable->m_pfnGetToolbarButton = &GetToolbarButton;
+    return true;
+  }
+  else 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* CSynapseClientModel::GetInfo()
+{
+  return "picomodel loader module built " __DATE__ " " RADIANT_VERSION;
+}
+
+const char* CSynapseClientModel::GetName()
+{
+  return "model";
+}