mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-08 07:03:25 -06:00
568 lines
19 KiB
C++
568 lines
19 KiB
C++
//##################################################################################################
|
|
//
|
|
// Custom Visualization Core library
|
|
// Copyright (C) 2011-2013 Ceetron AS
|
|
//
|
|
// This library may be used under the terms of either the GNU General Public License or
|
|
// the GNU Lesser General Public License as follows:
|
|
//
|
|
// GNU General Public License Usage
|
|
// This library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
|
|
// for more details.
|
|
//
|
|
// GNU Lesser General Public License Usage
|
|
// This library is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation; either version 2.1 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
|
|
// for more details.
|
|
//
|
|
//##################################################################################################
|
|
|
|
|
|
#include "cvfBase.h"
|
|
#include "cvfDrawableVectors.h"
|
|
#include "cvfOpenGL.h"
|
|
#include "cvfOpenGLResourceManager.h"
|
|
#include "cvfBufferObjectManaged.h"
|
|
#include "cvfDrawableGeo.h"
|
|
#include "cvfQuat.h"
|
|
#include "cvfShaderProgram.h"
|
|
#include "cvfUniform.h"
|
|
#include "cvfPrimitiveSetIndexedUShort.h"
|
|
#include "cvfRay.h"
|
|
|
|
#ifndef CVF_OPENGL_ES
|
|
#include "cvfRenderState_FF.h"
|
|
#endif
|
|
|
|
namespace cvf {
|
|
|
|
|
|
//==================================================================================================
|
|
///
|
|
/// \class cvf::DrawableVectors
|
|
/// \ingroup Render
|
|
///
|
|
/// DrawableVectors implements drawing of vector arrows.
|
|
///
|
|
//==================================================================================================
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Constructor to use when using fixed function rendering
|
|
//--------------------------------------------------------------------------------------------------
|
|
DrawableVectors::DrawableVectors()
|
|
: m_singleColor(Color3f(Color3::WHITE)),
|
|
m_renderWithVBO(true)
|
|
{
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Constructor to use when using shader based rendering
|
|
//--------------------------------------------------------------------------------------------------
|
|
DrawableVectors::DrawableVectors(String vectorMatrixUniformName, String colorUniformName)
|
|
: m_vectorMatrixUniformName(vectorMatrixUniformName),
|
|
m_colorUniformName(colorUniformName),
|
|
m_singleColor(Color3f(Color3::WHITE)),
|
|
m_renderWithVBO(true)
|
|
{
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
DrawableVectors::~DrawableVectors()
|
|
{
|
|
releaseBufferObjectsGPU();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void DrawableVectors::setGlyph(UShortArray* triangles, Vec3fArray* vertices)
|
|
{
|
|
m_vectorGlyph = new DrawableGeo;
|
|
m_vectorGlyphPrimSet = new PrimitiveSetIndexedUShort(PT_TRIANGLES);
|
|
|
|
m_vectorGlyphPrimSet->setIndices(triangles);
|
|
m_vectorGlyph->setVertexArray(vertices);
|
|
m_vectorGlyph->addPrimitiveSet(m_vectorGlyphPrimSet.p());
|
|
m_vectorGlyph->computeNormals();
|
|
|
|
if (m_renderWithVBO)
|
|
{
|
|
m_vectorGlyph->setRenderMode(DrawableGeo::BUFFER_OBJECT);
|
|
}
|
|
|
|
releaseBufferObjectsGPU();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void DrawableVectors::setSingleColor(Color3f color)
|
|
{
|
|
m_singleColor = color;
|
|
}
|
|
|
|
|
|
void DrawableVectors::setUniformNames(String vectorMatrixUniformName, String colorUniformName)
|
|
{
|
|
m_vectorMatrixUniformName = vectorMatrixUniformName;
|
|
m_colorUniformName = colorUniformName;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void DrawableVectors::setVectors(Vec3fArray* vertexArray, Vec3fArray* vectorArray)
|
|
{
|
|
CVF_ASSERT(vertexArray && vectorArray);
|
|
CVF_ASSERT(vertexArray->size() && vectorArray->size());
|
|
|
|
m_vertexArray = vertexArray;
|
|
m_vectorArray = vectorArray;
|
|
|
|
m_boundingBox.add(*m_vertexArray);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Set color of each corresponding vector
|
|
///
|
|
/// \param vectorColorArray Array of colors to be mapped one-by-one to the vector array
|
|
/// \param colorUniformName Name of uniform when used by a shader program. Ignored if not.
|
|
///
|
|
/// \sa setVectors
|
|
//--------------------------------------------------------------------------------------------------
|
|
void DrawableVectors::setColors(Color3fArray* vectorColorArray)
|
|
{
|
|
m_colorArray = vectorColorArray;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
size_t DrawableVectors::vectorCount() const
|
|
{
|
|
CVF_ASSERT(m_vertexArray->size() == m_vectorArray->size());
|
|
|
|
return m_vertexArray->size();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void DrawableVectors::render(OpenGLContext* oglContext, ShaderProgram* shaderProgram, const MatrixState&)
|
|
{
|
|
CVF_CALLSITE_OPENGL(oglContext);
|
|
|
|
CVF_ASSERT(shaderProgram);
|
|
CVF_ASSERT(shaderProgram->isProgramUsed(oglContext));
|
|
CVF_ASSERT(m_vertexArray->size() == m_vectorArray->size());
|
|
CVF_ASSERT(m_colorArray.isNull() || (m_colorArray->size() == m_vectorArray->size()));
|
|
CVF_ASSERT(m_vectorGlyph.notNull());
|
|
CVF_ASSERT(m_vectorGlyph->primitiveSetCount() == 1);
|
|
|
|
// Setup Vertex Arrays/vbos
|
|
const GLvoid* ptrOrOffset = 0;
|
|
|
|
if (m_renderWithVBO && m_glyphVerticesAndNormalsBO.notNull() && m_glyphVerticesAndNormalsBO->isUploaded())
|
|
{
|
|
// Bind VBO for vertex and normal data
|
|
m_glyphVerticesAndNormalsBO->bindBuffer(oglContext);
|
|
|
|
glVertexAttribPointer(ShaderProgram::NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(float)*6, (void*)(sizeof(float)*3));
|
|
glVertexAttribPointer(ShaderProgram::VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(float)*6, 0);
|
|
glEnableVertexAttribArray(ShaderProgram::NORMAL);
|
|
glEnableVertexAttribArray(ShaderProgram::VERTEX);
|
|
|
|
m_indicesBO->bindBuffer(oglContext);
|
|
}
|
|
else
|
|
{
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glVertexAttribPointer(ShaderProgram::NORMAL, 3, GL_FLOAT, GL_FALSE, 0, m_vectorGlyph->normalArray()->ptr()->ptr());
|
|
glEnableVertexAttribArray(ShaderProgram::NORMAL);
|
|
glVertexAttribPointer(ShaderProgram::VERTEX, 3, GL_FLOAT, GL_FALSE, 0, m_vectorGlyph->vertexArray()->ptr()->ptr());
|
|
glEnableVertexAttribArray(ShaderProgram::VERTEX);
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
ptrOrOffset = m_vectorGlyphPrimSet->indices()->ptr();
|
|
}
|
|
|
|
// Must use manual uniform setting, as setting the uniform through the Uniform* class requires a lookup for location
|
|
// every time, and this is always the same
|
|
GLint vectorMatrixUniformLocation = shaderProgram->uniformLocation(m_vectorMatrixUniformName.toAscii().ptr());
|
|
CVF_ASSERT(vectorMatrixUniformLocation != -1);
|
|
GLint colorUniformLocation = shaderProgram->uniformLocation(m_colorUniformName.toAscii().ptr());
|
|
CVF_ASSERT(colorUniformLocation != -1);
|
|
|
|
#ifndef CVF_OPENGL_ES
|
|
uint minIndex = m_vectorGlyphPrimSet->minIndex();
|
|
uint maxIndex = m_vectorGlyphPrimSet->maxIndex();
|
|
#endif
|
|
GLsizei indexCount = static_cast<GLsizei>(m_vectorGlyphPrimSet->indexCount());
|
|
|
|
// Set the single color to use
|
|
if (m_colorArray.isNull())
|
|
{
|
|
glUniform3fv(colorUniformLocation, 1, m_singleColor.ptr());
|
|
}
|
|
|
|
float vectorMat[16];
|
|
size_t numVectors = m_vectorArray->size();
|
|
size_t i;
|
|
for (i = 0; i < numVectors; i++)
|
|
{
|
|
// Compute the transformation matrix
|
|
vectorMatrix(i, vectorMat);
|
|
|
|
// Set this as a uniform to the shader program
|
|
glUniformMatrix4fv(vectorMatrixUniformLocation, 1, GL_FALSE, vectorMat);
|
|
|
|
if (m_colorArray.notNull())
|
|
{
|
|
glUniform3fv(colorUniformLocation, 1, m_colorArray->get(i).ptr());
|
|
}
|
|
|
|
// Draw the arrow
|
|
#ifdef CVF_OPENGL_ES
|
|
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, ptrOrOffset);
|
|
#else
|
|
glDrawRangeElements(GL_TRIANGLES, minIndex, maxIndex, indexCount, GL_UNSIGNED_SHORT, ptrOrOffset);
|
|
#endif
|
|
}
|
|
|
|
// Cleanup
|
|
glDisableVertexAttribArray(ShaderProgram::VERTEX);
|
|
glDisableVertexAttribArray(ShaderProgram::NORMAL);
|
|
|
|
CVF_CHECK_OGL(oglContext);
|
|
|
|
// Things to consider for performance:
|
|
|
|
// 1) Uniform arrays evt. Uniform buffer objects
|
|
// 2) Texture
|
|
// 3) Texture array
|
|
|
|
// GL_ARB_draw_instanced();
|
|
// glDrawElementsInstanced
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void DrawableVectors::renderFixedFunction(OpenGLContext* oglContext, const MatrixState& matrixState)
|
|
{
|
|
#ifdef CVF_OPENGL_ES
|
|
CVF_FAIL_MSG("Not supported on OpenGL ES");
|
|
#else
|
|
CVF_ASSERT(oglContext);
|
|
CVF_ASSERT(m_vertexArray->size() == m_vectorArray->size());
|
|
CVF_ASSERT(m_vectorGlyph.notNull());
|
|
|
|
glEnable(GL_NORMALIZE);
|
|
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
|
|
if (m_colorArray.isNull())
|
|
{
|
|
glColor3fv(m_singleColor.ptr());
|
|
}
|
|
|
|
float vectorMat[16];
|
|
size_t numVectors = m_vectorArray->size();
|
|
size_t i;
|
|
for (i = 0; i < numVectors; i++)
|
|
{
|
|
// Compute/retrieve "matrix"
|
|
vectorMatrix(i, vectorMat);
|
|
|
|
glPushMatrix();
|
|
glMultMatrixf(vectorMat);
|
|
|
|
if (m_colorArray.notNull())
|
|
{
|
|
glColor3fv(m_colorArray->get(i).ptr());
|
|
}
|
|
|
|
// Draw the geometry
|
|
m_vectorGlyph->renderFixedFunction(oglContext, matrixState);
|
|
|
|
glPopMatrix();
|
|
}
|
|
|
|
glDisable(GL_NORMALIZE);
|
|
|
|
CVF_CHECK_OGL(oglContext);
|
|
#endif // CVF_OPENGL_ES
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void DrawableVectors::renderImmediateMode(OpenGLContext* oglContext, const MatrixState& matrixState)
|
|
{
|
|
#ifdef CVF_OPENGL_ES
|
|
CVF_FAIL_MSG("Not supported on OpenGL ES");
|
|
#else
|
|
CVF_ASSERT(oglContext);
|
|
CVF_ASSERT(m_vertexArray->size() == m_vectorArray->size());
|
|
CVF_ASSERT(m_vectorGlyph.notNull());
|
|
|
|
glEnable(GL_NORMALIZE);
|
|
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
|
|
if (m_colorArray.isNull())
|
|
{
|
|
glColor3fv(m_singleColor.ptr());
|
|
}
|
|
|
|
float vectorMat[16];
|
|
size_t numVectors = m_vectorArray->size();
|
|
size_t i;
|
|
for (i = 0; i < numVectors; i++)
|
|
{
|
|
// Compute/retrieve "matrix"
|
|
vectorMatrix(i, vectorMat);
|
|
|
|
glPushMatrix();
|
|
glMultMatrixf(vectorMat);
|
|
|
|
if (m_colorArray.notNull())
|
|
{
|
|
glColor3fv(m_colorArray->get(i).ptr());
|
|
}
|
|
|
|
// Draw the geometry
|
|
m_vectorGlyph->renderImmediateMode(oglContext, matrixState);
|
|
|
|
glPopMatrix();
|
|
}
|
|
|
|
glDisable(GL_NORMALIZE);
|
|
|
|
CVF_CHECK_OGL(oglContext);
|
|
#endif // CVF_OPENGL_ES
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void DrawableVectors::createUploadBufferObjectsGPU(OpenGLContext* oglContext)
|
|
{
|
|
if (!m_renderWithVBO || m_vertexArray->size() == 0 || m_vectorGlyph.isNull() || m_vectorGlyphPrimSet.isNull())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_glyphVerticesAndNormalsBO.isNull() || !m_glyphVerticesAndNormalsBO->isUploaded())
|
|
{
|
|
// Build a interleaved VBO for glyphs vertices and normals to get better performance
|
|
// during the main shader based draw path
|
|
size_t numVertices = m_vectorGlyph->vertexArray()->size();
|
|
|
|
Vec3fArray data;
|
|
data.reserve(numVertices*2);
|
|
size_t i;
|
|
for (i = 0; i < numVertices; i++)
|
|
{
|
|
data.add(m_vectorGlyph->vertexArray()->get(i));
|
|
data.add(m_vectorGlyph->normalArray()->get(i));
|
|
}
|
|
|
|
GLuint uiSizeInBytes = static_cast<GLuint>(data.size()*3*sizeof(float));
|
|
m_glyphVerticesAndNormalsBO = oglContext->resourceManager()->getOrCreateManagedBufferObject(oglContext, GL_ARRAY_BUFFER, uiSizeInBytes, data.ptr()->ptr());
|
|
}
|
|
|
|
|
|
if (m_indicesBO.isNull() || !m_indicesBO->isUploaded())
|
|
{
|
|
const UShortArray* indices = m_vectorGlyphPrimSet->indices();
|
|
size_t numIndices = indices->size();
|
|
if (numIndices > 0)
|
|
{
|
|
GLuint uiSizeInBytes = static_cast<GLuint>(numIndices*sizeof(GLushort));
|
|
m_indicesBO = oglContext->resourceManager()->getOrCreateManagedBufferObject(oglContext, GL_ELEMENT_ARRAY_BUFFER, uiSizeInBytes, indices->ptr());
|
|
CVF_CHECK_OGL(oglContext);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void DrawableVectors::releaseBufferObjectsGPU()
|
|
{
|
|
m_glyphVerticesAndNormalsBO = NULL;
|
|
|
|
if (m_vectorGlyph.notNull())
|
|
{
|
|
m_vectorGlyph->releaseBufferObjectsGPU();
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
size_t DrawableVectors::vertexCount() const
|
|
{
|
|
if (m_vectorGlyph.isNull())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return m_vectorGlyph->vertexCount()*vectorCount();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
size_t DrawableVectors::triangleCount() const
|
|
{
|
|
if (m_vectorGlyph.isNull())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return m_vectorGlyph->triangleCount()*vectorCount();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
size_t DrawableVectors::faceCount() const
|
|
{
|
|
if (m_vectorGlyph.isNull())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return m_vectorGlyph->faceCount()*vectorCount();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
BoundingBox DrawableVectors::boundingBox() const
|
|
{
|
|
return m_boundingBox;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool DrawableVectors::rayIntersectCreateDetail(const Ray& ray, Vec3d* intersectionPoint, ref<HitDetail>* hitDetail) const
|
|
{
|
|
CVF_UNUSED(ray);
|
|
CVF_UNUSED(intersectionPoint);
|
|
CVF_UNUSED(hitDetail);
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void DrawableVectors::vectorMatrix(size_t vectorIndex, float vectorMatArray[16])
|
|
{
|
|
const Vec3f& anchorPt = m_vertexArray->get(vectorIndex);
|
|
Vec3f vec = m_vectorArray->get(vectorIndex);
|
|
float length = vec.length();
|
|
|
|
Quatf rotQuat;
|
|
|
|
// This should really be a ratio eval based on length of vector
|
|
// Copied from VTOVectorDrawer.cpp. TODO: refactor
|
|
static const float TINY_VEC_COMP = 0.0000000001f;
|
|
bool negZOnly = vec.z() < 0.0f && Math::abs(vec.x()) < TINY_VEC_COMP && Math::abs(vec.y()) < TINY_VEC_COMP;
|
|
|
|
if (negZOnly)
|
|
{
|
|
rotQuat.set(0.0f, 1.0f, 0.0f, 0.0f);
|
|
}
|
|
else
|
|
{
|
|
const Vec3f s = Vec3f::Z_AXIS;
|
|
Vec3f d = vec/length;
|
|
|
|
Vec3f v = s + d;
|
|
Vec3f cross = v ^ d;
|
|
float dot = v*d;
|
|
|
|
rotQuat.set(cross.x(), cross.y(), cross.z(), dot);
|
|
}
|
|
|
|
float Nq = rotQuat.x()*rotQuat.x() + rotQuat.y()*rotQuat.y() + rotQuat.z()*rotQuat.z() + rotQuat.w()*rotQuat.w();
|
|
float s = (Nq > 0.0f) ? (2.0f/Nq) : 0.0f;
|
|
float xs = rotQuat.x()*s;
|
|
float ys = rotQuat.y()*s;
|
|
float zs = rotQuat.z()*s;
|
|
float wx = rotQuat.w()*xs;
|
|
float wy = rotQuat.w()*ys;
|
|
float wz = rotQuat.w()*zs;
|
|
float xx = rotQuat.x()*xs;
|
|
float xy = rotQuat.x()*ys;
|
|
float xz = rotQuat.x()*zs;
|
|
float yy = rotQuat.y()*ys;
|
|
float yz = rotQuat.y()*zs;
|
|
float zz = rotQuat.z()*zs;
|
|
|
|
vectorMatArray[0] = length*(1.0f - (yy + zz));
|
|
vectorMatArray[1] = length*(xy + wz);
|
|
vectorMatArray[2] = length*(xz - wy);
|
|
vectorMatArray[3] = 0.0f;
|
|
|
|
vectorMatArray[4] = length*(xy - wz);
|
|
vectorMatArray[5] = length*(1.0f - (xx + zz));
|
|
vectorMatArray[6] = length*(yz + wx);
|
|
vectorMatArray[7] = 0.0f;
|
|
|
|
vectorMatArray[8] = length*(xz + wy);
|
|
vectorMatArray[9] = length*(yz - wx);
|
|
vectorMatArray[10] = length*(1.0f - (xx + yy));
|
|
vectorMatArray[11] = 0.0f;
|
|
|
|
// Set the translation
|
|
vectorMatArray[12] = anchorPt.x();
|
|
vectorMatArray[13] = anchorPt.y();
|
|
vectorMatArray[14] = anchorPt.z();
|
|
vectorMatArray[15] = 1.0f;
|
|
}
|
|
|
|
|
|
} // namespace cvf
|