2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
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.
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.
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
22 #if !defined(INCLUDED_CURVE_H)
23 #define INCLUDED_CURVE_H
26 #include "selectable.h"
27 #include "renderable.h"
31 #include "math/curve.h"
32 #include "stream/stringstream.h"
33 #include "selectionlib.h"
37 class RenderableCurve : public OpenGLRenderable
40 std::vector<PointVertex> m_vertices;
41 void render(RenderStateFlags state) const
43 pointvertex_gl_array(&m_vertices.front());
44 glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_vertices.size()));
48 inline void plotBasisFunction(std::size_t numSegments, int point, int degree)
51 KnotVector_openUniform(knots, 4, degree);
53 globalOutputStream() << "plotBasisFunction point " << point << " of 4, knot vector:";
54 for(Knots::iterator i = knots.begin(); i != knots.end(); ++i)
56 globalOutputStream() << " " << *i;
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)
62 double t = (1.0 / double(numSegments)) * double(i);
63 globalOutputStream() << "t=" << t << " basis=" << BSpline_basis(knots, point, degree, t) << "\n";
65 globalOutputStream() << "t=1 basis=" << BSpline_basis(knots, point, degree, 1.0) << "\n";
68 inline bool ControlPoints_parse(ControlPoints& controlPoints, const char* value)
70 StringTokeniser tokeniser(value, " ");
73 if(!string_parse_size(tokeniser.getToken(), size))
82 controlPoints.resize(size);
84 if(!string_equal(tokeniser.getToken(), "("))
88 for(ControlPoints::iterator i = controlPoints.begin(); i != controlPoints.end(); ++i)
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()))
97 if(!string_equal(tokeniser.getToken(), ")"))
104 inline void ControlPoints_write(const ControlPoints& controlPoints, StringOutputStream& value)
106 value << Unsigned(controlPoints.size()) << " (";
107 for(ControlPoints::const_iterator i = controlPoints.begin(); i != controlPoints.end(); ++i)
109 value << " " << (*i).x() << " " << (*i).y() << " " << (*i).z() << " ";
114 inline void ControlPoint_testSelect(const Vector3& point, ObservedSelectable& selectable, Selector& selector, SelectionTest& test)
116 SelectionIntersection best;
117 test.TestPoint(point, best);
120 Selector_add(selector, selectable, best);
124 class ControlPointTransform
126 const Matrix4& m_matrix;
128 ControlPointTransform(const Matrix4& matrix) : m_matrix(matrix)
131 void operator()(Vector3& point) const
133 matrix4_transform_point(m_matrix, point);
137 class ControlPointSnap
141 ControlPointSnap(float snap) : m_snap(snap)
144 void operator()(Vector3& point) const
146 vector3_snap(point, m_snap);
150 const Colour4b colour_vertex(0, 255, 0, 255);
151 const Colour4b colour_selected(0, 0, 255, 255);
153 class ControlPointAdd
155 RenderablePointVector& m_points;
157 ControlPointAdd(RenderablePointVector& points) : m_points(points)
160 void operator()(const Vector3& point) const
162 m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_vertex));
166 class ControlPointAddSelected
168 RenderablePointVector& m_points;
170 ControlPointAddSelected(RenderablePointVector& points) : m_points(points)
173 void operator()(const Vector3& point) const
175 m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_selected));
182 Shader* m_controlsShader;
183 Shader* m_selectedShader;
186 inline void ControlPoints_write(ControlPoints& controlPoints, const char* key, Entity& entity)
188 StringOutputStream value(256);
189 if(!controlPoints.empty())
191 ControlPoints_write(controlPoints, value);
193 entity.setKeyValue(key, value.c_str());
198 SelectionChangeCallback m_selectionChanged;
199 ControlPoints& m_controlPoints;
200 typedef Array<ObservedSelectable> Selectables;
201 Selectables m_selectables;
203 RenderablePointVector m_controlsRender;
204 mutable RenderablePointVector m_selectedRender;
207 typedef Static<CurveEditType> Type;
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)
217 template<typename Functor>
218 const Functor& forEachSelected(const Functor& functor)
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)
224 if((*i).isSelected())
231 template<typename Functor>
232 const Functor& forEachSelected(const Functor& functor) const
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)
238 if((*i).isSelected())
245 template<typename Functor>
246 const Functor& forEach(const Functor& functor) const
248 for(ControlPoints::const_iterator i = m_controlPoints.begin(); i != m_controlPoints.end(); ++i)
255 void testSelect(Selector& selector, SelectionTest& test)
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)
261 ControlPoint_testSelect(*p, *i, selector, test);
265 bool isSelected() const
267 for(Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i)
269 if((*i).isSelected())
276 void setSelected(bool selected)
278 for(Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i)
280 (*i).setSelected(selected);
284 void write(const char* key, Entity& entity)
286 ControlPoints_write(m_controlPoints, key, entity);
289 void transform(const Matrix4& matrix)
291 forEachSelected(ControlPointTransform(matrix));
293 void snapto(float snap)
295 forEachSelected(ControlPointSnap(snap));
298 void updateSelected() const
300 m_selectedRender.clear();
301 forEachSelected(ControlPointAddSelected(m_selectedRender));
304 void renderComponents(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
306 renderer.SetState(Type::instance().m_controlsShader, Renderer::eWireframeOnly);
307 renderer.SetState(Type::instance().m_controlsShader, Renderer::eFullMaterials);
308 renderer.addRenderable(m_controlsRender, localToWorld);
311 void renderComponentsSelected(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
314 if(!m_selectedRender.empty())
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);
325 m_selectables.resize(m_controlPoints.size(), m_selectionChanged);
327 m_controlsRender.clear();
328 m_controlsRender.reserve(m_controlPoints.size());
329 forEach(ControlPointAdd(m_controlsRender));
331 m_selectedRender.reserve(m_controlPoints.size());
333 typedef MemberCaller<CurveEdit, &CurveEdit::curveChanged> CurveChangedCaller;
338 const int NURBS_degree = 3;
342 typedef std::set<Callback> Callbacks;
343 Callbacks m_curveChanged;
344 Callback m_boundsChanged;
346 ControlPoints m_controlPoints;
347 ControlPoints m_controlPointsTransformed;
348 NURBSWeights m_weights;
350 RenderableCurve m_renderCurve;
353 NURBSCurve(const Callback& boundsChanged) : m_boundsChanged(boundsChanged)
357 void attach(const Callback& curveChanged)
359 m_curveChanged.insert(curveChanged);
362 void detach(const Callback& curveChanged)
364 m_curveChanged.erase(curveChanged);
368 std::for_each(m_curveChanged.begin(), m_curveChanged.end(), CallbackInvoke());
373 if(!m_controlPointsTransformed.empty())
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)
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)));
382 m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
386 m_renderCurve.m_vertices.clear();
395 for(ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i)
397 aabb_extend_by_point_safe(m_bounds, (*i));
404 bool parseCurve(const char* value)
406 if(!ControlPoints_parse(m_controlPoints, value))
411 m_weights.resize(m_controlPoints.size());
412 for(NURBSWeights::iterator i = m_weights.begin(); i != m_weights.end(); ++i)
417 KnotVector_openUniform(m_knots, m_controlPoints.size(), NURBS_degree);
419 //plotBasisFunction(8, 0, NURBS_degree);
424 void curveChanged(const char* value)
426 if(string_empty(value) || !parseCurve(value))
428 m_controlPoints.resize(0);
432 m_controlPointsTransformed = m_controlPoints;
435 typedef MemberCaller1<NURBSCurve, const char*, &NURBSCurve::curveChanged> CurveChangedCaller;
438 class CatmullRomSpline
440 typedef std::set<Callback> Callbacks;
441 Callbacks m_curveChanged;
442 Callback m_boundsChanged;
444 ControlPoints m_controlPoints;
445 ControlPoints m_controlPointsTransformed;
446 RenderableCurve m_renderCurve;
449 CatmullRomSpline(const Callback& boundsChanged) : m_boundsChanged(boundsChanged)
453 void attach(const Callback& curveChanged)
455 m_curveChanged.insert(curveChanged);
458 void detach(const Callback& curveChanged)
460 m_curveChanged.erase(curveChanged);
464 std::for_each(m_curveChanged.begin(), m_curveChanged.end(), CallbackInvoke());
469 if(!m_controlPointsTransformed.empty())
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)
476 m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(CatmullRom_evaluate(m_controlPointsTransformed, (1.0 / double(numSegments)) * double(i)));
478 m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
482 m_renderCurve.m_vertices.clear();
486 bool parseCurve(const char* value)
488 return ControlPoints_parse(m_controlPoints, value);
496 for(ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i)
498 aabb_extend_by_point_safe(m_bounds, (*i));
505 void curveChanged(const char* value)
507 if(string_empty(value) || !parseCurve(value))
509 m_controlPoints.resize(0);
511 m_controlPointsTransformed = m_controlPoints;
514 typedef MemberCaller1<CatmullRomSpline, const char*, &CatmullRomSpline::curveChanged> CurveChangedCaller;
517 const char* const curve_Nurbs = "curve_Nurbs";
518 const char* const curve_CatmullRomSpline = "curve_CatmullRomSpline";