Merge branch 'ingar/png_icons' into 'master'
[xonotic/netradiant.git] / contrib / bobtoolz / misc.cpp
1 /*
2    BobToolz plugin for GtkRadiant
3    Copyright (C) 2001 Gordon Biggans
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 #include "misc.h"
21
22 #include <list>
23 #include "str.h"
24
25 #include "DPoint.h"
26 #include "DPlane.h"
27 #include "DBrush.h"
28 #include "DEPair.h"
29 #include "DPatch.h"
30 #include "DEntity.h"
31
32 #include "funchandlers.h"
33
34 #if defined ( POSIX )
35 #include <sys/types.h>
36 #include <unistd.h>
37 #endif
38
39 #include "iundo.h"
40 #include "ientity.h"
41 #include "iscenegraph.h"
42 #include "qerplugin.h"
43
44 #include <vector>
45 #include <list>
46 #include <map>
47 #include <algorithm>
48
49 #include "scenelib.h"
50
51 /*==========================
52         Global Vars
53    ==========================*/
54
55 //HANDLE bsp_process;
56 char g_CurrentTexture[256] = "";
57
58 //=============================================================
59 //=============================================================
60
61 void ReadCurrentTexture(){
62         const char* textureName = GlobalRadiant().TextureBrowser_getSelectedShader();
63         strcpy( g_CurrentTexture, textureName );
64 }
65
66 const char*  GetCurrentTexture(){
67         ReadCurrentTexture();
68         return g_CurrentTexture;
69 }
70
71 void MoveBlock( int dir, vec3_t min, vec3_t max, float dist ){
72         switch ( dir )
73         {
74         case MOVE_EAST:
75         {
76                 min[0] += dist;
77                 max[0] += dist;
78                 break;
79         }
80         case MOVE_WEST:
81         {
82                 min[0] -= dist;
83                 max[0] -= dist;
84                 break;
85         }
86         case MOVE_NORTH:
87         {
88                 min[1] += dist;
89                 max[1] += dist;
90                 break;
91         }
92         case MOVE_SOUTH:
93         {
94                 min[1] -= dist;
95                 max[1] -= dist;
96                 break;
97         }
98         }
99 }
100
101 void SetInitialStairPos( int dir, vec3_t min, vec3_t max, float width ){
102         switch ( dir )
103         {
104         case MOVE_EAST:
105         {
106                 max[0] = min[0] + width;
107                 break;
108         }
109         case MOVE_WEST:
110         {
111                 min[0] = max[0] - width;
112                 break;
113         }
114         case MOVE_NORTH:
115         {
116                 max[1] = min[1] + width;
117                 break;
118         }
119         case MOVE_SOUTH:
120         {
121                 min[1] = max[1] - width;
122                 break;
123         }
124         }
125 }
126
127 char* TranslateString( char *buf ){
128         static char buf2[32768];
129
130         std::size_t l = strlen( buf );
131         char* out = buf2;
132         for ( int i = 0 ; i < l ; i++ )
133         {
134                 if ( buf[i] == '\n' ) {
135                         *out++ = '\r';
136                         *out++ = '\n';
137                 }
138                 else{
139                         *out++ = buf[i];
140                 }
141         }
142         *out++ = 0;
143
144         return buf2;
145 }
146
147
148 char* UnixToDosPath( char* path ){
149 #ifndef WIN32
150         return path;
151 #else
152         for ( char* p = path; *p; p++ )
153         {
154                 if ( *p == '/' ) {
155                         *p = '\\';
156                 }
157         }
158         return path;
159 #endif
160 }
161
162 const char* ExtractFilename( const char* path ){
163         const char* p = strrchr( path, '/' );
164         if ( !p ) {
165                 p = strrchr( path, '\\' );
166
167                 if ( !p ) {
168                         return path;
169                 }
170         }
171         return ++p;
172 }
173
174 extern char* PLUGIN_NAME;
175 /*char* GetGameFilename(char* buffer, const char* filename)
176    {
177     strcpy(buffer, g_FuncTable.m_pfnGetGamePath());
178     char* p = strrchr(buffer, '/');
179    *++p = '\0';
180     strcat(buffer, filename);
181     buffer = UnixToDosPath(buffer);
182     return buffer;
183    }*/
184
185 #if defined ( POSIX )
186 // the bCreateConsole parameter is ignored on linux ..
187 bool Q_Exec( const char *pCmd, bool bCreateConsole ){
188         switch ( fork() )
189         {
190         case -1:
191                 return false;
192 //      Error ("CreateProcess failed");
193                 break;
194         case 0:
195 #ifdef _DEBUG
196                 printf( "Running system...\n" );
197                 printf( "Command: %s\n", pCmd );
198 #endif
199                 // NOTE: we could use that to detect when a step finishes. But then it
200                 // would not work for remote compiling stuff.
201 //      execlp (pCmd, pCmd, NULL);
202                 system( pCmd );
203                 printf( "system() returned" );
204                 _exit( 0 );
205                 break;
206         }
207         return true;
208 }
209 #endif
210
211 #ifdef WIN32
212
213 #include <windows.h>
214
215 bool Q_Exec( const char *pCmd, bool bCreateConsole ){
216         // G_DeWan: Don't know if this is needed for linux version
217
218         PROCESS_INFORMATION pi;
219         STARTUPINFO si = {0};            // Initialize all members to zero
220         si.cb = sizeof( STARTUPINFO );     // Set byte count
221         DWORD dwCreationFlags;
222
223         if ( bCreateConsole ) {
224                 dwCreationFlags = CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS;
225         }
226         else{
227                 dwCreationFlags = DETACHED_PROCESS | NORMAL_PRIORITY_CLASS;
228         }
229
230         for (; *pCmd == ' '; pCmd++ ) ;
231
232         if ( !CreateProcess( NULL, (char *)pCmd, NULL, NULL, false, dwCreationFlags, NULL, NULL, &si, &pi ) ) {
233                 return false;
234         }
235
236         return true;
237 }
238 #endif
239
240 void StartBSP(){
241         char exename[256];
242         GetFilename( exename, "q3map" );
243         UnixToDosPath( exename ); // do we want this done in linux version?
244
245         char mapname[256];
246         const char *pn = GlobalRadiant().getMapsPath();
247
248         strcpy( mapname, pn );
249         strcat( mapname, "/ac_prt.map" );
250         UnixToDosPath( mapname );
251
252         char command[1024];
253         sprintf( command, "%s -nowater -fulldetail %s", exename, mapname );
254
255         Q_Exec( command, true );
256 }
257
258 class EntityWriteMiniPrt
259 {
260 mutable DEntity world;
261 FILE* pFile;
262 std::list<Str>* exclusionList;
263 public:
264 EntityWriteMiniPrt( FILE* pFile, std::list<Str>* exclusionList )
265         : pFile( pFile ), exclusionList( exclusionList ){
266 }
267 void operator()( scene::Instance& instance ) const {
268         const char* classname = Node_getEntity( instance.path().top() )->getKeyValue( "classname" );
269
270         if ( !strcmp( classname, "worldspawn" ) ) {
271                 world.LoadFromEntity( instance.path().top(), false );
272                 world.RemoveNonCheckBrushes( exclusionList, true );
273                 world.SaveToFile( pFile );
274         }
275         else if ( strstr( classname, "info_" ) ) {
276                 world.ClearBrushes();
277                 world.ClearEPairs();
278                 world.LoadEPairList( Node_getEntity( instance.path().top() ) );
279                 world.SaveToFile( pFile );
280         }
281 }
282 };
283
284 void BuildMiniPrt( std::list<Str>* exclusionList ){
285         // yes, we could just use -fulldetail option, but, as SPOG said
286         // it'd be faster without all the hint, donotenter etc textures and
287         // doors, etc
288
289
290
291         char buffer[128];
292         const char *pn = GlobalRadiant().getMapsPath();
293
294         strcpy( buffer, pn );
295         strcat( buffer, "/ac_prt.map" );
296         FILE* pFile = fopen( buffer, "w" );
297
298         // ahem, thx rr2
299         if ( !pFile ) {
300                 return;
301         }
302
303         Scene_forEachEntity( EntityWriteMiniPrt( pFile, exclusionList ) );
304
305         fclose( pFile );
306
307         StartBSP();
308 }
309
310 class EntityFindByTargetName
311 {
312 const char* targetname;
313 public:
314 mutable const scene::Path* result;
315 EntityFindByTargetName( const char* targetname )
316         : targetname( targetname ), result( 0 ){
317 }
318 void operator()( scene::Instance& instance ) const {
319         if ( result == 0 ) {
320                 const char* value = Node_getEntity( instance.path().top() )->getKeyValue( "targetname" );
321
322                 if ( !strcmp( value, targetname ) ) {
323                         result = &instance.path();
324                 }
325         }
326 }
327 };
328
329 const scene::Path* FindEntityFromTargetname( const char* targetname ){
330         return Scene_forEachEntity( EntityFindByTargetName( targetname ) ).result;
331 }
332
333 void FillDefaultTexture( _QERFaceData* faceData, vec3_t va, vec3_t vb, vec3_t vc, const char* texture ){
334         faceData->m_texdef.rotate = 0;
335         faceData->m_texdef.scale[0] = 0.5;
336         faceData->m_texdef.scale[1] = 0.5;
337         faceData->m_texdef.shift[0] = 0;
338         faceData->m_texdef.shift[1] = 0;
339         faceData->contents = 0;
340         faceData->flags = 0;
341         faceData->value = 0;
342         if ( *texture ) {
343                 faceData->m_shader = texture;
344         }
345         else{
346                 faceData->m_shader = "textures/common/caulk";
347         }
348         VectorCopy( va, faceData->m_p0 );
349         VectorCopy( vb, faceData->m_p1 );
350         VectorCopy( vc, faceData->m_p2 );
351 }
352
353 float Determinant3x3( float a1, float a2, float a3,
354                                           float b1, float b2, float b3,
355                                           float c1, float c2, float c3 ){
356         return a1 * ( b2 * c3 - b3 * c2 ) - a2 * ( b1 * c3 - b3 * c1 ) + a3 * ( b1 * c2 - b2 * c1 );
357 }
358
359 bool GetEntityCentre( const char* entity, vec3_t centre ){
360         const scene::Path* ent = FindEntityFromTargetname( entity );
361         if ( !ent ) {
362                 return false;
363         }
364
365         scene::Instance& instance = *GlobalSceneGraph().find( *ent );
366         VectorCopy( instance.worldAABB().origin, centre );
367
368         return true;
369 }
370
371 vec_t Min( vec_t a, vec_t b ){
372         if ( a < b ) {
373                 return a;
374         }
375         return b;
376 }
377
378 void MakeNormal( const vec_t* va, const vec_t* vb, const vec_t* vc, vec_t* out ) {
379         vec3_t v1, v2;
380         VectorSubtract( va, vb, v1 );
381         VectorSubtract( vc, vb, v2 );
382         CrossProduct( v1, v2, out );
383 }
384
385 char* GetFilename( char* buffer, const char* filename ) {
386         strcpy( buffer, GlobalRadiant().getAppPath() );
387         strcat( buffer, "plugins/" );
388         strcat( buffer, filename );
389         return buffer;
390 }