diff --git a/avogadro/rendering/CMakeLists.txt b/avogadro/rendering/CMakeLists.txt index ddebfe8483..db17081d8f 100644 --- a/avogadro/rendering/CMakeLists.txt +++ b/avogadro/rendering/CMakeLists.txt @@ -104,6 +104,10 @@ set(shader_files "linestrip_fs.glsl" "linestrip_vs.glsl" "mesh_fs.glsl" + "bspline_tev.glsl" + "bspline_tcs.glsl" + "bspline_fs.glsl" + "bspline_vs.glsl" "mesh_opaque_fs.glsl" "mesh_vs.glsl" "solid_vs.glsl" diff --git a/avogadro/rendering/bspline_fs.glsl b/avogadro/rendering/bspline_fs.glsl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/avogadro/rendering/bspline_tcs.glsl b/avogadro/rendering/bspline_tcs.glsl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/avogadro/rendering/bspline_tev.glsl b/avogadro/rendering/bspline_tev.glsl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/avogadro/rendering/bspline_vs.glsl b/avogadro/rendering/bspline_vs.glsl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/avogadro/rendering/cartoongeometry.cpp b/avogadro/rendering/cartoongeometry.cpp index 46b9f118a5..a4fffd4ab6 100644 --- a/avogadro/rendering/cartoongeometry.cpp +++ b/avogadro/rendering/cartoongeometry.cpp @@ -4,24 +4,174 @@ ******************************************************************************/ #include "cartoongeometry.h" +#include "shader.h" +#include "shaderprogram.h" +#include "camera.h" +#include "bufferobject.h" + + #include +namespace { + +#include "bspline_vs.h" +#include "bspline_fs.h" +#include "bspline_tcs.h" +#include "bspline_tev.h" + +} // namespace + +using Avogadro::Vector3f; +using Avogadro::Vector3ub; +using Avogadro::Vector4ub; + namespace Avogadro::Rendering { +class Cartoon::Private +{ +public: + Private() {} + + BufferObject vbo; + BufferObject ibo; + + inline static Shader* vertexShader = nullptr; + inline static Shader* fragmentShader = nullptr; + inline static Shader* fragmentShaderOpaque = nullptr; + inline static ShaderProgram* program = nullptr; + inline static ShaderProgram* programOpaque = nullptr; + + size_t numberOfVertices; + size_t numberOfIndices; +}; + + using Core::Residue; using std::vector; const float Cartoon::ELIPSE_RATIO = 0.75f; Cartoon::Cartoon() - : BSplineGeometry(false), m_minRadius(-1.0f), m_maxRadius(-1.0f) + : BSplineGeometry(false), m_minRadius(-1.0f), m_maxRadius(-1.0f), m_dirty(false), d(new Private) {} Cartoon::Cartoon(float minRadius, float maxRadius) - : BSplineGeometry(false), m_minRadius(minRadius), m_maxRadius(maxRadius) + : BSplineGeometry(false), m_minRadius(minRadius), m_maxRadius(maxRadius), m_dirty(true), + d(new Private), m_vertices(other.m_vertices), m_indices(other.m_indices) {} +Cartoon::~Cartoon() +{ + delete d; +} + +void Cartoon::update() +{ + if (m_vertices.empty() || m_indices.empty()) + return; + + // Check if the VBOs are ready, if not get them ready. + if (!d->vbo.ready() || m_dirty) { + d->vbo.upload(m_vertices, BufferObject::ArrayBuffer); + d->ibo.upload(m_indices, BufferObject::ElementArrayBuffer); + d->numberOfVertices = m_vertices.size(); + d->numberOfIndices = m_indices.size(); + m_dirty = false; + } + + // Build and link the shader if it has not been used yet. + if (d->vertexShader == nullptr) { + d->vertexShader = new Shader; + d->vertexShader->setType(Shader::Vertex); + d->vertexShader->setSource(bspline_vs); + + d->fragmentShader = new Shader; + d->fragmentShader->setType(Shader::Fragment); + d->fragmentShader->setSource(bspline_fs); + + if (!d->vertexShader->compile()) + std::cout << d->vertexShader->error() << std::endl; + if (!d->fragmentShader->compile()) + std::cout << d->fragmentShader->error() << std::endl; + + if (d->program == nullptr) + d->program = new ShaderProgram; + d->program->attachShader(*d->vertexShader); + d->program->attachShader(*d->fragmentShader); + if (!d->program->link()) + std::cout << d->program->error() << std::endl; + } +} + +void Cartoon::render(const Camera& camera) +{ + if (m_indices.empty() || m_vertices.empty()) + return; + + // Prepare the VBOs, IBOs and shader program if necessary. + update(); + + ShaderProgram* program; + program = d->programOpaque; + + if (!program->bind()) + std::cout << program->error() << std::endl; + + d->vbo.bind(); + d->ibo.bind(); + + // Set up our attribute arrays. + if (!program->enableAttributeArray("vertex")) + std::cout << program->error() << std::endl; + if (!program->useAttributeArray("vertex", PackedVertex::vertexOffset(), + sizeof(PackedVertex), FloatType, 3, + ShaderProgram::NoNormalize)) { + std::cout << program->error() << std::endl; + } + if (!program->enableAttributeArray("color")) + std::cout << program->error() << std::endl; + if (!program->useAttributeArray("color", PackedVertex::colorOffset(), + sizeof(PackedVertex), UCharType, 4, + ShaderProgram::Normalize)) { + std::cout << program->error() << std::endl; + } + if (!program->enableAttributeArray("normal")) + std::cout << program->error() << std::endl; + if (!program->useAttributeArray("normal", PackedVertex::normalOffset(), + sizeof(PackedVertex), FloatType, 3, + ShaderProgram::NoNormalize)) { + std::cout << program->error() << std::endl; + } + + // Set up our uniforms (model-view and projection matrices right now). + if (!program->setUniformValue("modelView", camera.modelView().matrix())) { + std::cout << program->error() << std::endl; + } + if (!program->setUniformValue("projection", camera.projection().matrix())) { + std::cout << program->error() << std::endl; + } + Matrix3f normalMatrix = camera.modelView().linear().inverse().transpose(); + if (!program->setUniformValue("normalMatrix", normalMatrix)) + std::cout << program->error() << std::endl; + + // Render the loaded spheres using the shader and bound VBO. + glDrawRangeElements(GL_TRIANGLES, 0, + static_cast(d->numberOfVertices - 1), + static_cast(d->numberOfIndices), GL_UNSIGNED_INT, + reinterpret_cast(0)); + + d->vbo.release(); + d->ibo.release(); + + program->disableAttributeArray("vertex"); + program->disableAttributeArray("color"); + program->disableAttributeArray("normal"); + + program->release(); +} + + vector Cartoon::computeCirclePoints(const Eigen::Affine3f& a, const Eigen::Affine3f& b, bool flat) const diff --git a/avogadro/rendering/cartoongeometry.h b/avogadro/rendering/cartoongeometry.h index dfe12bb68a..e2a153e6f8 100644 --- a/avogadro/rendering/cartoongeometry.h +++ b/avogadro/rendering/cartoongeometry.h @@ -24,7 +24,30 @@ enum CartoonType class AVOGADRORENDERING_EXPORT Cartoon : public BSplineGeometry { + public: + struct PackedVertex + { + Vector4ub color; // 4 bytes + Vector3f normal; // 12 bytes + Vector3f vertex; // 12 bytes + unsigned char padding[4]; // 4 bytes + + PackedVertex(const Vector4ub& c, const Vector3f& n, const Vector3f& v) + : color(c) + , normal(n) + , vertex(v) + {} + + static int colorOffset() { return 0; } + static int normalOffset() { return static_cast(sizeof(Vector4ub)); } + static int vertexOffset() + { + return normalOffset() + static_cast(sizeof(Vector3f)); + } + }; // 32 bytes total size - 16/32/64 are ideal for alignment. + + Cartoon(); Cartoon(float minRadius, float maxRadius); static const float ELIPSE_RATIO; @@ -39,6 +62,9 @@ class AVOGADRORENDERING_EXPORT Cartoon : public BSplineGeometry bool flat) const override; float computeScale(size_t index, float t, float scale) const override; + void render(const Camera& camera) override; + void update(); + std::vector> m_type; float m_minRadius, m_maxRadius;