* moved zeroradiant (1.6) into trunk
[xonotic/netradiant.git] / radiant / brushscript.cpp
1 /*
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 // BrushScript stuff
23 //
24
25 /*!
26 \todo is this still used / in working state?
27 should we cleanup and remove it for good
28 */
29
30 #include "stdafx.h"
31 #include "gtkmisc.h"
32
33 //
34 struct SVariableDef
35 {
36   CString m_strName;
37   CString m_strInput;
38   float m_fValue;
39 };
40
41 struct SVecVariableDef
42 {
43   CString m_strName;
44   CString m_strInput;
45   vec3_t m_vValue;
46 };
47
48
49
50 const int MAX_VARIABLES = 64;
51
52 brush_t* g_pHold1 = NULL;
53 brush_t* g_pHold2 = NULL;
54 brush_t* g_pHold3 = NULL;
55 bool g_bRotateAroundSelection;
56 int g_nVariableCount;
57 int g_nVecVariableCount;
58 int g_nLoopCounter;
59 float g_fDefault = 9999.9f;
60 vec3_t g_vDefault;
61 bool g_bStartLoop;
62 char* g_pLooper;
63 bool g_bKeepGoing;
64
65 SVariableDef g_Variables[MAX_VARIABLES];
66 SVecVariableDef g_VecVariables[MAX_VARIABLES];
67
68 void InitForScriptRun()
69 {
70   g_pHold1 = NULL;
71   g_pHold2 = NULL;
72   g_pHold3 = NULL;
73   g_bRotateAroundSelection = true;
74   g_nVariableCount = 0;
75   g_nVecVariableCount = 0;
76   g_nLoopCounter = 0;
77   g_bStartLoop = false;
78   g_pLooper = NULL;
79   g_bKeepGoing = true;
80 }
81
82 void AddVariable(const char* pName, float fValue, const char* pInput = NULL)
83 {
84   if (g_nVariableCount < MAX_VARIABLES)
85   {
86     g_Variables[g_nVariableCount].m_strName = pName;
87     g_Variables[g_nVariableCount].m_strName.MakeLower();
88     g_Variables[g_nVariableCount].m_fValue = fValue;
89     if (pInput)
90       g_Variables[g_nVariableCount].m_strInput = pInput;
91     g_nVariableCount++;
92   }
93   else
94     gtk_MessageBox(g_pParentWnd->m_pWidget, "Maximum script variable limit reached!");
95 }
96
97 float VariableValue(const char* pName)
98 {
99   CString strName = pName;
100   strName.MakeLower();
101   for (int n = 0; n < g_nVariableCount; n++)
102   {
103     if (strName == g_Variables[n].m_strName)
104       return g_Variables[n].m_fValue;
105   }
106   //strName.Format("Reference to non-existant varirable %s", pName);
107   //g_pParentWnd->MessageBox(strName);
108   return g_fDefault;
109 }
110
111 void SetVariableValue(const char* pName, float fValue)
112 {
113   CString strName = pName;
114   strName.MakeLower();
115   for (int n = 0; n < g_nVariableCount; n++)
116   {
117     if (strName == g_Variables[n].m_strName)
118       g_Variables[n].m_fValue = fValue;
119   }
120 }
121
122
123
124 void AddVectorVariable(const char* pName, const char* pInput = NULL)
125 {
126   if (g_nVecVariableCount < MAX_VARIABLES)
127   {
128     g_VecVariables[g_nVecVariableCount].m_strName = pName;
129     g_VecVariables[g_nVecVariableCount].m_strName.MakeLower();
130     if (pInput)
131       g_VecVariables[g_nVariableCount].m_strInput = pInput;
132     g_nVecVariableCount++;
133   }
134   else
135     gtk_MessageBox(g_pParentWnd->m_pWidget, "Maximum script variable limit reached!");
136 }
137
138 void VectorVariableValue(const char* pName, vec3_t& v)
139 {
140   CString strName = pName;
141   strName.MakeLower();
142   for (int n = 0; n < g_nVecVariableCount; n++)
143   {
144     if (strName == g_VecVariables[n].m_strName)
145     {
146       VectorCopy(g_VecVariables[n].m_vValue, v);
147       return;
148     }
149   }
150   strName.Format("Reference to non-existant variable %s", pName);
151   gtk_MessageBox(g_pParentWnd->m_pWidget, strName);
152 }
153
154 void SetVectorVariableValue(const char* pName, vec3_t v)
155 {
156   CString strName = pName;
157   strName.MakeLower();
158   for (int n = 0; n < g_nVecVariableCount; n++)
159   {
160     if (strName == g_VecVariables[n].m_strName)
161       VectorCopy(v, g_VecVariables[n].m_vValue);
162   }
163 }
164
165
166
167
168
169 // commands
170 //
171 // _CopySelected(nHoldPos)  
172 // copies selected brush to hold spot 1, 2 or 3
173 //
174 // _MoveSelected(x, y, z)
175 // moves selected brush by coords provided
176 //
177 // _RotateSelected(x, y, z)
178 // rotates selected brush by coords provided
179 //
180 // _MoveHold(nHoldPos, x, y, z)
181 // moves brush in hold pos by coords provided
182 //
183 // _RotateHold(nHoldPos, x, y, z)
184 // rotates brush in hold pos by coords provided
185 //
186 // _CopyToMap(nHoldPos)
187 // copies hold brush to map
188 //
189 // _CopyAndSelect(nHoldPos)
190 // copies hold brush to map and selects it
191 //
192 // _Input(VarName1, ... VarNamennn)
193 // inputs a list of values from the user
194 //
195
196 typedef void (PFNScript)(char*&);
197
198
199 struct SBrushScript
200 {
201   const char* m_pName;
202   PFNScript* m_pProc;
203 };
204
205
206 const char* GetParam(char*& pBuffer)
207 {
208   static CString strParam;
209   bool bStringMode = false;
210
211   while (*pBuffer != (char)NULL && isspace(*pBuffer))   // skip and whitespace
212     pBuffer++;
213
214   if (*pBuffer == '(') // if it's an opening paren, skip it
215     pBuffer++;
216
217   if (*pBuffer == '\"') // string ?
218   {
219     pBuffer++;
220     bStringMode = true;
221   }
222
223   strParam = "";
224
225   if (bStringMode)
226   {
227     while (*pBuffer != (char)NULL && *pBuffer != '\"')
228       strParam += *pBuffer++;
229   }
230   else
231   {
232     while (*pBuffer != (char)NULL && *pBuffer != ' ' && *pBuffer != ')' && *pBuffer != ',')
233       strParam += *pBuffer++;
234   }
235
236   if (*pBuffer != (char)NULL)   // skip last char
237     pBuffer++;
238
239   if (strParam.GetLength() > 0)
240   {
241     if (strParam.GetAt(0) == '$') // ? variable name
242     {
243       float f = VariableValue(strParam);
244       if (f != g_fDefault)
245         strParam.Format("%f", f);
246     }
247   }
248
249   return strParam;
250 }
251
252 brush_t* CopyBrush(brush_t* p)
253 {                            
254   brush_t* pCopy = Brush_Clone(p);
255         //Brush_AddToList (pCopy, &active_brushes);
256         //Entity_LinkBrush (world_entity, pCopy);
257         Brush_Build(pCopy, false);
258
259   return pCopy;
260 }
261
262
263 void CopySelected(char*& pBuffer)
264 {
265   // expects one param
266   CString strParam = GetParam(pBuffer);
267   int n = atoi(strParam);
268
269   brush_t* pCopy = NULL;
270   if (selected_brushes.next != &selected_brushes && 
271       selected_brushes.next->next == &selected_brushes)
272     pCopy = selected_brushes.next;
273
274   if (pCopy)
275   {
276     if (n == 1)
277     {
278       //if (g_pHold1)
279         //Brush_Free(g_pHold1);
280       g_pHold1 = CopyBrush(pCopy);
281     }
282     else if (n == 2)
283     {
284       //if (g_pHold2)
285         //Brush_Free(g_pHold2);
286       g_pHold2 = CopyBrush(pCopy);
287     }
288     else
289     {
290       //if (g_pHold3)
291         //Brush_Free(g_pHold3);
292       g_pHold3 = CopyBrush(pCopy);
293     }
294   }
295 }
296
297 void MoveSelected(char*& pBuffer)
298 {
299   vec3_t v;
300   CString strParam = GetParam(pBuffer);
301   v[0] = atof(strParam);
302   strParam = GetParam(pBuffer);
303   v[1] = atof(strParam);
304   strParam = GetParam(pBuffer);
305   v[2] = atof(strParam);
306   Select_Move(v, false);
307   Sys_UpdateWindows(W_ALL);
308 }
309
310 void RotateSelected(char*& pBuffer)
311 {
312   vec3_t v;
313
314   if (g_bRotateAroundSelection)
315   {
316     Select_GetTrueMid(v);
317     VectorCopy(v, g_pParentWnd->ActiveXY()->RotateOrigin());
318   }
319
320   CString strParam = GetParam(pBuffer);
321   v[0] = atof(strParam);
322   strParam = GetParam(pBuffer);
323   v[1] = atof(strParam);
324   strParam = GetParam(pBuffer);
325   v[2] = atof(strParam);
326   for (int i = 0; i < 3; i++)
327     if (v[i] != 0.0)
328       Select_RotateAxis(i, v[i], false , true);
329   Sys_UpdateWindows(W_ALL);
330 }
331
332 void MoveHold(char*& pBuffer)
333 {
334   CString strParam = GetParam(pBuffer);
335   brush_t* pBrush = NULL;
336   int nHold = atoi(strParam);
337   if (nHold == 1)
338     pBrush = g_pHold1;
339   else if (nHold == 2)
340     pBrush = g_pHold2;
341   else 
342     pBrush = g_pHold3;
343
344   if (pBrush)
345   {
346     vec3_t v;
347     strParam = GetParam(pBuffer);
348     v[0] = atof(strParam);
349     strParam = GetParam(pBuffer);
350     v[1] = atof(strParam);
351     strParam = GetParam(pBuffer);
352     v[2] = atof(strParam);
353                 Brush_Move (pBrush, v, false);
354   }
355 }
356
357 void RotateHold(char*& pBuffer)
358 {
359   CString strParam = GetParam(pBuffer);
360   brush_t* pBrush = NULL;
361   int nHold = atoi(strParam);
362   if (nHold == 1)
363     pBrush = g_pHold1;
364   else if (nHold == 2)
365     pBrush = g_pHold2;
366   else 
367     pBrush = g_pHold3;
368
369   if (pBrush)
370   {
371     vec3_t v;
372     strParam = GetParam(pBuffer);
373     v[0] = atof(strParam);
374     strParam = GetParam(pBuffer);
375     v[1] = atof(strParam);
376     strParam = GetParam(pBuffer);
377     v[2] = atof(strParam);
378     for (int i = 0; i < 3; i++)
379       if (v[i] != 0.0)
380         Select_RotateAxis(i, v[i]);
381   }
382 }
383
384 void CopyToMap(char*& pBuffer)
385 {
386   CString strParam = GetParam(pBuffer);
387   brush_t* pBrush = NULL;
388   int nHold = atoi(strParam);
389   if (nHold == 1)
390     pBrush = g_pHold1;
391   else if (nHold == 2)
392     pBrush = g_pHold2;
393   else 
394     pBrush = g_pHold3;
395
396   if (pBrush)
397   {
398     Brush_AddToList(pBrush, &active_brushes);
399                 Entity_LinkBrush (world_entity, pBrush);
400                 Brush_Build(pBrush, false);
401                 
402     Sys_UpdateWindows(W_ALL);
403   }
404 }
405
406 void CopyAndSelect(char*& pBuffer)
407 {
408   CString strParam = GetParam(pBuffer);
409   brush_t* pBrush = NULL;
410   int nHold = atoi(strParam);
411   if (nHold == 1)
412     pBrush = g_pHold1;
413   else if (nHold == 2)
414     pBrush = g_pHold2;
415   else 
416     pBrush = g_pHold3;
417
418   if (pBrush)
419   {
420     Select_Deselect();
421     Brush_AddToList(pBrush, &active_brushes);
422                 Entity_LinkBrush (world_entity, pBrush);
423                 Brush_Build(pBrush, false);
424
425         Select_Brush(pBrush);
426     Sys_UpdateWindows(W_ALL);
427   }
428 }
429
430 void Input(char*& pBuffer)
431 {
432   bool bGo = false;
433   const char *fields[5] = { "", "", "", "", "" };
434   float values[5];
435
436   for (int n = 0; n < g_nVariableCount; n++)
437   {
438     if (g_Variables[n].m_strInput.GetLength() > 0)
439     {
440       bGo = true;
441       if (n < 5)
442       {
443         switch (n)
444         {
445           case 0 : fields[1] = g_Variables[n].m_strInput.GetBuffer (); break;
446           case 1 : fields[2] = g_Variables[n].m_strInput.GetBuffer (); break;
447           case 2 : fields[3] = g_Variables[n].m_strInput.GetBuffer (); break;
448           case 3 : fields[4] = g_Variables[n].m_strInput.GetBuffer (); break;
449           case 4 : fields[5] = g_Variables[n].m_strInput.GetBuffer (); break;
450         }
451       }
452     }
453   }
454
455   if (bGo)
456   {
457     if (DoBSInputDlg (fields, values) == IDOK)
458     {
459       for (int n = 0; n < g_nVariableCount; n++)
460       {
461         if (g_Variables[n].m_strInput.GetLength() > 0)
462         {
463           if (n < 5)
464           {
465             switch (n)
466             {
467               case 0 : g_Variables[n].m_fValue = values[1]; break;
468               case 1 : g_Variables[n].m_fValue = values[2]; break;
469               case 2 : g_Variables[n].m_fValue = values[3]; break;
470               case 3 : g_Variables[n].m_fValue = values[4]; break;
471               case 4 : g_Variables[n].m_fValue = values[5]; break;
472             }
473           }
474         }
475       }
476     }
477     else g_bKeepGoing = false;
478   }
479 }
480
481 bool g_bWaiting;
482 void _3DPointDone(bool b, int n)
483 {
484   g_bWaiting = false;
485 }
486
487 void _3DPointInput(char*& pBuffer)
488 {
489   CString strParam = GetParam(pBuffer);
490   CString strParam2 = GetParam(pBuffer);
491   ShowInfoDialog(strParam2);
492   AddVectorVariable(strParam, strParam2);
493   g_bWaiting = true;
494   AcquirePath(2, &_3DPointDone);
495   while (g_bWaiting)
496     gtk_main_iteration ();
497   HideInfoDialog();
498   SetVectorVariableValue(strParam, g_PathPoints[0]);
499 }
500
501 void SetRotateOrigin(char*& pBuffer)
502 {
503   vec3_t v;
504   CString strParam = GetParam(pBuffer);
505   VectorVariableValue(strParam, v);
506   VectorCopy(v, g_pParentWnd->ActiveXY()->RotateOrigin());
507   g_bRotateAroundSelection = false;
508 }
509
510 void InputVar(char*& pBuffer)
511 {
512   CString strParam = GetParam(pBuffer);
513   CString strParam2 = GetParam(pBuffer);
514   AddVariable(strParam, 0.0, strParam2);
515 }
516
517 void LoopCount(char*& pBuffer)
518 {
519   CString strParam = GetParam(pBuffer);
520   g_nLoopCounter = atoi(strParam);
521   if (g_nLoopCounter == 0)
522     g_nLoopCounter = (int)VariableValue(strParam);
523   if (g_nLoopCounter > 0)
524     g_pLooper = pBuffer;
525 }
526
527 void LoopRun(char*& pBuffer)
528 {
529   if (g_bStartLoop == true)
530   {
531     g_nLoopCounter--;
532     if (g_nLoopCounter == 0)
533     {
534       g_bStartLoop = false;
535       GetParam(pBuffer);
536     }
537     else
538       pBuffer = g_pLooper;
539   }
540   else
541   {
542     if (g_pLooper && g_nLoopCounter > 0)
543     {
544       g_bStartLoop = true;
545       pBuffer = g_pLooper;
546     }
547     else
548     {
549       GetParam(pBuffer);
550     }
551   }
552 }
553
554
555 void ConfirmMessage(char*& pBuffer)
556 {
557   CString strParam = GetParam(pBuffer);
558   if (gtk_MessageBox(g_pParentWnd->m_pWidget, strParam, "Script Info", MB_OKCANCEL) == IDCANCEL)
559     g_bKeepGoing = false;
560 }
561
562 void Spherize(char*& pBuffer)
563 {
564   g_bScreenUpdates = false;
565   for (int n = 0; n < 120; n += 36)
566   {
567     for (int i = 0; i < 360; i += 36)
568     {
569       Select_RotateAxis(0, i, false , true);
570       CSG_Subtract();
571     }
572     Select_RotateAxis(2, n, false , true);
573   }
574   g_bScreenUpdates = true;
575 }
576
577 void RunIt(char*& pBuffer);
578 SBrushScript g_ScriptCmds[] =
579 {
580   {"_CopySelected", &CopySelected},
581   {"_MoveSelected", &MoveSelected},
582   {"_RotateSelected", &RotateSelected},
583   {"_MoveHold", &MoveHold},
584   {"_RotateHold", &RotateHold},
585   {"_CopyToMap", &CopyToMap},
586   {"_CopyAndSelect", &CopyAndSelect},
587   {"_Input", &Input},
588   {"_3DPointInput", &_3DPointInput},
589   {"_SetRotateOrigin", &SetRotateOrigin},
590   {"_InputVar", &InputVar},
591   {"_LoopCount", &LoopCount},
592   {"_LoopRun", &LoopRun},
593   {"_ConfirmMessage", &ConfirmMessage},
594   {"_Spherize", &Spherize},
595   {"_RunScript", RunIt}
596 };
597
598 const int g_nScriptCmdCount = sizeof(g_ScriptCmds) / sizeof(SBrushScript);
599
600 void RunScript(char* pBuffer)
601 {
602   g_pHold1 = NULL;
603   g_pHold2 = NULL;
604   g_pHold3 = NULL;
605
606   while (g_bKeepGoing && pBuffer && *pBuffer)
607   {
608     while (*pBuffer != (char)NULL && *pBuffer != '_')
609       pBuffer++;
610
611     char* pTemp = pBuffer;
612     int nLen = 0;
613     while (*pTemp != (char)NULL && *pTemp != '(')
614     {
615       pTemp++;
616       nLen++;
617     }
618     if (*pBuffer != (char)NULL)
619     {
620       bool bFound = false;
621       for (int i = 0; i < g_nScriptCmdCount; i++)
622       {
623         //if (strnicmp(g_ScriptCmds[i].m_pName, pBuffer, strlen(g_ScriptCmds[i].m_pName)) ==  0)
624         if (strnicmp(g_ScriptCmds[i].m_pName, pBuffer, nLen) ==  0)
625         {
626           pBuffer += strlen(g_ScriptCmds[i].m_pName);
627           g_ScriptCmds[i].m_pProc(pBuffer);
628           if (g_bStartLoop)
629           {
630           }
631           bFound = true;
632           break;
633         }
634       }
635       if (!bFound)
636         pBuffer++;
637     }
638   }
639 }
640
641
642 void RunScriptByName(char* pBuffer, bool bInit)
643 {
644   if (bInit)
645     InitForScriptRun();
646   char* pScript = new char[4096];
647   CString strINI;
648   strINI = g_strGameToolsPath;
649   strINI += "/scripts.ini";
650   CString strScript;
651   FILE *f;
652
653   f = fopen (strINI.GetBuffer(), "rt");
654   if (f != NULL)
655   {
656     char line[1024], *ptr;
657
658     // read section names
659     while (fgets (line, 1024, f) != 0)
660     {
661       if (line[0] != '[')
662         continue;
663
664       ptr = strchr (line, ']');
665       *ptr = '\0';
666
667       if (strcmp (line, pScript) == 0)
668       {
669         while (fgets (line, 1024, f) != 0)
670         {
671           if ((strchr (line, '=') == NULL) ||
672               strlen (line) == 0)
673             break;
674           strScript += line;
675         }
676         break;
677       }
678     }
679     fclose (f);
680   }
681   RunScript((char*)strScript.GetBuffer());
682 }
683
684
685 void RunIt(char*& pBuffer)
686 {
687   brush_t* p1 = g_pHold1;
688   brush_t* p2 = g_pHold2;
689   brush_t* p3 = g_pHold3;
690
691   CString strParam = GetParam(pBuffer);
692   RunScriptByName((char*)strParam.GetBuffer(), false);
693
694   g_pHold3 = p3;
695   g_pHold2 = p2;
696   g_pHold1 = p1;
697 }
698