]> icculus.org git repositories - divverent/netradiant.git/blob - plugins/entity/curve.h
Merge branch 'osxnetradiant'
[divverent/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 class ControlPointAdd
152 {
153   RenderablePointVector& m_points;
154 public:
155   ControlPointAdd(RenderablePointVector& points) : m_points(points)
156   {
157   }
158   void operator()(const Vector3& point) const
159   {
160     m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_vertex));
161   }
162 };
163
164 class ControlPointAddSelected
165 {
166   RenderablePointVector& m_points;
167 public:
168   ControlPointAddSelected(RenderablePointVector& points) : m_points(points)
169   {
170   }
171   void operator()(const Vector3& point) const
172   {
173     m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_selected));
174   }
175 };
176
177 class CurveEditType
178 {
179 public:
180   Shader* m_controlsShader;
181   Shader* m_selectedShader;
182 };
183
184 inline void ControlPoints_write(ControlPoints& controlPoints, const char* key, Entity& entity)
185 {
186   StringOutputStream value(256);
187   if(!controlPoints.empty())
188   {
189     ControlPoints_write(controlPoints, value);
190   }
191   entity.setKeyValue(key, value.c_str());
192 }
193
194 class CurveEdit
195 {
196   SelectionChangeCallback m_selectionChanged;
197   ControlPoints& m_controlPoints;
198   typedef Array<ObservedSelectable> Selectables;
199   Selectables m_selectables;
200
201   RenderablePointVector m_controlsRender;
202   mutable RenderablePointVector m_selectedRender;
203
204 public:
205   typedef Static<CurveEditType> Type;
206
207   CurveEdit(ControlPoints& controlPoints, const SelectionChangeCallback& selectionChanged) :
208     m_selectionChanged(selectionChanged),
209     m_controlPoints(controlPoints),
210     m_controlsRender(GL_POINTS),
211     m_selectedRender(GL_POINTS)
212   {
213   }
214
215   template<typename Functor>
216   const Functor& forEachSelected(const Functor& functor)
217   {
218     ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
219     ControlPoints::iterator p = m_controlPoints.begin();
220     for(Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p)
221     {
222       if((*i).isSelected())
223       {
224         functor(*p);
225       }
226     }
227     return functor;
228   }
229   template<typename Functor>
230   const Functor& forEachSelected(const Functor& functor) const
231   {
232     ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
233     ControlPoints::const_iterator p = m_controlPoints.begin();
234     for(Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p)
235     {
236       if((*i).isSelected())
237       {
238         functor(*p);
239       }
240     }
241     return functor;
242   }
243   template<typename Functor>
244   const Functor& forEach(const Functor& functor) const
245   {
246     for(ControlPoints::const_iterator i = m_controlPoints.begin(); i != m_controlPoints.end(); ++i)
247     {
248       functor(*i);
249     }
250     return functor;
251   }
252
253   void testSelect(Selector& selector, SelectionTest& test)
254   {
255     ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
256     ControlPoints::const_iterator p = m_controlPoints.begin();
257     for(Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p)
258     {
259       ControlPoint_testSelect(*p, *i, selector, test);
260     }
261   }
262
263   bool isSelected() const
264   {
265     for(Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i)
266     {
267       if((*i).isSelected())
268       {
269         return true;
270       }
271     }
272     return false;
273   }
274   void setSelected(bool selected)
275   {
276     for(Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i)
277     {
278       (*i).setSelected(selected);
279     }
280   }
281
282   void write(const char* key, Entity& entity)
283   {
284     ControlPoints_write(m_controlPoints, key, entity);
285   }
286
287   void transform(const Matrix4& matrix)
288   {
289     forEachSelected(ControlPointTransform(matrix));
290   }
291   void snapto(float snap)
292   {
293     forEachSelected(ControlPointSnap(snap));
294   }
295
296   void updateSelected() const
297   {
298     m_selectedRender.clear();
299     forEachSelected(ControlPointAddSelected(m_selectedRender));
300   }
301   
302   void renderComponents(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
303   {
304     renderer.SetState(Type::instance().m_controlsShader, Renderer::eWireframeOnly);
305     renderer.SetState(Type::instance().m_controlsShader, Renderer::eFullMaterials);
306     renderer.addRenderable(m_controlsRender, localToWorld);
307   }
308
309   void renderComponentsSelected(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
310   {
311     updateSelected();
312     if(!m_selectedRender.empty())
313     {
314       renderer.Highlight(Renderer::ePrimitive, false);
315       renderer.SetState(Type::instance().m_selectedShader, Renderer::eWireframeOnly);
316       renderer.SetState(Type::instance().m_selectedShader, Renderer::eFullMaterials);
317       renderer.addRenderable(m_selectedRender, localToWorld);
318     }
319   }
320
321   void curveChanged()
322   {
323     m_selectables.resize(m_controlPoints.size(), m_selectionChanged);
324
325     m_controlsRender.clear();
326     m_controlsRender.reserve(m_controlPoints.size());
327     forEach(ControlPointAdd(m_controlsRender));
328
329     m_selectedRender.reserve(m_controlPoints.size());
330   }
331   typedef MemberCaller<CurveEdit, &CurveEdit::curveChanged> CurveChangedCaller;
332 };
333
334
335
336 const int NURBS_degree = 3;
337
338 class NURBSCurve
339 {
340   Signal0 m_curveChanged;
341   Callback m_boundsChanged;
342 public:
343   ControlPoints m_controlPoints;
344   ControlPoints m_controlPointsTransformed;
345   NURBSWeights m_weights;
346   Knots m_knots;
347   RenderableCurve m_renderCurve;
348   AABB m_bounds;
349
350   NURBSCurve(const Callback& boundsChanged) : m_boundsChanged(boundsChanged)
351   {
352   }
353
354   SignalHandlerId connect(const SignalHandler& curveChanged)
355   {
356     curveChanged();
357     return m_curveChanged.connectLast(curveChanged);
358   }
359   void disconnect(SignalHandlerId id)
360   {
361     m_curveChanged.disconnect(id);
362   }
363   void notify()
364   {
365     m_curveChanged();
366   }
367
368   void tesselate()
369   {
370     if(!m_controlPointsTransformed.empty())
371     {
372       const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
373       m_renderCurve.m_vertices.resize(numSegments + 1);
374       m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
375       for(std::size_t i = 1; i < numSegments; ++i)
376       {
377         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)));
378       }
379       m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
380     }
381     else
382     {
383       m_renderCurve.m_vertices.clear();
384     }
385   }
386
387   void curveChanged()
388   {
389     tesselate();
390
391     m_bounds = AABB();
392     for(ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i)
393     {
394       aabb_extend_by_point_safe(m_bounds, (*i));
395     }
396
397     m_boundsChanged();
398     notify();
399   }
400
401   bool parseCurve(const char* value)
402   {
403     if(!ControlPoints_parse(m_controlPoints, value))
404     {
405       return false;
406     }
407
408     m_weights.resize(m_controlPoints.size());
409     for(NURBSWeights::iterator i = m_weights.begin(); i != m_weights.end(); ++i)
410     {
411       (*i) = 1;
412     }
413
414     KnotVector_openUniform(m_knots, m_controlPoints.size(), NURBS_degree);
415
416     //plotBasisFunction(8, 0, NURBS_degree);
417
418     return true;
419   }
420
421   void curveChanged(const char* value)
422   {
423     if(string_empty(value) || !parseCurve(value))
424     {
425       m_controlPoints.resize(0);
426       m_knots.resize(0);
427       m_weights.resize(0);
428     }
429     m_controlPointsTransformed = m_controlPoints;
430     curveChanged();
431   }
432   typedef MemberCaller1<NURBSCurve, const char*, &NURBSCurve::curveChanged> CurveChangedCaller;
433 };
434
435 class CatmullRomSpline
436 {
437   Signal0 m_curveChanged;
438   Callback m_boundsChanged;
439 public:
440   ControlPoints m_controlPoints;
441   ControlPoints m_controlPointsTransformed;
442   RenderableCurve m_renderCurve;
443   AABB m_bounds;
444
445   CatmullRomSpline(const Callback& boundsChanged) : m_boundsChanged(boundsChanged)
446   {
447   }
448
449   SignalHandlerId connect(const SignalHandler& curveChanged)
450   {
451     curveChanged();
452     return m_curveChanged.connectLast(curveChanged);
453   }
454   void disconnect(SignalHandlerId id)
455   {
456     m_curveChanged.disconnect(id);
457   }
458   void notify()
459   {
460     m_curveChanged();
461   }
462
463   void tesselate()
464   {
465     if(!m_controlPointsTransformed.empty())
466     {
467       const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
468       m_renderCurve.m_vertices.resize(numSegments + 1);
469       m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
470       for(std::size_t i = 1; i < numSegments; ++i)
471       {
472         m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(CatmullRom_evaluate(m_controlPointsTransformed, (1.0 / double(numSegments)) * double(i)));
473       }
474       m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
475     }
476     else
477     {
478       m_renderCurve.m_vertices.clear();
479     }
480   }
481
482   bool parseCurve(const char* value)
483   {
484     return ControlPoints_parse(m_controlPoints, value);
485   }
486
487   void curveChanged()
488   {
489     tesselate();
490
491     m_bounds = AABB();
492     for(ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i)
493     {
494       aabb_extend_by_point_safe(m_bounds, (*i));
495     }
496
497     m_boundsChanged();
498     notify();
499   }
500
501   void curveChanged(const char* value)
502   {
503     if(string_empty(value) || !parseCurve(value))
504     {
505       m_controlPoints.resize(0);
506     }
507     m_controlPointsTransformed = m_controlPoints;
508     curveChanged();
509   }
510   typedef MemberCaller1<CatmullRomSpline, const char*, &CatmullRomSpline::curveChanged> CurveChangedCaller;
511 };
512
513 const char* const curve_Nurbs = "curve_Nurbs";
514 const char* const curve_CatmullRomSpline = "curve_CatmullRomSpline";
515
516
517 #endif