refactored plugin api; refactored callback library; added signals library
[xonotic/netradiant.git] / contrib / bobtoolz / DBobView.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 // BobView.cpp: implementation of the DBobView class.
21 //
22 //////////////////////////////////////////////////////////////////////
23
24 #include "DBobView.h"
25 //#include "misc.h"
26 #include "funchandlers.h"
27
28 #include <list>
29
30 #include "iglrender.h"
31 #include "qerplugin.h"
32 #include "str.h"
33 #include "math/matrix.h"
34
35 #include "DEntity.h"
36 #include "DEPair.h"
37 #include "misc.h"
38 #include "dialogs/dialogs-gtk.h"
39
40 //////////////////////////////////////////////////////////////////////
41 // Construction/Destruction
42 //////////////////////////////////////////////////////////////////////
43
44 DBobView::DBobView()
45 {
46         nPathCount = 0;
47         
48         path = NULL;
49
50         boundingShow = BOUNDS_APEX;
51
52   constructShaders();
53   GlobalShaderCache().attachRenderable(*this);
54 }
55
56 DBobView::~DBobView()
57 {
58   GlobalShaderCache().detachRenderable(*this);
59   destroyShaders();
60
61   if(path)
62                 delete[] path;
63
64         g_PathView = NULL;
65 }
66
67 //////////////////////////////////////////////////////////////////////
68 // Implementation
69 //////////////////////////////////////////////////////////////////////
70
71 void DBobView::render(RenderStateFlags state) const
72 {
73         glBegin(GL_LINE_STRIP);
74
75         for(int i = 0; i < nPathCount; i++)
76                 glVertex3fv(path[i]);
77
78         glEnd();
79 }
80
81 const char* DBobView_state_line = "$bobtoolz/bobview/line";
82 const char* DBobView_state_box = "$bobtoolz/bobview/box";
83
84 void DBobView::constructShaders()
85 {
86   OpenGLState state;
87   GlobalOpenGLStateLibrary().getDefaultState(state);
88   state.m_state = RENDER_COLOURWRITE|RENDER_DEPTHWRITE|RENDER_BLEND|RENDER_LINESMOOTH;
89   state.m_sort = OpenGLState::eSortOpaque;
90   state.m_linewidth = 1;
91   state.m_colour[0] = 1;
92   state.m_colour[1] = 0;
93   state.m_colour[2] = 0;
94   state.m_colour[3] = 1;
95   GlobalOpenGLStateLibrary().insert(DBobView_state_line, state);
96
97   state.m_colour[0] = 0.25f;
98   state.m_colour[1] = 0.75f;
99   state.m_colour[2] = 0.75f;
100   state.m_colour[3] = 1;
101   GlobalOpenGLStateLibrary().insert(DBobView_state_box, state);
102
103   m_shader_line = GlobalShaderCache().capture(DBobView_state_line);
104   m_shader_box = GlobalShaderCache().capture(DBobView_state_box);
105 }
106
107 void DBobView::destroyShaders()
108 {
109   GlobalOpenGLStateLibrary().erase(DBobView_state_line);
110   GlobalOpenGLStateLibrary().erase(DBobView_state_box);
111   GlobalShaderCache().release(DBobView_state_line);
112   GlobalShaderCache().release(DBobView_state_box);
113 }
114
115 Matrix4 g_transform_box1 = matrix4_translation_for_vec3(Vector3(16.0f, 16.0f, 28.0f));
116 Matrix4 g_transform_box2 = matrix4_translation_for_vec3(Vector3(-16.0f, 16.0f, 28.0f));
117 Matrix4 g_transform_box3 = matrix4_translation_for_vec3(Vector3(16.0f, -16.0f, -28.0f));
118 Matrix4 g_transform_box4 = matrix4_translation_for_vec3(Vector3(-16.0f, -16.0f, -28.0f));
119
120 void DBobView::renderSolid(Renderer& renderer, const VolumeTest& volume) const
121 {
122         if(!path)
123                 return;
124
125   renderer.SetState(m_shader_line, eWireframeOnly);
126   renderer.SetState(m_shader_line, eFullMaterials);
127   renderer.addRenderable(*this, g_matrix4_identity);
128
129         if(m_bShowExtra)
130         {
131     renderer.SetState(m_shader_box, eWireframeOnly);
132     renderer.SetState(m_shader_box, eFullMaterials);
133     renderer.addRenderable(*this, g_transform_box1);
134     renderer.addRenderable(*this, g_transform_box2);
135     renderer.addRenderable(*this, g_transform_box3);
136     renderer.addRenderable(*this, g_transform_box4);
137   }
138 }
139 void DBobView::renderWireframe(Renderer& renderer, const VolumeTest& volume) const
140 {
141   renderSolid(renderer, volume);
142 }
143
144 void DBobView::SetPath(vec3_t *pPath)
145 {
146         if(path)
147                 delete[] path;
148
149         path = pPath;
150 }
151
152 #define LOCAL_GRAVITY -800.0f
153
154 bool DBobView::CalculateTrajectory(vec3_t start, vec3_t apex, float multiplier, int points, float varGravity)
155 {
156         if(apex[2] <= start[2])
157         {
158                 SetPath(NULL);
159                 return false;
160         }
161         // ----think q3a actually would allow these
162         //scrub that, coz the plugin wont :]
163
164         vec3_t dist, speed;
165         VectorSubtract(apex, start, dist);
166
167         vec_t speed_z = (float)sqrt(-2*LOCAL_GRAVITY*dist[2]);
168         float flight_time = -speed_z/LOCAL_GRAVITY;
169
170
171         VectorScale(dist, 1/flight_time, speed);
172         speed[2] = speed_z;
173
174 //      Sys_Printf("Speed: (%.4f %.4f %.4f)\n", speed[0], speed[1], speed[2]);
175
176         vec3_t* pPath = new vec3_t[points];
177
178         float interval = multiplier*flight_time/points;
179         for(int i = 0; i < points; i++)
180         {
181                 float ltime = interval*i;
182
183                 VectorScale(speed, ltime, pPath[i]);
184                 VectorAdd(pPath[i], start, pPath[i]);
185
186                 // could do this all with vectors
187                 // vGrav = {0, 0, -800.0f}
188                 // VectorScale(vGrav, 0.5f*ltime*ltime, vAdd);
189                 // VectorScale(speed, ltime, pPath[i]);
190                 // _VectorAdd(pPath[i], start, pPath[i])
191                 // _VectorAdd(pPath[i], vAdd, pPath[i])
192
193                 pPath[i][2] = start[2] + (speed_z*ltime) + (varGravity*0.5f*ltime*ltime);
194         }
195
196         SetPath(pPath);
197         return true;
198 }
199
200 void DBobView::Begin(const char* trigger, const char *target, float multiplier, int points, float varGravity, bool bNoUpdate, bool bShowExtra)
201 {
202         strcpy(entTrigger, trigger);
203         strcpy(entTarget, target);
204
205         fMultiplier = multiplier;
206         fVarGravity = varGravity;
207         nPathCount = points;
208         m_bShowExtra = bShowExtra;
209
210         if(!UpdatePath())
211         {
212                 globalErrorStream() << "Initialization Failure in DBobView::Begin";
213                 delete this;
214         }
215 }
216
217 bool DBobView::UpdatePath()
218 {
219         vec3_t start, apex;
220
221         if(GetEntityCentre(entTrigger, start))
222         {
223                 if(GetEntityCentre(entTarget, apex))
224                 {
225                         CalculateTrajectory(start, apex, fMultiplier, nPathCount, fVarGravity);
226                         return true;
227                 }
228         }
229         return false;
230 }
231
232 void DBobView_setEntity(Entity& entity, float multiplier, int points, float varGravity, bool bNoUpdate, bool bShowExtra)
233 {
234         DEntity trigger;
235         trigger.LoadEPairList(&entity);
236
237         DEPair* trigger_ep = trigger.FindEPairByKey("targetname");
238
239         if(trigger_ep)
240         {
241                 if(!strcmp(trigger.m_Classname, "trigger_push"))
242                 {
243                         DEPair* target_ep = trigger.FindEPairByKey("target");
244                         if(target_ep)
245                         {
246         scene::Path* entTarget = FindEntityFromTargetname(target_ep->value, NULL);
247                                 if(entTarget)
248                                 {
249                                         if(g_PathView)
250                                                 delete g_PathView;
251                                         g_PathView = new DBobView;
252
253           Entity* target = Node_getEntity(entTarget->top());
254           if(target != 0)
255           {
256             if(!bNoUpdate)
257             {
258               g_PathView->trigger = &entity;
259               entity.attach(*g_PathView);
260               g_PathView->target = target;
261               target->attach(*g_PathView);
262             }
263                                           g_PathView->Begin(trigger_ep->value, target_ep->value, multiplier, points, varGravity, bNoUpdate, bShowExtra);
264           }
265                                 }
266                                 else
267                                         DoMessageBox("trigger_push target could not be found.", "Error", eMB_OK);
268                         }
269                         else
270                                 DoMessageBox("trigger_push has no target.", "Error", eMB_OK);
271                 }
272                 else
273                         DoMessageBox("You must select a 'trigger_push' entity.", "Error", eMB_OK);
274         }       
275         else
276                 DoMessageBox("Entity must have a targetname", "Error", eMB_OK);
277 }