#pragma once #include "IndexedGeometry.h" #include "Vector.h" #include namespace Aftr { class IndexedGeometryRibbon : public IndexedGeometry { public: static IndexedGeometryRibbon* New( bool useNormals = true, bool useColors = true, bool useTextures = false, float minDistBetweenConsecutivePoints_meters = 0.01f ); virtual ~IndexedGeometryRibbon() {} virtual void render() override; /** When a point is appended, it becomes the new "front center" point of the ribbon. Internally, geometry is created about that point to make the ribbon have the desired width and roll. */ virtual void appendPoint( Vector const& pt, Vector const& upDir, const aftrColor4ub& color ); std::string toString() const; const Vector& getRibbonUpDirection() const {return this->up;} void setRibbonUpDirection( const Vector& upNormalized ) { this->up = up; } aftrColor4ub& getColorAtPt( size_t idx ); void updateRibbonData(); int getNumAddedPoints() const { return static_cast(this->verticesVec.size() / 6); } //each added pt becomes a left & right pt int getNumPointsInRibbon() const {return static_cast(this->verticesVec.size() / 3);} //double num added points struct TrackPoint { Vector pt = { 0,0,0 }; //The new XYZ point for this ribbon Vector upDir = 0; //the "up" direction specifying the roll of the ribbon at the new XYZ point. aftrColor4ub color = aftrColor4ub(); //The color of the ribbon at point XYZ. }; void setWidth( float w ) { this->width = w; } float getWidth() const { return this->width; } protected: IndexedGeometryRibbon( bool useNormals, bool useColors, bool useTextures, float minDistBetweenConsecutivePoints ); virtual void createVertices() override; virtual void createIndices() override; virtual void createColors() override; virtual void createTextureCoords() override; virtual void createNormals() override; virtual void createVAO() override; /// Called by appendPoint. This inserts two new vertices centered about /// the in passed control point (via appendPoint). This also inserts the /// corresponding normals, colors, tex Coords, etc for each new GL vertex. /// Essentially, this appends the new ribbon segment to the front of this /// ribbon. /// No GPU memory allocation is performed when the GPU already has /// sufficient VAO memory to handle a the vertex entry insertion. /// The GPU memory for each vertex array grows by matching the capacity of /// the corresponding CPU-side std::vectors of vertex entry data. /// This includes verticies, normals, indices, colors, and texture coords. /// The in passed bools notify this method if the CPU-side std::vector corresponding /// to a specific attribute grew in capacity during the most recent insertion. /// This method then uses that info to grow the GPU-side memory accordingly. void appendGLVertex( bool resizeVerts, bool resizeIndices, bool resizeColors, bool resizeTexCoords, bool resizeNormals ); //IndexedGeometry base class already has a few member pointers for things like // colors, normals, textureCoords, vertices, indices... However, in this class, // I'd like to replace those base members with std::vector to try to improve // testability and debugging. Furthermore, this ribbon will be somewhat dynamic in // the amount of points that may get added to it (the ribbon may grow over time) // so I will allocate more GPU RAM for points than are currently stored in the ribbon // and dynamically grow the GPU RAM by doubling just like a vector. std::vector< GLfloat > verticesVec; ///< (x,y,z) per vertex std::vector< GLfloat > normalsVec; ///< (x,y,z) per vertex (assumed to be normalized) std::vector< GLfloat > textureCoordsVec; ///< (u,v) per vertex std::vector< GLubyte > colorsVec; ///< (r,g,b,a) per vertex std::vector< GLuint > indicesVec; ///< assume the ribbon can easily surpass 65536 indices //std::vector< TrackPoint > controlPts; ///< Each control point added by user TrackPoint lastAddedTrackPt; /// if verticesVec.size() == 0 && hasAddedFirstPoint bool hasAddedFirstPoint = false; ///< Becomes true after the user adds at least 2 points to form a ribbon inline void computeAndInsertVertexEntryIntoGLBuffers( const Vector& newPoint, const aftrColor4ub& color, Vector const& upDir, Vector& lastTrackPt ); /// Specifies the expected usage pattern of the data store. /// The symbolic constant must be GL_STREAM_DRAW, GL_STREAM_READ, /// GL_STREAM_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, /// GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, or GL_DYNAMIC_COPY. GLenum usageModeForGLVertexAttributes = GL_DYNAMIC_DRAW; float width = 1.0f; ///< The initial width of the ribbon; defaults to 1.0 Vector up = { 0,0,1.0f }; ///< The "up" direction for this ribbon (commonly, /// it points against gravity, for example). Used to compute roll float minDistBetweenConsecutivePoints = 0.01f; }; }