0028572: Modeling Algorithms - Wrong result of the mkface command
[occt.git] / src / OpenGl / OpenGl_VertexBuffer.hxx
1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 2013-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #ifndef _OpenGl_VertexBuffer_H__
16 #define _OpenGl_VertexBuffer_H__
17
18 #include <OpenGl_GlCore20.hxx>
19 #include <OpenGl_Resource.hxx>
20 #include <OpenGl_Context.hxx>
21 #include <OpenGl_ShaderProgram.hxx>
22
23 #include <Graphic3d_IndexBuffer.hxx>
24
25 //! Vertex Buffer Object - is a general storage object for vertex attributes (position, normal, color).
26 //! Notice that you should use OpenGl_IndexBuffer specialization for array of indices.
27 class OpenGl_VertexBuffer : public OpenGl_Resource
28 {
29
30 public:
31
32   //! Helpful constants
33   static const GLuint NO_BUFFER = 0;
34
35 public:
36
37   //! Create uninitialized VBO.
38   Standard_EXPORT OpenGl_VertexBuffer();
39
40   //! Destroy object.
41   Standard_EXPORT virtual ~OpenGl_VertexBuffer();
42
43   Standard_EXPORT virtual GLenum GetTarget() const;
44
45   //! Return TRUE if this is a virtual (for backward compatibility) VBO object.
46   virtual bool IsVirtual() const { return false; }
47
48   //! @return true if current object was initialized
49   inline bool IsValid() const
50   {
51     return myBufferId != NO_BUFFER;
52   }
53
54   //! @return the number of components per generic vertex attribute.
55   inline GLuint GetComponentsNb() const
56   {
57     return myComponentsNb;
58   }
59
60   //! @return number of vertex attributes / number of vertices specified within ::Init()
61   inline GLsizei GetElemsNb() const
62   {
63     return myElemsNb;
64   }
65
66   //! Overrides the number of vertex attributes / number of vertexes.
67   //! It is up to user specifying this number correct (e.g. below initial value)!
68   void SetElemsNb (GLsizei theNbElems) { myElemsNb = theNbElems; }
69
70   //! @return data type of each component in the array.
71   inline GLenum GetDataType() const
72   {
73     return myDataType;
74   }
75
76   //! @return offset to data, NULL by default
77   inline GLubyte* GetDataOffset() const
78   {
79     return myOffset;
80   }
81
82   //! Creates VBO name (id) if not yet generated.
83   //! Data should be initialized by another method.
84   Standard_EXPORT virtual bool Create (const Handle(OpenGl_Context)& theGlCtx);
85
86   //! Destroy object - will release GPU memory if any.
87   Standard_EXPORT virtual void Release (OpenGl_Context* theGlCtx) Standard_OVERRIDE;
88
89   //! Bind this VBO.
90   Standard_EXPORT virtual void Bind (const Handle(OpenGl_Context)& theGlCtx) const;
91
92   //! Unbind this VBO.
93   Standard_EXPORT virtual void Unbind (const Handle(OpenGl_Context)& theGlCtx) const;
94
95   //! Notice that VBO will be unbound after this call.
96   //! @param theComponentsNb - specifies the number of components per generic vertex attribute; must be 1, 2, 3, or 4;
97   //! @param theElemsNb      - elements count;
98   //! @param theData         - pointer to GLfloat data (vertices/normals etc.).
99   bool Init (const Handle(OpenGl_Context)& theGlCtx,
100              const GLuint   theComponentsNb,
101              const GLsizei  theElemsNb,
102              const GLfloat* theData)
103   {
104     return init (theGlCtx, theComponentsNb, theElemsNb, theData, GL_FLOAT);
105   }
106
107   //! Notice that VBO will be unbound after this call.
108   //! @param theComponentsNb - specifies the number of components per generic vertex attribute; must be 1, 2, 3, or 4;
109   //! @param theElemsNb      - elements count;
110   //! @param theData         - pointer to GLuint data (indices etc.).
111   bool Init (const Handle(OpenGl_Context)& theGlCtx,
112              const GLuint  theComponentsNb,
113              const GLsizei theElemsNb,
114              const GLuint* theData)
115   {
116     return init (theGlCtx, theComponentsNb, theElemsNb, theData, GL_UNSIGNED_INT);
117   }
118
119   //! Notice that VBO will be unbound after this call.
120   //! @param theComponentsNb - specifies the number of components per generic vertex attribute; must be 1, 2, 3, or 4;
121   //! @param theElemsNb      - elements count;
122   //! @param theData         - pointer to GLushort data (indices etc.).
123   bool Init (const Handle(OpenGl_Context)& theGlCtx,
124              const GLuint    theComponentsNb,
125              const GLsizei   theElemsNb,
126              const GLushort* theData)
127   {
128     return init (theGlCtx, theComponentsNb, theElemsNb, theData, GL_UNSIGNED_SHORT);
129   }
130
131   //! Notice that VBO will be unbound after this call.
132   //! @param theComponentsNb - specifies the number of components per generic vertex attribute; must be 1, 2, 3, or 4;
133   //! @param theElemsNb      - elements count;
134   //! @param theData         - pointer to GLubyte data (indices/colors etc.).
135   bool Init (const Handle(OpenGl_Context)& theGlCtx,
136              const GLuint   theComponentsNb,
137              const GLsizei  theElemsNb,
138              const GLubyte* theData)
139   {
140     return init (theGlCtx, theComponentsNb, theElemsNb, theData, GL_UNSIGNED_BYTE);
141   }
142
143   //! Notice that VBO will be unbound after this call.
144   //! Function replaces portion of data within this VBO using glBufferSubData().
145   //! The VBO should be initialized before call.
146   //! @param theElemFrom - element id from which replace buffer data (>=0);
147   //! @param theElemsNb  - elements count (theElemFrom + theElemsNb <= GetElemsNb());
148   //! @param theData     - pointer to GLfloat data.
149   bool SubData (const Handle(OpenGl_Context)& theGlCtx,
150                 const GLsizei  theElemFrom,
151                 const GLsizei  theElemsNb,
152                 const GLfloat* theData)
153   {
154     return subData (theGlCtx, theElemFrom, theElemsNb, theData, GL_FLOAT);
155   }
156
157   //! Read back buffer sub-range.
158   //! Notice that VBO will be unbound after this call.
159   //! Function reads portion of data from this VBO using glGetBufferSubData().
160   //! @param theElemFrom [in] element id from which replace buffer data (>=0);
161   //! @param theElemsNb  [in] elements count (theElemFrom + theElemsNb <= GetElemsNb());
162   //! @param theData    [out] destination pointer to GLfloat data.
163   bool GetSubData (const Handle(OpenGl_Context)& theGlCtx,
164                    const GLsizei theElemFrom,
165                    const GLsizei theElemsNb,
166                    GLfloat* theData)
167   {
168     return getSubData (theGlCtx, theElemFrom, theElemsNb, theData, GL_FLOAT);
169   }
170
171   //! Notice that VBO will be unbound after this call.
172   //! Function replaces portion of data within this VBO using glBufferSubData().
173   //! The VBO should be initialized before call.
174   //! @param theElemFrom element id from which replace buffer data (>=0);
175   //! @param theElemsNb  elements count (theElemFrom + theElemsNb <= GetElemsNb());
176   //! @param theData     pointer to GLuint data.
177   bool SubData (const Handle(OpenGl_Context)& theGlCtx,
178                 const GLsizei theElemFrom,
179                 const GLsizei theElemsNb,
180                 const GLuint* theData)
181   {
182     return subData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_INT);
183   }
184
185   //! Read back buffer sub-range.
186   //! Notice that VBO will be unbound after this call.
187   //! Function reads portion of data from this VBO using glGetBufferSubData().
188   //! @param theElemFrom [in] element id from which replace buffer data (>=0);
189   //! @param theElemsNb  [in] elements count (theElemFrom + theElemsNb <= GetElemsNb());
190   //! @param theData    [out] destination pointer to GLuint data.
191   bool GetSubData (const Handle(OpenGl_Context)& theGlCtx,
192                    const GLsizei theElemFrom,
193                    const GLsizei theElemsNb,
194                    GLuint* theData)
195   {
196     return getSubData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_INT);
197   }
198
199   //! Notice that VBO will be unbound after this call.
200   //! Function replaces portion of data within this VBO using glBufferSubData().
201   //! The VBO should be initialized before call.
202   //! @param theElemFrom element id from which replace buffer data (>=0);
203   //! @param theElemsNb  elements count (theElemFrom + theElemsNb <= GetElemsNb());
204   //! @param theData     pointer to GLushort data.
205   bool SubData (const Handle(OpenGl_Context)& theGlCtx,
206                 const GLsizei   theElemFrom,
207                 const GLsizei   theElemsNb,
208                 const GLushort* theData)
209   {
210     return subData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_SHORT);
211   }
212
213   //! Read back buffer sub-range.
214   //! Notice that VBO will be unbound after this call.
215   //! Function reads portion of data from this VBO using glGetBufferSubData().
216   //! @param theElemFrom [in] element id from which replace buffer data (>=0);
217   //! @param theElemsNb  [in] elements count (theElemFrom + theElemsNb <= GetElemsNb());
218   //! @param theData    [out] destination pointer to GLushort data.
219   bool GetSubData (const Handle(OpenGl_Context)& theGlCtx,
220                    const GLsizei theElemFrom,
221                    const GLsizei theElemsNb,
222                    GLushort* theData)
223   {
224     return getSubData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_SHORT);
225   }
226
227   //! Notice that VBO will be unbound after this call.
228   //! Function replaces portion of data within this VBO using glBufferSubData().
229   //! The VBO should be initialized before call.
230   //! @param theElemFrom element id from which replace buffer data (>=0);
231   //! @param theElemsNb  elements count (theElemFrom + theElemsNb <= GetElemsNb());
232   //! @param theData     pointer to GLubyte data.
233   bool SubData (const Handle(OpenGl_Context)& theGlCtx,
234                 const GLsizei  theElemFrom,
235                 const GLsizei  theElemsNb,
236                 const GLubyte* theData)
237   {
238     return subData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_BYTE);
239   }
240
241   //! Read back buffer sub-range.
242   //! Notice that VBO will be unbound after this call.
243   //! Function reads portion of data from this VBO using glGetBufferSubData().
244   //! @param theElemFrom [in] element id from which replace buffer data (>=0);
245   //! @param theElemsNb  [in] elements count (theElemFrom + theElemsNb <= GetElemsNb());
246   //! @param theData    [out] destination pointer to GLubyte data.
247   bool GetSubData (const Handle(OpenGl_Context)& theGlCtx,
248                    const GLsizei theElemFrom,
249                    const GLsizei theElemsNb,
250                    GLubyte* theData)
251   {
252     return getSubData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_BYTE);
253   }
254
255   //! Bind this VBO to active GLSL program.
256   Standard_EXPORT void BindVertexAttrib (const Handle(OpenGl_Context)& theGlCtx,
257                                          const GLuint                  theAttribLoc) const;
258
259   //! Unbind any VBO from active GLSL program.
260   Standard_EXPORT void UnbindVertexAttrib (const Handle(OpenGl_Context)& theGlCtx,
261                                            const GLuint                  theAttribLoc) const;
262
263   //! Bind this VBO and enable specified attribute in OpenGl_Context::ActiveProgram() or FFP.
264   //! @param theGlCtx - handle to bound GL context;
265   //! @param theMode  - array mode (GL_VERTEX_ARRAY, GL_NORMAL_ARRAY, GL_COLOR_ARRAY, GL_INDEX_ARRAY, GL_TEXTURE_COORD_ARRAY).
266   void BindAttribute (const Handle(OpenGl_Context)&   theCtx,
267                       const Graphic3d_TypeOfAttribute theMode) const
268   {
269     if (IsValid())
270     {
271       Bind (theCtx);
272       bindAttribute (theCtx, theMode, static_cast<GLint> (myComponentsNb), myDataType, 0, myOffset);
273     }
274   }
275
276   //! Unbind this VBO and disable specified attribute in OpenGl_Context::ActiveProgram() or FFP.
277   //! @param theCtx handle to bound GL context
278   //! @param theMode  array mode
279   void UnbindAttribute (const Handle(OpenGl_Context)&   theCtx,
280                         const Graphic3d_TypeOfAttribute theMode) const
281   {
282     if (IsValid())
283     {
284       Unbind (theCtx);
285       unbindAttribute (theCtx, theMode);
286     }
287   }
288
289 public: //! @name advanced methods
290
291   //! Returns estimated GPU memory usage for holding data without considering overheads and allocation alignment rules.
292   virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE
293   {
294     return IsValid()
295          ? sizeOfGlType (myDataType) * myComponentsNb * myElemsNb
296          : 0;
297   }
298
299   //! @return size of specified GL type
300   static size_t sizeOfGlType (const GLenum theType)
301   {
302     switch (theType)
303     {
304       case GL_BYTE:
305       case GL_UNSIGNED_BYTE:  return sizeof(GLubyte);
306       case GL_SHORT:
307       case GL_UNSIGNED_SHORT: return sizeof(GLushort);
308     #ifdef GL_INT
309       case GL_INT:
310     #endif
311       case GL_UNSIGNED_INT:   return sizeof(GLuint);
312       case GL_FLOAT:          return sizeof(GLfloat);
313     #ifdef GL_DOUBLE
314       case GL_DOUBLE:         return sizeof(GLdouble);
315     #endif
316       default:                return 0;
317     }
318   }
319
320   //! Initialize buffer with new data.
321   Standard_EXPORT virtual bool init (const Handle(OpenGl_Context)& theGlCtx,
322                                      const GLuint   theComponentsNb,
323                                      const GLsizei  theElemsNb,
324                                      const void*    theData,
325                                      const GLenum   theDataType,
326                                      const GLsizei  theStride);
327
328   //! Initialize buffer with new data.
329   bool init (const Handle(OpenGl_Context)& theGlCtx,
330              const GLuint   theComponentsNb,
331              const GLsizei  theElemsNb,
332              const void*    theData,
333              const GLenum   theDataType)
334   {
335     return init (theGlCtx, theComponentsNb, theElemsNb, theData, theDataType, GLsizei(theComponentsNb) * GLsizei(sizeOfGlType (theDataType)));
336   }
337
338   //! Update part of the buffer with new data.
339   Standard_EXPORT virtual bool subData (const Handle(OpenGl_Context)& theGlCtx,
340                                         const GLsizei  theElemFrom,
341                                         const GLsizei  theElemsNb,
342                                         const void*    theData,
343                                         const GLenum   theDataType);
344
345   //! Read back buffer sub-range.
346   Standard_EXPORT virtual bool getSubData (const Handle(OpenGl_Context)& theGlCtx,
347                                            const GLsizei theElemFrom,
348                                            const GLsizei theElemsNb,
349                                            void*         theData,
350                                            const GLenum  theDataType);
351
352   //! Setup array pointer - either for active GLSL program OpenGl_Context::ActiveProgram()
353   //! or for FFP using bindFixed() when no program bound.
354   static void bindAttribute (const Handle(OpenGl_Context)&   theGlCtx,
355                              const Graphic3d_TypeOfAttribute theMode,
356                              const GLint                     theNbComp,
357                              const GLenum                    theDataType,
358                              const GLsizei                   theStride,
359                              const GLvoid*                   theOffset);
360
361   //! Disable GLSL array pointer - either for active GLSL program OpenGl_Context::ActiveProgram()
362   //! or for FFP using unbindFixed() when no program bound.
363   static void unbindAttribute (const Handle(OpenGl_Context)&   theGlCtx,
364                                const Graphic3d_TypeOfAttribute theMode);
365
366 private:
367 #if !defined(GL_ES_VERSION_2_0)
368   //! Setup FFP array pointer.
369   static void bindFixed (const Handle(OpenGl_Context)&   theGlCtx,
370                          const Graphic3d_TypeOfAttribute theMode,
371                          const GLint                     theNbComp,
372                          const GLenum                    theDataType,
373                          const GLsizei                   theStride,
374                          const GLvoid*                   theOffset);
375
376   //! Disable FFP array pointer.
377   static void unbindFixed (const Handle(OpenGl_Context)&   theGlCtx,
378                            const Graphic3d_TypeOfAttribute theMode);
379
380   //! Disable FFP color array pointer.
381   Standard_EXPORT static void unbindFixedColor (const Handle(OpenGl_Context)& theCtx);
382
383 #endif
384 public: //! @name methods for interleaved attributes array
385
386   //! @return true if buffer contains per-vertex color attribute
387   Standard_EXPORT virtual bool HasColorAttribute() const;
388
389   //! @return true if buffer contains per-vertex normal attribute
390   Standard_EXPORT virtual bool HasNormalAttribute() const;
391
392   //! Bind all vertex attributes to active program OpenGl_Context::ActiveProgram() or for FFP.
393   //! Default implementation does nothing.
394   Standard_EXPORT virtual void BindAllAttributes (const Handle(OpenGl_Context)& theGlCtx) const;
395
396   //! Bind vertex position attribute only. Default implementation does nothing.
397   Standard_EXPORT virtual void BindPositionAttribute (const Handle(OpenGl_Context)& theGlCtx) const;
398
399   //! Unbind all vertex attributes. Default implementation does nothing.
400   Standard_EXPORT virtual void UnbindAllAttributes (const Handle(OpenGl_Context)& theGlCtx) const;
401
402   //! Dumps the content of me into the stream
403   Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const Standard_OVERRIDE;
404
405 protected:
406
407   GLubyte* myOffset;       //!< offset to data
408   GLuint   myBufferId;     //!< VBO name (index)
409   GLuint   myComponentsNb; //!< Number of components per generic vertex attribute, must be 1, 2, 3, or 4
410   GLsizei  myElemsNb;      //!< Number of vertex attributes / number of vertices
411   GLenum   myDataType;     //!< Data type (GL_FLOAT, GL_UNSIGNED_INT, GL_UNSIGNED_BYTE etc.)
412
413 public:
414
415   DEFINE_STANDARD_RTTIEXT(OpenGl_VertexBuffer,OpenGl_Resource) // Type definition
416
417 };
418
419 DEFINE_STANDARD_HANDLE(OpenGl_VertexBuffer, OpenGl_Resource)
420
421 #include <OpenGl_VertexBuffer.lxx>
422
423 #endif // _OpenGl_VertexBuffer_H__