/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * ***** END GPL LICENSE BLOCK ***** */ #ifndef __FREESTYLE_STROKE_H__ #define __FREESTYLE_STROKE_H__ /** \file blender/freestyle/intern/stroke/Stroke.h * \ingroup freestyle * \brief Classes to define a stroke * \author Stephane Grabli * \date 09/09/2002 */ #include #include #include "Curve.h" #include "../view_map/Interface1D.h" #include "../view_map/Silhouette.h" #include "../system/FreestyleConfig.h" #include "../system/StringUtils.h" #ifdef WITH_CXX_GUARDEDALLOC #include "MEM_guardedalloc.h" #endif extern "C" { #include "DNA_material_types.h" struct bNodeTree; } #ifndef MAX_MTEX #define MAX_MTEX 18 #endif namespace Freestyle { // // StrokeAttribute // //////////////////////////////////////////////////////// /*! Class to define an attribute associated to a Stroke Vertex. * This attribute stores the color, alpha and thickness values for a Stroke Vertex. */ class StrokeAttribute { public: /*! default constructor */ StrokeAttribute(); /*! Copy constructor */ StrokeAttribute(const StrokeAttribute& iBrother); /*! Builds a stroke vertex attribute from a set of parameters. * \param iRColor * The Red Component value. * \param iGColor * The Green Component value. * \param iBColor * The Blue Component value. * \param iAlpha * The transparency value * \param iRThickness * The thickness of the stroke on the right * \param iLThickness * The Thickness of the stroke on the left */ StrokeAttribute(float iRColor, float iGColor, float iBColor, float iAlpha, float iRThickness, float iLThickness); /*! Interpolation constructor. * Builds a StrokeAttribute from two StrokeAttributes and an interpolation parameter. * \param a1 * The first Attribute. * \param a2 * The second parameter. * \param t * The interpolation parameter. */ StrokeAttribute(const StrokeAttribute& a1, const StrokeAttribute& a2, float t); /*! destructor */ virtual ~StrokeAttribute(); /* operators */ /*! operator = */ StrokeAttribute& operator=(const StrokeAttribute& iBrother); /* accessors */ /*! Returns the attribute's color. * \return The array of 3 floats containing the R,G,B values of the attribute's color. */ inline const float *getColor() const { return _color; } /*! Returns the R color component. */ inline const float getColorR() const { return _color[0]; } /*! Returns the G color component. */ inline const float getColorG() const { return _color[1]; } /*! Returns the B color component. */ inline const float getColorB() const { return _color[2]; } /*! Returns the RGB color components. */ inline Vec3f getColorRGB() const { return Vec3f(_color[0], _color[1], _color[2]); } /*! Returns the alpha color component. */ inline float getAlpha() const { return _alpha; } /*! Returns the attribute's thickness. * \return an array of 2 floats. the first value is the thickness on the right of the vertex when following * the stroke, the second one is the thickness on the left. */ inline const float *getThickness() const { return _thickness; } /*! Returns the thickness on the right of the vertex when following the stroke. */ inline const float getThicknessR() const { return _thickness[0]; } /*! Returns the thickness on the left of the vertex when following the stroke. */ inline const float getThicknessL() const { return _thickness[1]; } /*! Returns the thickness on the right and on the left of the vertex when following the stroke. */ inline Vec2f getThicknessRL() const { return Vec2f(_thickness[0], _thickness[1]); } /*! Returns true if the strokevertex is visible, false otherwise */ inline bool isVisible() const { return _visible; } /*! Returns an attribute of type real * \param iName * The name of the attribute */ float getAttributeReal(const char *iName) const; /*! Returns an attribute of type Vec2f * \param iName * The name of the attribute */ Vec2f getAttributeVec2f(const char *iName) const; /*! Returns an attribute of type Vec3f * \param iName * The name of the attribute */ Vec3f getAttributeVec3f(const char *iName) const; /*! Checks whether the attribute iName is availbale */ bool isAttributeAvailableReal(const char *iName) const; /*! Checks whether the attribute iName is availbale */ bool isAttributeAvailableVec2f(const char *iName) const; /*! Checks whether the attribute iName is availbale */ bool isAttributeAvailableVec3f(const char *iName) const; /* modifiers */ /*! sets the attribute's color. * \param r * The new R value. * \param g * The new G value. * \param b * The new B value. */ inline void setColor(float r, float g, float b) { _color[0] = r; _color[1] = g; _color[2] = b; } /*! sets the attribute's color. * \param iRGB * The new RGB values. */ inline void setColor(const Vec3f& iRGB) { _color[0] = iRGB[0]; _color[1] = iRGB[1]; _color[2] = iRGB[2]; } /*! sets the attribute's alpha value. * \param alpha * The new alpha value. */ inline void setAlpha(float alpha) { _alpha = alpha; } /*! sets the attribute's thickness. * \param tr * The thickness on the right of the vertex when following the stroke. * \param tl * The thickness on the left of the vertex when following the stroke. */ inline void setThickness(float tr, float tl) { _thickness[0] = tr; _thickness[1] = tl; } /*! sets the attribute's thickness. * \param tRL * The thickness on the right and on the left of the vertex when following the stroke. */ inline void setThickness(const Vec2f& tRL) { _thickness[0] = tRL[0]; _thickness[1] = tRL[1]; } /*! sets the visible flag. True means visible. */ inline void setVisible(bool iVisible) { _visible = iVisible; } /*! Adds a user defined attribute of type real * If there is no attribute of name iName, it is added. * Otherwise, the new value replaces the old one. * \param iName * The name of the attribute * \param att * The attribute's value */ void setAttributeReal(const char *iName, float att); /*! Adds a user defined attribute of type Vec2f * If there is no attribute of name iName, it is added. * Otherwise, the new value replaces the old one. * \param iName * The name of the attribute * \param att * The attribute's value */ void setAttributeVec2f(const char *iName, const Vec2f& att); /*! Adds a user defined attribute of type Vec3f * If there is no attribute of name iName, it is added. * Otherwise, the new value replaces the old one. * \param iName * The name of the attribute * \param att * The attribute's value */ void setAttributeVec3f(const char *iName, const Vec3f& att); private: typedef std::map realMap; typedef std::map Vec2fMap; typedef std::map Vec3fMap; float _color[3]; //! the color float _alpha; //! alpha float _thickness[2]; //! the thickness on the right and on the left of the backbone vertex (the stroke is oriented) bool _visible; realMap *_userAttributesReal; Vec2fMap *_userAttributesVec2f; Vec3fMap *_userAttributesVec3f; #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:StrokeAttribute") #endif }; // // StrokeVertex // //////////////////////////////////////////////////////// /*! Class to define a stroke vertex. */ class StrokeVertex : public CurvePoint { public: // Implementation of Interface0D /*! Returns the string "StrokeVertex" */ virtual string getExactTypeName() const { return "StrokeVertex"; } private: StrokeAttribute _Attribute; //! The attribute associated to the vertex float _CurvilignAbscissa; //! the curvilign abscissa float _StrokeLength; // stroke length public: /*! default constructor */ StrokeVertex(); /*! Copy constructor */ StrokeVertex(const StrokeVertex& iBrother); /*! Builds a stroke vertex from a SVertex */ StrokeVertex(SVertex *iSVertex); /*! Builds a stroke vertex from a CurvePoint */ StrokeVertex(CurvePoint *iPoint); /*! Builds Stroke Vertex from 2 stroke vertices and an interpolation parameter*/ StrokeVertex(StrokeVertex *iA, StrokeVertex *iB, float t3); /*! Builds a stroke from a view vertex and an attribute */ StrokeVertex(SVertex *iSVertex, const StrokeAttribute& iAttribute); /*! destructor */ virtual ~StrokeVertex(); /* operators */ /*! operator = */ StrokeVertex& operator=(const StrokeVertex& iBrother); /* accessors */ /*! Returns the 2D point x coordinate */ inline real x() const { return _Point2d[0]; } /*! Returns the 2D point y coordinate */ inline real y() const { return _Point2d[1]; } /*! Returns the 2D point coordinates as a Vec2r */ inline Vec2r getPoint() const { return getPoint2D(); } /*! Returns the ith 2D point coordinate (i=0 or 1)*/ inline real operator[](const int i) const { return _Point2d[i]; } /*! Returns the StrokeAttribute for this StrokeVertex */ inline const StrokeAttribute& attribute() const { return _Attribute; } /*! Returns a non-const reference to the StrokeAttribute of this StrokeVertex */ inline StrokeAttribute& attribute() { return _Attribute; } /*! Returns the curvilinear abscissa */ inline float curvilinearAbscissa() const { return _CurvilignAbscissa; } /*! Returns the length of the Stroke to which this StrokeVertex belongs */ inline float strokeLength() const { return _StrokeLength; } /*! Returns the curvilinear abscissa of this StrokeVertex in the Stroke */ inline float u() const { return _CurvilignAbscissa / _StrokeLength; } /* modifiers */ /*! sets the 2D x value */ inline void setX(real x) { _Point2d[0] = x; } /*! sets the 2D y value */ inline void setY(real y) { _Point2d[1] = y; } /*! sets the 2D x and y values */ inline void setPoint(real x, real y) { _Point2d[0] = x; _Point2d[1] = y; } /*! sets the 2D x and y values */ inline void setPoint(const Vec2r& p) { _Point2d[0] = p[0]; _Point2d[1] = p[1]; } /*! Returns a reference to the ith 2D point coordinate (i=0 or 1) */ inline real& operator[](const int i) { return _Point2d[i]; } /*! sets the attribute. */ inline void setAttribute(const StrokeAttribute& iAttribute) { _Attribute = iAttribute; } /*! sets the curvilinear abscissa of this StrokeVertex in the Stroke */ inline void setCurvilinearAbscissa(float iAbscissa) { _CurvilignAbscissa = iAbscissa; } /*! sets the Stroke's length (it's only a value stored by the Stroke Vertex, it won't change the real * Stroke's length.) */ inline void setStrokeLength(float iLength) { _StrokeLength = iLength; } /* interface definition */ /* inherited */ }; // // Stroke // //////////////////////////////////////////////////////// class StrokeRenderer; class StrokeRep; namespace StrokeInternal { class vertex_const_traits; class vertex_nonconst_traits; template class vertex_iterator_base; class StrokeVertexIterator; } // end of namespace StrokeInternal /*! Class to define a stroke. * A stroke is made of a set of 2D vertices (StrokeVertex), regularly spaced out. * This set of vertices defines the stroke's backbone geometry. * Each of these stroke vertices defines the stroke's shape and appearance at this vertex position. */ class Stroke : public Interface1D { public: // Implementation of Interface1D /*! Returns the string "Stroke" */ virtual string getExactTypeName() const { return "Stroke"; } // Data access methods /*! Returns the Id of the Stroke */ virtual Id getId() const { return _id; } /*! The different blending modes available to similate the interaction media-medium. */ typedef enum { DRY_MEDIUM, /*!< To simulate a dry medium such as Pencil or Charcoal.*/ HUMID_MEDIUM, /*!< To simulate ink painting (color substraction blending).*/ OPAQUE_MEDIUM, /*!< To simulate an opaque medium (oil, spray...).*/ } MediumType; public: typedef std::deque vertex_container; // the vertices container typedef std::vector viewedge_container; // the viewedges container typedef StrokeInternal::vertex_iterator_base vertex_iterator; typedef StrokeInternal::vertex_iterator_base const_vertex_iterator; public: //typedef StrokeVertex vertex_type; private: vertex_container _Vertices; //! The stroke's backbone vertices Id _id; float _Length; // The stroke length viewedge_container _ViewEdges; float _sampling; float _textureStep; // StrokeRenderer *_renderer; // mark implementation OpenGL renderer MediumType _mediumType; unsigned int _textureId; MTex *_mtex[MAX_MTEX]; bNodeTree *_nodeTree; bool _tips; Vec2r _extremityOrientations[2]; // the orientations of the first and last extermity public: /*! default constructor */ Stroke(); /*! copy constructor */ Stroke(const Stroke& iBrother); /*! Builds a stroke from a set of StrokeVertex. * This constructor is templated by an iterator type. * This iterator type must allow the vertices parsing using the ++ operator. * \param iBegin * The iterator pointing to the first vertex. * \param iEnd * The iterator pointing to the end of the vertex list. */ template Stroke(InputVertexIterator iBegin, InputVertexIterator iEnd); /*! Destructor */ virtual ~Stroke(); /* operators */ /*! operator = */ Stroke& operator=(const Stroke& iBrother); /*! Compute the sampling needed to get iNVertices vertices. * If the specified number of vertices is less than the actual number of vertices, the actual sampling value * is returned. (To remove Vertices, use the RemoveVertex() method of this class). * \param iNVertices * The number of StrokeVertices we eventually want in our Stroke. * \return the sampling that must be used in the Resample(float) method. * @see Resample(int) * @see Resample(float) */ float ComputeSampling(int iNVertices); /*! Resampling method. * Resamples the curve so that it eventually has iNPoints. That means it is going to add iNPoints-vertices_size, * if vertices_size is the number of points we already have. * If vertices_size >= iNPoints, no resampling is done. * \param iNPoints * The number of vertices we eventually want in our stroke. */ int Resample(int iNPoints); /*! Resampling method. * Resamples the curve with a given sampling. * If this sampling is < to the actual sampling value, no resampling is done. * \param iSampling * The new sampling value. */ int Resample(float iSampling); /*! Removes all vertices from the Stroke. */ void RemoveAllVertices(); /*! Removes the stroke vertex iVertex * from the stroke. * The length and curvilinear abscissa are updated * consequently. */ void RemoveVertex(StrokeVertex *iVertex); /*! Inserts the stroke vertex iVertex in the stroke before next. * The length, curvilinear abscissa are updated consequently. * \param iVertex * The StrokeVertex to insert in the Stroke. * \param next * A StrokeVertexIterator pointing to the StrokeVeretx before which iVertex must be inserted. */ void InsertVertex(StrokeVertex *iVertex, StrokeInternal::StrokeVertexIterator next); /*! Updates the 2D length of the Stroke */ void UpdateLength(); /* Render method */ void ScaleThickness(float iFactor); void Render(const StrokeRenderer *iRenderer); void RenderBasic(const StrokeRenderer *iRenderer); /* Iterator definition */ /* accessors */ /*! Returns the 2D length of the Stroke */ inline real getLength2D() const { return _Length; } /*! Returns a reference to the time stamp value of the stroke. */ /*! Returns the MediumType used for this Stroke. */ inline MediumType getMediumType() const { return _mediumType; } /*! Returns the id of the texture used to simulate th marks system for this Stroke */ inline unsigned int getTextureId() {return _textureId;} /*! Returns the spacing of texture coordinates along the stroke lenght */ inline float getTextureStep() {return _textureStep;} /*! Returns the texture used at given index to simulate the marks system for this Stroke */ inline MTex *getMTex(int idx) { return _mtex[idx]; } /*! Return the shader node tree to define textures. */ inline bNodeTree *getNodeTree() { return _nodeTree; } /*! Returns true if this Stroke has textures assigned, false otherwise. */ inline bool hasTex() const { return (_mtex[0] != NULL) || _nodeTree; } /*! Returns true if this Stroke uses a texture with tips, false otherwise. */ inline bool hasTips() const { return _tips; } /* these advanced iterators are used only in C++ */ inline int vertices_size() const { return _Vertices.size(); } inline viewedge_container::const_iterator viewedges_begin() const { return _ViewEdges.begin(); } inline viewedge_container::iterator viewedges_begin() { return _ViewEdges.begin(); } inline viewedge_container::const_iterator viewedges_end() const { return _ViewEdges.end(); } inline viewedge_container::iterator viewedges_end() { return _ViewEdges.end(); } inline int viewedges_size() const { return _ViewEdges.size(); } inline Vec2r getBeginningOrientation() const { return _extremityOrientations[0]; } inline real getBeginningOrientationX() const { return _extremityOrientations[0].x(); } inline real getBeginningOrientationY() const { return _extremityOrientations[0].y(); } inline Vec2r getEndingOrientation() const { return _extremityOrientations[1]; } inline real getEndingOrientationX() const { return _extremityOrientations[1].x(); } inline real getEndingOrientationY() const { return _extremityOrientations[1].y(); } /* modifiers */ /*! sets the Id of the Stroke. */ inline void setId(const Id& id) { _id = id; } /*! sets the 2D length of the Stroke. */ void setLength(float iLength); /*! sets the medium type that must be used for this Stroke. */ inline void setMediumType(MediumType iType) { _mediumType = iType; } /*! sets the texture id to be used to simulate the marks system for this Stroke. */ inline void setTextureId(unsigned int id) { _textureId = id; } /*! sets the spacing of texture coordinates along the stroke lenght. */ inline void setTextureStep(float step) { _textureStep = step; } /*! assigns a blender texture to the first available slot. */ inline int setMTex(MTex *mtex) { for (int a = 0; a < MAX_MTEX; a++) { if (!_mtex[a]) { _mtex[a] = mtex; return 0; } } return -1; /* no free slots */ } /*! assigns a node tree (of new shading nodes) to define textures. */ inline void setNodeTree(bNodeTree *iNodeTree) { _nodeTree = iNodeTree; } /*! sets the flag telling whether this stroke is using a texture with tips or not. */ inline void setTips(bool iTips) { _tips = iTips; } inline void push_back(StrokeVertex *iVertex) { _Vertices.push_back(iVertex); } inline void push_front(StrokeVertex *iVertex) { _Vertices.push_front(iVertex); } inline void AddViewEdge(ViewEdge *iViewEdge) { _ViewEdges.push_back(iViewEdge); } inline void setBeginningOrientation(const Vec2r& iOrientation) { _extremityOrientations[0] = iOrientation; } inline void setBeginningOrientation(real x, real y) { _extremityOrientations[0] = Vec2r(x, y); } inline void setEndingOrientation(const Vec2r& iOrientation) { _extremityOrientations[1] = iOrientation; } inline void setEndingOrientation(real x, real y) { _extremityOrientations[1] = Vec2r(x, y); } /* Information access interface */ // embedding vertex iterator const_vertex_iterator vertices_begin() const; vertex_iterator vertices_begin(float t = 0.0f); const_vertex_iterator vertices_end() const; vertex_iterator vertices_end(); /*! Returns a StrokeVertexIterator pointing on the first StrokeVertex of the Stroke. One can specify a sampling * value to resample the Stroke on the fly if needed. * \param t * The resampling value with which we want our Stroke to be resampled. * If 0 is specified, no resampling is done. */ StrokeInternal::StrokeVertexIterator strokeVerticesBegin(float t = 0.0f); /*! Returns a StrokeVertexIterator pointing after the last StrokeVertex of the Stroke. */ StrokeInternal::StrokeVertexIterator strokeVerticesEnd(); /*! Returns the number of StrokeVertex constituting the Stroke. */ inline unsigned int strokeVerticesSize() const { return _Vertices.size(); } /*! Returns the i-th StrokeVertex constituting the Stroke. */ inline StrokeVertex& strokeVerticeAt(unsigned int i) { return *(_Vertices.at(i)); } // Iterator access (Interface1D) /*! Returns an Interface0DIterator pointing on the first StrokeVertex of the Stroke. */ virtual Interface0DIterator verticesBegin(); /*! Returns an Interface0DIterator pointing after the last StrokeVertex of the Stroke. */ virtual Interface0DIterator verticesEnd(); virtual Interface0DIterator pointsBegin(float t = 0.0f); virtual Interface0DIterator pointsEnd(float t = 0.0f); }; // // Implementation // //////////////////////////////////////////////////////// template Stroke::Stroke(InputVertexIterator iBegin, InputVertexIterator iEnd) { for (InputVertexIterator v = iBegin, vend = iEnd; v != vend; v++) { _Vertices.push_back(*v); } _Length = 0; _id = 0; } } /* namespace Freestyle */ #endif // __FREESTYLE_STROKE_H__