]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/entity/curve.h
refactored plugin api; refactored callback library; added signals library
[xonotic/netradiant.git] / plugins / entity / curve.h
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
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 #if !defined(INCLUDED_CURVE_H)
23 #define INCLUDED_CURVE_H
24
25 #include "ientity.h"
26 #include "selectable.h"
27 #include "renderable.h"
28
29 #include <set>
30
31 #include "math/curve.h"
32 #include "stream/stringstream.h"
33 #include "signal/signal.h"
34 #include "selectionlib.h"
35 #include "render.h"
36 #include "stringio.h"
37
38 class RenderableCurve : public OpenGLRenderable
39 {
40 public:
41   std::vector<PointVertex> m_vertices;
42   void render(RenderStateFlags state) const
43   {
44     pointvertex_gl_array(&m_vertices.front());
45     glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_vertices.size()));
46   }
47 };
48
49 inline void plotBasisFunction(std::size_t numSegments, int point, int degree)
50 {
51   Knots knots;
52   KnotVector_openUniform(knots, 4, degree);
53
54   globalOutputStream() << "plotBasisFunction point " << point << " of 4, knot vector:";
55   for(Knots::iterator i = knots.begin(); i != knots.end(); ++i)
56   {
57     globalOutputStream() << " " << *i;
58   }
59   globalOutputStream() << "\n";
60   globalOutputStream() << "t=0 basis=" << BSpline_basis(knots, point, degree, 0.0) << "\n";
61   for(std::size_t i = 1; i < numSegments; ++i)
62   {
63     double t = (1.0 / double(numSegments)) * double(i);
64     globalOutputStream() << "t=" << t << " basis=" << BSpline_basis(knots, point, degree, t) << "\n";
65   }
66   globalOutputStream() << "t=1 basis=" << BSpline_basis(knots, point, degree, 1.0) << "\n";  
67 }
68
69 inline bool ControlPoints_parse(ControlPoints& controlPoints, const char* value)
70 {
71   StringTokeniser tokeniser(value, " ");
72
73   std::size_t size;
74   if(!string_parse_size(tokeniser.getToken(), size))
75   {
76     return false;
77   }
78
79   if(size < 3)
80   {
81     return false;
82   }
83   controlPoints.resize(size);
84
85   if(!string_equal(tokeniser.getToken(), "("))
86   {
87     return false;
88   }
89   for(ControlPoints::iterator i = controlPoints.begin(); i != controlPoints.end(); ++i)
90   {
91     if(!string_parse_float(tokeniser.getToken(), (*i).x())
92       || !string_parse_float(tokeniser.getToken(), (*i).y())
93       || !string_parse_float(tokeniser.getToken(), (*i).z()))
94     {
95       return false;
96     }
97   }
98   if(!string_equal(tokeniser.getToken(), ")"))
99   {
100     return false;
101   }
102   return true;
103 }
104
105 inline void ControlPoints_write(const ControlPoints& controlPoints, StringOutputStream& value)
106 {
107   value << Unsigned(controlPoints.size()) << " (";
108   for(ControlPoints::const_iterator i = controlPoints.begin(); i != controlPoints.end(); ++i)
109   {
110     value << " " << (*i).x() << " " << (*i).y() << " " << (*i).z() << " ";
111   }
112   value << ")";
113 }
114
115 inline void ControlPoint_testSelect(const Vector3& point, ObservedSelectable& selectable, Selector& selector, SelectionTest& test)
116 {
117   SelectionIntersection best;
118   test.TestPoint(point, best);
119   if(best.valid())
120   {
121     Selector_add(selector, selectable, best);
122   }
123 }
124
125 class ControlPointTransform
126 {
127   const Matrix4& m_matrix;
128 public:
129   ControlPointTransform(const Matrix4& matrix) : m_matrix(matrix)
130   {
131   }
132   void operator()(Vector3& point) const
133   {
134     matrix4_transform_point(m_matrix, point);
135   }
136 };
137
138 class ControlPointSnap
139 {
140   float m_snap;
141 public:
142   ControlPointSnap(float snap) : m_snap(snap)
143   {
144   }
145   void operator()(Vector3& point) const
146   {
147     vector3_snap(point, m_snap);
148   }
149 };
150
151 const Colour4b colour_vertex(0, 255, 0, 255);
152 const Colour4b colour_selected(0, 0, 255, 255);
153
154 class ControlPointAdd
155 {
156   RenderablePointVector& m_points;
157 public:
158   ControlPointAdd(RenderablePointVector& points) : m_points(points)
159   {
160   }
161   void operator()(const Vector3& point) const
162   {
163     m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_vertex));
164   }
165 };
166
167 class ControlPointAddSelected
168 {
169   RenderablePointVector& m_points;
170 public:
171   ControlPointAddSelected(RenderablePointVector& points) : m_points(points)
172   {
173   }
174   void operator()(const Vector3& point) const
175   {
176     m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_selected));
177   }
178 };
179
180 class CurveEditType
181 {
182 public:
183   Shader* m_controlsShader;
184   Shader* m_selectedShader;
185 };
186
187 inline void ControlPoints_write(ControlPoints& controlPoints, const char* key, Entity& entity)
188 {
189   StringOutputStream value(256);
190   if(!controlPoints.empty())
191   {
192     ControlPoints_write(controlPoints, value);
193   }
194   entity.setKeyValue(key, value.c_str());
195 }
196
197 class CurveEdit
198 {
199   SelectionChangeCallback m_selectionChanged;
200   ControlPoints& m_controlPoints;
201   typedef Array<ObservedSelectable> Selectables;
202   Selectables m_selectables;
203
204   RenderablePointVector m_controlsRender;
205   mutable RenderablePointVector m_selectedRender;
206
207 public:
208   typedef Static<CurveEditType> Type;
209
210   CurveEdit(ControlPoints& controlPoints, const SelectionChangeCallback& selectionChanged) :
211     m_selectionChanged(selectionChanged),
212     m_controlPoints(controlPoints),
213     m_controlsRender(GL_POINTS),
214     m_selectedRender(GL_POINTS)
215   {
216   }
217
218   template<typename Functor>
219   const Functor& forEachSelected(const Functor& functor)
220   {
221     ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
222     ControlPoints::iterator p = m_controlPoints.begin();
223     for(Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p)
224     {
225       if((*i).isSelected())
226       {
227         functor(*p);
228       }
229     }
230     return functor;
231   }
232   template<typename Functor>
233   const Functor& forEachSelected(const Functor& functor) const
234   {
235     ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
236     ControlPoints::const_iterator p = m_controlPoints.begin();
237     for(Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p)
238     {
239       if((*i).isSelected())
240       {
241         functor(*p);
242       }
243     }
244     return functor;
245   }
246   template<typename Functor>
247   const Functor& forEach(const Functor& functor) const
248   {
249     for(ControlPoints::const_iterator i = m_controlPoints.begin(); i != m_controlPoints.end(); ++i)
250     {
251       functor(*i);
252     }
253     return functor;
254   }
255
256   void testSelect(Selector& selector, SelectionTest& test)
257   {
258     ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
259     ControlPoints::const_iterator p = m_controlPoints.begin();
260     for(Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p)
261     {
262       ControlPoint_testSelect(*p, *i, selector, test);
263     }
264   }
265
266   bool isSelected() const
267   {
268     for(Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i)
269     {
270       if((*i).isSelected())
271       {
272         return true;
273       }
274     }
275     return false;
276   }
277   void setSelected(bool selected)
278   {
279     for(Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i)
280     {
281       (*i).setSelected(selected);
282     }
283   }
284
285   void write(const char* key, Entity& entity)
286   {
287     ControlPoints_write(m_controlPoints, key, entity);
288   }
289
290   void transform(const Matrix4& matrix)
291   {
292     forEachSelected(ControlPointTransform(matrix));
293   }
294   void snapto(float snap)
295   {
296     forEachSelected(ControlPointSnap(snap));
297   }
298
299   void updateSelected() const
300   {
301     m_selectedRender.clear();
302     forEachSelected(ControlPointAddSelected(m_selectedRender));
303   }
304   
305   void renderComponents(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
306   {
307     renderer.SetState(Type::instance().m_controlsShader, Renderer::eWireframeOnly);
308     renderer.SetState(Type::instance().m_controlsShader, Renderer::eFullMaterials);
309     renderer.addRenderable(m_controlsRender, localToWorld);
310   }
311
312   void renderComponentsSelected(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
313   {
314     updateSelected();
315     if(!m_selectedRender.empty())
316     {
317       renderer.Highlight(Renderer::ePrimitive, false);
318       renderer.SetState(Type::instance().m_selectedShader, Renderer::eWireframeOnly);
319       renderer.SetState(Type::instance().m_selectedShader, Renderer::eFullMaterials);
320       renderer.addRenderable(m_selectedRender, localToWorld);
321     }
322   }
323
324   void curveChanged()
325   {
326     m_selectables.resize(m_controlPoints.size(), m_selectionChanged);
327
328     m_controlsRender.clear();
329     m_controlsRender.reserve(m_controlPoints.size());
330     forEach(ControlPointAdd(m_controlsRender));
331
332     m_selectedRender.reserve(m_controlPoints.size());
333   }
334   typedef MemberCaller<CurveEdit, &CurveEdit::curveChanged> CurveChangedCaller;
335 };
336
337
338
339 const int NURBS_degree = 3;
340
341 class NURBSCurve
342 {
343   Signal0 m_curveChanged;
344   Callback m_boundsChanged;
345 public:
346   ControlPoints m_controlPoints;
347   ControlPoints m_controlPointsTransformed;
348   NURBSWeights m_weights;
349   Knots m_knots;
350   RenderableCurve m_renderCurve;
351   AABB m_bounds;
352
353   NURBSCurve(const Callback& boundsChanged) : m_boundsChanged(boundsChanged)
354   {
355   }
356
357   SignalHandlerId connect(const SignalHandler& curveChanged)
358   {
359     curveChanged();
360     return m_curveChanged.connectLast(curveChanged);
361   }
362   void disconnect(SignalHandlerId id)
363   {
364     m_curveChanged.disconnect(id);
365   }
366   void notify()
367   {
368     m_curveChanged();
369   }
370
371   void tesselate()
372   {
373     if(!m_controlPointsTransformed.empty())
374     {
375       const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
376       m_renderCurve.m_vertices.resize(numSegments + 1);
377       m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
378       for(std::size_t i = 1; i < numSegments; ++i)
379       {
380         m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(NURBS_evaluate(m_controlPointsTransformed, m_weights, m_knots, NURBS_degree, (1.0 / double(numSegments)) * double(i)));
381       }
382       m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
383     }
384     else
385     {
386       m_renderCurve.m_vertices.clear();
387     }
388   }
389
390   void curveChanged()
391   {
392     tesselate();
393
394     m_bounds = AABB();
395     for(ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i)
396     {
397       aabb_extend_by_point_safe(m_bounds, (*i));
398     }
399
400     m_boundsChanged();
401     notify();
402   }
403
404   bool parseCurve(const char* value)
405   {
406     if(!ControlPoints_parse(m_controlPoints, value))
407     {
408       return false;
409     }
410
411     m_weights.resize(m_controlPoints.size());
412     for(NURBSWeights::iterator i = m_weights.begin(); i != m_weights.end(); ++i)
413     {
414       (*i) = 1;
415     }
416
417     KnotVector_openUniform(m_knots, m_controlPoints.size(), NURBS_degree);
418
419     //plotBasisFunction(8, 0, NURBS_degree);
420
421     return true;
422   }
423
424   void curveChanged(const char* value)
425   {
426     if(string_empty(value) || !parseCurve(value))
427     {
428       m_controlPoints.resize(0);
429       m_knots.resize(0);
430       m_weights.resize(0);
431     }
432     m_controlPointsTransformed = m_controlPoints;
433     curveChanged();
434   }
435   typedef MemberCaller1<NURBSCurve, const char*, &NURBSCurve::curveChanged> CurveChangedCaller;
436 };
437
438 class CatmullRomSpline
439 {
440   Signal0 m_curveChanged;
441   Callback m_boundsChanged;
442 public:
443   ControlPoints m_controlPoints;
444   ControlPoints m_controlPointsTransformed;
445   RenderableCurve m_renderCurve;
446   AABB m_bounds;
447
448   CatmullRomSpline(const Callback& boundsChanged) : m_boundsChanged(boundsChanged)
449   {
450   }
451
452   SignalHandlerId connect(const SignalHandler& curveChanged)
453   {
454     curveChanged();
455     return m_curveChanged.connectLast(curveChanged);
456   }
457   void disconnect(SignalHandlerId id)
458   {
459     m_curveChanged.disconnect(id);
460   }
461   void notify()
462   {
463     m_curveChanged();
464   }
465
466   void tesselate()
467   {
468     if(!m_controlPointsTransformed.empty())
469     {
470       const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
471       m_renderCurve.m_vertices.resize(numSegments + 1);
472       m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
473       for(std::size_t i = 1; i < numSegments; ++i)
474       {
475         m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(CatmullRom_evaluate(m_controlPointsTransformed, (1.0 / double(numSegments)) * double(i)));
476       }
477       m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
478     }
479     else
480     {
481       m_renderCurve.m_vertices.clear();
482     }
483   }
484
485   bool parseCurve(const char* value)
486   {
487     return ControlPoints_parse(m_controlPoints, value);
488   }
489
490   void curveChanged()
491   {
492     tesselate();
493
494     m_bounds = AABB();
495     for(ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i)
496     {
497       aabb_extend_by_point_safe(m_bounds, (*i));
498     }
499
500     m_boundsChanged();
501     notify();
502   }
503
504   void curveChanged(const char* value)
505   {
506     if(string_empty(value) || !parseCurve(value))
507     {
508       m_controlPoints.resize(0);
509     }
510     m_controlPointsTransformed = m_controlPoints;
511     curveChanged();
512   }
513   typedef MemberCaller1<CatmullRomSpline, const char*, &CatmullRomSpline::curveChanged> CurveChangedCaller;
514 };
515
516 const char* const curve_Nurbs = "curve_Nurbs";
517 const char* const curve_CatmullRomSpline = "curve_CatmullRomSpline";
518
519
520 #endif