]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/entity/curve.h
Merge branch 'fix-fast' into 'master'
[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 public:
40     std::vector<PointVertex> m_vertices;
41
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         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         double t = (1.0 / double(numSegments)) * double(i);
62         globalOutputStream() << "t=" << t << " basis=" << BSpline_basis(knots, point, degree, t) << "\n";
63     }
64     globalOutputStream() << "t=1 basis=" << BSpline_basis(knots, point, degree, 1.0) << "\n";
65 }
66
67 inline bool ControlPoints_parse(ControlPoints &controlPoints, const char *value)
68 {
69     StringTokeniser tokeniser(value, " ");
70
71     std::size_t size;
72     if (!string_parse_size(tokeniser.getToken(), size)) {
73         return false;
74     }
75
76     if (size < 3) {
77         return false;
78     }
79     controlPoints.resize(size);
80
81     if (!string_equal(tokeniser.getToken(), "(")) {
82         return false;
83     }
84     for (ControlPoints::iterator i = controlPoints.begin(); i != controlPoints.end(); ++i) {
85         if (!string_parse_float(tokeniser.getToken(), (*i).x())
86             || !string_parse_float(tokeniser.getToken(), (*i).y())
87             || !string_parse_float(tokeniser.getToken(), (*i).z())) {
88             return false;
89         }
90     }
91     if (!string_equal(tokeniser.getToken(), ")")) {
92         return false;
93     }
94     return true;
95 }
96
97 inline void ControlPoints_write(const ControlPoints &controlPoints, StringOutputStream &value)
98 {
99     value << Unsigned(controlPoints.size()) << " (";
100     for (ControlPoints::const_iterator i = controlPoints.begin(); i != controlPoints.end(); ++i) {
101         value << " " << (*i).x() << " " << (*i).y() << " " << (*i).z() << " ";
102     }
103     value << ")";
104 }
105
106 inline void
107 ControlPoint_testSelect(const Vector3 &point, ObservedSelectable &selectable, Selector &selector, SelectionTest &test)
108 {
109     SelectionIntersection best;
110     test.TestPoint(point, best);
111     if (best.valid()) {
112         Selector_add(selector, selectable, best);
113     }
114 }
115
116 class CurveEditType {
117 public:
118     Shader *m_controlsShader;
119     Shader *m_selectedShader;
120 };
121
122 inline void ControlPoints_write(ControlPoints &controlPoints, const char *key, Entity &entity)
123 {
124     StringOutputStream value(256);
125     if (!controlPoints.empty()) {
126         ControlPoints_write(controlPoints, value);
127     }
128     entity.setKeyValue(key, value.c_str());
129 }
130
131 class CurveEdit {
132     SelectionChangeCallback m_selectionChanged;
133     ControlPoints &m_controlPoints;
134     typedef Array<ObservedSelectable> Selectables;
135     Selectables m_selectables;
136
137     RenderablePointVector m_controlsRender;
138     mutable RenderablePointVector m_selectedRender;
139
140 public:
141     typedef Static<CurveEditType> Type;
142
143     CurveEdit(ControlPoints &controlPoints, const SelectionChangeCallback &selectionChanged) :
144             m_selectionChanged(selectionChanged),
145             m_controlPoints(controlPoints),
146             m_controlsRender(GL_POINTS),
147             m_selectedRender(GL_POINTS)
148     {
149     }
150
151     template<typename Functor>
152     const Functor &forEachSelected(const Functor &functor)
153     {
154         ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
155         ControlPoints::iterator p = m_controlPoints.begin();
156         for (Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p) {
157             if ((*i).isSelected()) {
158                 functor(*p);
159             }
160         }
161         return functor;
162     }
163
164     template<typename Functor>
165     const Functor &forEachSelected(const Functor &functor) const
166     {
167         ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
168         ControlPoints::const_iterator p = m_controlPoints.begin();
169         for (Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p) {
170             if ((*i).isSelected()) {
171                 functor(*p);
172             }
173         }
174         return functor;
175     }
176
177     template<typename Functor>
178     const Functor &forEach(const Functor &functor) const
179     {
180         for (ControlPoints::const_iterator i = m_controlPoints.begin(); i != m_controlPoints.end(); ++i) {
181             functor(*i);
182         }
183         return functor;
184     }
185
186     void testSelect(Selector &selector, SelectionTest &test)
187     {
188         ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
189         ControlPoints::const_iterator p = m_controlPoints.begin();
190         for (Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p) {
191             ControlPoint_testSelect(*p, *i, selector, test);
192         }
193     }
194
195     bool isSelected() const
196     {
197         for (Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i) {
198             if ((*i).isSelected()) {
199                 return true;
200             }
201         }
202         return false;
203     }
204
205     void setSelected(bool selected)
206     {
207         for (Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i) {
208             (*i).setSelected(selected);
209         }
210     }
211
212     void write(const char *key, Entity &entity)
213     {
214         ControlPoints_write(m_controlPoints, key, entity);
215     }
216
217     void transform(const Matrix4 &matrix)
218     {
219         forEachSelected([&](Vector3 &point) {
220             matrix4_transform_point(matrix, point);
221         });
222     }
223
224     void snapto(float snap)
225     {
226         forEachSelected([&](Vector3 &point) {
227             vector3_snap(point, snap);
228         });
229     }
230
231     void updateSelected() const
232     {
233         m_selectedRender.clear();
234         forEachSelected([&](const Vector3 &point) {
235             m_selectedRender.push_back(PointVertex(vertex3f_for_vector3(point), colour_selected));
236         });
237     }
238
239     void renderComponents(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
240     {
241         renderer.SetState(Type::instance().m_controlsShader, Renderer::eWireframeOnly);
242         renderer.SetState(Type::instance().m_controlsShader, Renderer::eFullMaterials);
243         renderer.addRenderable(m_controlsRender, localToWorld);
244     }
245
246     void renderComponentsSelected(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
247     {
248         updateSelected();
249         if (!m_selectedRender.empty()) {
250             renderer.Highlight(Renderer::ePrimitive, false);
251             renderer.SetState(Type::instance().m_selectedShader, Renderer::eWireframeOnly);
252             renderer.SetState(Type::instance().m_selectedShader, Renderer::eFullMaterials);
253             renderer.addRenderable(m_selectedRender, localToWorld);
254         }
255     }
256
257     void curveChanged()
258     {
259         m_selectables.resize(m_controlPoints.size(), m_selectionChanged);
260
261         m_controlsRender.clear();
262         m_controlsRender.reserve(m_controlPoints.size());
263         forEach([&](const Vector3 &point) {
264             m_controlsRender.push_back(PointVertex(vertex3f_for_vector3(point), colour_vertex));
265         });
266
267         m_selectedRender.reserve(m_controlPoints.size());
268     }
269
270     typedef MemberCaller<CurveEdit, void(), &CurveEdit::curveChanged> CurveChangedCaller;
271 };
272
273
274 const int NURBS_degree = 3;
275
276 class NURBSCurve {
277     Signal0 m_curveChanged;
278     Callback<void()> m_boundsChanged;
279 public:
280     ControlPoints m_controlPoints;
281     ControlPoints m_controlPointsTransformed;
282     NURBSWeights m_weights;
283     Knots m_knots;
284     RenderableCurve m_renderCurve;
285     AABB m_bounds;
286
287     NURBSCurve(const Callback<void()> &boundsChanged) : m_boundsChanged(boundsChanged)
288     {
289     }
290
291     SignalHandlerId connect(const SignalHandler &curveChanged)
292     {
293         curveChanged();
294         return m_curveChanged.connectLast(curveChanged);
295     }
296
297     void disconnect(SignalHandlerId id)
298     {
299         m_curveChanged.disconnect(id);
300     }
301
302     void notify()
303     {
304         m_curveChanged();
305     }
306
307     void tesselate()
308     {
309         if (!m_controlPointsTransformed.empty()) {
310             const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
311             m_renderCurve.m_vertices.resize(numSegments + 1);
312             m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
313             for (std::size_t i = 1; i < numSegments; ++i) {
314                 m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(
315                         NURBS_evaluate(m_controlPointsTransformed, m_weights, m_knots, NURBS_degree,
316                                        (1.0 / double(numSegments)) * double(i)));
317             }
318             m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(
319                     m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
320         } else {
321             m_renderCurve.m_vertices.clear();
322         }
323     }
324
325     void curveChanged()
326     {
327         tesselate();
328
329         m_bounds = AABB();
330         for (ControlPoints::iterator i = m_controlPointsTransformed.begin();
331              i != m_controlPointsTransformed.end(); ++i) {
332             aabb_extend_by_point_safe(m_bounds, (*i));
333         }
334
335         m_boundsChanged();
336         notify();
337     }
338
339     bool parseCurve(const char *value)
340     {
341         if (!ControlPoints_parse(m_controlPoints, value)) {
342             return false;
343         }
344
345         m_weights.resize(m_controlPoints.size());
346         for (NURBSWeights::iterator i = m_weights.begin(); i != m_weights.end(); ++i) {
347             (*i) = 1;
348         }
349
350         KnotVector_openUniform(m_knots, m_controlPoints.size(), NURBS_degree);
351
352         //plotBasisFunction(8, 0, NURBS_degree);
353
354         return true;
355     }
356
357     void curveChanged(const char *value)
358     {
359         if (string_empty(value) || !parseCurve(value)) {
360             m_controlPoints.resize(0);
361             m_knots.resize(0);
362             m_weights.resize(0);
363         }
364         m_controlPointsTransformed = m_controlPoints;
365         curveChanged();
366     }
367
368     typedef MemberCaller<NURBSCurve, void(const char *), &NURBSCurve::curveChanged> CurveChangedCaller;
369 };
370
371 class CatmullRomSpline {
372     Signal0 m_curveChanged;
373     Callback<void()> m_boundsChanged;
374 public:
375     ControlPoints m_controlPoints;
376     ControlPoints m_controlPointsTransformed;
377     RenderableCurve m_renderCurve;
378     AABB m_bounds;
379
380     CatmullRomSpline(const Callback<void()> &boundsChanged) : m_boundsChanged(boundsChanged)
381     {
382     }
383
384     SignalHandlerId connect(const SignalHandler &curveChanged)
385     {
386         curveChanged();
387         return m_curveChanged.connectLast(curveChanged);
388     }
389
390     void disconnect(SignalHandlerId id)
391     {
392         m_curveChanged.disconnect(id);
393     }
394
395     void notify()
396     {
397         m_curveChanged();
398     }
399
400     void tesselate()
401     {
402         if (!m_controlPointsTransformed.empty()) {
403             const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
404             m_renderCurve.m_vertices.resize(numSegments + 1);
405             m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
406             for (std::size_t i = 1; i < numSegments; ++i) {
407                 m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(
408                         CatmullRom_evaluate(m_controlPointsTransformed, (1.0 / double(numSegments)) * double(i)));
409             }
410             m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(
411                     m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
412         } else {
413             m_renderCurve.m_vertices.clear();
414         }
415     }
416
417     bool parseCurve(const char *value)
418     {
419         return ControlPoints_parse(m_controlPoints, value);
420     }
421
422     void curveChanged()
423     {
424         tesselate();
425
426         m_bounds = AABB();
427         for (ControlPoints::iterator i = m_controlPointsTransformed.begin();
428              i != m_controlPointsTransformed.end(); ++i) {
429             aabb_extend_by_point_safe(m_bounds, (*i));
430         }
431
432         m_boundsChanged();
433         notify();
434     }
435
436     void curveChanged(const char *value)
437     {
438         if (string_empty(value) || !parseCurve(value)) {
439             m_controlPoints.resize(0);
440         }
441         m_controlPointsTransformed = m_controlPoints;
442         curveChanged();
443     }
444
445     typedef MemberCaller<CatmullRomSpline, void(const char *), &CatmullRomSpline::curveChanged> CurveChangedCaller;
446 };
447
448 const char *const curve_Nurbs = "curve_Nurbs";
449 const char *const curve_CatmullRomSpline = "curve_CatmullRomSpline";
450
451
452 #endif