/****************************************************************************** * Allocates a particle buffer with the given number of elements. ******************************************************************************/ void OpenGLArrowPrimitive::startSetElements(int elementCount) { OVITO_ASSERT(elementCount >= 0); OVITO_ASSERT(QOpenGLContextGroup::currentContextGroup() == _contextGroup); OVITO_ASSERT(_mappedChunkIndex == -1); _verticesWithNormals.clear(); _verticesWithElementInfo.clear(); _elementCount = elementCount; bool renderMesh = true; int stripsPerElement; int fansPerElement; int verticesPerStrip; int verticesPerFan; if(shadingMode() == NormalShading) { verticesPerStrip = _cylinderSegments * 2 + 2; verticesPerFan = _cylinderSegments; if(shape() == ArrowShape) { stripsPerElement = 2; fansPerElement = 2; } else { stripsPerElement = 1; fansPerElement = 2; if(renderingQuality() == HighQuality) { if(_usingGeometryShader) { verticesPerStrip = 1; stripsPerElement = 1; } else { verticesPerStrip = 14; } fansPerElement = verticesPerFan = 0; renderMesh = false; } } } else if(shadingMode() == FlatShading) { fansPerElement = 1; stripsPerElement = 0; verticesPerStrip = 0; if(shape() == ArrowShape) verticesPerFan = 7; else verticesPerFan = 4; if(_usingGeometryShader && shape() == CylinderShape) { verticesPerFan = 1; } renderMesh = false; } else OVITO_ASSERT(false); // Determine the VBO chunk size. _verticesPerElement = stripsPerElement * verticesPerStrip + fansPerElement * verticesPerFan; int bytesPerVertex = renderMesh ? sizeof(VertexWithNormal) : sizeof(VertexWithElementInfo); _chunkSize = std::min(_maxVBOSize / _verticesPerElement / bytesPerVertex, _elementCount); // Allocate VBOs. for(int i = _elementCount; i > 0; i -= _chunkSize) { if(renderMesh) { OpenGLBuffer<VertexWithNormal> buffer; buffer.create(QOpenGLBuffer::StaticDraw, std::min(i, _chunkSize), _verticesPerElement); _verticesWithNormals.push_back(buffer); } else { OpenGLBuffer<VertexWithElementInfo> buffer; buffer.create(QOpenGLBuffer::StaticDraw, std::min(i, _chunkSize), _verticesPerElement); _verticesWithElementInfo.push_back(buffer); } } OVITO_REPORT_OPENGL_ERRORS(); // Prepare arrays to be passed to the glMultiDrawArrays() function. _stripPrimitiveVertexStarts.resize(_chunkSize * stripsPerElement); _stripPrimitiveVertexCounts.resize(_chunkSize * stripsPerElement); _fanPrimitiveVertexStarts.resize(_chunkSize * fansPerElement); _fanPrimitiveVertexCounts.resize(_chunkSize * fansPerElement); std::fill(_stripPrimitiveVertexCounts.begin(), _stripPrimitiveVertexCounts.end(), verticesPerStrip); std::fill(_fanPrimitiveVertexCounts.begin(), _fanPrimitiveVertexCounts.end(), verticesPerFan); auto ps_strip = _stripPrimitiveVertexStarts.begin(); auto ps_fan = _fanPrimitiveVertexStarts.begin(); for(GLint index = 0, baseIndex = 0; index < _chunkSize; index++) { for(int p = 0; p < stripsPerElement; p++, baseIndex += verticesPerStrip) *ps_strip++ = baseIndex; for(int p = 0; p < fansPerElement; p++, baseIndex += verticesPerFan) *ps_fan++ = baseIndex; } // Precompute cos() and sin() functions. if(shadingMode() == NormalShading) { _cosTable.resize(_cylinderSegments+1); _sinTable.resize(_cylinderSegments+1); for(int i = 0; i <= _cylinderSegments; i++) { float angle = (FLOATTYPE_PI * 2 / _cylinderSegments) * i; _cosTable[i] = std::cos(angle); _sinTable[i] = std::sin(angle); } } }
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(); }