00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #if !defined(INCLUDED_CURVE_H)
00027 #define INCLUDED_CURVE_H
00028
00029 #include "ientity.h"
00030 #include "selectable.h"
00031 #include "renderable.h"
00032
00033 #include <set>
00034
00035 #include "math/curve.h"
00036 #include "stream/stringstream.h"
00037 #include "signal/signal.h"
00038 #include "selectionlib.h"
00039 #include "render.h"
00040 #include "stringio.h"
00041
00042 class RenderableCurve: public OpenGLRenderable
00043 {
00044 public:
00045 std::vector<PointVertex> m_vertices;
00046 void render (RenderStateFlags state) const
00047 {
00048 pointvertex_gl_array(&m_vertices.front());
00049 glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_vertices.size()));
00050 }
00051 };
00052
00053 inline void plotBasisFunction (std::size_t numSegments, int point, int degree)
00054 {
00055 Knots knots;
00056 KnotVector_openUniform(knots, 4, degree);
00057
00058 globalOutputStream() << "plotBasisFunction point " << point << " of 4, knot vector:";
00059 for (Knots::iterator i = knots.begin(); i != knots.end(); ++i) {
00060 globalOutputStream() << " " << *i;
00061 }
00062 globalOutputStream() << "\n";
00063 globalOutputStream() << "t=0 basis=" << BSpline_basis(knots, point, degree, 0.0) << "\n";
00064 for (std::size_t i = 1; i < numSegments; ++i) {
00065 double t = (1.0 / double(numSegments)) * double(i);
00066 globalOutputStream() << "t=" << t << " basis=" << BSpline_basis(knots, point, degree, t) << "\n";
00067 }
00068 globalOutputStream() << "t=1 basis=" << BSpline_basis(knots, point, degree, 1.0) << "\n";
00069 }
00070
00071 inline bool ControlPoints_parse (ControlPoints& controlPoints, const char* value)
00072 {
00073 StringTokeniser tokeniser(value, " ");
00074
00075 std::size_t size;
00076 if (!string_parse_size(tokeniser.getToken(), size)) {
00077 return false;
00078 }
00079
00080 if (size < 3) {
00081 return false;
00082 }
00083 controlPoints.resize(size);
00084
00085 if (!string_equal(tokeniser.getToken(), "(")) {
00086 return false;
00087 }
00088 for (ControlPoints::iterator i = controlPoints.begin(); i != controlPoints.end(); ++i) {
00089 if (!string_parse_float(tokeniser.getToken(), (*i).x()) || !string_parse_float(tokeniser.getToken(), (*i).y())
00090 || !string_parse_float(tokeniser.getToken(), (*i).z())) {
00091 return false;
00092 }
00093 }
00094 if (!string_equal(tokeniser.getToken(), ")")) {
00095 return false;
00096 }
00097 return true;
00098 }
00099
00100 inline void ControlPoints_write (const ControlPoints& controlPoints, StringOutputStream& value)
00101 {
00102 value << Unsigned(controlPoints.size()) << " (";
00103 for (ControlPoints::const_iterator i = controlPoints.begin(); i != controlPoints.end(); ++i) {
00104 value << " " << (*i).x() << " " << (*i).y() << " " << (*i).z() << " ";
00105 }
00106 value << ")";
00107 }
00108
00109 inline void ControlPoint_testSelect (const Vector3& point, ObservedSelectable& selectable, Selector& selector,
00110 SelectionTest& test)
00111 {
00112 SelectionIntersection best;
00113 test.TestPoint(point, best);
00114 if (best.valid()) {
00115 Selector_add(selector, selectable, best);
00116 }
00117 }
00118
00119 class ControlPointTransform
00120 {
00121 const Matrix4& m_matrix;
00122 public:
00123 ControlPointTransform (const Matrix4& matrix) :
00124 m_matrix(matrix)
00125 {
00126 }
00127 void operator() (Vector3& point) const
00128 {
00129 matrix4_transform_point(m_matrix, point);
00130 }
00131 };
00132
00133 class ControlPointSnap
00134 {
00135 float m_snap;
00136 public:
00137 ControlPointSnap (float snap) :
00138 m_snap(snap)
00139 {
00140 }
00141 void operator() (Vector3& point) const
00142 {
00143 vector3_snap(point, m_snap);
00144 }
00145 };
00146
00147 class ControlPointAdd
00148 {
00149 RenderablePointVector& m_points;
00150 public:
00151 ControlPointAdd (RenderablePointVector& points) :
00152 m_points(points)
00153 {
00154 }
00155 void operator() (const Vector3& point) const
00156 {
00157 m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_vertex));
00158 }
00159 };
00160
00161 class ControlPointAddSelected
00162 {
00163 RenderablePointVector& m_points;
00164 public:
00165 ControlPointAddSelected (RenderablePointVector& points) :
00166 m_points(points)
00167 {
00168 }
00169 void operator() (const Vector3& point) const
00170 {
00171 m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_selected));
00172 }
00173 };
00174
00175 class CurveEditType
00176 {
00177 public:
00178 Shader* m_controlsShader;
00179 Shader* m_selectedShader;
00180 };
00181
00182 inline void ControlPoints_write (ControlPoints& controlPoints, const char* key, Entity& entity)
00183 {
00184 StringOutputStream value(256);
00185 if (!controlPoints.empty()) {
00186 ControlPoints_write(controlPoints, value);
00187 }
00188 entity.setKeyValue(key, value.c_str());
00189 }
00190
00191 class CurveEdit
00192 {
00193 SelectionChangeCallback m_selectionChanged;
00194 ControlPoints& m_controlPoints;
00195 typedef Array<ObservedSelectable> Selectables;
00196 Selectables m_selectables;
00197
00198 RenderablePointVector m_controlsRender;
00199 mutable RenderablePointVector m_selectedRender;
00200
00201 public:
00202 typedef Static<CurveEditType> Type;
00203
00204 CurveEdit (ControlPoints& controlPoints, const SelectionChangeCallback& selectionChanged) :
00205 m_selectionChanged(selectionChanged), m_controlPoints(controlPoints), m_controlsRender(GL_POINTS),
00206 m_selectedRender(GL_POINTS)
00207 {
00208 }
00209
00210 template<typename Functor>
00211 const Functor& forEachSelected (const Functor& functor)
00212 {
00213 ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
00214 ControlPoints::iterator p = m_controlPoints.begin();
00215 for (Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p) {
00216 if ((*i).isSelected()) {
00217 functor(*p);
00218 }
00219 }
00220 return functor;
00221 }
00222 template<typename Functor>
00223 const Functor& forEachSelected (const Functor& functor) const
00224 {
00225 ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
00226 ControlPoints::const_iterator p = m_controlPoints.begin();
00227 for (Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p) {
00228 if ((*i).isSelected()) {
00229 functor(*p);
00230 }
00231 }
00232 return functor;
00233 }
00234 template<typename Functor>
00235 const Functor& forEach (const Functor& functor) const
00236 {
00237 for (ControlPoints::const_iterator i = m_controlPoints.begin(); i != m_controlPoints.end(); ++i) {
00238 functor(*i);
00239 }
00240 return functor;
00241 }
00242
00243 void testSelect (Selector& selector, SelectionTest& test)
00244 {
00245 ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
00246 ControlPoints::const_iterator p = m_controlPoints.begin();
00247 for (Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p) {
00248 ControlPoint_testSelect(*p, *i, selector, test);
00249 }
00250 }
00251
00252 bool isSelected () const
00253 {
00254 for (Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i) {
00255 if ((*i).isSelected()) {
00256 return true;
00257 }
00258 }
00259 return false;
00260 }
00261 void setSelected (bool selected)
00262 {
00263 for (Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i) {
00264 (*i).setSelected(selected);
00265 }
00266 }
00267
00268 void write (const char* key, Entity& entity)
00269 {
00270 ControlPoints_write(m_controlPoints, key, entity);
00271 }
00272
00273 void transform (const Matrix4& matrix)
00274 {
00275 forEachSelected(ControlPointTransform(matrix));
00276 }
00277 void snapto (float snap)
00278 {
00279 forEachSelected(ControlPointSnap(snap));
00280 }
00281
00282 void updateSelected () const
00283 {
00284 m_selectedRender.clear();
00285 forEachSelected(ControlPointAddSelected(m_selectedRender));
00286 }
00287
00288 void renderComponents (Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
00289 {
00290 renderer.SetState(Type::instance().m_controlsShader, Renderer::eWireframeOnly);
00291 renderer.SetState(Type::instance().m_controlsShader, Renderer::eFullMaterials);
00292 renderer.addRenderable(m_controlsRender, localToWorld);
00293 }
00294
00295 void renderComponentsSelected (Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
00296 {
00297 updateSelected();
00298 if (!m_selectedRender.empty()) {
00299 renderer.Highlight(Renderer::ePrimitive, false);
00300 renderer.SetState(Type::instance().m_selectedShader, Renderer::eWireframeOnly);
00301 renderer.SetState(Type::instance().m_selectedShader, Renderer::eFullMaterials);
00302 renderer.addRenderable(m_selectedRender, localToWorld);
00303 }
00304 }
00305
00306 void curveChanged ()
00307 {
00308 m_selectables.resize(m_controlPoints.size(), m_selectionChanged);
00309
00310 m_controlsRender.clear();
00311 m_controlsRender.reserve(m_controlPoints.size());
00312 forEach(ControlPointAdd(m_controlsRender));
00313
00314 m_selectedRender.reserve(m_controlPoints.size());
00315 }
00316 typedef MemberCaller<CurveEdit, &CurveEdit::curveChanged> CurveChangedCaller;
00317 };
00318
00319 const int NURBS_degree = 3;
00320
00321 class NURBSCurve
00322 {
00323 Signal0 m_curveChanged;
00324 Callback m_boundsChanged;
00325 public:
00326 ControlPoints m_controlPoints;
00327 ControlPoints m_controlPointsTransformed;
00328 NURBSWeights m_weights;
00329 Knots m_knots;
00330 RenderableCurve m_renderCurve;
00331 AABB m_bounds;
00332
00333 NURBSCurve (const Callback& boundsChanged) :
00334 m_boundsChanged(boundsChanged)
00335 {
00336 }
00337
00338 SignalHandlerId connect (const SignalHandler& curveChanged)
00339 {
00340 curveChanged();
00341 return m_curveChanged.connectLast(curveChanged);
00342 }
00343 void disconnect (SignalHandlerId id)
00344 {
00345 m_curveChanged.disconnect(id);
00346 }
00347 void notify ()
00348 {
00349 m_curveChanged();
00350 }
00351
00352 void tesselate ()
00353 {
00354 if (!m_controlPointsTransformed.empty()) {
00355 const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
00356 m_renderCurve.m_vertices.resize(numSegments + 1);
00357 m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
00358 for (std::size_t i = 1; i < numSegments; ++i) {
00359 m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(NURBS_evaluate(
00360 m_controlPointsTransformed, m_weights, m_knots, NURBS_degree, (1.0 / double(numSegments))
00361 * double(i)));
00362 }
00363 m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(
00364 m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
00365 } else {
00366 m_renderCurve.m_vertices.clear();
00367 }
00368 }
00369
00370 void curveChanged ()
00371 {
00372 tesselate();
00373
00374 m_bounds = AABB();
00375 for (ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i) {
00376 aabb_extend_by_point_safe(m_bounds, (*i));
00377 }
00378
00379 m_boundsChanged();
00380 notify();
00381 }
00382
00383 bool parseCurve (const char* value)
00384 {
00385 if (!ControlPoints_parse(m_controlPoints, value)) {
00386 return false;
00387 }
00388
00389 m_weights.resize(m_controlPoints.size());
00390 for (NURBSWeights::iterator i = m_weights.begin(); i != m_weights.end(); ++i) {
00391 (*i) = 1;
00392 }
00393
00394 KnotVector_openUniform(m_knots, m_controlPoints.size(), NURBS_degree);
00395
00396
00397
00398 return true;
00399 }
00400
00401 void curveChanged (const char* value)
00402 {
00403 if (string_empty(value) || !parseCurve(value)) {
00404 m_controlPoints.resize(0);
00405 m_knots.resize(0);
00406 m_weights.resize(0);
00407 }
00408 m_controlPointsTransformed = m_controlPoints;
00409 curveChanged();
00410 }
00411 typedef MemberCaller1<NURBSCurve, const char*, &NURBSCurve::curveChanged> CurveChangedCaller;
00412 };
00413
00414 class CatmullRomSpline
00415 {
00416 Signal0 m_curveChanged;
00417 Callback m_boundsChanged;
00418 public:
00419 ControlPoints m_controlPoints;
00420 ControlPoints m_controlPointsTransformed;
00421 RenderableCurve m_renderCurve;
00422 AABB m_bounds;
00423
00424 CatmullRomSpline (const Callback& boundsChanged) :
00425 m_boundsChanged(boundsChanged)
00426 {
00427 }
00428
00429 SignalHandlerId connect (const SignalHandler& curveChanged)
00430 {
00431 curveChanged();
00432 return m_curveChanged.connectLast(curveChanged);
00433 }
00434 void disconnect (SignalHandlerId id)
00435 {
00436 m_curveChanged.disconnect(id);
00437 }
00438 void notify ()
00439 {
00440 m_curveChanged();
00441 }
00442
00443 void tesselate ()
00444 {
00445 if (!m_controlPointsTransformed.empty()) {
00446 const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
00447 m_renderCurve.m_vertices.resize(numSegments + 1);
00448 m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
00449 for (std::size_t i = 1; i < numSegments; ++i) {
00450 m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(CatmullRom_evaluate(
00451 m_controlPointsTransformed, (1.0 / double(numSegments)) * double(i)));
00452 }
00453 m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(
00454 m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
00455 } else {
00456 m_renderCurve.m_vertices.clear();
00457 }
00458 }
00459
00460 bool parseCurve (const char* value)
00461 {
00462 return ControlPoints_parse(m_controlPoints, value);
00463 }
00464
00465 void curveChanged ()
00466 {
00467 tesselate();
00468
00469 m_bounds = AABB();
00470 for (ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i) {
00471 aabb_extend_by_point_safe(m_bounds, (*i));
00472 }
00473
00474 m_boundsChanged();
00475 notify();
00476 }
00477
00478 void curveChanged (const char* value)
00479 {
00480 if (string_empty(value) || !parseCurve(value)) {
00481 m_controlPoints.resize(0);
00482 }
00483 m_controlPointsTransformed = m_controlPoints;
00484 curveChanged();
00485 }
00486 typedef MemberCaller1<CatmullRomSpline, const char*, &CatmullRomSpline::curveChanged> CurveChangedCaller;
00487 };
00488
00489 const char* const curve_Nurbs = "curve_Nurbs";
00490 const char* const curve_CatmullRomSpline = "curve_CatmullRomSpline";
00491
00492 #endif