3497ba2176bd32299ce968f30b6248ffb51401cb
[xonotic/netradiant.git] / contrib / prtview / prtview.cpp
1 /*
2 PrtView plugin for GtkRadiant
3 Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20 // PrtView.cpp : Defines the initialization routines for the DLL.
21 //
22
23 #include "stdafx.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include "missing.h"
27
28 #define Q3R_CMD_SPLITTER "-"
29 #define Q3R_CMD_ABOUT "About Portal Viewer"
30 #define Q3R_CMD_LOAD "Load .prt file"
31 #define Q3R_CMD_RELEASE "Unload .prt file"
32 #define Q3R_CMD_SHOW_3D "Toggle portals (3D)"
33 #define Q3R_CMD_SHOW_2D "Toggle portals (2D)"
34 #define Q3R_CMD_OPTIONS "Configure Portal Viewer"
35
36 static char INIfn[PATH_MAX];
37
38 /////////////////////////////////////////////////////////////////////////////
39 // CPrtViewApp construction
40
41 #define RENDER_2D "Render2D"
42 #define WIDTH_2D "Width2D"
43 #define AA_2D "AntiAlias2D"
44 #define COLOR_2D "Color2D"
45
46 #define RENDER_3D "Render3D"
47 #define WIDTH_3D "Width3D"
48 #define AA_3D "AntiAlias3D"
49 #define COLOR_3D "Color3D"
50 #define COLOR_FOG "ColorFog"
51 #define FOG "Fog"
52 #define ZBUFFER "ZBuffer"
53 #define POLYGON "Polygons"
54 #define LINE "Lines"
55 #define TRANS_3D "Transparency"
56 #define CLIP_RANGE "ClipRange"
57 #define CLIP "Clip"
58
59 void InitInstance () 
60 {
61 #ifdef WIN32
62   char fn[_MAX_PATH];
63   char fn_drive[_MAX_DRIVE];
64   char fn_dir[_MAX_DIR];
65   char fn_name[_MAX_FNAME];
66   char fn_ext[_MAX_EXT];
67
68   GetModuleFileName(GetModuleHandle("PrtView.dll"), fn, _MAX_PATH);
69
70   _splitpath(fn, fn_drive, fn_dir, fn_name, fn_ext);
71
72   strcpy(INIfn, fn_drive);
73   strcat(INIfn, fn_dir);
74   strcat(INIfn, fn_name);
75   strcat(INIfn, ".ini");
76 #else // if def __linux__
77   strcpy (INIfn, g_get_home_dir ());
78   strcat (INIfn, "/.radiant/");
79   strcat (INIfn, RADIANT_VERSION);
80   strcat (INIfn, "/prtview.ini");
81 #endif
82
83   portals.show_2d = INIGetInt(RENDER_2D, FALSE) ? qtrue : qfalse;
84   portals.aa_2d = INIGetInt(AA_2D, FALSE) ? qtrue : qfalse;
85   portals.width_2d = (float)INIGetInt(WIDTH_2D, 10);
86   portals.color_2d = (COLORREF)INIGetInt(COLOR_2D, RGB(0, 0, 255)) & 0xFFFFFF;
87
88   if (portals.width_2d > 40.0f)
89     portals.width_2d = 40.0f;
90   else if (portals.width_2d < 2.0f)
91     portals.width_2d = 2.0f;
92
93   portals.show_3d = INIGetInt(RENDER_3D, TRUE) ? qtrue : qfalse;
94
95   portals.zbuffer = INIGetInt(ZBUFFER, 1);
96   portals.fog = INIGetInt(FOG, FALSE) ? qtrue : qfalse;
97   portals.polygons = INIGetInt(POLYGON, TRUE);
98   portals.lines = INIGetInt(LINE, TRUE);
99   portals.aa_3d = INIGetInt(AA_3D, FALSE) ? qtrue : qfalse;
100   portals.width_3d = (float)INIGetInt(WIDTH_3D, 4);
101   portals.color_3d = (COLORREF)INIGetInt(COLOR_3D, RGB(255, 255, 0)) & 0xFFFFFF;
102   portals.color_fog = (COLORREF)INIGetInt(COLOR_FOG, RGB(127, 127, 127)) & 0xFFFFFF;
103   portals.trans_3d = (float)INIGetInt(TRANS_3D, 50);
104   portals.clip = INIGetInt(CLIP, FALSE) ? qtrue : qfalse;
105   portals.clip_range = (float)INIGetInt(CLIP_RANGE, 16);
106
107   if (portals.clip_range < 1)
108     portals.clip_range = 1;
109   else if (portals.clip_range > 128)
110     portals.clip_range = 128;
111
112   if (portals.zbuffer < 0)
113     portals.zbuffer = 0;
114   else if (portals.zbuffer > 2)
115     portals.zbuffer = 0;
116
117   if (portals.width_3d > 40.0f)
118     portals.width_3d = 40.0f;
119   else if (portals.width_3d < 2.0f)
120     portals.width_3d = 2.0f;
121
122   if (portals.trans_3d > 100.0f)
123     portals.trans_3d = 100.0f;
124   else if (portals.trans_3d < 0.0f)
125     portals.trans_3d = 0.0f;
126
127   SaveConfig();
128
129   portals.FixColors();
130 }
131
132 void SaveConfig () 
133 {
134   INISetInt(RENDER_2D, portals.show_2d, "Draw in 2D windows");
135   INISetInt(WIDTH_2D, (int)portals.width_2d, "Width of lines in 2D windows (in units of 1/2)");
136   INISetInt(COLOR_2D, (int)portals.color_2d, "Color of lines in 2D windows");
137   INISetInt(AA_2D, portals.aa_2d, "Draw lines in 2D window anti-aliased");
138
139   INISetInt(ZBUFFER, portals.zbuffer, "ZBuffer level in 3D window");
140   INISetInt(FOG, portals.fog, "Use depth cueing in 3D window");
141   INISetInt(POLYGON, portals.polygons, "Render using polygons polygons in 3D window");
142   INISetInt(LINE, portals.polygons, "Render using lines in 3D window");
143   INISetInt(RENDER_3D, portals.show_3d, "Draw in 3D windows");
144   INISetInt(WIDTH_3D, (int)portals.width_3d, "Width of lines in 3D window (in units of 1/2)");
145   INISetInt(COLOR_3D, (int)portals.color_3d, "Color of lines/polygons in 3D window");
146   INISetInt(COLOR_FOG, (int)portals.color_fog, "Color of distant lines/polygons in 3D window");
147   INISetInt(AA_3D, portals.aa_3d, "Draw lines in 3D window anti-aliased");
148   INISetInt(TRANS_3D, (int)portals.trans_3d, "Transparency in 3d view (0 = solid, 100 = invisible)");
149   INISetInt(CLIP, portals.clip, "Cubic clipper active for portal viewer");
150   INISetInt(CLIP_RANGE, (int)portals.clip_range, "Portal viewer cubic clip distance (in units of 64)");
151 }
152
153 // Radiant function table
154 // use to access what Radiant provides
155 _QERFuncTable_1 g_FuncTable;
156 _QERQglTable g_QglTable;
157
158 #define CONFIG_SECTION "Configuration"
159
160 #if defined(__linux__) || defined(__APPLE__)
161
162 static bool read_var (const char *filename, const char *section, const char *key, char *value)
163 {
164   char line[1024], *ptr;
165   FILE *rc;
166   
167   rc = fopen (filename, "rt");
168   
169   if (rc == NULL)
170     return false;
171   
172   while (fgets (line, 1024, rc) != 0)
173   {
174     // First we find the section
175     if (line[0] != '[')
176       continue;
177     
178     ptr = strchr (line, ']');
179     *ptr = '\0';
180     
181     if (strcmp (&line[1], section) == 0)
182     {
183       while (fgets (line, 1024, rc) != 0)
184       {
185         ptr = strchr (line, '=');
186         
187         if (ptr == NULL)
188         {
189           // reached the end of the section
190           fclose (rc);
191           return false;
192         }
193         *ptr = '\0';
194         
195         if (strcmp (line, key) == 0)
196         {
197           strcpy (value, ptr+1);
198           fclose (rc);
199           
200           while (value[strlen (value)-1] == 10 || 
201             value[strlen (value)-1] == 13 ||
202             value[strlen (value)-1] == 32)
203             value[strlen (value)-1] = 0; 
204           return true;
205         }
206       }
207     }
208   }
209
210   fclose (rc);
211   return false;
212 }
213
214 static bool save_var (const char *filename, const char *section, const char *key, const char *value)
215 {
216   char line[1024], *ptr;
217   FILE *old_rc = NULL, *rc;
218   bool found;
219
220   rc = fopen (filename, "rb");
221
222   if (rc != NULL)
223   {
224     guint32 len;
225     void *buf;
226
227     char *tmpname = g_strdup_printf ("%s.tmp", filename);
228     old_rc = fopen (tmpname, "w+b");
229     g_free (tmpname);
230
231     fseek (rc, 0, SEEK_END);
232     len = ftell (rc);
233     rewind (rc);
234     buf = g_malloc (len);
235     fread (buf, len, 1, rc);
236     fwrite (buf, len, 1, old_rc);
237     g_free (buf);
238     fclose (rc);
239     rewind (old_rc);
240   }
241
242   rc = fopen (filename, "wb");
243
244   if (rc == NULL)
245     return false;
246
247   // First we need to find the section
248   found = false;
249   if (old_rc != NULL)
250   while (fgets (line, 1024, old_rc) != NULL)
251   {
252     fputs (line, rc);
253
254     if (line[0] == '[')
255     {
256       ptr = strchr (line, ']');
257       *ptr = '\0';
258
259       if (strcmp (&line[1], section) == 0)
260       {
261         found = true;
262         break;
263       }
264     }
265   } 
266
267   if (!found)
268   {
269     fputs ("\n", rc);
270     fprintf (rc, "[%s]\n", section);
271   }
272
273   fprintf (rc, "%s=%s\n", key, value);
274
275   if (old_rc != NULL)
276   {
277     while (fgets (line, 1024, old_rc) != NULL)
278     {
279       ptr = strchr (line, '=');
280
281       if (ptr != NULL)
282       {
283         *ptr = '\0';
284
285         if (strcmp (line, key) == 0)
286           break;
287  
288         *ptr = '=';
289         fputs (line, rc);
290       }
291       else
292       {
293         fputs (line, rc);
294         break;
295       }
296     }
297
298     while (fgets (line, 1024, old_rc) != NULL)
299       fputs (line, rc);
300     
301     fclose (old_rc);
302
303     char *tmpname = g_strdup_printf ("%s.tmp", filename);
304     remove (tmpname);
305     g_free (tmpname);
306   }
307
308   fclose (rc);
309
310   return true;
311 }
312
313 #endif
314
315 int INIGetInt(char *key, int def)
316 {
317 #if defined(__linux__) || defined(__APPLE__)
318   char value[1024];
319
320   if (read_var (INIfn, CONFIG_SECTION, key, value))
321     return atoi (value);
322   else
323     return def;
324 #else
325   return GetPrivateProfileInt(CONFIG_SECTION, key, def, INIfn);
326 #endif
327 }
328
329 void INISetInt(char *key, int val, char *comment /* = NULL */)
330 {
331   char s[1000];
332
333   if(comment)
334     sprintf(s, "%d        ; %s", val, comment);
335   else
336     sprintf(s, "%d", val);
337 #if defined(__linux__) || defined(__APPLE__)
338   save_var (INIfn, CONFIG_SECTION, key, s);
339 #else
340   WritePrivateProfileString(CONFIG_SECTION, key, s, INIfn);
341 #endif
342 }
343
344
345 // plugin name
346 static const char *PLUGIN_NAME = "Portal Viewer";
347 // commands in the menu
348 static const char *PLUGIN_COMMANDS =
349         Q3R_CMD_ABOUT ";"
350         Q3R_CMD_SPLITTER ";"
351         Q3R_CMD_OPTIONS ";"
352         Q3R_CMD_SPLITTER ";"
353         Q3R_CMD_SHOW_2D ";"
354         Q3R_CMD_SHOW_3D ";"
355         Q3R_CMD_SPLITTER ";"
356         Q3R_CMD_RELEASE ";"
357         Q3R_CMD_LOAD;
358
359 extern "C" LPVOID WINAPI QERPlug_GetFuncTable()
360 {
361   return &g_FuncTable;
362 }
363
364
365 //extern "C" LPCSTR WINAPI QERPlug_Init (HMODULE hApp, GtkWidget* hwndMain)
366 extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget)
367 {  
368   // Setup defaults & load config
369   InitInstance();
370   
371   return "Portal Viewer for Q3Radiant";
372 }
373
374 extern "C" const char* QERPlug_GetName()
375 {
376   return (char*)PLUGIN_NAME;
377 }
378
379 extern "C" const char* QERPlug_GetCommandList()
380 {
381   return (char*)PLUGIN_COMMANDS;
382 }
383
384 /*
385 void Sys_Printf (char *text, ...)
386 {
387   va_list argptr;
388   char buf[32768];
389
390   va_start (argptr,text);
391   vsprintf (buf, text, argptr);
392   va_end (argptr);
393
394   g_FuncTable.m_pfnSysMsg (buf);
395 }
396 */
397
398 bool interfaces_started = false;
399
400 static void CheckInterfaces()
401 {
402   if (interfaces_started)
403     return;
404
405   render.Register();
406
407   interfaces_started = true;
408 }
409
410 extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush)
411 {
412   Sys_Printf (MSG_PREFIX "Command \"%s\"\n",p);
413
414   if (!strcmp(p,Q3R_CMD_ABOUT))
415   {
416     DoAboutDlg ();
417   }
418   else if (!strcmp(p,Q3R_CMD_LOAD))
419   {
420     CheckInterfaces();
421
422     if (interfaces_started)
423     {
424       if (DoLoadPortalFileDialog () == IDOK)
425       {
426         portals.Load();
427         g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL);
428       }
429       else
430       {
431         Sys_Printf(MSG_PREFIX "Portal file load aborted.\n", portals.fn);
432       }
433     }
434   }
435   else if (!strcmp(p,Q3R_CMD_RELEASE))
436   {
437     portals.Purge();
438
439     if (interfaces_started)
440       g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL);
441
442     Sys_Printf(MSG_PREFIX "Portals unloaded.\n");
443   }
444   else if (!strcmp(p,Q3R_CMD_SHOW_2D))
445   {
446     portals.show_2d = !portals.show_2d;
447
448     if(interfaces_started)
449       g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL);
450     SaveConfig();
451
452     if(portals.show_2d)
453       Sys_Printf(MSG_PREFIX "Portals will be rendered in 2D view.\n");
454     else
455       Sys_Printf(MSG_PREFIX "Portals will NOT be rendered in 2D view.\n");
456   }
457   else if (!strcmp(p,Q3R_CMD_SHOW_3D))
458   {
459     portals.show_3d = !portals.show_3d;
460     SaveConfig();
461
462     if (interfaces_started)
463       g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL);
464
465     if (portals.show_3d)
466       Sys_Printf(MSG_PREFIX "Portals will be rendered in 3D view.\n");
467     else
468       Sys_Printf(MSG_PREFIX "Portals will NOT be rendered in 3D view.\n");
469   }
470   else if (!strcmp(p,Q3R_CMD_OPTIONS))
471   {
472     DoConfigDialog ();
473     SaveConfig();
474
475     if (interfaces_started)
476       g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL);
477   }
478 }
479
480
481
482 // =============================================================================
483 // SYNAPSE
484
485 #include "synapse.h"
486
487 class CSynapseClientPrtView : public CSynapseClient
488 {
489 public:
490   // CSynapseClient API
491   bool RequestAPI(APIDescriptor_t *pAPI);
492   const char* GetInfo();
493   
494   CSynapseClientPrtView() { }
495   virtual ~CSynapseClientPrtView() { }
496 };
497
498
499 CSynapseServer* g_pSynapseServer = NULL;
500 CSynapseClientPrtView g_SynapseClient;
501
502 extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer)
503 {
504   if (strcmp(version, SYNAPSE_VERSION))
505   {
506     Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version);
507     return NULL;
508   }
509   g_pSynapseServer = pServer;
510   g_pSynapseServer->IncRef();
511   Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf());
512     
513   g_SynapseClient.AddAPI(PLUGIN_MAJOR, PRTVIEW_MINOR, sizeof(_QERPluginTable));
514
515   g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable);
516   g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(g_QglTable), SYN_REQUIRE, &g_QglTable);
517
518   return &g_SynapseClient;
519 }
520
521 bool CSynapseClientPrtView::RequestAPI(APIDescriptor_t *pAPI)
522 {
523   if( !strcmp(pAPI->major_name, PLUGIN_MAJOR) )
524   {
525     if( !strcmp(pAPI->minor_name, PRTVIEW_MINOR) )
526     {
527       _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable);
528
529       pTable->m_pfnQERPlug_Init = QERPlug_Init;
530       pTable->m_pfnQERPlug_GetName = QERPlug_GetName;
531       pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList;
532       pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch;
533       return true;
534     }
535   }
536
537   Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo());
538   return false;
539 }
540
541 #include "version.h"
542
543 const char* CSynapseClientPrtView::GetInfo()
544 {
545   return "PrtView module built " __DATE__ " " RADIANT_VERSION;
546 }