/******************************************************************************
* 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);
		}
	}
}
Beispiel #2
0
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();
}