void OpenGLMeshPrivate::vertexAttribPointer(int location, int elements, int count, OpenGLElementType type, bool normalized, int stride, int offset) { for (int i = 0; i < count; ++i) { vertexAttribPointer(location + i, elements, type, normalized, stride, static_cast<int>(offset + i * elements * OpenGLElementSize(type))); } }
void OpenGLMeshPrivate::create(const KHalfEdgeMesh &mesh) { // Helpers m_aabb = KAabbBoundingVolume(mesh.aabb()); KHalfEdgeMesh::FaceContainer const &faces = mesh.faces(); KHalfEdgeMesh::VertexContainer const &vertices = mesh.vertices(); size_t verticesSize = sizeof(KVertex) * vertices.size(); size_t indicesCount = faces.size() * 3; size_t indicesSize = sizeof(uint32_t) * indicesCount; OpenGLBuffer::RangeAccessFlags flags = OpenGLBuffer::RangeInvalidate | OpenGLBuffer::RangeUnsynchronized | OpenGLBuffer::RangeWrite; // Create Buffers m_elementCount = static_cast<GLsizei>(indicesCount); m_vertexArrayObject.create(); m_vertexBuffer.create(); m_indexBuffer.create(); // Bind mesh m_vertexArrayObject.bind(); m_vertexBuffer.bind(); m_indexBuffer.bind(); // Allocate Mesh m_vertexBuffer.allocate(verticesSize); m_indexBuffer.allocate(indicesSize); KVertex *vertDest = (KVertex*)m_vertexBuffer.mapRange(0, verticesSize, flags); uint32_t *indDest = (uint32_t*)m_indexBuffer.mapRange(0, indicesSize, flags); // Iterators uint32_t *baseIndDest; const KHalfEdgeMesh::HalfEdge *halfEdge; // Construct Mesh for (size_t i = 0; i < vertices.size(); ++i) { vertDest[i] = KVertex(vertices[i].position, vertices[i].normal); } for (size_t i = 0; i < faces.size(); ++i) { baseIndDest = &indDest[3 * i]; halfEdge = mesh.halfEdge(faces[i].first); baseIndDest[0] = halfEdge->to - 1; halfEdge = mesh.halfEdge(halfEdge->next); baseIndDest[1] = halfEdge->to - 1; halfEdge = mesh.halfEdge(halfEdge->next); baseIndDest[2] = halfEdge->to - 1; } // Setup Vertex Pointers vertexAttribPointer(0, KVertex::PositionTupleSize, OpenGLElementType::Float, false, KVertex::stride(), KVertex::positionOffset()); vertexAttribPointer(1, KVertex::NormalTupleSize, OpenGLElementType::Float, true, KVertex::stride(), KVertex::normalOffset()); // Finalize Construction m_indexBuffer.unmap(); m_vertexBuffer.unmap(); m_vertexArrayObject.release(); }
void OpenGLMeshPrivate::vertexAttribPointerDivisor(int location, int elements, OpenGLElementType type, bool normalized, int stride, int offset, int divisor) { vertexAttribPointer(location, elements, type, normalized, stride, offset); GL::glVertexAttribDivisor(location, divisor); }
// Leaves mVAO bound void VertBatch::setupBuffers() { auto ctx = gl::context(); auto glslProg = ctx->getGlslProg(); if( ! glslProg ) return; const size_t verticesSizeBytes = mVertices.size() * sizeof(vec4); const size_t normalsSizeBytes = mNormals.size() * sizeof(vec3); const size_t colorsSizeBytes = mColors.size() * sizeof(ColorAf); const size_t texCoordsSizeBytes = mTexCoords.size() * sizeof(vec4); size_t totalSizeBytes = verticesSizeBytes + normalsSizeBytes + colorsSizeBytes + texCoordsSizeBytes; // allocate the VBO if we don't have one yet (which implies we're not using the context defaults) bool forceUpload = false; if( ! mVbo ) { // allocate the VBO and upload the data mVbo = gl::Vbo::create( GL_ARRAY_BUFFER, totalSizeBytes ); forceUpload = true; } ScopedBuffer ScopedBuffer( mVbo ); // if this VBO was freshly made, or we don't own the buffer because we use the context defaults if( ( forceUpload || ( ! mOwnsBuffers ) ) && ( ! mVertices.empty() ) ) { mVbo->ensureMinimumSize( totalSizeBytes ); // upload positions GLintptr offset = 0; mVbo->bufferSubData( offset, verticesSizeBytes, &mVertices[0] ); offset += verticesSizeBytes; // upload normals if( ! mNormals.empty() ) { mVbo->bufferSubData( offset, normalsSizeBytes, &mNormals[0] ); offset += normalsSizeBytes; } // upload colors if( ! mColors.empty() ) { mVbo->bufferSubData( offset, colorsSizeBytes, &mColors[0] ); offset += colorsSizeBytes; } // upload texCoords if( ! mTexCoords.empty() ) { mVbo->bufferSubData( offset, texCoordsSizeBytes, &mTexCoords[0] ); offset += texCoordsSizeBytes; } } // Setup the VAO ctx->pushVao(); // this will be popped by draw() if( ! mOwnsBuffers ) mVao->replacementBindBegin(); else { mVaoStorage = gl::Vao::create(); mVao = mVaoStorage.get(); mVao->bind(); } gl::ScopedBuffer vboScope( mVbo ); size_t offset = 0; if( glslProg->hasAttribSemantic( geom::Attrib::POSITION ) ) { int loc = glslProg->getAttribSemanticLocation( geom::Attrib::POSITION ); ctx->enableVertexAttribArray( loc ); ctx->vertexAttribPointer( loc, 4, GL_FLOAT, false, 0, (const GLvoid*)offset ); offset += verticesSizeBytes; } if( glslProg->hasAttribSemantic( geom::Attrib::NORMAL ) && ( ! mNormals.empty() ) ) { int loc = glslProg->getAttribSemanticLocation( geom::Attrib::NORMAL ); ctx->enableVertexAttribArray( loc ); ctx->vertexAttribPointer( loc, 3, GL_FLOAT, false, 0, (const GLvoid*)offset ); offset += normalsSizeBytes; } if( glslProg->hasAttribSemantic( geom::Attrib::COLOR ) && ( ! mColors.empty() ) ) { int loc = glslProg->getAttribSemanticLocation( geom::Attrib::COLOR ); ctx->enableVertexAttribArray( loc ); ctx->vertexAttribPointer( loc, 4, GL_FLOAT, false, 0, (const GLvoid*)offset ); offset += colorsSizeBytes; } if( glslProg->hasAttribSemantic( geom::Attrib::TEX_COORD_0 ) && ( ! mTexCoords.empty() ) ) { int loc = glslProg->getAttribSemanticLocation( geom::Attrib::TEX_COORD_0 ); ctx->enableVertexAttribArray( loc ); ctx->vertexAttribPointer( loc, 4, GL_FLOAT, false, 0, (const GLvoid*)offset ); } if( ! mOwnsBuffers ) mVao->replacementBindEnd(); ctx->popVao(); }