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