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