11#include < cstddef>
22
3+ #ifdef __APPLE__
4+ #define GL_SILENCE_DEPRECATION
5+ #endif
6+
7+ #include < QOpenGLExtraFunctions>
38#include < QOpenGLFunctions>
49#include < QOpenGLContext>
510
1116void GLVertexBuffer::_init (const GLVertexBuffer *pBuffer)
1217{
1318 this ->vboId = 0 ;
19+ this ->vaoId = 0 ;
1420 this ->vertexCount = 0 ;
1521 this ->valid = false ;
1622 this ->recording = false ;
@@ -110,6 +116,7 @@ void GLVertexBuffer::uploadToGPU()
110116
111117 QOpenGLContext *ctx = QOpenGLContext::currentContext ();
112118 QOpenGLFunctions *f = ctx->functions ();
119+ QOpenGLExtraFunctions *ef = ctx->extraFunctions ();
113120
114121 // Generate VBO if needed (reuse existing handle if present).
115122 if (this ->vboId == 0 )
@@ -123,6 +130,36 @@ void GLVertexBuffer::uploadToGPU()
123130 GLsizeiptr (this ->vertices .size () * sizeof (GLVertexData)),
124131 this ->vertices .data (),
125132 GL_STATIC_DRAW));
133+
134+ // Create the VAO (or recreate it after a reset) and record the attribute layout
135+ // while the VBO is still bound so the VAO captures the binding.
136+ if (this ->vaoId == 0 )
137+ {
138+ GL_SAFE_CALL (ef->glGenVertexArrays (1 , &this ->vaoId ));
139+ }
140+ GL_SAFE_CALL (ef->glBindVertexArray (this ->vaoId ));
141+
142+ // aPosition — location 0
143+ GL_SAFE_CALL (f->glEnableVertexAttribArray (0 ));
144+ GL_SAFE_CALL (f->glVertexAttribPointer (0 , 3 , GL_FLOAT, GL_FALSE, sizeof (GLVertexData),
145+ reinterpret_cast <const void *>(offsetof (GLVertexData, position))));
146+
147+ // aNormal — location 1
148+ GL_SAFE_CALL (f->glEnableVertexAttribArray (1 ));
149+ GL_SAFE_CALL (f->glVertexAttribPointer (1 , 3 , GL_FLOAT, GL_FALSE, sizeof (GLVertexData),
150+ reinterpret_cast <const void *>(offsetof (GLVertexData, normal))));
151+
152+ // aColor — location 2 (UNSIGNED_BYTE normalised to [0,1] in shader)
153+ GL_SAFE_CALL (f->glEnableVertexAttribArray (2 ));
154+ GL_SAFE_CALL (f->glVertexAttribPointer (2 , 4 , GL_UNSIGNED_BYTE, GL_TRUE, sizeof (GLVertexData),
155+ reinterpret_cast <const void *>(offsetof (GLVertexData, color))));
156+
157+ // aTexCoord — location 3
158+ GL_SAFE_CALL (f->glEnableVertexAttribArray (3 ));
159+ GL_SAFE_CALL (f->glVertexAttribPointer (3 , 1 , GL_FLOAT, GL_FALSE, sizeof (GLVertexData),
160+ reinterpret_cast <const void *>(offsetof (GLVertexData, texCoord))));
161+
162+ GL_SAFE_CALL (ef->glBindVertexArray (0 ));
126163 GL_SAFE_CALL (f->glBindBuffer (GL_ARRAY_BUFFER, 0 ));
127164
128165 this ->vertexCount = GLsizei (this ->vertices .size ());
@@ -178,43 +215,23 @@ void GLVertexBuffer::addVertex(GLfloat x, GLfloat y, GLfloat z)
178215
179216void GLVertexBuffer::render () const
180217{
181- if (!this ->valid || this ->vboId == 0 || this ->batches .empty ())
218+ if (!this ->valid || this ->vaoId == 0 || this ->batches .empty ())
182219 {
183220 return ;
184221 }
185222
186- QOpenGLContext *ctx = QOpenGLContext::currentContext ();
187- QOpenGLFunctions *f = ctx->functions ();
188-
189- // Bind VBO — with a VBO bound, the pointer offsets below are byte offsets
190- // from the start of the buffer (fixed-function VBO path, OpenGL 1.5+).
191- f->glBindBuffer (GL_ARRAY_BUFFER, this ->vboId );
223+ // The VAO already encapsulates the VBO binding and all attribute pointers
224+ // recorded in uploadToGPU(). Just bind it and draw.
225+ QOpenGLExtraFunctions *ef = QOpenGLContext::currentContext ()->extraFunctions ();
192226
193- glEnableClientState (GL_VERTEX_ARRAY);
194- glEnableClientState (GL_NORMAL_ARRAY);
195- glEnableClientState (GL_COLOR_ARRAY);
196- glEnableClientState (GL_TEXTURE_COORD_ARRAY);
197-
198- glVertexPointer (3 , GL_FLOAT, sizeof (GLVertexData),
199- reinterpret_cast <const void *>(offsetof (GLVertexData, position)));
200- glNormalPointer (GL_FLOAT, sizeof (GLVertexData),
201- reinterpret_cast <const void *>(offsetof (GLVertexData, normal)));
202- glTexCoordPointer (1 , GL_FLOAT, sizeof (GLVertexData),
203- reinterpret_cast <const void *>(offsetof (GLVertexData, texCoord)));
204- glColorPointer (4 , GL_UNSIGNED_BYTE, sizeof (GLVertexData),
205- reinterpret_cast <const void *>(offsetof (GLVertexData, color)));
227+ GL_SAFE_CALL (ef->glBindVertexArray (this ->vaoId ));
206228
207229 for (const Batch &batch : this ->batches )
208230 {
209231 glDrawArrays (batch.primitiveType , batch.start , batch.count );
210232 }
211233
212- glDisableClientState (GL_TEXTURE_COORD_ARRAY);
213- glDisableClientState (GL_COLOR_ARRAY);
214- glDisableClientState (GL_NORMAL_ARRAY);
215- glDisableClientState (GL_VERTEX_ARRAY);
216-
217- f->glBindBuffer (GL_ARRAY_BUFFER, 0 );
234+ GL_SAFE_CALL (ef->glBindVertexArray (0 ));
218235}
219236
220237void GLVertexBuffer::release ()
@@ -223,6 +240,12 @@ void GLVertexBuffer::release()
223240 if (ctx)
224241 {
225242 QOpenGLFunctions *f = ctx->functions ();
243+ QOpenGLExtraFunctions *ef = ctx->extraFunctions ();
244+ if (this ->vaoId != 0 )
245+ {
246+ GL_SAFE_CALL (ef->glDeleteVertexArrays (1 , &this ->vaoId ));
247+ this ->vaoId = 0 ;
248+ }
226249 if (this ->vboId != 0 )
227250 {
228251 GL_SAFE_CALL (f->glDeleteBuffers (1 , &this ->vboId ));
0 commit comments