From 67535a386c3d2e4b5843918080c0b9a578766db5 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 6 Nov 2014 09:55:34 -0800 Subject: [PATCH 01/44] first take at the Transform encapsulating a transform matrix --- interface/src/gpu/Batch.cpp | 19 ++++++++ interface/src/gpu/Batch.h | 22 +++++++-- interface/src/gpu/GLBackend.cpp | 76 ++++++++++++++++++++++++++++++-- interface/src/gpu/GLBackend.h | 46 ++++++++++++++----- interface/src/renderer/Model.cpp | 43 ++++++++++++++++-- 5 files changed, 183 insertions(+), 23 deletions(-) diff --git a/interface/src/gpu/Batch.cpp b/interface/src/gpu/Batch.cpp index e213007191..0b8f505f0f 100644 --- a/interface/src/gpu/Batch.cpp +++ b/interface/src/gpu/Batch.cpp @@ -156,3 +156,22 @@ void Batch::setIndexBuffer(Type type, const BufferPointer& buffer, Offset offset _params.push_back(_buffers.cache(buffer)); _params.push_back(type); } + +void Batch::setModelTransform(const TransformPointer& model) { + ADD_COMMAND(setModelTransform); + + _params.push_back(_transforms.cache(model)); +} + +void Batch::setViewTransform(const TransformPointer& view) { + ADD_COMMAND(setViewTransform); + + _params.push_back(_transforms.cache(view)); +} + +void Batch::setProjectionTransform(const TransformPointer& proj) { + ADD_COMMAND(setProjectionTransform); + + _params.push_back(_transforms.cache(proj)); +} + diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index 4149d88233..1758463a09 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -16,9 +16,8 @@ #include -#include "gpu/Format.h" -#include "gpu/Resource.h" #include "gpu/Stream.h" +#include "gpu/Transform.h" #if defined(NSIGHT_FOUND) #include "nvToolsExt.h" @@ -60,11 +59,16 @@ public: void clear(); + // Drawcalls void draw(Primitive primitiveType, uint32 numVertices, uint32 startVertex = 0); void drawIndexed(Primitive primitiveType, uint32 nbIndices, uint32 startIndex = 0); void drawInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbVertices, uint32 startVertex = 0, uint32 startInstance = 0); void drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbIndices, uint32 startIndex = 0, uint32 startInstance = 0); + // Input Stage + // InputFormat + // InputBuffers + // IndexBuffer void setInputFormat(const Stream::FormatPointer& format); void setInputStream(Slot startChannel, const BufferStream& stream); // not a command, just unroll into a loop of setInputBuffer @@ -72,6 +76,11 @@ public: void setIndexBuffer(Type type, const BufferPointer& buffer, Offset offset); + // Transform Stage + void setModelTransform(const TransformPointer& model); + void setViewTransform(const TransformPointer& view); + void setProjectionTransform(const TransformPointer& proj); + // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long @@ -138,11 +147,13 @@ public: COMMAND_drawIndexedInstanced, COMMAND_setInputFormat, - COMMAND_setInputBuffer, - COMMAND_setIndexBuffer, + COMMAND_setModelTransform, + COMMAND_setViewTransform, + COMMAND_setProjectionTransform, + // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API @@ -265,6 +276,7 @@ public: typedef Cache::Vector BufferCaches; typedef Cache::Vector StreamFormatCaches; + typedef Cache::Vector TransformCaches; typedef unsigned char Byte; typedef std::vector Bytes; @@ -299,6 +311,8 @@ public: BufferCaches _buffers; StreamFormatCaches _streamFormats; + TransformCaches _transforms; + Bytes _data; protected: }; diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 5a159d920d..452ad4ec3b 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -24,11 +24,13 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_drawIndexedInstanced), (&::gpu::GLBackend::do_setInputFormat), - (&::gpu::GLBackend::do_setInputBuffer), - (&::gpu::GLBackend::do_setIndexBuffer), + (&::gpu::GLBackend::do_setModelTransform), + (&::gpu::GLBackend::do_setViewTransform), + (&::gpu::GLBackend::do_setProjectionTransform), + (&::gpu::GLBackend::do_glEnable), (&::gpu::GLBackend::do_glDisable), @@ -111,7 +113,6 @@ static const GLenum _elementTypeToGLType[NUM_TYPES]= { GLBackend::GLBackend() : - _inputFormat(0), _inputAttributeActivation(0), _needInputFormatUpdate(true), @@ -122,7 +123,10 @@ GLBackend::GLBackend() : _inputBufferStrides(_inputBuffersState.size(), 0), _indexBuffer(0), - _indexBufferOffset(0) + _indexBufferOffset(0), + + _transform() + { } @@ -183,6 +187,7 @@ void GLBackend::checkGLError() { void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { updateInput(); + updateTransform(); Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = _primitiveToGLmode[primitiveType]; @@ -195,6 +200,7 @@ void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { updateInput(); + updateTransform(); Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = _primitiveToGLmode[primitiveType]; @@ -424,6 +430,68 @@ void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { CHECK_GL_ERROR(); } +// Transform Stage + +void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { + TransformPointer modelTransform = batch._transforms.get(batch._params[paramOffset]._uint); + + if (modelTransform != _transform._model) { + _transform._invalidModel = true; + } +} + +void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { + TransformPointer viewTransform = batch._transforms.get(batch._params[paramOffset]._uint); + + if (viewTransform != _transform._view) { + _transform._invalidView = true; + } +} + +void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { + TransformPointer projectionTransform = batch._transforms.get(batch._params[paramOffset]._uint); + + if (projectionTransform != _transform._projection) { + _transform._invalidProj = true; + } +} + +void GLBackend::updateTransform() { + if (_transform._invalidProj) { + if (_transform._lastMode != GL_PROJECTION) { + glMatrixMode(GL_PROJECTION); + _transform._lastMode = GL_PROJECTION; + } + CHECK_GL_ERROR(); + } + + if (_transform._invalidModel || _transform._invalidView) { + if (_transform._lastMode != GL_MODELVIEW) { + glMatrixMode(GL_MODELVIEW); + _transform._lastMode = GL_MODELVIEW; + } + + if (!_transform._model.isNull()) { + if (!_transform._view.isNull()) { + Transform::Mat4 mv = _transform._view->getMatrix() * _transform._model->getMatrix(); + glLoadMatrixf((const GLfloat*) &mv[0]); + } else { + glLoadMatrixf((const GLfloat*) &_transform._model->getMatrix()); + } + } else { + if (!_transform._view.isNull()) { + glLoadMatrixf((const GLfloat*) & _transform._view->getMatrix()); + } else { + // glLoadIdentity(); + } + } + CHECK_GL_ERROR(); + + _transform._invalidModel = false; + _transform._invalidView = false; + } +} + // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API diff --git a/interface/src/gpu/GLBackend.h b/interface/src/gpu/GLBackend.h index 2cce6cbedc..0f58ec192d 100644 --- a/interface/src/gpu/GLBackend.h +++ b/interface/src/gpu/GLBackend.h @@ -52,11 +52,22 @@ public: protected: + // Draw Stage + void do_draw(Batch& batch, uint32 paramOffset); + void do_drawIndexed(Batch& batch, uint32 paramOffset); + void do_drawInstanced(Batch& batch, uint32 paramOffset); + void do_drawIndexedInstanced(Batch& batch, uint32 paramOffset); + + // Input Stage + void do_setInputFormat(Batch& batch, uint32 paramOffset); + void do_setInputBuffer(Batch& batch, uint32 paramOffset); + void do_setIndexBuffer(Batch& batch, uint32 paramOffset); + void updateInput(); bool _needInputFormatUpdate; Stream::FormatPointer _inputFormat; - typedef std::bitset InputBuffersState; InputBuffersState _inputBuffersState; + Buffers _inputBuffers; Offsets _inputBufferOffsets; Offsets _inputBufferStrides; @@ -68,18 +79,31 @@ protected: typedef std::bitset InputActivationCache; InputActivationCache _inputAttributeActivation; - void do_draw(Batch& batch, uint32 paramOffset); - void do_drawIndexed(Batch& batch, uint32 paramOffset); - void do_drawInstanced(Batch& batch, uint32 paramOffset); - void do_drawIndexedInstanced(Batch& batch, uint32 paramOffset); + // Transform Stage + void do_setModelTransform(Batch& batch, uint32 paramOffset); + void do_setViewTransform(Batch& batch, uint32 paramOffset); + void do_setProjectionTransform(Batch& batch, uint32 paramOffset); - void updateInput(); - void do_setInputFormat(Batch& batch, uint32 paramOffset); - - void do_setInputBuffer(Batch& batch, uint32 paramOffset); + void updateTransform(); + struct TransformStageState { + TransformPointer _model; + TransformPointer _view; + TransformPointer _projection; + bool _invalidModel; + bool _invalidView; + bool _invalidProj; - void do_setVertexBuffer(Batch& batch, uint32 paramOffset); - void do_setIndexBuffer(Batch& batch, uint32 paramOffset); + GLenum _lastMode; + + TransformStageState() : + _model(0), + _view(0), + _projection(0), + _invalidModel(true), + _invalidView(true), + _invalidProj(true), + _lastMode(GL_TEXTURE) {} + } _transform; // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index a3fd3374a0..75eafcc0fb 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -556,6 +556,16 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { // Let's introduce a gpu::Batch to capture all the calls to the graphics api gpu::Batch batch; + // Capture the view matrix once for the rendering of this model + gpu::TransformPointer viewTransform(new gpu::Transform()); + + glm::mat4 v = Application::getInstance()->getUntranslatedViewMatrix(); + viewTransform->evalFromRawMatrix(v); + glm::mat4 v2 = viewTransform->getMatrix(); + + viewTransform->localTranslate(Application::getInstance()->getViewMatrixTranslation()); + + // batch.setViewTransform(viewTransform); GLBATCH(glDisable)(GL_COLOR_MATERIAL); @@ -1853,17 +1863,42 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl GLBATCH(glPushMatrix)(); //Application::getInstance()->loadTranslatedViewMatrix(_translation); - GLBATCH(glLoadMatrixf)((const GLfloat*)&Application::getInstance()->getUntranslatedViewMatrix()); + // GLBATCH(glLoadMatrixf)((const GLfloat*)&Application::getInstance()->getUntranslatedViewMatrix()); + + // Capture the view matrix once for the rendering of this model + glm::mat4 v = Application::getInstance()->getUntranslatedViewMatrix(); + + gpu::TransformPointer viewTransform(new gpu::Transform()); + viewTransform->evalFromRawMatrix(v); + glm::vec3 viewMatTranslation = Application::getInstance()->getViewMatrixTranslation(); - GLBATCH(glTranslatef)(_translation.x + viewMatTranslation.x, _translation.y + viewMatTranslation.y, - _translation.z + viewMatTranslation.z); + + viewTransform->localTranslate(viewMatTranslation + _translation); + glm::mat4 v2 = viewTransform->getMatrix(); + // batch.setViewTransform(viewTransform); + + // GLBATCH(glTranslatef)(_translation.x + viewMatTranslation.x, _translation.y + viewMatTranslation.y, + // _translation.z + viewMatTranslation.z); const MeshState& state = _meshStates.at(i); if (state.clusterMatrices.size() > 1) { GLBATCH(glUniformMatrix4fv)(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, (const float*)state.clusterMatrices.constData()); + + // gpu::TransformPointer modelTransform(new gpu::Transform()); + // modelTransform->setTranslation(_translation); + // batch.setModelTransform(viewTransform); + + // gpu::TransformPointer mv(new gpu::Transform()); + // gpu::Transform::mult(*mv, *viewTransform, *modelTransform); + batch.setModelTransform(viewTransform); } else { - GLBATCH(glMultMatrixf)((const GLfloat*)&state.clusterMatrices[0]); + // GLBATCH(glMultMatrixf)((const GLfloat*)&state.clusterMatrices[0]); + gpu::TransformPointer modelTransform(new gpu::Transform(state.clusterMatrices[0])); + + gpu::TransformPointer mv(new gpu::Transform()); + gpu::Transform::mult(*mv, *viewTransform, *modelTransform); + batch.setModelTransform(mv); } if (mesh.blendshapes.isEmpty()) { From 4a73b0773b77d901a215fea1f8de3ab14a475597 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 6 Nov 2014 09:56:05 -0800 Subject: [PATCH 02/44] first take at the Transform encapsulating a transform matrix --- interface/src/gpu/Transform.cpp | 109 ++++++++++++++++++++++++++++++ interface/src/gpu/Transform.h | 113 ++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 interface/src/gpu/Transform.cpp create mode 100644 interface/src/gpu/Transform.h diff --git a/interface/src/gpu/Transform.cpp b/interface/src/gpu/Transform.cpp new file mode 100644 index 0000000000..cb1607dd0b --- /dev/null +++ b/interface/src/gpu/Transform.cpp @@ -0,0 +1,109 @@ +// +// Transform.cpp +// interface/src/gpu +// +// Created by Sam Gateau on 11/4/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Transform.h" + +#include + +using namespace gpu; + +Transform::Transform() : + _translation(0), + _rotation(1.f, 0, 0, 0), + _scale(1.f), + _flags(1) // invalid cache +{ +} +Transform::Transform(const Mat4& raw) { + evalFromRawMatrix(raw); +} + +void Transform::updateCache() const { + if (isCacheInvalid()) { + glm::mat3x3 rot = glm::mat3_cast(_rotation); + + if ((_scale.x != 1.f) || (_scale.y != 1.f) || (_scale.z != 1.f)) { + rot[0] *= _scale.x; + rot[1] *= _scale.y; + rot[2] *= _scale.z; + } + + _matrix[0] = Vec4(rot[0], 0.f); + _matrix[1] = Vec4(rot[1], 0.f); + _matrix[2] = Vec4(rot[2], 0.f); + + _matrix[3] = Vec4(_translation, 0.f); + + validCache(); + } +} + +void Transform::localTranslate( Vec3 const & translation) { + Vec3 tt = glm::rotate(_rotation, translation); + _translation += tt * _scale; +} + +Transform::Mat4& Transform::evalRelativeTransform( Mat4& result, const Vec3& origin) { + updateCache(); + result = _matrix; + result[3] = Vec4(_translation - origin, 0.f); + return result; +} + +void Transform::evalFromRawMatrix(const Mat4& matrix) { + if ((matrix[0][3] == 0) && (matrix[1][3] == 0) && (matrix[2][3] == 0) && (matrix[3][3] == 1.f)) { + setTranslation(Vec3(matrix[3])); + + Mat3 matRS = Mat3(matrix); + + Vec3 scale(glm::length(matRS[0]), glm::length(matRS[1]), glm::length(matRS[2])); + + matRS[0] *= 1/scale.x; + matRS[1] *= 1/scale.y; + matRS[2] *= 1/scale.z; + + setRotation(glm::quat_cast(matRS)); + setScale(scale); + } +} + +Transform& Transform::evalInverseTranspose(Transform& result) { + result.setTranslation(-_translation); + result.setRotation(-_rotation); + + if (isScaling()) { + result.setScale(Vec3(1.f/_scale.x, 1.f/_scale.y, 1.f/_scale.z)); + } + return result; +} + +Transform& Transform::mult( Transform& result, const Transform& left, const Transform& right) { + right.updateCache(); + left.updateCache(); + + result.setTranslation(Vec3(left.getMatrix() * Vec4(right.getTranslation(), 1.f))); + + Mat4 mat = left.getMatrix() * right.getMatrix(); + Mat3 matRS = Mat3(mat); + + Vec3 scale(glm::length(matRS[0]), glm::length(matRS[1]), glm::length(matRS[2])); + + matRS[0] *= 1/scale.x; + matRS[1] *= 1/scale.y; + matRS[2] *= 1/scale.z; + + result.setRotation(glm::quat_cast(matRS)); + result.setScale(scale); + + return result; +} + + diff --git a/interface/src/gpu/Transform.h b/interface/src/gpu/Transform.h new file mode 100644 index 0000000000..e1e3f574e9 --- /dev/null +++ b/interface/src/gpu/Transform.h @@ -0,0 +1,113 @@ +// +// Transform.h +// interface/src/gpu +// +// Created by Sam Gateau on 11/4/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_Transform_h +#define hifi_gpu_Transform_h + +#include +#include "InterfaceConfig.h" + +#include "gpu/Format.h" + + +#include + +#include +#include +#include + +#include + +namespace gpu { + +class Transform { +public: + typedef glm::mat4 Mat4; + typedef glm::mat3 Mat3; + typedef glm::vec4 Vec4; + typedef glm::vec3 Vec3; + typedef glm::vec2 Vec2; + typedef glm::quat Quat; + + Transform(); + Transform(const Mat4& raw); + ~Transform() {} + + void setTranslation(const Vec3& translation) { invalidCache(); flagTranslation(); _translation = translation; } + const Vec3& getTranslation() const { return _translation; } + void parentTranslate(const Vec3& translation) { _translation += translation; } + void localTranslate( Vec3 const & translation); + + void setRotation(const Quat& rotation) { invalidCache(); flagRotation(); _rotation = rotation; } + const Quat& getRotation() const { return _rotation; } + + void setNoScale() { invalidCache(); flagNoScaling(); _scale = Vec3(1.f); } + void setScale(float scale) { invalidCache(); flagUniformScaling(); _scale = Vec3(scale); } + void setScale(const Vec3& scale) { invalidCache(); flagNonUniformScaling(); _scale = scale; } + const Vec3& getScale() const { return _scale; } + + const Mat4& getMatrix() const { updateCache(); return _matrix; } + + Mat4& evalRelativeTransform(Mat4& result, const Vec3& origin); + + Transform& evalInverseTranspose(Transform& result); + void evalFromRawMatrix(const Mat4& matrix); + + static Transform& mult( Transform& result, const Transform& left, const Transform& right); + + bool isScaling() const { return _flags[FLAG_UNIFORM_SCALING] || _flags[FLAG_NON_UNIFORM_SCALING]; } +protected: + + enum Flag { + FLAG_CACHE_INVALID = 0, + + FLAG_TRANSLATION, + FLAG_ROTATION, + FLAG_UNIFORM_SCALING, + FLAG_NON_UNIFORM_SCALING, + FLAG_SHEARING, + + FLAG_PROJECTION, + + NUM_FLAGS, + }; + + typedef std::bitset Flags; + + + // TRS + Vec3 _translation; + Quat _rotation; + Vec3 _scale; + + mutable Flags _flags; + + // Cached transform + mutable Mat4 _matrix; + bool isCacheInvalid() const { return _flags[FLAG_CACHE_INVALID]; } + void validCache() const { _flags.set(FLAG_CACHE_INVALID, false); } + void invalidCache() const { _flags.set(FLAG_CACHE_INVALID, true); } + + void flagTranslation() { _flags.set(FLAG_TRANSLATION, true); } + void flagRotation() { _flags.set(FLAG_ROTATION, true); } + + void flagNoScaling() { _flags.set(FLAG_UNIFORM_SCALING, false); _flags.set(FLAG_NON_UNIFORM_SCALING, false); } + void flagUniformScaling() { _flags.set(FLAG_UNIFORM_SCALING, true); _flags.set(FLAG_NON_UNIFORM_SCALING, false); } + void flagNonUniformScaling() { _flags.set(FLAG_UNIFORM_SCALING, false); _flags.set(FLAG_NON_UNIFORM_SCALING, true); } + + void updateCache() const; +}; + +typedef QSharedPointer< Transform > TransformPointer; + +}; + + +#endif From e1a9830d9aa99ca4c6831cc1281ad097e0c62e7d Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 7 Nov 2014 09:58:32 -0800 Subject: [PATCH 03/44] mirror doesn't work with the new transform stack --- interface/src/gpu/GLBackend.cpp | 21 ++++++++----- interface/src/gpu/Transform.cpp | 11 ++++--- interface/src/gpu/Transform.h | 10 ++++-- interface/src/renderer/Model.cpp | 54 +++++++++++--------------------- 4 files changed, 46 insertions(+), 50 deletions(-) diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 7572f4a5d2..f40290c8d4 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -436,6 +436,7 @@ void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { TransformPointer modelTransform = batch._transforms.get(batch._params[paramOffset]._uint); if (modelTransform != _transform._model) { + _transform._model = modelTransform; _transform._invalidModel = true; } } @@ -444,6 +445,7 @@ void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { TransformPointer viewTransform = batch._transforms.get(batch._params[paramOffset]._uint); if (viewTransform != _transform._view) { + _transform._view = viewTransform; _transform._invalidView = true; } } @@ -452,26 +454,27 @@ void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { TransformPointer projectionTransform = batch._transforms.get(batch._params[paramOffset]._uint); if (projectionTransform != _transform._projection) { + _transform._projection = projectionTransform; _transform._invalidProj = true; } } void GLBackend::updateTransform() { if (_transform._invalidProj) { - if (_transform._lastMode != GL_PROJECTION) { + /* if (_transform._lastMode != GL_PROJECTION) { glMatrixMode(GL_PROJECTION); _transform._lastMode = GL_PROJECTION; } - CHECK_GL_ERROR(); + CHECK_GL_ERROR();*/ + _transform._invalidProj; } if (_transform._invalidModel || _transform._invalidView) { - if (_transform._lastMode != GL_MODELVIEW) { - glMatrixMode(GL_MODELVIEW); - _transform._lastMode = GL_MODELVIEW; - } - if (!_transform._model.isNull()) { + if (_transform._lastMode != GL_MODELVIEW) { + glMatrixMode(GL_MODELVIEW); + _transform._lastMode = GL_MODELVIEW; + } if (!_transform._view.isNull()) { Transform::Mat4 mv = _transform._view->getMatrix() * _transform._model->getMatrix(); glLoadMatrixf((const GLfloat*) &mv[0]); @@ -480,6 +483,10 @@ void GLBackend::updateTransform() { } } else { if (!_transform._view.isNull()) { + if (_transform._lastMode != GL_MODELVIEW) { + glMatrixMode(GL_MODELVIEW); + _transform._lastMode = GL_MODELVIEW; + } glLoadMatrixf((const GLfloat*) & _transform._view->getMatrix()); } else { // glLoadIdentity(); diff --git a/interface/src/gpu/Transform.cpp b/interface/src/gpu/Transform.cpp index cb1607dd0b..71b8b0ec92 100644 --- a/interface/src/gpu/Transform.cpp +++ b/interface/src/gpu/Transform.cpp @@ -40,21 +40,22 @@ void Transform::updateCache() const { _matrix[1] = Vec4(rot[1], 0.f); _matrix[2] = Vec4(rot[2], 0.f); - _matrix[3] = Vec4(_translation, 0.f); + _matrix[3] = Vec4(_translation, 1.f); validCache(); } } -void Transform::localTranslate( Vec3 const & translation) { - Vec3 tt = glm::rotate(_rotation, translation); - _translation += tt * _scale; +void Transform::postTranslate(const Vec3& translation) { + invalidCache(); + Vec3 tt = glm::rotate(_rotation, translation * _scale); + _translation += tt; } Transform::Mat4& Transform::evalRelativeTransform( Mat4& result, const Vec3& origin) { updateCache(); result = _matrix; - result[3] = Vec4(_translation - origin, 0.f); + result[3] = Vec4(_translation - origin, 1.f); return result; } diff --git a/interface/src/gpu/Transform.h b/interface/src/gpu/Transform.h index e1e3f574e9..2760241480 100644 --- a/interface/src/gpu/Transform.h +++ b/interface/src/gpu/Transform.h @@ -42,10 +42,11 @@ public: void setTranslation(const Vec3& translation) { invalidCache(); flagTranslation(); _translation = translation; } const Vec3& getTranslation() const { return _translation; } - void parentTranslate(const Vec3& translation) { _translation += translation; } - void localTranslate( Vec3 const & translation); - void setRotation(const Quat& rotation) { invalidCache(); flagRotation(); _rotation = rotation; } + void preTranslate(const Vec3& translation) { invalidCache(); _translation += translation; } + void postTranslate( Vec3 const & translation); + + void setRotation(const Quat& rotation) { invalidCache(); flagRotation(); _rotation = glm::normalize(rotation); } const Quat& getRotation() const { return _rotation; } void setNoScale() { invalidCache(); flagNoScaling(); _scale = Vec3(1.f); } @@ -63,6 +64,9 @@ public: static Transform& mult( Transform& result, const Transform& left, const Transform& right); bool isScaling() const { return _flags[FLAG_UNIFORM_SCALING] || _flags[FLAG_NON_UNIFORM_SCALING]; } + bool isUniform() const { return !isNonUniform(); } + bool isNonUniform() const { return _flags[FLAG_NON_UNIFORM_SCALING]; } + protected: enum Flag { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 12975584d2..6627ce3e2b 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -555,17 +555,13 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { // Let's introduce a gpu::Batch to capture all the calls to the graphics api gpu::Batch batch; + GLBATCH(glPushMatrix)(); // Capture the view matrix once for the rendering of this model - gpu::TransformPointer viewTransform(new gpu::Transform()); + gpu::TransformPointer viewTransform(new gpu::Transform(Application::getInstance()->getUntranslatedViewMatrix())); + viewTransform->postTranslate(Application::getInstance()->getViewMatrixTranslation()); - glm::mat4 v = Application::getInstance()->getUntranslatedViewMatrix(); - viewTransform->evalFromRawMatrix(v); - glm::mat4 v2 = viewTransform->getMatrix(); - - viewTransform->localTranslate(Application::getInstance()->getViewMatrixTranslation()); - - // batch.setViewTransform(viewTransform); + batch.setViewTransform(viewTransform); GLBATCH(glDisable)(GL_COLOR_MATERIAL); @@ -690,6 +686,8 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { GLBATCH(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, 0); GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); + GLBATCH(glPopMatrix)(); + // Render! { PROFILE_RANGE("render Batch"); @@ -1861,46 +1859,32 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl } } - GLBATCH(glPushMatrix)(); - //Application::getInstance()->loadTranslatedViewMatrix(_translation); + // GLBATCH(glPushMatrix)(); + // Application::getInstance()->loadTranslatedViewMatrix(_translation); // GLBATCH(glLoadMatrixf)((const GLfloat*)&Application::getInstance()->getUntranslatedViewMatrix()); - // Capture the view matrix once for the rendering of this model - glm::mat4 v = Application::getInstance()->getUntranslatedViewMatrix(); - - gpu::TransformPointer viewTransform(new gpu::Transform()); - viewTransform->evalFromRawMatrix(v); - glm::vec3 viewMatTranslation = Application::getInstance()->getViewMatrixTranslation(); - viewTransform->localTranslate(viewMatTranslation + _translation); - glm::mat4 v2 = viewTransform->getMatrix(); - // batch.setViewTransform(viewTransform); - // GLBATCH(glTranslatef)(_translation.x + viewMatTranslation.x, _translation.y + viewMatTranslation.y, - // _translation.z + viewMatTranslation.z); + + // GLBATCH(glTranslatef)(_translation.x + viewMatTranslation.x, _translation.y + viewMatTranslation.y, _translation.z + viewMatTranslation.z); const MeshState& state = _meshStates.at(i); if (state.clusterMatrices.size() > 1) { GLBATCH(glUniformMatrix4fv)(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, (const float*)state.clusterMatrices.constData()); - // gpu::TransformPointer modelTransform(new gpu::Transform()); - // modelTransform->setTranslation(_translation); - // batch.setModelTransform(viewTransform); - - // gpu::TransformPointer mv(new gpu::Transform()); - // gpu::Transform::mult(*mv, *viewTransform, *modelTransform); - batch.setModelTransform(viewTransform); + gpu::TransformPointer modelTransform(new gpu::Transform()); + modelTransform->preTranslate(_translation); + batch.setModelTransform(modelTransform); } else { - // GLBATCH(glMultMatrixf)((const GLfloat*)&state.clusterMatrices[0]); + // GLBATCH(glMultMatrixf)((const GLfloat*)&state.clusterMatrices[0]); + gpu::TransformPointer modelTransform(new gpu::Transform(state.clusterMatrices[0])); - - gpu::TransformPointer mv(new gpu::Transform()); - gpu::Transform::mult(*mv, *viewTransform, *modelTransform); - batch.setModelTransform(mv); + modelTransform->preTranslate(_translation); + batch.setModelTransform(modelTransform); } - + if (mesh.blendshapes.isEmpty()) { batch.setInputFormat(networkMesh._vertexFormat); batch.setInputStream(0, *networkMesh._vertexStream); @@ -2010,7 +1994,7 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl GLBATCH(glActiveTexture)(GL_TEXTURE0); } - GLBATCH(glPopMatrix)(); + // GLBATCH(glPopMatrix)(); } From 9d146e7ea34b796e053a7c753f4bb1863b79797b Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 7 Nov 2014 14:27:22 -0800 Subject: [PATCH 04/44] improving the evalFromRawMatrix decomposition --- interface/src/gpu/Transform.cpp | 44 +++++++++++++++++--------------- interface/src/gpu/Transform.h | 2 ++ interface/src/renderer/Model.cpp | 15 ++++++----- interface/src/renderer/Model.h | 9 ++++--- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/interface/src/gpu/Transform.cpp b/interface/src/gpu/Transform.cpp index 71b8b0ec92..88922488a4 100644 --- a/interface/src/gpu/Transform.cpp +++ b/interface/src/gpu/Transform.cpp @@ -59,20 +59,31 @@ Transform::Mat4& Transform::evalRelativeTransform( Mat4& result, const Vec3& ori return result; } +void Transform::evalRotationScale(const Mat3& rotationScaleMatrix) { + Vec3 scale(glm::length(rotationScaleMatrix[0]), glm::length(rotationScaleMatrix[1]), glm::length(rotationScaleMatrix[2])); + if (scale.x < 0.00001f) scale.x = 0.00001f; + if (scale.y < 0.00001f) scale.y = 0.00001f; + if (scale.z < 0.00001f) scale.z = 0.00001f; + + Mat3 matRotScale( + rotationScaleMatrix[0] / scale.x, + rotationScaleMatrix[1] / scale.y, + rotationScaleMatrix[2] / scale.z); + setRotation(glm::quat_cast(matRotScale)); + + float determinant = glm::determinant(matRotScale); + if (determinant < 0.f) { + scale.x = -scale.x; + } + + setScale(scale); +} + void Transform::evalFromRawMatrix(const Mat4& matrix) { if ((matrix[0][3] == 0) && (matrix[1][3] == 0) && (matrix[2][3] == 0) && (matrix[3][3] == 1.f)) { setTranslation(Vec3(matrix[3])); - Mat3 matRS = Mat3(matrix); - - Vec3 scale(glm::length(matRS[0]), glm::length(matRS[1]), glm::length(matRS[2])); - - matRS[0] *= 1/scale.x; - matRS[1] *= 1/scale.y; - matRS[2] *= 1/scale.z; - - setRotation(glm::quat_cast(matRS)); - setScale(scale); + evalRotationScale(Mat3(matrix)); } } @@ -91,18 +102,9 @@ Transform& Transform::mult( Transform& result, const Transform& left, const Tran left.updateCache(); result.setTranslation(Vec3(left.getMatrix() * Vec4(right.getTranslation(), 1.f))); - + Mat4 mat = left.getMatrix() * right.getMatrix(); - Mat3 matRS = Mat3(mat); - - Vec3 scale(glm::length(matRS[0]), glm::length(matRS[1]), glm::length(matRS[2])); - - matRS[0] *= 1/scale.x; - matRS[1] *= 1/scale.y; - matRS[2] *= 1/scale.z; - - result.setRotation(glm::quat_cast(matRS)); - result.setScale(scale); + result.evalRotationScale(Mat3(mat)); return result; } diff --git a/interface/src/gpu/Transform.h b/interface/src/gpu/Transform.h index 2760241480..bcb353c578 100644 --- a/interface/src/gpu/Transform.h +++ b/interface/src/gpu/Transform.h @@ -60,6 +60,7 @@ public: Transform& evalInverseTranspose(Transform& result); void evalFromRawMatrix(const Mat4& matrix); + void evalRotationScale(const Mat3& rotationScalematrix); static Transform& mult( Transform& result, const Transform& left, const Transform& right); @@ -110,6 +111,7 @@ protected: }; typedef QSharedPointer< Transform > TransformPointer; +typedef std::vector< TransformPointer > Transforms; }; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 6627ce3e2b..965f43acb7 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -554,14 +554,18 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { } // Let's introduce a gpu::Batch to capture all the calls to the graphics api - gpu::Batch batch; + _renderBatch.clear(); + gpu::Batch& batch = _renderBatch; GLBATCH(glPushMatrix)(); // Capture the view matrix once for the rendering of this model - gpu::TransformPointer viewTransform(new gpu::Transform(Application::getInstance()->getUntranslatedViewMatrix())); - viewTransform->postTranslate(Application::getInstance()->getViewMatrixTranslation()); + if (_transforms.empty()) { + _transforms.push_back(gpu::TransformPointer(new gpu::Transform())); + } + _transforms[0]->evalFromRawMatrix(Application::getInstance()->getUntranslatedViewMatrix()); + _transforms[0]->postTranslate(Application::getInstance()->getViewMatrixTranslation() + _translation); - batch.setViewTransform(viewTransform); + batch.setViewTransform(_transforms[0]); GLBATCH(glDisable)(GL_COLOR_MATERIAL); @@ -692,7 +696,6 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { { PROFILE_RANGE("render Batch"); ::gpu::GLBackend::renderBatch(batch); - batch.clear(); } // restore all the default material settings @@ -1875,13 +1878,11 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl (const float*)state.clusterMatrices.constData()); gpu::TransformPointer modelTransform(new gpu::Transform()); - modelTransform->preTranslate(_translation); batch.setModelTransform(modelTransform); } else { // GLBATCH(glMultMatrixf)((const GLfloat*)&state.clusterMatrices[0]); gpu::TransformPointer modelTransform(new gpu::Transform(state.clusterMatrices[0])); - modelTransform->preTranslate(_translation); batch.setModelTransform(modelTransform); } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 34d6a34c06..ac4f6bde1b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -36,11 +36,10 @@ class ViewFrustum; typedef QSharedPointer AnimationHandlePointer; typedef QWeakPointer WeakAnimationHandlePointer; -namespace gpu { - class Batch; -} #include "gpu/Stream.h" +#include "gpu/Transform.h" +#include "gpu/Batch.h" /// A generic 3D model displaying geometry loaded from a URL. class Model : public QObject, public PhysicsEntity { @@ -283,7 +282,9 @@ private: QUrl _url; gpu::Buffers _blendedVertexBuffers; - + gpu::Transforms _transforms; + gpu::Batch _renderBatch; + QVector > > _dilatedTextures; QVector _attachments; From 631ed9da78350438b5c875a6d4e031ed3c15a9a0 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 10 Nov 2014 10:04:19 -0800 Subject: [PATCH 05/44] let's start reusing the Batch per model from frame to frame --- interface/src/Application.cpp | 8 ++- interface/src/Application.h | 3 + interface/src/gpu/Transform.cpp | 38 ----------- interface/src/gpu/Transform.h | 105 ++++++++++++++++++++++++++----- interface/src/renderer/Model.cpp | 12 +++- 5 files changed, 106 insertions(+), 60 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e58f79cb5e..85ef70677e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -108,7 +108,8 @@ static unsigned STARFIELD_SEED = 1; static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored -const unsigned MAXIMUM_CACHE_SIZE = 10737418240; // 10GB +//const unsigned MAXIMUM_CACHE_SIZE = 10737418240; // 10GB +const quint64 MAXIMUM_CACHE_SIZE = 10737418240L; // 10GB static QTimer* idleTimer = NULL; @@ -186,7 +187,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _lastNackTime(usecTimestampNow()), _lastSendDownstreamAudioStats(usecTimestampNow()), _isVSyncOn(true), - _aboutToQuit(false) + _aboutToQuit(false), + _viewTransform(new gpu::Transform()) { // read the ApplicationInfo.ini file for Name/Version/Domain information @@ -3115,6 +3117,8 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { void Application::updateUntranslatedViewMatrix(const glm::vec3& viewMatrixTranslation) { glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); _viewMatrixTranslation = viewMatrixTranslation; + _viewTransform->evalFromRawMatrix(_untranslatedViewMatrix); + _viewTransform->postTranslate(viewMatrixTranslation); } void Application::loadTranslatedViewMatrix(const glm::vec3& translation) { diff --git a/interface/src/Application.h b/interface/src/Application.h index eee2581e2e..ca8651867f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -233,6 +233,8 @@ public: const glm::vec3& getViewMatrixTranslation() const { return _viewMatrixTranslation; } void setViewMatrixTranslation(const glm::vec3& translation) { _viewMatrixTranslation = translation; } + const gpu::TransformPointer& getViewTransform() const { return _viewTransform; } + /// if you need to access the application settings, use lockSettings()/unlockSettings() QSettings* lockSettings() { _settingsMutex.lock(); return _settings; } void unlockSettings() { _settingsMutex.unlock(); } @@ -526,6 +528,7 @@ private: QRect _mirrorViewRect; RearMirrorTools* _rearMirrorTools; + gpu::TransformPointer _viewTransform; glm::mat4 _untranslatedViewMatrix; glm::vec3 _viewMatrixTranslation; glm::mat4 _projectionMatrix; diff --git a/interface/src/gpu/Transform.cpp b/interface/src/gpu/Transform.cpp index 88922488a4..a51dba8ce3 100644 --- a/interface/src/gpu/Transform.cpp +++ b/interface/src/gpu/Transform.cpp @@ -11,7 +11,6 @@ #include "Transform.h" -#include using namespace gpu; @@ -26,32 +25,6 @@ Transform::Transform(const Mat4& raw) { evalFromRawMatrix(raw); } -void Transform::updateCache() const { - if (isCacheInvalid()) { - glm::mat3x3 rot = glm::mat3_cast(_rotation); - - if ((_scale.x != 1.f) || (_scale.y != 1.f) || (_scale.z != 1.f)) { - rot[0] *= _scale.x; - rot[1] *= _scale.y; - rot[2] *= _scale.z; - } - - _matrix[0] = Vec4(rot[0], 0.f); - _matrix[1] = Vec4(rot[1], 0.f); - _matrix[2] = Vec4(rot[2], 0.f); - - _matrix[3] = Vec4(_translation, 1.f); - - validCache(); - } -} - -void Transform::postTranslate(const Vec3& translation) { - invalidCache(); - Vec3 tt = glm::rotate(_rotation, translation * _scale); - _translation += tt; -} - Transform::Mat4& Transform::evalRelativeTransform( Mat4& result, const Vec3& origin) { updateCache(); result = _matrix; @@ -97,16 +70,5 @@ Transform& Transform::evalInverseTranspose(Transform& result) { return result; } -Transform& Transform::mult( Transform& result, const Transform& left, const Transform& right) { - right.updateCache(); - left.updateCache(); - - result.setTranslation(Vec3(left.getMatrix() * Vec4(right.getTranslation(), 1.f))); - - Mat4 mat = left.getMatrix() * right.getMatrix(); - result.evalRotationScale(Mat3(mat)); - - return result; -} diff --git a/interface/src/gpu/Transform.h b/interface/src/gpu/Transform.h index bcb353c578..72dc843044 100644 --- a/interface/src/gpu/Transform.h +++ b/interface/src/gpu/Transform.h @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -37,23 +38,68 @@ public: typedef glm::quat Quat; Transform(); + Transform(const Transform& transform) : + _translation(transform._translation), + _rotation(transform._rotation), + _scale(transform._scale), + _flags(transform._flags) + { + invalidCache(); + } Transform(const Mat4& raw); ~Transform() {} void setTranslation(const Vec3& translation) { invalidCache(); flagTranslation(); _translation = translation; } const Vec3& getTranslation() const { return _translation; } - void preTranslate(const Vec3& translation) { invalidCache(); _translation += translation; } - void postTranslate( Vec3 const & translation); + void preTranslate(const Vec3& translation) { invalidCache(); flagTranslation(); _translation += translation; } + void postTranslate(const Vec3& translation) { + invalidCache(); + flagTranslation(); + if (isRotating()) { + _translation += glm::rotate(_rotation, translation * _scale); + } else { + _translation += translation * _scale; + } + } - void setRotation(const Quat& rotation) { invalidCache(); flagRotation(); _rotation = glm::normalize(rotation); } + void setRotation(const Quat& rotation) { invalidCache(); flagRotation(); _rotation = rotation; } const Quat& getRotation() const { return _rotation; } - void setNoScale() { invalidCache(); flagNoScaling(); _scale = Vec3(1.f); } - void setScale(float scale) { invalidCache(); flagUniformScaling(); _scale = Vec3(scale); } - void setScale(const Vec3& scale) { invalidCache(); flagNonUniformScaling(); _scale = scale; } + void preRotate(const Quat& rotation) { + invalidCache(); + if (isRotating()) { + _rotation = rotation * _rotation; + } else { + _rotation = rotation; + } + flagRotation(); + _translation = glm::rotate(rotation, _translation); + } + void postRotate(const Quat& rotation) { + invalidCache(); + if (isRotating()) { + _rotation *= rotation; + } else { + _rotation = rotation; + } + flagRotation(); + } + + void setScale(float scale) { invalidCache(); flagScaling(); _scale = Vec3(scale); } + void setScale(const Vec3& scale) { invalidCache(); flagScaling(); _scale = scale; } const Vec3& getScale() const { return _scale; } + void postScale(const Vec3& scale) { + invalidCache(); + if (isScaling()) { + _scale *= scale; + } else { + _scale = scale; + } + flagScaling(); + } + const Mat4& getMatrix() const { updateCache(); return _matrix; } Mat4& evalRelativeTransform(Mat4& result, const Vec3& origin); @@ -62,11 +108,17 @@ public: void evalFromRawMatrix(const Mat4& matrix); void evalRotationScale(const Mat3& rotationScalematrix); - static Transform& mult( Transform& result, const Transform& left, const Transform& right); + static Transform& mult( Transform& result, const Transform& left, const Transform& right) { + result = left; + if ( right.isTranslating()) result.postTranslate(right.getTranslation()); + if ( right.isRotating()) result.postRotate(right.getRotation()); + if (right.isScaling()) result.postScale(right.getScale()); + return result; + } - bool isScaling() const { return _flags[FLAG_UNIFORM_SCALING] || _flags[FLAG_NON_UNIFORM_SCALING]; } - bool isUniform() const { return !isNonUniform(); } - bool isNonUniform() const { return _flags[FLAG_NON_UNIFORM_SCALING]; } + bool isTranslating() const { return _flags[FLAG_TRANSLATION]; } + bool isRotating() const { return _flags[FLAG_ROTATION]; } + bool isScaling() const { return _flags[FLAG_SCALING]; } protected: @@ -75,9 +127,7 @@ protected: FLAG_TRANSLATION, FLAG_ROTATION, - FLAG_UNIFORM_SCALING, - FLAG_NON_UNIFORM_SCALING, - FLAG_SHEARING, + FLAG_SCALING, FLAG_PROJECTION, @@ -103,11 +153,32 @@ protected: void flagTranslation() { _flags.set(FLAG_TRANSLATION, true); } void flagRotation() { _flags.set(FLAG_ROTATION, true); } - void flagNoScaling() { _flags.set(FLAG_UNIFORM_SCALING, false); _flags.set(FLAG_NON_UNIFORM_SCALING, false); } - void flagUniformScaling() { _flags.set(FLAG_UNIFORM_SCALING, true); _flags.set(FLAG_NON_UNIFORM_SCALING, false); } - void flagNonUniformScaling() { _flags.set(FLAG_UNIFORM_SCALING, false); _flags.set(FLAG_NON_UNIFORM_SCALING, true); } + void flagScaling() { _flags.set(FLAG_SCALING, true); } - void updateCache() const; + void updateCache() const { + if (isCacheInvalid()) { + if (isRotating()) { + glm::mat3x3 rot = glm::mat3_cast(_rotation); + + if ((_scale.x != 1.f) || (_scale.y != 1.f) || (_scale.z != 1.f)) { + rot[0] *= _scale.x; + rot[1] *= _scale.y; + rot[2] *= _scale.z; + } + + _matrix[0] = Vec4(rot[0], 0.f); + _matrix[1] = Vec4(rot[1], 0.f); + _matrix[2] = Vec4(rot[2], 0.f); + } else { + _matrix[0] = Vec4(_scale.x, 0.f, 0.f, 0.f); + _matrix[1] = Vec4(0.f, _scale.y, 0.f, 0.f); + _matrix[2] = Vec4(0.f, 0.f, _scale.z, 0.f); + } + + _matrix[3] = Vec4(_translation, 1.f); + validCache(); + } + } }; typedef QSharedPointer< Transform > TransformPointer; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 965f43acb7..5c8fab1118 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -563,7 +563,13 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { _transforms.push_back(gpu::TransformPointer(new gpu::Transform())); } _transforms[0]->evalFromRawMatrix(Application::getInstance()->getUntranslatedViewMatrix()); - _transforms[0]->postTranslate(Application::getInstance()->getViewMatrixTranslation() + _translation); + + gpu::TransformPointer currentView(Application::getInstance()->getViewTransform()); + + _transforms[0]->setTranslation(currentView->getTranslation()); + _transforms[0]->setRotation(currentView->getRotation()); + _transforms[0]->setScale(currentView->getScale()); + _transforms[0]->postTranslate(_translation); batch.setViewTransform(_transforms[0]); @@ -1862,7 +1868,7 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl } } - // GLBATCH(glPushMatrix)(); + GLBATCH(glPushMatrix)(); // Application::getInstance()->loadTranslatedViewMatrix(_translation); // GLBATCH(glLoadMatrixf)((const GLfloat*)&Application::getInstance()->getUntranslatedViewMatrix()); @@ -1995,7 +2001,7 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl GLBATCH(glActiveTexture)(GL_TEXTURE0); } - // GLBATCH(glPopMatrix)(); + GLBATCH(glPopMatrix)(); } From ad51416c282f234e8b08f19f31c925e642a5342c Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 11 Nov 2014 09:54:35 -0800 Subject: [PATCH 06/44] move the transform class files to the Shared library, still problem with negative scale composition --- interface/src/Application.cpp | 9 +- interface/src/gpu/Batch.h | 7 +- interface/src/gpu/GLBackend.cpp | 4 +- interface/src/gpu/Transform.cpp | 74 ----------- interface/src/renderer/Model.cpp | 3 + interface/src/renderer/Model.h | 2 +- libraries/shared/src/Transform.cpp | 118 ++++++++++++++++++ .../gpu => libraries/shared/src}/Transform.h | 22 ++-- 8 files changed, 147 insertions(+), 92 deletions(-) delete mode 100644 interface/src/gpu/Transform.cpp create mode 100644 libraries/shared/src/Transform.cpp rename {interface/src/gpu => libraries/shared/src}/Transform.h (95%) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3487f45e1f..31115e39a3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2890,12 +2890,15 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()"); // transform by eye offset + gpu::Transform viewTransform; + // load the view frustum loadViewFrustum(whichCamera, _displayViewFrustum); // flip x if in mirror mode (also requires reversing winding order for backface culling) if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { glScalef(-1.0f, 1.0f, 1.0f); + viewTransform.setScale(gpu::Transform::Vec3(-1.0f, 1.0f, 1.0f)); glFrontFace(GL_CW); } else { @@ -2906,7 +2909,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glm::quat eyeOffsetOrient = whichCamera.getEyeOffsetOrientation(); glm::vec3 eyeOffsetAxis = glm::axis(eyeOffsetOrient); glRotatef(-glm::degrees(glm::angle(eyeOffsetOrient)), eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z); - glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); + viewTransform.preRotate(glm::quat(-glm::angle(eyeOffsetOrient), glm::vec3(eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z))); + glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); + viewTransform.preTranslate(glm::vec3(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z)); // transform view according to whichCamera // could be myCamera (if in normal mode) @@ -2915,9 +2920,11 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glm::quat rotation = whichCamera.getRotation(); glm::vec3 axis = glm::axis(rotation); glRotatef(-glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + viewTransform.preRotate(glm::quat(-glm::angle(rotation), axis)); // store view matrix without translation, which we'll use for precision-sensitive objects updateUntranslatedViewMatrix(-whichCamera.getPosition()); + viewTransform.preTranslate(-whichCamera.getPosition()); glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z); diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index 8a9bf6f300..cbda6627d3 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -14,10 +14,11 @@ #include #include "InterfaceConfig.h" +#include "Transform.h" + #include #include "gpu/Stream.h" -#include "gpu/Transform.h" #if defined(NSIGHT_FOUND) #include "nvToolsExt.h" @@ -49,6 +50,10 @@ enum Primitive { NUM_PRIMITIVES, }; +typedef ::Transform Transform; +typedef QSharedPointer<::gpu::Transform> TransformPointer; +typedef std::vector< TransformPointer > Transforms; + class Batch { public: typedef Stream::Slot Slot; diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index f40290c8d4..115e569177 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -476,7 +476,9 @@ void GLBackend::updateTransform() { _transform._lastMode = GL_MODELVIEW; } if (!_transform._view.isNull()) { - Transform::Mat4 mv = _transform._view->getMatrix() * _transform._model->getMatrix(); + Transform mvx; + Transform::mult(mvx, (*_transform._view), (*_transform._model)); + Transform::Mat4 mv = mvx.getMatrix(); glLoadMatrixf((const GLfloat*) &mv[0]); } else { glLoadMatrixf((const GLfloat*) &_transform._model->getMatrix()); diff --git a/interface/src/gpu/Transform.cpp b/interface/src/gpu/Transform.cpp deleted file mode 100644 index a51dba8ce3..0000000000 --- a/interface/src/gpu/Transform.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// -// Transform.cpp -// interface/src/gpu -// -// Created by Sam Gateau on 11/4/2014. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "Transform.h" - - -using namespace gpu; - -Transform::Transform() : - _translation(0), - _rotation(1.f, 0, 0, 0), - _scale(1.f), - _flags(1) // invalid cache -{ -} -Transform::Transform(const Mat4& raw) { - evalFromRawMatrix(raw); -} - -Transform::Mat4& Transform::evalRelativeTransform( Mat4& result, const Vec3& origin) { - updateCache(); - result = _matrix; - result[3] = Vec4(_translation - origin, 1.f); - return result; -} - -void Transform::evalRotationScale(const Mat3& rotationScaleMatrix) { - Vec3 scale(glm::length(rotationScaleMatrix[0]), glm::length(rotationScaleMatrix[1]), glm::length(rotationScaleMatrix[2])); - if (scale.x < 0.00001f) scale.x = 0.00001f; - if (scale.y < 0.00001f) scale.y = 0.00001f; - if (scale.z < 0.00001f) scale.z = 0.00001f; - - Mat3 matRotScale( - rotationScaleMatrix[0] / scale.x, - rotationScaleMatrix[1] / scale.y, - rotationScaleMatrix[2] / scale.z); - setRotation(glm::quat_cast(matRotScale)); - - float determinant = glm::determinant(matRotScale); - if (determinant < 0.f) { - scale.x = -scale.x; - } - - setScale(scale); -} - -void Transform::evalFromRawMatrix(const Mat4& matrix) { - if ((matrix[0][3] == 0) && (matrix[1][3] == 0) && (matrix[2][3] == 0) && (matrix[3][3] == 1.f)) { - setTranslation(Vec3(matrix[3])); - - evalRotationScale(Mat3(matrix)); - } -} - -Transform& Transform::evalInverseTranspose(Transform& result) { - result.setTranslation(-_translation); - result.setRotation(-_rotation); - - if (isScaling()) { - result.setScale(Vec3(1.f/_scale.x, 1.f/_scale.y, 1.f/_scale.z)); - } - return result; -} - - - diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 5c8fab1118..31801922a4 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -565,7 +565,10 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { _transforms[0]->evalFromRawMatrix(Application::getInstance()->getUntranslatedViewMatrix()); gpu::TransformPointer currentView(Application::getInstance()->getViewTransform()); + currentView->getMatrix(); + gpu::Transform::Mat4 glview = Application::getInstance()->getUntranslatedViewMatrix(); + _transforms[0]->setTranslation(currentView->getTranslation()); _transforms[0]->setRotation(currentView->getRotation()); _transforms[0]->setScale(currentView->getScale()); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index ac4f6bde1b..29d4f35167 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -16,6 +16,7 @@ #include #include +#include "Transform.h" #include #include #include @@ -38,7 +39,6 @@ typedef QWeakPointer WeakAnimationHandlePointer; #include "gpu/Stream.h" -#include "gpu/Transform.h" #include "gpu/Batch.h" /// A generic 3D model displaying geometry loaded from a URL. diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp new file mode 100644 index 0000000000..a6e9439512 --- /dev/null +++ b/libraries/shared/src/Transform.cpp @@ -0,0 +1,118 @@ +// +// Transform.cpp +// shared/src/gpu +// +// Created by Sam Gateau on 11/4/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Transform.h" + + +Transform::Transform() : + _translation(0), + _rotation(1.f, 0, 0, 0), + _scale(1.f), + _flags(1) // invalid cache +{ +} +Transform::Transform(const Mat4& raw) { + evalFromRawMatrix(raw); +} + +Transform::Mat4& Transform::evalRelativeTransform( Mat4& result, const Vec3& origin) { + updateCache(); + result = _matrix; + result[3] = Vec4(_translation - origin, 1.f); + return result; +} + +void Transform::evalRotationScale(const Mat3& rotationScaleMatrix) { + const float ACCURACY_THREASHOLD = 0.00001f; + + // Extract the rotation component - this is done using polar decompostion, where + // we successively average the matrix with its inverse transpose until there is + // no/a very small difference between successive averages + float norm; + int count = 0; + Mat3 rotationMat = rotationScaleMatrix; + do { + Mat3 nextRotation; + Mat3 currInvTranspose = + glm::inverse(glm::transpose(rotationMat)); + + // Go through every component in the matrices and find the next matrix + for (int i = 0; i < 3; i++) { + for (int j = 0; j <3; j++) { + nextRotation[j][i] = 0.5f * + (rotationMat[j][i] + currInvTranspose[j][i]); + } + } + + norm = 0.0; + for (int i = 0; i < 3; i++) { + float n = static_cast( + fabs(rotationMat[0][i] - nextRotation[0][i]) + + fabs(rotationMat[1][i] - nextRotation[1][i]) + + fabs(rotationMat[2][i] - nextRotation[2][i])); + norm = (norm > n ? norm : n); + } + rotationMat = nextRotation; + } while (count < 100 && norm > ACCURACY_THREASHOLD); + + + // extract scale of the matrix as the length of each axis + Mat3 scaleMat = glm::inverse(rotationMat) * rotationScaleMatrix; + + Vec3 scale2(glm::length(rotationScaleMatrix[0]), glm::length(rotationScaleMatrix[1]), glm::length(rotationScaleMatrix[2])); + Vec3 scale(scaleMat[0][0], scaleMat[1][1], scaleMat[2][2]); + if (scale.x < ACCURACY_THREASHOLD) scale.x = ACCURACY_THREASHOLD; + if (scale.y < ACCURACY_THREASHOLD) scale.y = ACCURACY_THREASHOLD; + if (scale.z < ACCURACY_THREASHOLD) scale.z = ACCURACY_THREASHOLD; + + + // Let's work on a local matrix containing rotation only + Mat3 matRot( + rotationScaleMatrix[0] / scale.x, + rotationScaleMatrix[1] / scale.y, + rotationScaleMatrix[2] / scale.z); + + // Beware!!! needs to detect for the case there is a negative scale + // Based on the determinant sign we just can flip the scale sign of one component: we choose X axis + float determinant = glm::determinant(matRot); + if (determinant < 0.f) { + scale.x = -scale.x; + // matRot[0] *= -1.f; + } + + // Beware: even though the matRot is supposed to be normalized at that point, + // glm::quat_cast doesn't always return a normalized quaternion... + setRotation(glm::normalize(glm::quat_cast(matRot))); + + // and assign the scale + setScale(scale); +} + +void Transform::evalFromRawMatrix(const Mat4& matrix) { + // for now works only in the case of TRS transformation + if ((matrix[0][3] == 0) && (matrix[1][3] == 0) && (matrix[2][3] == 0) && (matrix[3][3] == 1.f)) { + setTranslation(Vec3(matrix[3])); + evalRotationScale(Mat3(matrix)); + } +} + +Transform& Transform::evalInverseTranspose(Transform& result) { + result.setTranslation(-_translation); + result.setRotation(-_rotation); + + if (isScaling()) { + result.setScale(Vec3(1.f/_scale.x, 1.f/_scale.y, 1.f/_scale.z)); + } + return result; +} + + + diff --git a/interface/src/gpu/Transform.h b/libraries/shared/src/Transform.h similarity index 95% rename from interface/src/gpu/Transform.h rename to libraries/shared/src/Transform.h index 72dc843044..c2ed99de93 100644 --- a/interface/src/gpu/Transform.h +++ b/libraries/shared/src/Transform.h @@ -1,6 +1,6 @@ // // Transform.h -// interface/src/gpu +// shared/src/gpu // // Created by Sam Gateau on 11/4/2014. // Copyright 2014 High Fidelity, Inc. @@ -12,12 +12,6 @@ #define hifi_gpu_Transform_h #include -#include "InterfaceConfig.h" - -#include "gpu/Format.h" - - -#include #include #include @@ -26,8 +20,6 @@ #include -namespace gpu { - class Transform { public: typedef glm::mat4 Mat4; @@ -113,6 +105,13 @@ public: if ( right.isTranslating()) result.postTranslate(right.getTranslation()); if ( right.isRotating()) result.postRotate(right.getRotation()); if (right.isScaling()) result.postScale(right.getScale()); + + Transform::Mat4 mv = left.getMatrix() * right.getMatrix(); + Transform::Mat4 mv2 = result.getMatrix(); + + result.evalFromRawMatrix(mv); + Transform::Mat4 mv3 = result.getMatrix(); + return result; } @@ -181,10 +180,5 @@ protected: } }; -typedef QSharedPointer< Transform > TransformPointer; -typedef std::vector< TransformPointer > Transforms; - -}; - #endif From b716a512c69a8ae68b913c4c1a1940a0ec354fdd Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 00:26:44 -0800 Subject: [PATCH 07/44] Stable version of the Transform and usage for Model rendering with soimilar performances and same accuracy level --- interface/src/Application.cpp | 23 ++++++++++++++++------- interface/src/Application.h | 1 + interface/src/gpu/Batch.cpp | 10 ++++++++-- interface/src/gpu/Batch.h | 3 +-- interface/src/gpu/GLBackend.cpp | 1 + interface/src/renderer/Model.cpp | 3 ++- interface/src/ui/MetavoxelEditor.cpp | 4 +++- libraries/shared/src/Transform.cpp | 9 ++++----- libraries/shared/src/Transform.h | 2 +- 9 files changed, 37 insertions(+), 19 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c65e314cc2..923f7821d2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2805,6 +2805,8 @@ void Application::updateShadowMap() { // store view matrix without translation, which we'll use for precision-sensitive objects updateUntranslatedViewMatrix(); + // TODO: assign an equivalent viewTransform object to the application to match the current path which uses glMatrixStack + // setViewTransform(viewTransform); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt @@ -2883,6 +2885,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()"); // transform by eye offset + gpu::Transform viewTransform; // load the view frustum @@ -2902,9 +2905,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glm::quat eyeOffsetOrient = whichCamera.getEyeOffsetOrientation(); glm::vec3 eyeOffsetAxis = glm::axis(eyeOffsetOrient); glRotatef(-glm::degrees(glm::angle(eyeOffsetOrient)), eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z); - viewTransform.preRotate(glm::quat(-glm::angle(eyeOffsetOrient), glm::vec3(eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z))); - glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); - viewTransform.preTranslate(glm::vec3(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z)); + viewTransform.postRotate(glm::conjugate(eyeOffsetOrient)); + glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); + viewTransform.postTranslate(-eyeOffsetPos); // transform view according to whichCamera // could be myCamera (if in normal mode) @@ -2913,11 +2916,15 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glm::quat rotation = whichCamera.getRotation(); glm::vec3 axis = glm::axis(rotation); glRotatef(-glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - viewTransform.preRotate(glm::quat(-glm::angle(rotation), axis)); + viewTransform.postRotate(glm::conjugate(rotation)); // store view matrix without translation, which we'll use for precision-sensitive objects updateUntranslatedViewMatrix(-whichCamera.getPosition()); - viewTransform.preTranslate(-whichCamera.getPosition()); + + // Equivalent to what is happening with _untranslatedViewMatrix and the _viewMatrixTranslation + // the viewTransofmr object is updated with the correct value and saved, + // this is what is used for rendering the ENtities and avatars + setViewTransform(viewTransform); glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z); @@ -3120,8 +3127,10 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { void Application::updateUntranslatedViewMatrix(const glm::vec3& viewMatrixTranslation) { glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); _viewMatrixTranslation = viewMatrixTranslation; - _viewTransform->evalFromRawMatrix(_untranslatedViewMatrix); - _viewTransform->postTranslate(viewMatrixTranslation); +} + +void Application::setViewTransform(const gpu::Transform& view) { + (*_viewTransform) = view; } void Application::loadTranslatedViewMatrix(const glm::vec3& translation) { diff --git a/interface/src/Application.h b/interface/src/Application.h index ca8651867f..b59b9c90a0 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -234,6 +234,7 @@ public: void setViewMatrixTranslation(const glm::vec3& translation) { _viewMatrixTranslation = translation; } const gpu::TransformPointer& getViewTransform() const { return _viewTransform; } + void setViewTransform(const gpu::Transform& view); /// if you need to access the application settings, use lockSettings()/unlockSettings() QSettings* lockSettings() { _settingsMutex.lock(); return _settings; } diff --git a/interface/src/gpu/Batch.cpp b/interface/src/gpu/Batch.cpp index a29e0f87a3..2bf92f43cf 100644 --- a/interface/src/gpu/Batch.cpp +++ b/interface/src/gpu/Batch.cpp @@ -21,7 +21,11 @@ Batch::Batch() : _commandOffsets(), _params(), _resources(), - _data(){ + _data(), + _buffers(), + _streamFormats(), + _transforms() +{ } Batch::~Batch() { @@ -32,8 +36,10 @@ void Batch::clear() { _commandOffsets.clear(); _params.clear(); _resources.clear(); - _buffers.clear(); _data.clear(); + _buffers.clear(); + _streamFormats.clear(); + _transforms.clear(); } uint32 Batch::cacheResource(Resource* res) { diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index cbda6627d3..cc838a8839 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -316,13 +316,12 @@ public: CommandOffsets _commandOffsets; Params _params; Resources _resources; + Bytes _data; BufferCaches _buffers; StreamFormatCaches _streamFormats; - TransformCaches _transforms; - Bytes _data; protected: }; diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index df62b3813c..24141cccdc 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -458,6 +458,7 @@ void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { void GLBackend::updateTransform() { if (_transform._invalidProj) { + // TODO: implement the projection matrix assignment to gl state /* if (_transform._lastMode != GL_PROJECTION) { glMatrixMode(GL_PROJECTION); _transform._lastMode = GL_PROJECTION; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index dcf70e418d..0919850f97 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -560,7 +560,8 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { _transforms.push_back(gpu::TransformPointer(new gpu::Transform())); } (*_transforms[0]) = gpu::Transform((*Application::getInstance()->getViewTransform())); - _transforms[0]->postTranslate(_translation); + // apply entity translation + camera position offset to the viewTransform in one go + _transforms[0]->postTranslate(Application::getInstance()->getViewMatrixTranslation() + _translation); batch.setViewTransform(_transforms[0]); diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index e5a1f7f7a4..c0d8261427 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -919,7 +919,9 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb Application::getInstance()->setupWorldLight(); Application::getInstance()->updateUntranslatedViewMatrix(); - + // TODO: assign an equivalent viewTransform object to the application to match the current path which uses glMatrixStack + // setViewTransform(viewTransform); + const glm::vec4 OPAQUE_WHITE(1.0f, 1.0f, 1.0f, 1.0f); spannerData->getRenderer()->render(OPAQUE_WHITE, SpannerRenderer::DIFFUSE_MODE, glm::vec3(), 0.0f); diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index c7438a058c..7e4a3724c9 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -25,14 +25,12 @@ void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotat Mat3 rotationMat = rotationScaleMatrix; do { Mat3 nextRotation; - Mat3 currInvTranspose = - glm::inverse(glm::transpose(rotationMat)); + Mat3 currInvTranspose = glm::inverse(glm::transpose(rotationMat)); // Go through every component in the matrices and find the next matrix for (int i = 0; i < 3; i++) { for (int j = 0; j <3; j++) { - nextRotation[j][i] = 0.5f * - (rotationMat[j][i] + currInvTranspose[j][i]); + nextRotation[j][i] = 0.5f * (rotationMat[j][i] + currInvTranspose[j][i]); } } @@ -73,7 +71,8 @@ void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotat // Beware: even though the matRot is supposed to be normalized at that point, // glm::quat_cast doesn't always return a normalized quaternion... - rotation = glm::normalize(glm::quat_cast(matRot)); + // rotation = glm::normalize(glm::quat_cast(matRot)); + rotation = (glm::quat_cast(matRot)); } diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 37f8eddef8..635b4924c7 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -296,7 +296,7 @@ inline Transform& Transform::evalInverse(Transform& inverse) const { } } if (isRotating()) { - inverse.postRotate(-_rotation); + inverse.postRotate(glm::conjugate(_rotation)); } if (isTranslating()) { inverse.postTranslate(-_translation); From 6096a61ecc496496ac5631968d6d9d5af2dbb5f4 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 00:52:40 -0800 Subject: [PATCH 08/44] avoid for a new Transform for identity gpu::Batch::setTransformModel when rendering model part which are blend shapes --- interface/src/renderer/Model.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 0919850f97..1b723652f1 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1866,11 +1866,8 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl if (state.clusterMatrices.size() > 1) { GLBATCH(glUniformMatrix4fv)(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, (const float*)state.clusterMatrices.constData()); - - gpu::TransformPointer modelTransform(new gpu::Transform()); - batch.setModelTransform(modelTransform); + batch.setModelTransform(gpu::TransformPointer()); } else { - gpu::TransformPointer modelTransform(new gpu::Transform(state.clusterMatrices[0])); batch.setModelTransform(modelTransform); } From f634b1c5cb80feea4163591f9017f0ce4d7bea3b Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 01:03:53 -0800 Subject: [PATCH 09/44] avoid for a new Transform for identity gpu::Batch::setTransformModel when rendering model part which are blend shapes AND fix a bug in GLBackend when the ModelTransform is NULL then let's use the ViewTransform only --- interface/src/gpu/GLBackend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 24141cccdc..527739d8b0 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -489,7 +489,7 @@ void GLBackend::updateTransform() { _transform._lastMode = GL_MODELVIEW; } Transform::Mat4 modelView; - _transform._model->getMatrix(modelView); + _transform._view->getMatrix(modelView); glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); } else { // glLoadIdentity(); From 30615f09c5d9f3f530926eccf4e616c8bb45480d Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 01:07:28 -0800 Subject: [PATCH 10/44] fixing template syntax for linux, hope we can move to c++11 soon:) --- interface/src/gpu/Batch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index cc838a8839..773b1ee6a4 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -51,7 +51,7 @@ enum Primitive { }; typedef ::Transform Transform; -typedef QSharedPointer<::gpu::Transform> TransformPointer; +typedef QSharedPointer< ::gpu::Transform > TransformPointer; typedef std::vector< TransformPointer > Transforms; class Batch { From e47524d70a357fc8bc5ea1e0e1ae7c83d8ae1f38 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 10:41:50 -0800 Subject: [PATCH 11/44] fix syntax and missing constant name --- libraries/shared/src/Transform.cpp | 6 ++-- libraries/shared/src/Transform.h | 46 +++++++++++++++++++----------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index 7e4a3724c9..4c049a8f92 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -24,15 +24,15 @@ void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotat int count = 0; Mat3 rotationMat = rotationScaleMatrix; do { - Mat3 nextRotation; Mat3 currInvTranspose = glm::inverse(glm::transpose(rotationMat)); + Mat3 nextRotation = 0.5f * (rotationMat + currInvTranspose); // Go through every component in the matrices and find the next matrix - for (int i = 0; i < 3; i++) { + /* for (int i = 0; i < 3; i++) { for (int j = 0; j <3; j++) { nextRotation[j][i] = 0.5f * (rotationMat[j][i] + currInvTranspose[j][i]); } - } + }*/ norm = 0.0; for (int i = 0; i < 3; i++) { diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 635b4924c7..13e30f6520 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -31,9 +31,9 @@ public: Transform() : _translation(0), - _rotation(1.f, 0, 0, 0), - _scale(1.f), - _flags(1) // invalid cache + _rotation(1.0f, 0, 0, 0), + _scale(1.0f), + _flags(FLAG_CACHE_INVALID_BITSET) // invalid cache { } Transform(const Transform& transform) : @@ -67,7 +67,7 @@ public: void postScale(float scale); void postScale(const Vec3& scale); - bool isIdentity() const { return (_flags & ~Flags(1)).none(); } + bool isIdentity() const { return (_flags & ~Flags(FLAG_CACHE_INVALID_BITSET)).none(); } bool isTranslating() const { return _flags[FLAG_TRANSLATION]; } bool isRotating() const { return _flags[FLAG_ROTATION]; } bool isScaling() const { return _flags[FLAG_SCALING]; } @@ -99,8 +99,9 @@ protected: FLAG_PROJECTION, NUM_FLAGS, - }; + FLAG_CACHE_INVALID_BITSET = 1, + }; typedef std::bitset Flags; @@ -133,9 +134,9 @@ protected: inline void Transform::setIdentity() { _translation = Vec3(0); - _rotation = Quat(1.f, 0, 0, 0); - _scale = Vec3(1.f); - _flags = Flags(1); + _rotation = Quat(1.0f, 0, 0, 0); + _scale = Vec3(1.0f); + _flags = Flags(FLAG_CACHE_INVALID_BITSET); } inline const Transform::Vec3& Transform::getTranslation() const { @@ -224,7 +225,7 @@ inline const Transform::Vec3& Transform::getScale() const { inline void Transform::setScale(float scale) { invalidCache(); flagUniform(); - if (scale == 1.f) { + if (scale == 1.0f) { unflagScaling(); } else { flagScaling(); @@ -244,7 +245,7 @@ inline void Transform::setScale(const Vec3& scale) { } inline void Transform::postScale(float scale) { - if (scale == 1.f) return; + if (scale == 1.0f) return; if (isScaling()) { // if already scaling, just invalid cache and aply uniform scale invalidCache(); @@ -289,10 +290,15 @@ inline void Transform::evalFromRawMatrix(const Mat3& rotationScaleMatrix) { inline Transform& Transform::evalInverse(Transform& inverse) const { inverse.setIdentity(); if (isScaling()) { + // TODO: At some point we will face the case when scale is 0 and so 1/0 will blow up... + // WHat should we do for this one? + assert(_scale.x != 0); + assert(_scale.y != 0); + assert(_scale.z != 0); if (isNonUniform()) { - inverse.setScale(Vec3(1.f/_scale.x, 1.f/_scale.y, 1.f/_scale.z)); + inverse.setScale(Vec3(1.0f/_scale.x, 1.0f/_scale.y, 1.0f/_scale.z)); } else { - inverse.setScale(1.f/_scale.x); + inverse.setScale(1.0f/_scale.x); } } if (isRotating()) { @@ -306,9 +312,15 @@ inline Transform& Transform::evalInverse(Transform& inverse) const { inline Transform& Transform::mult( Transform& result, const Transform& left, const Transform& right) { result = left; - if ( right.isTranslating()) result.postTranslate(right.getTranslation()); - if ( right.isRotating()) result.postRotate(right.getRotation()); - if (right.isScaling()) result.postScale(right.getScale()); + if (right.isTranslating()) { + result.postTranslate(right.getTranslation()); + } + if (right.isRotating()) { + result.postRotate(right.getRotation()); + } + if (right.isScaling()) { + result.postScale(right.getScale()); + } // HACK: In case of an issue in the Transform multiplication results, to make sure this code is // working properly uncomment the next 2 lines and compare the results, they should be the same... @@ -321,7 +333,7 @@ inline Transform& Transform::mult( Transform& result, const Transform& left, con inline void Transform::updateCache() const { if (isCacheInvalid()) { if (isRotating()) { - glm::mat3x3 rot = glm::mat3_cast(_rotation); + Mat3 rot = glm::mat3_cast(_rotation); if (isScaling()) { rot[0] *= _scale.x; @@ -338,7 +350,7 @@ inline void Transform::updateCache() const { _matrix[2] = Vec4(0.f, 0.f, _scale.z, 0.f); } - _matrix[3] = Vec4(_translation, 1.f); + _matrix[3] = Vec4(_translation, 1.0f); validCache(); } } From 4b22dadf0971c20749f9f0734f34762b704cb90c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 11:53:22 -0800 Subject: [PATCH 12/44] first cut at implementing model scene rendering --- interface/src/avatar/MyAvatar.cpp | 1 + interface/src/entities/EntityTreeRenderer.cpp | 35 +- .../entities/RenderableModelEntityItem.cpp | 3 +- interface/src/renderer/AnimationHandle.cpp | 176 ++++++++ interface/src/renderer/AnimationHandle.h | 112 +++++ interface/src/renderer/Model.cpp | 391 +++++++++++------- interface/src/renderer/Model.h | 103 +---- 7 files changed, 578 insertions(+), 243 deletions(-) create mode 100644 interface/src/renderer/AnimationHandle.cpp create mode 100644 interface/src/renderer/AnimationHandle.h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9ceb073167..cab1913e14 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -39,6 +39,7 @@ #include "Recorder.h" #include "devices/Faceshift.h" #include "devices/OculusManager.h" +#include "renderer/AnimationHandle.h" #include "ui/TextRenderer.h" using namespace std; diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 1876b6c624..0107b43293 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -253,7 +253,40 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { } void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode) { - OctreeRenderer::render(renderMode); + Model::startScene(); + //OctreeRenderer::render(renderMode); + + RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + if (_tree) { + _tree->lockForRead(); + _tree->recurseTreeWithOperation(renderOperation, &args); + _tree->unlock(); + } + + Model::RenderMode modelRenderMode = renderMode == RenderArgs::SHADOW_RENDER_MODE + ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + + Model::endScene(modelRenderMode, &args); + + // stats... + _meshesConsidered = args._meshesConsidered; + _meshesRendered = args._meshesRendered; + _meshesOutOfView = args._meshesOutOfView; + _meshesTooSmall = args._meshesTooSmall; + + _elementsTouched = args._elementsTouched; + _itemsRendered = args._itemsRendered; + _itemsOutOfView = args._itemsOutOfView; + _itemsTooSmall = args._itemsTooSmall; + + _materialSwitches = args._materialSwitches; + _trianglesRendered = args._trianglesRendered; + _quadsRendered = args._quadsRendered; + + _translucentMeshPartsRendered = args._translucentMeshPartsRendered; + _opaqueMeshPartsRendered = args._opaqueMeshPartsRendered; + deleteReleasedModels(); // seems like as good as any other place to do some memory cleanup } diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 3cee527273..7feecfafd7 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -172,7 +172,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // TODO: this is the majority of model render time. And rendering of a cube model vs the basic Box render // is significantly more expensive. Is there a way to call this that doesn't cost us as much? PerformanceTimer perfTimer("model->render"); - _model->render(alpha, modelRenderMode, args); + //_model->render(alpha, modelRenderMode, args); + _model->renderInScene(alpha, args); } else { // if we couldn't get a model, then just draw a cube glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]); diff --git a/interface/src/renderer/AnimationHandle.cpp b/interface/src/renderer/AnimationHandle.cpp new file mode 100644 index 0000000000..246ebaa9ed --- /dev/null +++ b/interface/src/renderer/AnimationHandle.cpp @@ -0,0 +1,176 @@ +// +// Model.cpp +// interface/src/renderer +// +// Created by Andrzej Kapolka on 10/18/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AnimationHandle.h" +#include "Application.h" + +void AnimationHandle::setURL(const QUrl& url) { + if (_url != url) { + _animation = Application::getInstance()->getAnimationCache()->getAnimation(_url = url); + _jointMappings.clear(); + } +} + +static void insertSorted(QList& handles, const AnimationHandlePointer& handle) { + for (QList::iterator it = handles.begin(); it != handles.end(); it++) { + if (handle->getPriority() > (*it)->getPriority()) { + handles.insert(it, handle); + return; + } + } + handles.append(handle); +} + +void AnimationHandle::setPriority(float priority) { + if (_priority == priority) { + return; + } + if (_running) { + _model->_runningAnimations.removeOne(_self); + if (priority < _priority) { + replaceMatchingPriorities(priority); + } + _priority = priority; + insertSorted(_model->_runningAnimations, _self); + + } else { + _priority = priority; + } +} + +void AnimationHandle::setStartAutomatically(bool startAutomatically) { + if ((_startAutomatically = startAutomatically) && !_running) { + start(); + } +} + +void AnimationHandle::setMaskedJoints(const QStringList& maskedJoints) { + _maskedJoints = maskedJoints; + _jointMappings.clear(); +} + +void AnimationHandle::setRunning(bool running) { + if (_running == running) { + if (running) { + // move back to the beginning + _frameIndex = _firstFrame; + } + return; + } + if ((_running = running)) { + if (!_model->_runningAnimations.contains(_self)) { + insertSorted(_model->_runningAnimations, _self); + } + _frameIndex = _firstFrame; + + } else { + _model->_runningAnimations.removeOne(_self); + replaceMatchingPriorities(0.0f); + } + emit runningChanged(_running); +} + +AnimationHandle::AnimationHandle(Model* model) : + QObject(model), + _model(model), + _fps(30.0f), + _priority(1.0f), + _loop(false), + _hold(false), + _startAutomatically(false), + _firstFrame(0.0f), + _lastFrame(FLT_MAX), + _running(false) { +} + +AnimationDetails AnimationHandle::getAnimationDetails() const { + AnimationDetails details(_role, _url, _fps, _priority, _loop, _hold, + _startAutomatically, _firstFrame, _lastFrame, _running, _frameIndex); + return details; +} + + +void AnimationHandle::simulate(float deltaTime) { + _frameIndex += deltaTime * _fps; + + // update the joint mappings if necessary/possible + if (_jointMappings.isEmpty()) { + if (_model->isActive()) { + _jointMappings = _model->getGeometry()->getJointMappings(_animation); + } + if (_jointMappings.isEmpty()) { + return; + } + if (!_maskedJoints.isEmpty()) { + const FBXGeometry& geometry = _model->getGeometry()->getFBXGeometry(); + for (int i = 0; i < _jointMappings.size(); i++) { + int& mapping = _jointMappings[i]; + if (mapping != -1 && _maskedJoints.contains(geometry.joints.at(mapping).name)) { + mapping = -1; + } + } + } + } + + const FBXGeometry& animationGeometry = _animation->getGeometry(); + if (animationGeometry.animationFrames.isEmpty()) { + stop(); + return; + } + float endFrameIndex = qMin(_lastFrame, animationGeometry.animationFrames.size() - (_loop ? 0.0f : 1.0f)); + float startFrameIndex = qMin(_firstFrame, endFrameIndex); + if ((!_loop && (_frameIndex < startFrameIndex || _frameIndex > endFrameIndex)) || startFrameIndex == endFrameIndex) { + // passed the end; apply the last frame + applyFrame(glm::clamp(_frameIndex, startFrameIndex, endFrameIndex)); + if (!_hold) { + stop(); + } + return; + } + // wrap within the the desired range + if (_frameIndex < startFrameIndex) { + _frameIndex = endFrameIndex - glm::mod(endFrameIndex - _frameIndex, endFrameIndex - startFrameIndex); + + } else if (_frameIndex > endFrameIndex) { + _frameIndex = startFrameIndex + glm::mod(_frameIndex - startFrameIndex, endFrameIndex - startFrameIndex); + } + + // blend between the closest two frames + applyFrame(_frameIndex); +} + +void AnimationHandle::applyFrame(float frameIndex) { + const FBXGeometry& animationGeometry = _animation->getGeometry(); + int frameCount = animationGeometry.animationFrames.size(); + const FBXAnimationFrame& floorFrame = animationGeometry.animationFrames.at((int)glm::floor(frameIndex) % frameCount); + const FBXAnimationFrame& ceilFrame = animationGeometry.animationFrames.at((int)glm::ceil(frameIndex) % frameCount); + float frameFraction = glm::fract(frameIndex); + for (int i = 0; i < _jointMappings.size(); i++) { + int mapping = _jointMappings.at(i); + if (mapping != -1) { + JointState& state = _model->_jointStates[mapping]; + state.setRotationInConstrainedFrame(safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction), _priority); + } + } +} + +void AnimationHandle::replaceMatchingPriorities(float newPriority) { + for (int i = 0; i < _jointMappings.size(); i++) { + int mapping = _jointMappings.at(i); + if (mapping != -1) { + JointState& state = _model->_jointStates[mapping]; + if (_priority == state._animationPriority) { + state._animationPriority = newPriority; + } + } + } +} + diff --git a/interface/src/renderer/AnimationHandle.h b/interface/src/renderer/AnimationHandle.h new file mode 100644 index 0000000000..3b736698df --- /dev/null +++ b/interface/src/renderer/AnimationHandle.h @@ -0,0 +1,112 @@ +// +// AnimationHandle.h +// interface/src/renderer +// +// Created by Andrzej Kapolka on 10/18/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AnimationHandle_h +#define hifi_AnimationHandle_h + +#include +#include +#include +#include +#include + +#include + +class AnimationHandle; +class Model; + +typedef QSharedPointer AnimationHandlePointer; +typedef QWeakPointer WeakAnimationHandlePointer; + + +/// Represents a handle to a model animation. +class AnimationHandle : public QObject { + Q_OBJECT + +public: + + void setRole(const QString& role) { _role = role; } + const QString& getRole() const { return _role; } + + void setURL(const QUrl& url); + const QUrl& getURL() const { return _url; } + + void setFPS(float fps) { _fps = fps; } + float getFPS() const { return _fps; } + + void setPriority(float priority); + float getPriority() const { return _priority; } + + void setLoop(bool loop) { _loop = loop; } + bool getLoop() const { return _loop; } + + void setHold(bool hold) { _hold = hold; } + bool getHold() const { return _hold; } + + void setStartAutomatically(bool startAutomatically); + bool getStartAutomatically() const { return _startAutomatically; } + + void setFirstFrame(float firstFrame) { _firstFrame = firstFrame; } + float getFirstFrame() const { return _firstFrame; } + + void setLastFrame(float lastFrame) { _lastFrame = lastFrame; } + float getLastFrame() const { return _lastFrame; } + + void setMaskedJoints(const QStringList& maskedJoints); + const QStringList& getMaskedJoints() const { return _maskedJoints; } + + void setRunning(bool running); + bool isRunning() const { return _running; } + + void setFrameIndex(float frameIndex) { _frameIndex = glm::clamp(_frameIndex, _firstFrame, _lastFrame); } + float getFrameIndex() const { return _frameIndex; } + + AnimationDetails getAnimationDetails() const; + +signals: + + void runningChanged(bool running); + +public slots: + + void start() { setRunning(true); } + void stop() { setRunning(false); } + +private: + + friend class Model; + + AnimationHandle(Model* model); + + void simulate(float deltaTime); + void applyFrame(float frameIndex); + void replaceMatchingPriorities(float newPriority); + + Model* _model; + WeakAnimationHandlePointer _self; + AnimationPointer _animation; + QString _role; + QUrl _url; + float _fps; + float _priority; + bool _loop; + bool _hold; + bool _startAutomatically; + float _firstFrame; + float _lastFrame; + QStringList _maskedJoints; + bool _running; + QVector _jointMappings; + float _frameIndex; +}; + + +#endif // hifi_AnimationHandle_h diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 8d426d067b..6252e7c2d7 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -23,6 +23,7 @@ #include #include +#include "AnimationHandle.h" #include "Application.h" #include "Model.h" @@ -517,17 +518,7 @@ void Model::recalcuateMeshBoxes() { } } -bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { - PROFILE_RANGE(__FUNCTION__); - - // render the attachments - foreach (Model* attachment, _attachments) { - attachment->render(alpha, mode); - } - if (_meshStates.isEmpty()) { - return false; - } - +void Model::renderSetup(RenderArgs* args) { // if we don't have valid mesh boxes, calculate them now, this only matters in cases // where our caller has passed RenderArgs which will include a view frustum we can cull // against. We cache the results of these calculations so long as the model hasn't been @@ -549,6 +540,25 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { if (!_meshGroupsKnown) { segregateMeshGroups(); } +} + +bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { + PROFILE_RANGE(__FUNCTION__); + + // render the attachments + foreach (Model* attachment, _attachments) { + attachment->render(alpha, mode); + } + if (_meshStates.isEmpty()) { + return false; + } + + renderSetup(args); + return renderCore(alpha, mode, args); +} + +bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { + PROFILE_RANGE(__FUNCTION__); // Let's introduce a gpu::Batch to capture all the calls to the graphics api gpu::Batch batch; @@ -1981,165 +1991,236 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl return meshPartsRendered; } -void AnimationHandle::setURL(const QUrl& url) { - if (_url != url) { - _animation = Application::getInstance()->getAnimationCache()->getAnimation(_url = url); - _jointMappings.clear(); - } + + +// Scene rendering support +QVector Model::_modelsInScene; +void Model::startScene() { + _modelsInScene.clear(); } -static void insertSorted(QList& handles, const AnimationHandlePointer& handle) { - for (QList::iterator it = handles.begin(); it != handles.end(); it++) { - if (handle->getPriority() > (*it)->getPriority()) { - handles.insert(it, handle); - return; - } - } - handles.append(handle); -} +void Model::endSceneSplitPass(RenderMode mode, RenderArgs* args) { -void AnimationHandle::setPriority(float priority) { - if (_priority == priority) { - return; - } - if (_running) { - _model->_runningAnimations.removeOne(_self); - if (priority < _priority) { - replaceMatchingPriorities(priority); - } - _priority = priority; - insertSorted(_model->_runningAnimations, _self); - + // first, do all the batch/GPU setup work.... + // Let's introduce a gpu::Batch to capture all the calls to the graphics api + gpu::Batch batch; + + + GLBATCH(glDisable)(GL_COLOR_MATERIAL); + + if (mode == DIFFUSE_RENDER_MODE || mode == NORMAL_RENDER_MODE) { + GLBATCH(glDisable)(GL_CULL_FACE); } else { - _priority = priority; - } -} - -void AnimationHandle::setStartAutomatically(bool startAutomatically) { - if ((_startAutomatically = startAutomatically) && !_running) { - start(); - } -} - -void AnimationHandle::setMaskedJoints(const QStringList& maskedJoints) { - _maskedJoints = maskedJoints; - _jointMappings.clear(); -} - -void AnimationHandle::setRunning(bool running) { - if (_running == running) { - if (running) { - // move back to the beginning - _frameIndex = _firstFrame; - } - return; - } - if ((_running = running)) { - if (!_model->_runningAnimations.contains(_self)) { - insertSorted(_model->_runningAnimations, _self); - } - _frameIndex = _firstFrame; - - } else { - _model->_runningAnimations.removeOne(_self); - replaceMatchingPriorities(0.0f); - } - emit runningChanged(_running); -} - -AnimationHandle::AnimationHandle(Model* model) : - QObject(model), - _model(model), - _fps(30.0f), - _priority(1.0f), - _loop(false), - _hold(false), - _startAutomatically(false), - _firstFrame(0.0f), - _lastFrame(FLT_MAX), - _running(false) { -} - -AnimationDetails AnimationHandle::getAnimationDetails() const { - AnimationDetails details(_role, _url, _fps, _priority, _loop, _hold, - _startAutomatically, _firstFrame, _lastFrame, _running, _frameIndex); - return details; -} - - -void AnimationHandle::simulate(float deltaTime) { - _frameIndex += deltaTime * _fps; - - // update the joint mappings if necessary/possible - if (_jointMappings.isEmpty()) { - if (_model->isActive()) { - _jointMappings = _model->getGeometry()->getJointMappings(_animation); - } - if (_jointMappings.isEmpty()) { - return; - } - if (!_maskedJoints.isEmpty()) { - const FBXGeometry& geometry = _model->getGeometry()->getFBXGeometry(); - for (int i = 0; i < _jointMappings.size(); i++) { - int& mapping = _jointMappings[i]; - if (mapping != -1 && _maskedJoints.contains(geometry.joints.at(mapping).name)) { - mapping = -1; - } - } + GLBATCH(glEnable)(GL_CULL_FACE); + if (mode == SHADOW_RENDER_MODE) { + GLBATCH(glCullFace)(GL_FRONT); } } - const FBXGeometry& animationGeometry = _animation->getGeometry(); - if (animationGeometry.animationFrames.isEmpty()) { - stop(); - return; - } - float endFrameIndex = qMin(_lastFrame, animationGeometry.animationFrames.size() - (_loop ? 0.0f : 1.0f)); - float startFrameIndex = qMin(_firstFrame, endFrameIndex); - if ((!_loop && (_frameIndex < startFrameIndex || _frameIndex > endFrameIndex)) || startFrameIndex == endFrameIndex) { - // passed the end; apply the last frame - applyFrame(glm::clamp(_frameIndex, startFrameIndex, endFrameIndex)); - if (!_hold) { - stop(); - } - return; - } - // wrap within the the desired range - if (_frameIndex < startFrameIndex) { - _frameIndex = endFrameIndex - glm::mod(endFrameIndex - _frameIndex, endFrameIndex - startFrameIndex); + // render opaque meshes with alpha testing + + GLBATCH(glDisable)(GL_BLEND); + GLBATCH(glEnable)(GL_ALPHA_TEST); - } else if (_frameIndex > endFrameIndex) { - _frameIndex = startFrameIndex + glm::mod(_frameIndex - startFrameIndex, endFrameIndex - startFrameIndex); + if (mode == SHADOW_RENDER_MODE) { + GLBATCH(glAlphaFunc)(GL_EQUAL, 0.0f); + } + + + /*Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers( + mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE, + mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE, + mode == DEFAULT_RENDER_MODE); + */ + { + GLenum buffers[3]; + int bufferCount = 0; + if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { + buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; + } + if (mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE) { + buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; + } + if (mode == DEFAULT_RENDER_MODE) { + buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; + } + GLBATCH(glDrawBuffers)(bufferCount, buffers); + } + + const float DEFAULT_ALPHA_THRESHOLD = 0.5f; + + int opaqueMeshPartsRendered = 0; + + // now, for each model in the scene, render the mesh portions + float alpha = 1.0f; // at this point we don't support per model alphas + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); } - // blend between the closest two frames - applyFrame(_frameIndex); -} + // render translucent meshes afterwards + //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true); + { + GLenum buffers[2]; + int bufferCount = 0; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; + GLBATCH(glDrawBuffers)(bufferCount, buffers); + } -void AnimationHandle::applyFrame(float frameIndex) { - const FBXGeometry& animationGeometry = _animation->getGeometry(); - int frameCount = animationGeometry.animationFrames.size(); - const FBXAnimationFrame& floorFrame = animationGeometry.animationFrames.at((int)glm::floor(frameIndex) % frameCount); - const FBXAnimationFrame& ceilFrame = animationGeometry.animationFrames.at((int)glm::ceil(frameIndex) % frameCount); - float frameFraction = glm::fract(frameIndex); - for (int i = 0; i < _jointMappings.size(); i++) { - int mapping = _jointMappings.at(i); - if (mapping != -1) { - JointState& state = _model->_jointStates[mapping]; - state.setRotationInConstrainedFrame(safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction), _priority); + int translucentMeshPartsRendered = 0; + const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); + } + + GLBATCH(glDisable)(GL_ALPHA_TEST); + GLBATCH(glEnable)(GL_BLEND); + GLBATCH(glDepthMask)(false); + GLBATCH(glDepthFunc)(GL_LEQUAL); + + //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true); + { + GLenum buffers[1]; + int bufferCount = 0; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; + GLBATCH(glDrawBuffers)(bufferCount, buffers); + } + + if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { + const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args); } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); + } + } + + GLBATCH(glDepthMask)(true); + GLBATCH(glDepthFunc)(GL_LESS); + GLBATCH(glDisable)(GL_CULL_FACE); + + if (mode == SHADOW_RENDER_MODE) { + GLBATCH(glCullFace)(GL_BACK); + } + + // deactivate vertex arrays after drawing + GLBATCH(glDisableClientState)(GL_NORMAL_ARRAY); + GLBATCH(glDisableClientState)(GL_VERTEX_ARRAY); + GLBATCH(glDisableClientState)(GL_TEXTURE_COORD_ARRAY); + GLBATCH(glDisableClientState)(GL_COLOR_ARRAY); + GLBATCH(glDisableVertexAttribArray)(gpu::Stream::TANGENT); + GLBATCH(glDisableVertexAttribArray)(gpu::Stream::SKIN_CLUSTER_INDEX); + GLBATCH(glDisableVertexAttribArray)(gpu::Stream::SKIN_CLUSTER_WEIGHT); + + // bind with 0 to switch back to normal operation + GLBATCH(glBindBuffer)(GL_ARRAY_BUFFER, 0); + GLBATCH(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, 0); + GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); + + // Render! + { + PROFILE_RANGE("render Batch"); + ::gpu::GLBackend::renderBatch(batch); + batch.clear(); + } + + // restore all the default material settings + Application::getInstance()->setupWorldLight(); + + if (args) { + args->_translucentMeshPartsRendered = translucentMeshPartsRendered; + args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered; } } -void AnimationHandle::replaceMatchingPriorities(float newPriority) { - for (int i = 0; i < _jointMappings.size(); i++) { - int mapping = _jointMappings.at(i); - if (mapping != -1) { - JointState& state = _model->_jointStates[mapping]; - if (_priority == state._animationPriority) { - state._animationPriority = newPriority; - } - } +void Model::endScene(RenderMode mode, RenderArgs* args) { + //endSceneSimple(mode, args); + endSceneSplitPass(mode, args); +} + +void Model::endSceneSimple(RenderMode mode, RenderArgs* args) { + // now, for each model in the scene, render the mesh portions + foreach(Model* model, _modelsInScene) { + float alpha = 1.0f; + model->render(alpha, mode, args); } } +bool Model::renderInScene(float alpha, RenderArgs* args) { + // do we really need alpha? + + // render the attachments + foreach (Model* attachment, _attachments) { + attachment->renderInScene(alpha); + } + if (_meshStates.isEmpty()) { + return false; + } + + renderSetup(args); + + _modelsInScene.push_back(this); + return true; +} + diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 34d6a34c06..d77501e0f9 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -20,6 +20,7 @@ #include #include +#include "AnimationHandle.h" #include "GeometryCache.h" #include "InterfaceConfig.h" #include "JointState.h" @@ -28,14 +29,10 @@ class QScriptEngine; -class AnimationHandle; class Shape; class RenderArgs; class ViewFrustum; -typedef QSharedPointer AnimationHandlePointer; -typedef QWeakPointer WeakAnimationHandlePointer; - namespace gpu { class Batch; } @@ -93,6 +90,12 @@ public: enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE }; bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); + bool renderCore(float alpha, RenderMode mode, RenderArgs* args); + + // Scene rendering support + static void startScene(); + bool renderInScene(float alpha = 1.0f, RenderArgs* args = NULL); + static void endScene(RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); /// Sets the URL of the model to render. /// \param fallback the URL of a fallback model to render if the requested model fails to load @@ -259,14 +262,13 @@ protected: /// Computes and returns the extended length of the limb terminating at the specified joint and starting at the joint's /// first free ancestor. float getLimbLength(int jointIndex) const; - + private: friend class AnimationHandle; void applyNextGeometry(); void deleteGeometry(); - int renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL); QVector createJointStates(const FBXGeometry& geometry); void initJointTransforms(); @@ -394,91 +396,20 @@ private: QVector _meshesOpaqueTangentsSpecularSkinned; QVector _meshesOpaqueSpecularSkinned; + // Scene rendering support + static QVector _modelsInScene; + static void endSceneSimple(RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); + static void endSceneSplitPass(RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); + + // helper functions used by render() or renderInScene() + void renderSetup(RenderArgs* args); + int renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, + bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL); }; Q_DECLARE_METATYPE(QPointer) Q_DECLARE_METATYPE(QWeakPointer) Q_DECLARE_METATYPE(QVector) -/// Represents a handle to a model animation. -class AnimationHandle : public QObject { - Q_OBJECT - -public: - - void setRole(const QString& role) { _role = role; } - const QString& getRole() const { return _role; } - - void setURL(const QUrl& url); - const QUrl& getURL() const { return _url; } - - void setFPS(float fps) { _fps = fps; } - float getFPS() const { return _fps; } - - void setPriority(float priority); - float getPriority() const { return _priority; } - - void setLoop(bool loop) { _loop = loop; } - bool getLoop() const { return _loop; } - - void setHold(bool hold) { _hold = hold; } - bool getHold() const { return _hold; } - - void setStartAutomatically(bool startAutomatically); - bool getStartAutomatically() const { return _startAutomatically; } - - void setFirstFrame(float firstFrame) { _firstFrame = firstFrame; } - float getFirstFrame() const { return _firstFrame; } - - void setLastFrame(float lastFrame) { _lastFrame = lastFrame; } - float getLastFrame() const { return _lastFrame; } - - void setMaskedJoints(const QStringList& maskedJoints); - const QStringList& getMaskedJoints() const { return _maskedJoints; } - - void setRunning(bool running); - bool isRunning() const { return _running; } - - void setFrameIndex(float frameIndex) { _frameIndex = glm::clamp(_frameIndex, _firstFrame, _lastFrame); } - float getFrameIndex() const { return _frameIndex; } - - AnimationDetails getAnimationDetails() const; - -signals: - - void runningChanged(bool running); - -public slots: - - void start() { setRunning(true); } - void stop() { setRunning(false); } - -private: - - friend class Model; - - AnimationHandle(Model* model); - - void simulate(float deltaTime); - void applyFrame(float frameIndex); - void replaceMatchingPriorities(float newPriority); - - Model* _model; - WeakAnimationHandlePointer _self; - AnimationPointer _animation; - QString _role; - QUrl _url; - float _fps; - float _priority; - bool _loop; - bool _hold; - bool _startAutomatically; - float _firstFrame; - float _lastFrame; - QStringList _maskedJoints; - bool _running; - QVector _jointMappings; - float _frameIndex; -}; #endif // hifi_Model_h From 4245da51574bd8f5a8d67e373556f6e364089740 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 12:07:27 -0800 Subject: [PATCH 13/44] add menu item to enable/disable rendering as scene --- interface/src/Menu.cpp | 7 +- interface/src/Menu.h | 1 + interface/src/entities/EntityTreeRenderer.cpp | 67 ++++++++++--------- .../entities/RenderableModelEntityItem.cpp | 8 ++- 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index cd074805b6..075fab38b8 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -438,10 +438,15 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisplayModelElementChildProxies, 0, false); addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisableLightEntities, 0, false); + addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DontReduceMaterialSwitches, 0, false); + addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DontRenderEntitiesAsScene, 0, false); + QMenu* entityCullingMenu = entitiesDebugMenu->addMenu("Culling"); addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontCullOutOfViewMeshParts, 0, false); addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontCullTooSmallMeshParts, 0, false); - addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontReduceMaterialSwitches, 0, false); + + + QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxels"); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 8af91ccae4..56e98def9d 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -378,6 +378,7 @@ namespace MenuOption { const QString DontCullOutOfViewMeshParts = "Don't Cull Out Of View Mesh Parts"; const QString DontCullTooSmallMeshParts = "Don't Cull Too Small Mesh Parts"; const QString DontReduceMaterialSwitches = "Don't Attempt to Reduce Material Switches"; + const QString DontRenderEntitiesAsScene = "Don't Render Entities as Scene"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableActivityLogger = "Disable Activity Logger"; diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 0107b43293..6961df4680 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -253,40 +253,43 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { } void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode) { - Model::startScene(); - //OctreeRenderer::render(renderMode); + bool dontRenderAsScene = Menu::getInstance()->isOptionChecked(MenuOption::DontRenderEntitiesAsScene); - RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - if (_tree) { - _tree->lockForRead(); - _tree->recurseTreeWithOperation(renderOperation, &args); - _tree->unlock(); + if (dontRenderAsScene) { + OctreeRenderer::render(renderMode); + } else { + Model::startScene(); + RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + if (_tree) { + _tree->lockForRead(); + _tree->recurseTreeWithOperation(renderOperation, &args); + _tree->unlock(); + } + + Model::RenderMode modelRenderMode = renderMode == RenderArgs::SHADOW_RENDER_MODE + ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + + Model::endScene(modelRenderMode, &args); + + // stats... + _meshesConsidered = args._meshesConsidered; + _meshesRendered = args._meshesRendered; + _meshesOutOfView = args._meshesOutOfView; + _meshesTooSmall = args._meshesTooSmall; + + _elementsTouched = args._elementsTouched; + _itemsRendered = args._itemsRendered; + _itemsOutOfView = args._itemsOutOfView; + _itemsTooSmall = args._itemsTooSmall; + + _materialSwitches = args._materialSwitches; + _trianglesRendered = args._trianglesRendered; + _quadsRendered = args._quadsRendered; + + _translucentMeshPartsRendered = args._translucentMeshPartsRendered; + _opaqueMeshPartsRendered = args._opaqueMeshPartsRendered; } - - Model::RenderMode modelRenderMode = renderMode == RenderArgs::SHADOW_RENDER_MODE - ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; - - Model::endScene(modelRenderMode, &args); - - // stats... - _meshesConsidered = args._meshesConsidered; - _meshesRendered = args._meshesRendered; - _meshesOutOfView = args._meshesOutOfView; - _meshesTooSmall = args._meshesTooSmall; - - _elementsTouched = args._elementsTouched; - _itemsRendered = args._itemsRendered; - _itemsOutOfView = args._itemsOutOfView; - _itemsTooSmall = args._itemsTooSmall; - - _materialSwitches = args._materialSwitches; - _trianglesRendered = args._trianglesRendered; - _quadsRendered = args._quadsRendered; - - _translucentMeshPartsRendered = args._translucentMeshPartsRendered; - _opaqueMeshPartsRendered = args._opaqueMeshPartsRendered; - deleteReleasedModels(); // seems like as good as any other place to do some memory cleanup } diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 7feecfafd7..0864b34d0e 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -172,8 +172,12 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // TODO: this is the majority of model render time. And rendering of a cube model vs the basic Box render // is significantly more expensive. Is there a way to call this that doesn't cost us as much? PerformanceTimer perfTimer("model->render"); - //_model->render(alpha, modelRenderMode, args); - _model->renderInScene(alpha, args); + bool dontRenderAsScene = Menu::getInstance()->isOptionChecked(MenuOption::DontRenderEntitiesAsScene); + if (dontRenderAsScene) { + _model->render(alpha, modelRenderMode, args); + } else { + _model->renderInScene(alpha, args); + } } else { // if we couldn't get a model, then just draw a cube glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]); From 9f3f815f5594000ddafa1d7b6e03902d0e06270f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 12:10:57 -0800 Subject: [PATCH 14/44] shuffle to hopefully cleanup diff --- interface/src/renderer/AnimationHandle.cpp | 2 +- interface/src/renderer/Model.cpp | 461 ++++++++++----------- 2 files changed, 228 insertions(+), 235 deletions(-) diff --git a/interface/src/renderer/AnimationHandle.cpp b/interface/src/renderer/AnimationHandle.cpp index 246ebaa9ed..8ecf5d9699 100644 --- a/interface/src/renderer/AnimationHandle.cpp +++ b/interface/src/renderer/AnimationHandle.cpp @@ -1,5 +1,5 @@ // -// Model.cpp +// AnimationHandle.cpp // interface/src/renderer // // Created by Andrzej Kapolka on 10/18/13. diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 6252e7c2d7..3e9536a8db 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1469,6 +1469,233 @@ void Model::deleteGeometry() { _blendedBlendshapeCoefficients.clear(); } +// Scene rendering support +QVector Model::_modelsInScene; +void Model::startScene() { + _modelsInScene.clear(); +} + +void Model::endSceneSplitPass(RenderMode mode, RenderArgs* args) { + + // first, do all the batch/GPU setup work.... + // Let's introduce a gpu::Batch to capture all the calls to the graphics api + gpu::Batch batch; + + + GLBATCH(glDisable)(GL_COLOR_MATERIAL); + + if (mode == DIFFUSE_RENDER_MODE || mode == NORMAL_RENDER_MODE) { + GLBATCH(glDisable)(GL_CULL_FACE); + } else { + GLBATCH(glEnable)(GL_CULL_FACE); + if (mode == SHADOW_RENDER_MODE) { + GLBATCH(glCullFace)(GL_FRONT); + } + } + + // render opaque meshes with alpha testing + + GLBATCH(glDisable)(GL_BLEND); + GLBATCH(glEnable)(GL_ALPHA_TEST); + + if (mode == SHADOW_RENDER_MODE) { + GLBATCH(glAlphaFunc)(GL_EQUAL, 0.0f); + } + + + /*Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers( + mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE, + mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE, + mode == DEFAULT_RENDER_MODE); + */ + { + GLenum buffers[3]; + int bufferCount = 0; + if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { + buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; + } + if (mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE) { + buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; + } + if (mode == DEFAULT_RENDER_MODE) { + buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; + } + GLBATCH(glDrawBuffers)(bufferCount, buffers); + } + + const float DEFAULT_ALPHA_THRESHOLD = 0.5f; + + int opaqueMeshPartsRendered = 0; + + // now, for each model in the scene, render the mesh portions + float alpha = 1.0f; // at this point we don't support per model alphas + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args); + } + foreach(Model* model, _modelsInScene) { + opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); + } + + // render translucent meshes afterwards + //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true); + { + GLenum buffers[2]; + int bufferCount = 0; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; + GLBATCH(glDrawBuffers)(bufferCount, buffers); + } + + int translucentMeshPartsRendered = 0; + const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); + } + + GLBATCH(glDisable)(GL_ALPHA_TEST); + GLBATCH(glEnable)(GL_BLEND); + GLBATCH(glDepthMask)(false); + GLBATCH(glDepthFunc)(GL_LEQUAL); + + //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true); + { + GLenum buffers[1]; + int bufferCount = 0; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; + GLBATCH(glDrawBuffers)(bufferCount, buffers); + } + + if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { + const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args); + } + foreach(Model* model, _modelsInScene) { + translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); + } + } + + GLBATCH(glDepthMask)(true); + GLBATCH(glDepthFunc)(GL_LESS); + GLBATCH(glDisable)(GL_CULL_FACE); + + if (mode == SHADOW_RENDER_MODE) { + GLBATCH(glCullFace)(GL_BACK); + } + + // deactivate vertex arrays after drawing + GLBATCH(glDisableClientState)(GL_NORMAL_ARRAY); + GLBATCH(glDisableClientState)(GL_VERTEX_ARRAY); + GLBATCH(glDisableClientState)(GL_TEXTURE_COORD_ARRAY); + GLBATCH(glDisableClientState)(GL_COLOR_ARRAY); + GLBATCH(glDisableVertexAttribArray)(gpu::Stream::TANGENT); + GLBATCH(glDisableVertexAttribArray)(gpu::Stream::SKIN_CLUSTER_INDEX); + GLBATCH(glDisableVertexAttribArray)(gpu::Stream::SKIN_CLUSTER_WEIGHT); + + // bind with 0 to switch back to normal operation + GLBATCH(glBindBuffer)(GL_ARRAY_BUFFER, 0); + GLBATCH(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, 0); + GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); + + // Render! + { + PROFILE_RANGE("render Batch"); + ::gpu::GLBackend::renderBatch(batch); + batch.clear(); + } + + // restore all the default material settings + Application::getInstance()->setupWorldLight(); + + if (args) { + args->_translucentMeshPartsRendered = translucentMeshPartsRendered; + args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered; + } +} + +void Model::endScene(RenderMode mode, RenderArgs* args) { + //endSceneSimple(mode, args); + endSceneSplitPass(mode, args); +} + +void Model::endSceneSimple(RenderMode mode, RenderArgs* args) { + // now, for each model in the scene, render the mesh portions + foreach(Model* model, _modelsInScene) { + float alpha = 1.0f; + model->render(alpha, mode, args); + } +} + +bool Model::renderInScene(float alpha, RenderArgs* args) { + // render the attachments + foreach (Model* attachment, _attachments) { + attachment->renderInScene(alpha); + } + if (_meshStates.isEmpty()) { + return false; + } + renderSetup(args); + _modelsInScene.push_back(this); + return true; +} + void Model::segregateMeshGroups() { _meshesTranslucentTangents.clear(); _meshesTranslucent.clear(); @@ -1990,237 +2217,3 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl return meshPartsRendered; } - - - -// Scene rendering support -QVector Model::_modelsInScene; -void Model::startScene() { - _modelsInScene.clear(); -} - -void Model::endSceneSplitPass(RenderMode mode, RenderArgs* args) { - - // first, do all the batch/GPU setup work.... - // Let's introduce a gpu::Batch to capture all the calls to the graphics api - gpu::Batch batch; - - - GLBATCH(glDisable)(GL_COLOR_MATERIAL); - - if (mode == DIFFUSE_RENDER_MODE || mode == NORMAL_RENDER_MODE) { - GLBATCH(glDisable)(GL_CULL_FACE); - } else { - GLBATCH(glEnable)(GL_CULL_FACE); - if (mode == SHADOW_RENDER_MODE) { - GLBATCH(glCullFace)(GL_FRONT); - } - } - - // render opaque meshes with alpha testing - - GLBATCH(glDisable)(GL_BLEND); - GLBATCH(glEnable)(GL_ALPHA_TEST); - - if (mode == SHADOW_RENDER_MODE) { - GLBATCH(glAlphaFunc)(GL_EQUAL, 0.0f); - } - - - /*Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers( - mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE, - mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE, - mode == DEFAULT_RENDER_MODE); - */ - { - GLenum buffers[3]; - int bufferCount = 0; - if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { - buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; - } - if (mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE) { - buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; - } - if (mode == DEFAULT_RENDER_MODE) { - buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; - } - GLBATCH(glDrawBuffers)(bufferCount, buffers); - } - - const float DEFAULT_ALPHA_THRESHOLD = 0.5f; - - int opaqueMeshPartsRendered = 0; - - // now, for each model in the scene, render the mesh portions - float alpha = 1.0f; // at this point we don't support per model alphas - foreach(Model* model, _modelsInScene) { - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args); - } - foreach(Model* model, _modelsInScene) { - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args); - } - foreach(Model* model, _modelsInScene) { - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args); - } - foreach(Model* model, _modelsInScene) { - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, args); - } - foreach(Model* model, _modelsInScene) { - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args); - } - foreach(Model* model, _modelsInScene) { - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); - } - foreach(Model* model, _modelsInScene) { - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args); - } - foreach(Model* model, _modelsInScene) { - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); - } - - // render translucent meshes afterwards - //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true); - { - GLenum buffers[2]; - int bufferCount = 0; - buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; - buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; - GLBATCH(glDrawBuffers)(bufferCount, buffers); - } - - int translucentMeshPartsRendered = 0; - const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); - } - - GLBATCH(glDisable)(GL_ALPHA_TEST); - GLBATCH(glEnable)(GL_BLEND); - GLBATCH(glDepthMask)(false); - GLBATCH(glDepthFunc)(GL_LEQUAL); - - //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true); - { - GLenum buffers[1]; - int bufferCount = 0; - buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; - GLBATCH(glDrawBuffers)(bufferCount, buffers); - } - - if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { - const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args); - } - foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); - } - } - - GLBATCH(glDepthMask)(true); - GLBATCH(glDepthFunc)(GL_LESS); - GLBATCH(glDisable)(GL_CULL_FACE); - - if (mode == SHADOW_RENDER_MODE) { - GLBATCH(glCullFace)(GL_BACK); - } - - // deactivate vertex arrays after drawing - GLBATCH(glDisableClientState)(GL_NORMAL_ARRAY); - GLBATCH(glDisableClientState)(GL_VERTEX_ARRAY); - GLBATCH(glDisableClientState)(GL_TEXTURE_COORD_ARRAY); - GLBATCH(glDisableClientState)(GL_COLOR_ARRAY); - GLBATCH(glDisableVertexAttribArray)(gpu::Stream::TANGENT); - GLBATCH(glDisableVertexAttribArray)(gpu::Stream::SKIN_CLUSTER_INDEX); - GLBATCH(glDisableVertexAttribArray)(gpu::Stream::SKIN_CLUSTER_WEIGHT); - - // bind with 0 to switch back to normal operation - GLBATCH(glBindBuffer)(GL_ARRAY_BUFFER, 0); - GLBATCH(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, 0); - GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); - - // Render! - { - PROFILE_RANGE("render Batch"); - ::gpu::GLBackend::renderBatch(batch); - batch.clear(); - } - - // restore all the default material settings - Application::getInstance()->setupWorldLight(); - - if (args) { - args->_translucentMeshPartsRendered = translucentMeshPartsRendered; - args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered; - } -} - -void Model::endScene(RenderMode mode, RenderArgs* args) { - //endSceneSimple(mode, args); - endSceneSplitPass(mode, args); -} - -void Model::endSceneSimple(RenderMode mode, RenderArgs* args) { - // now, for each model in the scene, render the mesh portions - foreach(Model* model, _modelsInScene) { - float alpha = 1.0f; - model->render(alpha, mode, args); - } -} - -bool Model::renderInScene(float alpha, RenderArgs* args) { - // do we really need alpha? - - // render the attachments - foreach (Model* attachment, _attachments) { - attachment->renderInScene(alpha); - } - if (_meshStates.isEmpty()) { - return false; - } - - renderSetup(args); - - _modelsInScene.push_back(this); - return true; -} - From b2f64b9362370afe78bfce2bdeab0e4f28c5c53d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 12:17:46 -0800 Subject: [PATCH 15/44] cleanup --- interface/src/renderer/Model.cpp | 52 ++++++++++++-------------------- interface/src/renderer/Model.h | 2 +- 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 3e9536a8db..7455e528b7 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1475,13 +1475,12 @@ void Model::startScene() { _modelsInScene.clear(); } -void Model::endSceneSplitPass(RenderMode mode, RenderArgs* args) { +void Model::endScene(RenderMode mode, RenderArgs* args) { // first, do all the batch/GPU setup work.... // Let's introduce a gpu::Batch to capture all the calls to the graphics api gpu::Batch batch; - GLBATCH(glDisable)(GL_COLOR_MATERIAL); if (mode == DIFFUSE_RENDER_MODE || mode == NORMAL_RENDER_MODE) { @@ -1564,31 +1563,31 @@ void Model::endSceneSplitPass(RenderMode mode, RenderArgs* args) { GLBATCH(glDrawBuffers)(bufferCount, buffers); } - int translucentMeshPartsRendered = 0; + int translucentParts = 0; const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); } GLBATCH(glDisable)(GL_ALPHA_TEST); @@ -1607,28 +1606,28 @@ void Model::endSceneSplitPass(RenderMode mode, RenderArgs* args) { if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args); } foreach(Model* model, _modelsInScene) { - translucentMeshPartsRendered += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); + translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); } } @@ -1665,24 +1664,11 @@ void Model::endSceneSplitPass(RenderMode mode, RenderArgs* args) { Application::getInstance()->setupWorldLight(); if (args) { - args->_translucentMeshPartsRendered = translucentMeshPartsRendered; + args->_translucentMeshPartsRendered = translucentParts; args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered; } } -void Model::endScene(RenderMode mode, RenderArgs* args) { - //endSceneSimple(mode, args); - endSceneSplitPass(mode, args); -} - -void Model::endSceneSimple(RenderMode mode, RenderArgs* args) { - // now, for each model in the scene, render the mesh portions - foreach(Model* model, _modelsInScene) { - float alpha = 1.0f; - model->render(alpha, mode, args); - } -} - bool Model::renderInScene(float alpha, RenderArgs* args) { // render the attachments foreach (Model* attachment, _attachments) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index d77501e0f9..bfe1475d4b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -90,7 +90,6 @@ public: enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE }; bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); - bool renderCore(float alpha, RenderMode mode, RenderArgs* args); // Scene rendering support static void startScene(); @@ -403,6 +402,7 @@ private: // helper functions used by render() or renderInScene() void renderSetup(RenderArgs* args); + bool renderCore(float alpha, RenderMode mode, RenderArgs* args); int renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL); }; From d97d1119c780b88023d8627967ee3d9a8953fc6c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 12:25:02 -0800 Subject: [PATCH 16/44] keep tree locked until after endScene --- interface/src/entities/EntityTreeRenderer.cpp | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 6961df4680..f2ad41f045 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -258,37 +258,39 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode) { if (dontRenderAsScene) { OctreeRenderer::render(renderMode); } else { - Model::startScene(); - RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (_tree) { + Model::startScene(); + RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; _tree->lockForRead(); _tree->recurseTreeWithOperation(renderOperation, &args); + + Model::RenderMode modelRenderMode = renderMode == RenderArgs::SHADOW_RENDER_MODE + ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + + // we must call endScene while we still have the tree locked so that no one deletes a model + // on us while rendering the scene + Model::endScene(modelRenderMode, &args); _tree->unlock(); - } - - Model::RenderMode modelRenderMode = renderMode == RenderArgs::SHADOW_RENDER_MODE - ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; - - Model::endScene(modelRenderMode, &args); - // stats... - _meshesConsidered = args._meshesConsidered; - _meshesRendered = args._meshesRendered; - _meshesOutOfView = args._meshesOutOfView; - _meshesTooSmall = args._meshesTooSmall; + // stats... + _meshesConsidered = args._meshesConsidered; + _meshesRendered = args._meshesRendered; + _meshesOutOfView = args._meshesOutOfView; + _meshesTooSmall = args._meshesTooSmall; - _elementsTouched = args._elementsTouched; - _itemsRendered = args._itemsRendered; - _itemsOutOfView = args._itemsOutOfView; - _itemsTooSmall = args._itemsTooSmall; + _elementsTouched = args._elementsTouched; + _itemsRendered = args._itemsRendered; + _itemsOutOfView = args._itemsOutOfView; + _itemsTooSmall = args._itemsTooSmall; - _materialSwitches = args._materialSwitches; - _trianglesRendered = args._trianglesRendered; - _quadsRendered = args._quadsRendered; + _materialSwitches = args._materialSwitches; + _trianglesRendered = args._trianglesRendered; + _quadsRendered = args._quadsRendered; - _translucentMeshPartsRendered = args._translucentMeshPartsRendered; - _opaqueMeshPartsRendered = args._opaqueMeshPartsRendered; + _translucentMeshPartsRendered = args._translucentMeshPartsRendered; + _opaqueMeshPartsRendered = args._opaqueMeshPartsRendered; + } } deleteReleasedModels(); // seems like as good as any other place to do some memory cleanup } From 96705bfd74618a9db898e709e711f02952ce7d5f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 13:36:08 -0800 Subject: [PATCH 17/44] allow AnimationHandle to be set from AnimationDetails --- interface/src/renderer/AnimationHandle.cpp | 17 +++++++++++++++++ interface/src/renderer/AnimationHandle.h | 1 + interface/src/renderer/Model.cpp | 1 - 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/interface/src/renderer/AnimationHandle.cpp b/interface/src/renderer/AnimationHandle.cpp index 8ecf5d9699..957787abb2 100644 --- a/interface/src/renderer/AnimationHandle.cpp +++ b/interface/src/renderer/AnimationHandle.cpp @@ -97,6 +97,23 @@ AnimationDetails AnimationHandle::getAnimationDetails() const { return details; } +void AnimationHandle::setAnimationDetails(const AnimationDetails& details) { + setRole(details.role); + setURL(details.url); + setFPS(details.fps); + setPriority(details.priority); + setLoop(details.loop); + setHold(details.hold); + setStartAutomatically(details.startAutomatically); + setFirstFrame(details.firstFrame); + setLastFrame(details.lastFrame); + setRunning(details.running); + setFrameIndex(details.frameIndex); + + // NOTE: AnimationDetails doesn't support maskedJoints + //setMaskedJoints(const QStringList& maskedJoints); +} + void AnimationHandle::simulate(float deltaTime) { _frameIndex += deltaTime * _fps; diff --git a/interface/src/renderer/AnimationHandle.h b/interface/src/renderer/AnimationHandle.h index 3b736698df..48026fe4b7 100644 --- a/interface/src/renderer/AnimationHandle.h +++ b/interface/src/renderer/AnimationHandle.h @@ -70,6 +70,7 @@ public: float getFrameIndex() const { return _frameIndex; } AnimationDetails getAnimationDetails() const; + void setAnimationDetails(const AnimationDetails& details); signals: diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 7455e528b7..5369ee7fe4 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1527,7 +1527,6 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { int opaqueMeshPartsRendered = 0; // now, for each model in the scene, render the mesh portions - float alpha = 1.0f; // at this point we don't support per model alphas foreach(Model* model, _modelsInScene) { opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args); } From ba760c4108330a67edf1906177d5357d8a469abd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 13:38:10 -0800 Subject: [PATCH 18/44] remove warning --- interface/src/renderer/Model.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 7455e528b7..5369ee7fe4 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1527,7 +1527,6 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { int opaqueMeshPartsRendered = 0; // now, for each model in the scene, render the mesh portions - float alpha = 1.0f; // at this point we don't support per model alphas foreach(Model* model, _modelsInScene) { opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args); } From 68bd6c23d9d3d6d5ba41ea9f1182f4ca8eac0aa3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 14:47:02 -0800 Subject: [PATCH 19/44] sepearate looping logic from AnimationHandle --- libraries/animation/src/AnimationLoop.cpp | 95 +++++++++++++++++++++++ libraries/animation/src/AnimationLoop.h | 63 +++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 libraries/animation/src/AnimationLoop.cpp create mode 100644 libraries/animation/src/AnimationLoop.h diff --git a/libraries/animation/src/AnimationLoop.cpp b/libraries/animation/src/AnimationLoop.cpp new file mode 100644 index 0000000000..f81904990f --- /dev/null +++ b/libraries/animation/src/AnimationLoop.cpp @@ -0,0 +1,95 @@ +// +// AnimationLoop.cpp +// libraries/animation +// +// Created by Brad Hefta-Gaub on 11/12/14. +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AnimationCache.h" +#include "AnimationLoop.h" + +AnimationLoop::AnimationLoop() : + _fps(30.0f), + _loop(false), + _hold(false), + _startAutomatically(false), + _firstFrame(0.0f), + _lastFrame(FLT_MAX), + _running(false), + _frameIndex(0.0f) +{ +} + +AnimationLoop::AnimationLoop(const AnimationDetails& animationDetails) : + _fps(animationDetails.fps), + _loop(animationDetails.loop), + _hold(animationDetails.hold), + _startAutomatically(animationDetails.startAutomatically), + _firstFrame(animationDetails.firstFrame), + _lastFrame(animationDetails.lastFrame), + _running(animationDetails.running), + _frameIndex(animationDetails.frameIndex) +{ +} + +AnimationLoop::AnimationLoop(float fps, bool loop, bool hold, bool startAutomatically, float firstFrame, + float lastFrame, bool running, float frameIndex) : + _fps(fps), + _loop(loop), + _hold(hold), + _startAutomatically(startAutomatically), + _firstFrame(firstFrame), + _lastFrame(lastFrame), + _running(running), + _frameIndex(frameIndex) +{ +} + +void AnimationLoop::simulate(float deltaTime) { + _frameIndex += deltaTime * _fps; + + + // If we knew the number of frames from the animation, we'd consider using it here + // animationGeometry.animationFrames.size() + float maxFrame = _lastFrame; + float endFrameIndex = qMin(_lastFrame, maxFrame - (_loop ? 0.0f : 1.0f)); + float startFrameIndex = qMin(_firstFrame, endFrameIndex); + if ((!_loop && (_frameIndex < startFrameIndex || _frameIndex > endFrameIndex)) || startFrameIndex == endFrameIndex) { + // passed the end; apply the last frame + _frameIndex = glm::clamp(_frameIndex, startFrameIndex, endFrameIndex); + if (!_hold) { + stop(); + } + } else { + // wrap within the the desired range + if (_frameIndex < startFrameIndex) { + _frameIndex = endFrameIndex - glm::mod(endFrameIndex - _frameIndex, endFrameIndex - startFrameIndex); + + } else if (_frameIndex > endFrameIndex) { + _frameIndex = startFrameIndex + glm::mod(_frameIndex - startFrameIndex, endFrameIndex - startFrameIndex); + } + } +} + +void AnimationLoop::setStartAutomatically(bool startAutomatically) { + if ((_startAutomatically = startAutomatically) && !isRunning()) { + start(); + } +} + +void AnimationLoop::setRunning(bool running) { + if (_running == running) { + if (running) { + // move back to the beginning + _frameIndex = _firstFrame; + } + return; + } + if ((_running = running)) { + _frameIndex = _firstFrame; + } +} diff --git a/libraries/animation/src/AnimationLoop.h b/libraries/animation/src/AnimationLoop.h new file mode 100644 index 0000000000..33d4d8e5bc --- /dev/null +++ b/libraries/animation/src/AnimationLoop.h @@ -0,0 +1,63 @@ +// +// AnimationLoop.h +// libraries/script-engine/src/ +// +// Created by Brad Hefta-Gaub on 11/12/14. +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AnimationLoop_h +#define hifi_AnimationLoop_h + +class AnimationDetails; + +class AnimationLoop { +public: + AnimationLoop(); + AnimationLoop(const AnimationDetails& animationDetails); + AnimationLoop(float fps, bool loop, bool hold, bool startAutomatically, float firstFrame, + float lastFrame, bool running, float frameIndex); + + void setFPS(float fps) { _fps = fps; } + float getFPS() const { return _fps; } + + void setLoop(bool loop) { _loop = loop; } + bool getLoop() const { return _loop; } + + void setHold(bool hold) { _hold = hold; } + bool getHold() const { return _hold; } + + void setStartAutomatically(bool startAutomatically); + bool getStartAutomatically() const { return _startAutomatically; } + + void setFirstFrame(float firstFrame) { _firstFrame = firstFrame; } + float getFirstFrame() const { return _firstFrame; } + + void setLastFrame(float lastFrame) { _lastFrame = lastFrame; } + float getLastFrame() const { return _lastFrame; } + + void setRunning(bool running); + bool isRunning() const { return _running; } + + void setFrameIndex(float frameIndex) { _frameIndex = glm::clamp(_frameIndex, _firstFrame, _lastFrame); } + float getFrameIndex() const { return _frameIndex; } + + void start() { setRunning(true); } + void stop() { setRunning(false); } + void simulate(float deltaTime); + +private: + float _fps; + bool _loop; + bool _hold; + bool _startAutomatically; + float _firstFrame; + float _lastFrame; + bool _running; + float _frameIndex; +}; + +#endif // hifi_AnimationLoop_h From 6ff8abcbdd45bf0ab77353861422e85c4b83076f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 14:47:10 -0800 Subject: [PATCH 20/44] sepearate looping logic from AnimationHandle --- interface/src/renderer/AnimationHandle.cpp | 38 +++++++------- interface/src/renderer/AnimationHandle.h | 60 ++++++++++++---------- libraries/animation/src/AnimationCache.h | 1 - 3 files changed, 52 insertions(+), 47 deletions(-) diff --git a/interface/src/renderer/AnimationHandle.cpp b/interface/src/renderer/AnimationHandle.cpp index 957787abb2..caddd8c4b6 100644 --- a/interface/src/renderer/AnimationHandle.cpp +++ b/interface/src/renderer/AnimationHandle.cpp @@ -33,7 +33,7 @@ void AnimationHandle::setPriority(float priority) { if (_priority == priority) { return; } - if (_running) { + if (isRunning()) { _model->_runningAnimations.removeOne(_self); if (priority < _priority) { replaceMatchingPriorities(priority); @@ -47,7 +47,8 @@ void AnimationHandle::setPriority(float priority) { } void AnimationHandle::setStartAutomatically(bool startAutomatically) { - if ((_startAutomatically = startAutomatically) && !_running) { + _animationLoop.setStartAutomatically(startAutomatically); + if (getStartAutomatically() && !isRunning()) { start(); } } @@ -58,42 +59,36 @@ void AnimationHandle::setMaskedJoints(const QStringList& maskedJoints) { } void AnimationHandle::setRunning(bool running) { - if (_running == running) { + if (isRunning() == running) { + // if we're already running, this is the same as a restart if (running) { // move back to the beginning - _frameIndex = _firstFrame; + setFrameIndex(getFirstFrame()); } return; } - if ((_running = running)) { + _animationLoop.setRunning(running); + if (isRunning()) { if (!_model->_runningAnimations.contains(_self)) { insertSorted(_model->_runningAnimations, _self); } - _frameIndex = _firstFrame; - } else { _model->_runningAnimations.removeOne(_self); replaceMatchingPriorities(0.0f); } - emit runningChanged(_running); + emit runningChanged(isRunning()); } AnimationHandle::AnimationHandle(Model* model) : QObject(model), _model(model), - _fps(30.0f), - _priority(1.0f), - _loop(false), - _hold(false), - _startAutomatically(false), - _firstFrame(0.0f), - _lastFrame(FLT_MAX), - _running(false) { + _priority(1.0f) +{ } AnimationDetails AnimationHandle::getAnimationDetails() const { - AnimationDetails details(_role, _url, _fps, _priority, _loop, _hold, - _startAutomatically, _firstFrame, _lastFrame, _running, _frameIndex); + AnimationDetails details(_role, _url, getFPS(), _priority, getLoop(), getHold(), + getStartAutomatically(), getFirstFrame(), getLastFrame(), isRunning(), getFrameIndex()); return details; } @@ -116,7 +111,7 @@ void AnimationHandle::setAnimationDetails(const AnimationDetails& details) { void AnimationHandle::simulate(float deltaTime) { - _frameIndex += deltaTime * _fps; + _animationLoop.simulate(deltaTime); // update the joint mappings if necessary/possible if (_jointMappings.isEmpty()) { @@ -142,6 +137,8 @@ void AnimationHandle::simulate(float deltaTime) { stop(); return; } + + /* float endFrameIndex = qMin(_lastFrame, animationGeometry.animationFrames.size() - (_loop ? 0.0f : 1.0f)); float startFrameIndex = qMin(_firstFrame, endFrameIndex); if ((!_loop && (_frameIndex < startFrameIndex || _frameIndex > endFrameIndex)) || startFrameIndex == endFrameIndex) { @@ -159,9 +156,10 @@ void AnimationHandle::simulate(float deltaTime) { } else if (_frameIndex > endFrameIndex) { _frameIndex = startFrameIndex + glm::mod(_frameIndex - startFrameIndex, endFrameIndex - startFrameIndex); } + */ // blend between the closest two frames - applyFrame(_frameIndex); + applyFrame(getFrameIndex()); } void AnimationHandle::applyFrame(float frameIndex) { diff --git a/interface/src/renderer/AnimationHandle.h b/interface/src/renderer/AnimationHandle.h index 48026fe4b7..aa030e6350 100644 --- a/interface/src/renderer/AnimationHandle.h +++ b/interface/src/renderer/AnimationHandle.h @@ -19,6 +19,7 @@ #include #include +#include class AnimationHandle; class Model; @@ -38,36 +39,37 @@ public: void setURL(const QUrl& url); const QUrl& getURL() const { return _url; } - - void setFPS(float fps) { _fps = fps; } - float getFPS() const { return _fps; } void setPriority(float priority); float getPriority() const { return _priority; } - - void setLoop(bool loop) { _loop = loop; } - bool getLoop() const { return _loop; } - - void setHold(bool hold) { _hold = hold; } - bool getHold() const { return _hold; } - - void setStartAutomatically(bool startAutomatically); - bool getStartAutomatically() const { return _startAutomatically; } - - void setFirstFrame(float firstFrame) { _firstFrame = firstFrame; } - float getFirstFrame() const { return _firstFrame; } - - void setLastFrame(float lastFrame) { _lastFrame = lastFrame; } - float getLastFrame() const { return _lastFrame; } - + void setMaskedJoints(const QStringList& maskedJoints); const QStringList& getMaskedJoints() const { return _maskedJoints; } - void setRunning(bool running); - bool isRunning() const { return _running; } - void setFrameIndex(float frameIndex) { _frameIndex = glm::clamp(_frameIndex, _firstFrame, _lastFrame); } - float getFrameIndex() const { return _frameIndex; } + void setFPS(float fps) { _animationLoop.setFPS(fps); } + float getFPS() const { return _animationLoop.getFPS(); } + + void setLoop(bool loop) { _animationLoop.setLoop(loop); } + bool getLoop() const { return _animationLoop.getLoop(); } + + void setHold(bool hold) { _animationLoop.setHold(hold); } + bool getHold() const { return _animationLoop.getHold(); } + + void setStartAutomatically(bool startAutomatically); + bool getStartAutomatically() const { return _animationLoop.getStartAutomatically(); } + + void setFirstFrame(float firstFrame) { _animationLoop.setFirstFrame(firstFrame); } + float getFirstFrame() const { return _animationLoop.getFirstFrame(); } + + void setLastFrame(float lastFrame) { _animationLoop.setLastFrame(lastFrame); } + float getLastFrame() const { return _animationLoop.getLastFrame(); } + + void setRunning(bool running); + bool isRunning() const { return _animationLoop.isRunning(); } + + void setFrameIndex(float frameIndex) { _animationLoop.setFrameIndex(frameIndex); } + float getFrameIndex() const { return _animationLoop.getFrameIndex(); } AnimationDetails getAnimationDetails() const; void setAnimationDetails(const AnimationDetails& details); @@ -96,17 +98,23 @@ private: AnimationPointer _animation; QString _role; QUrl _url; - float _fps; float _priority; + + QStringList _maskedJoints; + QVector _jointMappings; + + AnimationLoop _animationLoop; + + /* + float _fps; bool _loop; bool _hold; bool _startAutomatically; float _firstFrame; float _lastFrame; - QStringList _maskedJoints; bool _running; - QVector _jointMappings; float _frameIndex; + */ }; diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index 4af9f0a83f..8a9e371cb0 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -94,5 +94,4 @@ Q_DECLARE_METATYPE(AnimationDetails); QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& event); void animationDetailsFromScriptValue(const QScriptValue& object, AnimationDetails& event); - #endif // hifi_AnimationCache_h From d2ab3e69f09b27ffcd6e9e3eb7433a86fc8f15ad Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 14:59:03 -0800 Subject: [PATCH 21/44] some cleanup --- interface/src/renderer/AnimationHandle.cpp | 26 +++++----------------- interface/src/renderer/AnimationHandle.h | 11 --------- 2 files changed, 6 insertions(+), 31 deletions(-) diff --git a/interface/src/renderer/AnimationHandle.cpp b/interface/src/renderer/AnimationHandle.cpp index caddd8c4b6..767f941049 100644 --- a/interface/src/renderer/AnimationHandle.cpp +++ b/interface/src/renderer/AnimationHandle.cpp @@ -138,26 +138,12 @@ void AnimationHandle::simulate(float deltaTime) { return; } - /* - float endFrameIndex = qMin(_lastFrame, animationGeometry.animationFrames.size() - (_loop ? 0.0f : 1.0f)); - float startFrameIndex = qMin(_firstFrame, endFrameIndex); - if ((!_loop && (_frameIndex < startFrameIndex || _frameIndex > endFrameIndex)) || startFrameIndex == endFrameIndex) { - // passed the end; apply the last frame - applyFrame(glm::clamp(_frameIndex, startFrameIndex, endFrameIndex)); - if (!_hold) { - stop(); - } - return; - } - // wrap within the the desired range - if (_frameIndex < startFrameIndex) { - _frameIndex = endFrameIndex - glm::mod(endFrameIndex - _frameIndex, endFrameIndex - startFrameIndex); - - } else if (_frameIndex > endFrameIndex) { - _frameIndex = startFrameIndex + glm::mod(_frameIndex - startFrameIndex, endFrameIndex - startFrameIndex); - } - */ - + // TODO: When moving the loop/frame calculations to AnimationLoop class, we changed this behavior + // see AnimationLoop class for more details. Do we need to support clamping the endFrameIndex to + // the max number of frames in the geometry??? + // + // float endFrameIndex = qMin(_lastFrame, animationGeometry.animationFrames.size() - (_loop ? 0.0f : 1.0f)); + // blend between the closest two frames applyFrame(getFrameIndex()); } diff --git a/interface/src/renderer/AnimationHandle.h b/interface/src/renderer/AnimationHandle.h index aa030e6350..3956b01ebf 100644 --- a/interface/src/renderer/AnimationHandle.h +++ b/interface/src/renderer/AnimationHandle.h @@ -104,17 +104,6 @@ private: QVector _jointMappings; AnimationLoop _animationLoop; - - /* - float _fps; - bool _loop; - bool _hold; - bool _startAutomatically; - float _firstFrame; - float _lastFrame; - bool _running; - float _frameIndex; - */ }; From 7fa4ea752777b713891034972d77c09dd0290d9c Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 15:04:52 -0800 Subject: [PATCH 22/44] commented on the else branch in the update TRansform stack doing nothing --- interface/src/gpu/GLBackend.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 527739d8b0..46020a2398 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -492,7 +492,8 @@ void GLBackend::updateTransform() { _transform._view->getMatrix(modelView); glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); } else { - // glLoadIdentity(); + // TODO: eventually do something about the matrix when neither view nor model is specified? + // glLoadIdentity(); } } CHECK_GL_ERROR(); From 245f019836a637cac46d52e5516c153ae4e9bba9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 16:10:35 -0800 Subject: [PATCH 23/44] first cut at migrating entity animation frame calculations to use AnimationLoop --- .../entities/src/EntityItemPropertiesMacros.h | 12 ++++++ libraries/entities/src/ModelEntityItem.cpp | 37 +++++++++++-------- libraries/entities/src/ModelEntityItem.h | 18 ++++----- 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index b5a489f88c..77782cb90f 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -40,6 +40,18 @@ } \ } +#define READ_ENTITY_PROPERTY_SETTER(P,T,M) \ + if (propertyFlags.getHasProperty(P)) { \ + T fromBuffer; \ + memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); \ + dataAt += sizeof(fromBuffer); \ + bytesRead += sizeof(fromBuffer); \ + if (overwriteLocalData) { \ + M(fromBuffer); \ + } \ + } + + #define READ_ENTITY_PROPERTY_QUAT(P,M) \ if (propertyFlags.getHasProperty(P)) { \ glm::quat fromBuffer; \ diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 827f4f7e39..339f630f35 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -33,10 +33,11 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityI { _type = EntityTypes::Model; setProperties(properties, true); - _animationFrameIndex = 0.0f; _lastAnimated = usecTimestampNow(); _jointMappingCompleted = false; _color[0] = _color[1] = _color[2] = 0; + + //_animationFrameIndex = 0.0f; } EntityItemProperties ModelEntityItem::getProperties() const { @@ -100,9 +101,9 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color); READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL); READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL); - READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, _animationFPS); - READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, _animationFrameIndex); - READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, _animationIsPlaying); + READ_ENTITY_PROPERTY_SETTER(PROP_ANIMATION_FPS, float, setAnimationFPS); + READ_ENTITY_PROPERTY_SETTER(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex); + READ_ENTITY_PROPERTY_SETTER(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying); READ_ENTITY_PROPERTY_STRING(PROP_TEXTURES, setTextures); return bytesRead; @@ -199,19 +200,25 @@ int ModelEntityItem::oldVersionReadEntityDataFromBuffer(const unsigned char* dat bytesRead += animationURLLength; // animationIsPlaying - memcpy(&_animationIsPlaying, dataAt, sizeof(_animationIsPlaying)); - dataAt += sizeof(_animationIsPlaying); - bytesRead += sizeof(_animationIsPlaying); + bool animationIsPlaying; + memcpy(&animationIsPlaying, dataAt, sizeof(animationIsPlaying)); + dataAt += sizeof(animationIsPlaying); + bytesRead += sizeof(animationIsPlaying); + setAnimationIsPlaying(animationIsPlaying); // animationFrameIndex - memcpy(&_animationFrameIndex, dataAt, sizeof(_animationFrameIndex)); - dataAt += sizeof(_animationFrameIndex); - bytesRead += sizeof(_animationFrameIndex); + float animationFrameIndex; + memcpy(&animationFrameIndex, dataAt, sizeof(animationFrameIndex)); + dataAt += sizeof(animationFrameIndex); + bytesRead += sizeof(animationFrameIndex); + setAnimationFrameIndex(animationFrameIndex); // animationFPS - memcpy(&_animationFPS, dataAt, sizeof(_animationFPS)); - dataAt += sizeof(_animationFPS); - bytesRead += sizeof(_animationFPS); + float animationFPS; + memcpy(&animationFPS, dataAt, sizeof(animationFPS)); + dataAt += sizeof(animationFPS); + bytesRead += sizeof(animationFPS); + setAnimationFPS(animationFPS); } } return bytesRead; @@ -314,7 +321,7 @@ QVector ModelEntityItem::getAnimationFrame() { int frameCount = frames.size(); if (frameCount > 0) { - int animationFrameIndex = (int)(glm::floor(_animationFrameIndex)) % frameCount; + int animationFrameIndex = (int)(glm::floor(getAnimationFrameIndex())) % frameCount; if (animationFrameIndex < 0 || animationFrameIndex > frameCount) { animationFrameIndex = 0; @@ -363,7 +370,7 @@ void ModelEntityItem::update(const quint64& updateTime) { if (getAnimationIsPlaying()) { float deltaTime = (float)(now - _lastAnimated) / (float)USECS_PER_SECOND; _lastAnimated = now; - _animationFrameIndex += deltaTime * _animationFPS; + _animationLoop.simulate(deltaTime); } else { _lastAnimated = now; } diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 4c79a46c5e..aea9407e8b 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -12,6 +12,8 @@ #ifndef hifi_ModelEntityItem_h #define hifi_ModelEntityItem_h +#include + #include "EntityItem.h" class ModelEntityItem : public EntityItem { @@ -73,21 +75,21 @@ public: void setModelURL(const QString& url) { _modelURL = url; } void setAnimationURL(const QString& url) { _animationURL = url; } static const float DEFAULT_ANIMATION_FRAME_INDEX; - void setAnimationFrameIndex(float value) { _animationFrameIndex = value; } + void setAnimationFrameIndex(float value) { _animationLoop.setFrameIndex(value); } static const bool DEFAULT_ANIMATION_IS_PLAYING; - void setAnimationIsPlaying(bool value) { _animationIsPlaying = value; } + void setAnimationIsPlaying(bool value) { _animationLoop.setRunning(value); } static const float DEFAULT_ANIMATION_FPS; - void setAnimationFPS(float value) { _animationFPS = value; } + void setAnimationFPS(float value) { _animationLoop.setFPS(value); } void mapJoints(const QStringList& modelJointNames); QVector getAnimationFrame(); bool jointsMapped() const { return _jointMappingCompleted; } - bool getAnimationIsPlaying() const { return _animationIsPlaying; } - float getAnimationFrameIndex() const { return _animationFrameIndex; } - float getAnimationFPS() const { return _animationFPS; } + bool getAnimationIsPlaying() const { return _animationLoop.isRunning(); } + float getAnimationFrameIndex() const { return _animationLoop.getFrameIndex(); } + float getAnimationFPS() const { return _animationLoop.getFPS(); } static const QString DEFAULT_TEXTURES; const QString& getTextures() const { return _textures; } @@ -106,9 +108,7 @@ protected: quint64 _lastAnimated; QString _animationURL; - float _animationFrameIndex; // we keep this as a float and round to int only when we need the exact index - bool _animationIsPlaying; - float _animationFPS; + AnimationLoop _animationLoop; QString _textures; // used on client side From ba79f40007ad42225cbefcd4d613f4c363cf1c8d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 16:12:34 -0800 Subject: [PATCH 24/44] add some debug --- libraries/animation/src/AnimationLoop.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/animation/src/AnimationLoop.cpp b/libraries/animation/src/AnimationLoop.cpp index f81904990f..6943b2e010 100644 --- a/libraries/animation/src/AnimationLoop.cpp +++ b/libraries/animation/src/AnimationLoop.cpp @@ -73,6 +73,10 @@ void AnimationLoop::simulate(float deltaTime) { _frameIndex = startFrameIndex + glm::mod(_frameIndex - startFrameIndex, endFrameIndex - startFrameIndex); } } + + qDebug() << "AnimationLoop::simulate()"; + qDebug() << " deltaTime:" << deltaTime; + qDebug() << " _frameIndex:" << _frameIndex; } void AnimationLoop::setStartAutomatically(bool startAutomatically) { From 8fb04af59dfeb5e13909e627a5a218a94c121a9f Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 16:40:45 -0800 Subject: [PATCH 25/44] defined the ViewTransform as the matrix transforming from eye space to world space (the opposite of before this commit) since it seems a better design --- interface/src/Application.cpp | 22 +++++++++++------- interface/src/gpu/Batch.h | 5 ++++ interface/src/gpu/GLBackend.cpp | 4 ++-- interface/src/renderer/Model.cpp | 4 ++-- libraries/shared/src/Transform.cpp | 6 ----- libraries/shared/src/Transform.h | 37 ++++++++++++++++++++++++++++++ 6 files changed, 60 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 919f414c78..e7dbf1e460 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -839,12 +839,14 @@ void Application::controlledBroadcastToNodes(const QByteArray& packet, const Nod } bool Application::event(QEvent* event) { + // handle custom URL if (event->type() == QEvent::FileOpen) { QFileOpenEvent* fileEvent = static_cast(event); - if (fileEvent->url().isValid()) { - openUrl(fileEvent->url()); + + if (!fileEvent->url().isEmpty()) { + AddressManager::getInstance().handleLookupString(fileEvent->url().toLocalFile()); } return false; @@ -2899,14 +2901,16 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glFrontFace(GL_CCW); } - glm::vec3 eyeOffsetPos = whichCamera.getEyeOffsetPosition(); +/* glm::vec3 eyeOffsetPos = whichCamera.getEyeOffsetPosition(); glm::quat eyeOffsetOrient = whichCamera.getEyeOffsetOrientation(); glm::vec3 eyeOffsetAxis = glm::axis(eyeOffsetOrient); glRotatef(-glm::degrees(glm::angle(eyeOffsetOrient)), eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z); - viewTransform.postRotate(glm::conjugate(eyeOffsetOrient)); + // viewTransform.postRotate(glm::conjugate(eyeOffsetOrient)); + viewTransform.preRotate(eyeOffsetOrient); glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); - viewTransform.postTranslate(-eyeOffsetPos); - + //viewTransform.postTranslate(-eyeOffsetPos); + viewTransform.preTranslate(eyeOffsetPos); +*/ // transform view according to whichCamera // could be myCamera (if in normal mode) // or could be viewFrustumOffsetCamera if in offset mode @@ -2914,14 +2918,16 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glm::quat rotation = whichCamera.getRotation(); glm::vec3 axis = glm::axis(rotation); glRotatef(-glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - viewTransform.postRotate(glm::conjugate(rotation)); + // viewTransform.postRotate(glm::conjugate(rotation)); + viewTransform.setRotation(rotation); // store view matrix without translation, which we'll use for precision-sensitive objects updateUntranslatedViewMatrix(-whichCamera.getPosition()); // Equivalent to what is happening with _untranslatedViewMatrix and the _viewMatrixTranslation - // the viewTransofmr object is updated with the correct value and saved, + // the viewTransofmr object is updatded with the correct value and saved, // this is what is used for rendering the ENtities and avatars + viewTransform.setTranslation(whichCamera.getPosition()); setViewTransform(viewTransform); glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z); diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index 773b1ee6a4..3c15fef63b 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -82,6 +82,11 @@ public: void setIndexBuffer(Type type, const BufferPointer& buffer, Offset offset); // Transform Stage + // Vertex position is transformed by ModelTransform from object space to world space + // Then by the inverse of the ViewTransform from world space to eye space + // finaly projected into the clip space by the projection transform + // WARNING: ViewTransform transform from eye space to world space, its inverse is composed + // with the ModelTransformu to create the equivalent of the glModelViewMatrix void setModelTransform(const TransformPointer& model); void setViewTransform(const TransformPointer& view); void setProjectionTransform(const TransformPointer& proj); diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 46020a2398..774aaf6ae6 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -476,7 +476,7 @@ void GLBackend::updateTransform() { Transform::Mat4 modelView; if (!_transform._view.isNull()) { Transform mvx; - Transform::mult(mvx, (*_transform._view), (*_transform._model)); + Transform::inverseMult(mvx, (*_transform._view), (*_transform._model)); mvx.getMatrix(modelView); } else { _transform._model->getMatrix(modelView); @@ -489,7 +489,7 @@ void GLBackend::updateTransform() { _transform._lastMode = GL_MODELVIEW; } Transform::Mat4 modelView; - _transform._view->getMatrix(modelView); + _transform._view->getInverseMatrix(modelView); glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); } else { // TODO: eventually do something about the matrix when neither view nor model is specified? diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 1b723652f1..246d4abfbf 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -560,8 +560,8 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { _transforms.push_back(gpu::TransformPointer(new gpu::Transform())); } (*_transforms[0]) = gpu::Transform((*Application::getInstance()->getViewTransform())); - // apply entity translation + camera position offset to the viewTransform in one go - _transforms[0]->postTranslate(Application::getInstance()->getViewMatrixTranslation() + _translation); + // apply entity translation offset to the viewTransform in one go (it's a preTranslate because viewTransform goes from world to eye space) + _transforms[0]->preTranslate(-_translation); batch.setViewTransform(_transforms[0]); diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index 4c049a8f92..296f0743ca 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -27,12 +27,6 @@ void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotat Mat3 currInvTranspose = glm::inverse(glm::transpose(rotationMat)); Mat3 nextRotation = 0.5f * (rotationMat + currInvTranspose); - // Go through every component in the matrices and find the next matrix - /* for (int i = 0; i < 3; i++) { - for (int j = 0; j <3; j++) { - nextRotation[j][i] = 0.5f * (rotationMat[j][i] + currInvTranspose[j][i]); - } - }*/ norm = 0.0; for (int i = 0; i < 3; i++) { diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 13e30f6520..d1dd04811f 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -78,12 +78,17 @@ public: void evalFromRawMatrix(const Mat3& rotationScalematrix); Mat4& getMatrix(Mat4& result) const; + Mat4& getInverseMatrix(Mat4& result) const; Transform& evalInverse(Transform& result) const; static void evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotationScaleMatrix); + static Transform& mult(Transform& result, const Transform& left, const Transform& right); + // Left will be inversed before the multiplication + static Transform& inverseMult(Transform& result, const Transform& left, const Transform& right); + protected: @@ -271,6 +276,10 @@ inline Transform::Mat4& Transform::getMatrix(Transform::Mat4& result) const { return result; } +inline Transform::Mat4& Transform::getInverseMatrix(Transform::Mat4& result) const { + return evalInverse(Transform()).getMatrix(result); +} + inline void Transform::evalFromRawMatrix(const Mat4& matrix) { // for now works only in the case of TRS transformation if ((matrix[0][3] == 0) && (matrix[1][3] == 0) && (matrix[2][3] == 0) && (matrix[3][3] == 1.f)) { @@ -330,6 +339,34 @@ inline Transform& Transform::mult( Transform& result, const Transform& left, con return result; } +inline Transform& Transform::inverseMult( Transform& result, const Transform& left, const Transform& right) { + result.setIdentity(); + + if (left.isScaling()) { + const Vec3& s = left.getScale(); + result.setScale(Vec3(1.0f / s.x, 1.0f / s.y, 1.0f / s.z)); + } + if (left.isRotating()) { + result.postRotate(glm::conjugate(left.getRotation())); + } + if (left.isTranslating() || right.isTranslating()) { + result.postTranslate(right.getTranslation() - left.getTranslation()); + } + if (right.isRotating()) { + result.postRotate(right.getRotation()); + } + if (right.isScaling()) { + result.postScale(right.getScale()); + } + + // HACK: In case of an issue in the Transform multiplication results, to make sure this code is + // working properly uncomment the next 2 lines and compare the results, they should be the same... + // Transform::Mat4 mv = left.getMatrix() * right.getMatrix(); + // Transform::Mat4 mv2 = result.getMatrix(); + + return result; +} + inline void Transform::updateCache() const { if (isCacheInvalid()) { if (isRotating()) { From d3a7b011bffdc0e2e280f8932e88a376264f266a Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 16:52:11 -0800 Subject: [PATCH 26/44] defined the ViewTransform as the matrix transforming from eye space to world space (the opposite of before this commit) since it seems a better design. And cleaned the dead code in Application.cpp --- interface/src/Application.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e7dbf1e460..d9f86d5bfc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2885,32 +2885,24 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()"); // transform by eye offset - - gpu::Transform viewTransform; - // load the view frustum loadViewFrustum(whichCamera, _displayViewFrustum); // flip x if in mirror mode (also requires reversing winding order for backface culling) if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { glScalef(-1.0f, 1.0f, 1.0f); - viewTransform.setScale(gpu::Transform::Vec3(-1.0f, 1.0f, 1.0f)); glFrontFace(GL_CW); } else { glFrontFace(GL_CCW); } -/* glm::vec3 eyeOffsetPos = whichCamera.getEyeOffsetPosition(); + glm::vec3 eyeOffsetPos = whichCamera.getEyeOffsetPosition(); glm::quat eyeOffsetOrient = whichCamera.getEyeOffsetOrientation(); glm::vec3 eyeOffsetAxis = glm::axis(eyeOffsetOrient); glRotatef(-glm::degrees(glm::angle(eyeOffsetOrient)), eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z); - // viewTransform.postRotate(glm::conjugate(eyeOffsetOrient)); - viewTransform.preRotate(eyeOffsetOrient); glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); - //viewTransform.postTranslate(-eyeOffsetPos); - viewTransform.preTranslate(eyeOffsetPos); -*/ + // transform view according to whichCamera // could be myCamera (if in normal mode) // or could be viewFrustumOffsetCamera if in offset mode @@ -2918,16 +2910,21 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glm::quat rotation = whichCamera.getRotation(); glm::vec3 axis = glm::axis(rotation); glRotatef(-glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - // viewTransform.postRotate(glm::conjugate(rotation)); - viewTransform.setRotation(rotation); // store view matrix without translation, which we'll use for precision-sensitive objects updateUntranslatedViewMatrix(-whichCamera.getPosition()); // Equivalent to what is happening with _untranslatedViewMatrix and the _viewMatrixTranslation - // the viewTransofmr object is updatded with the correct value and saved, - // this is what is used for rendering the ENtities and avatars + // the viewTransofmr object is updatded with the correct values and saved, + // this is what is used for rendering the Entities and avatars + gpu::Transform viewTransform; viewTransform.setTranslation(whichCamera.getPosition()); + viewTransform.setRotation(rotation); + viewTransform.postTranslate(eyeOffsetPos); + viewTransform.postRotate(eyeOffsetOrient); + if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { + viewTransform.setScale(gpu::Transform::Vec3(-1.0f, 1.0f, 1.0f)); + } setViewTransform(viewTransform); glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z); From dd22683672f99cbe21587fa5d212c7bf8b970e6c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 16:53:16 -0800 Subject: [PATCH 27/44] fixing up animation loop issues --- libraries/animation/src/AnimationLoop.cpp | 4 +++- libraries/animation/src/AnimationLoop.h | 2 +- libraries/entities/src/ModelEntityItem.cpp | 20 +++++++++++++++++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/libraries/animation/src/AnimationLoop.cpp b/libraries/animation/src/AnimationLoop.cpp index 6943b2e010..27039da4ad 100644 --- a/libraries/animation/src/AnimationLoop.cpp +++ b/libraries/animation/src/AnimationLoop.cpp @@ -73,10 +73,12 @@ void AnimationLoop::simulate(float deltaTime) { _frameIndex = startFrameIndex + glm::mod(_frameIndex - startFrameIndex, endFrameIndex - startFrameIndex); } } - + + /* qDebug() << "AnimationLoop::simulate()"; qDebug() << " deltaTime:" << deltaTime; qDebug() << " _frameIndex:" << _frameIndex; + */ } void AnimationLoop::setStartAutomatically(bool startAutomatically) { diff --git a/libraries/animation/src/AnimationLoop.h b/libraries/animation/src/AnimationLoop.h index 33d4d8e5bc..b56f68f23b 100644 --- a/libraries/animation/src/AnimationLoop.h +++ b/libraries/animation/src/AnimationLoop.h @@ -42,7 +42,7 @@ public: void setRunning(bool running); bool isRunning() const { return _running; } - void setFrameIndex(float frameIndex) { _frameIndex = glm::clamp(_frameIndex, _firstFrame, _lastFrame); } + void setFrameIndex(float frameIndex) { _frameIndex = glm::clamp(frameIndex, _firstFrame, _lastFrame); } float getFrameIndex() const { return _frameIndex; } void start() { setRunning(true); } diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 339f630f35..bc0ade66f4 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -101,9 +101,23 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color); READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL); READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL); - READ_ENTITY_PROPERTY_SETTER(PROP_ANIMATION_FPS, float, setAnimationFPS); - READ_ENTITY_PROPERTY_SETTER(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex); - READ_ENTITY_PROPERTY_SETTER(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying); + + // Because we're using AnimationLoop which will reset the frame index if you change it's running state + // we want to read these values in the order they appear in the buffer, but call our setters in an + // order that allows AnimationLoop to preserve the correct frame rate. + float animationFPS = getAnimationFPS(); + float animationFrameIndex = getAnimationFrameIndex(); + bool animationIsPlaying = getAnimationIsPlaying(); + READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, animationFPS); + READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, animationFrameIndex); + READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, animationIsPlaying); + + setAnimationIsPlaying(animationIsPlaying); + setAnimationFPS(animationFPS); + setAnimationFrameIndex(animationFrameIndex); + +qDebug() << "just read PROP_ANIMATION_FRAME_INDEX, getAnimationFrameIndex():" << getAnimationFrameIndex(); + READ_ENTITY_PROPERTY_STRING(PROP_TEXTURES, setTextures); return bytesRead; From ef17659ea21f54518e0d3a011388b78399675d45 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 16:57:42 -0800 Subject: [PATCH 28/44] cleanup --- libraries/animation/src/AnimationLoop.cpp | 6 ------ libraries/entities/src/ModelEntityItem.cpp | 4 ---- 2 files changed, 10 deletions(-) diff --git a/libraries/animation/src/AnimationLoop.cpp b/libraries/animation/src/AnimationLoop.cpp index 27039da4ad..f81904990f 100644 --- a/libraries/animation/src/AnimationLoop.cpp +++ b/libraries/animation/src/AnimationLoop.cpp @@ -73,12 +73,6 @@ void AnimationLoop::simulate(float deltaTime) { _frameIndex = startFrameIndex + glm::mod(_frameIndex - startFrameIndex, endFrameIndex - startFrameIndex); } } - - /* - qDebug() << "AnimationLoop::simulate()"; - qDebug() << " deltaTime:" << deltaTime; - qDebug() << " _frameIndex:" << _frameIndex; - */ } void AnimationLoop::setStartAutomatically(bool startAutomatically) { diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index bc0ade66f4..265476b09d 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -36,8 +36,6 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityI _lastAnimated = usecTimestampNow(); _jointMappingCompleted = false; _color[0] = _color[1] = _color[2] = 0; - - //_animationFrameIndex = 0.0f; } EntityItemProperties ModelEntityItem::getProperties() const { @@ -116,8 +114,6 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, setAnimationFPS(animationFPS); setAnimationFrameIndex(animationFrameIndex); -qDebug() << "just read PROP_ANIMATION_FRAME_INDEX, getAnimationFrameIndex():" << getAnimationFrameIndex(); - READ_ENTITY_PROPERTY_STRING(PROP_TEXTURES, setTextures); return bytesRead; From b6c004c43140d188f8ad00efe2d983f8deec5b0e Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 17:16:43 -0800 Subject: [PATCH 29/44] Fix syntax that doesn't compile on linux and used smart glm::max instruction --- libraries/shared/src/Transform.cpp | 6 +----- libraries/shared/src/Transform.h | 4 +++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index 296f0743ca..9945091ed0 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -43,12 +43,8 @@ void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotat // extract scale of the matrix as the length of each axis Mat3 scaleMat = glm::inverse(rotationMat) * rotationScaleMatrix; - scale = Vec3(scaleMat[0][0], scaleMat[1][1], scaleMat[2][2]); - if (scale.x < ACCURACY_THREASHOLD) scale.x = ACCURACY_THREASHOLD; - if (scale.y < ACCURACY_THREASHOLD) scale.y = ACCURACY_THREASHOLD; - if (scale.z < ACCURACY_THREASHOLD) scale.z = ACCURACY_THREASHOLD; + scale = glm::max(Vec3(ACCURACY_THREASHOLD), Vec3(scaleMat[0][0], scaleMat[1][1], scaleMat[2][2])); - // Let's work on a local matrix containing rotation only Mat3 matRot( rotationScaleMatrix[0] / scale.x, diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index d1dd04811f..6ad106063f 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -277,7 +277,9 @@ inline Transform::Mat4& Transform::getMatrix(Transform::Mat4& result) const { } inline Transform::Mat4& Transform::getInverseMatrix(Transform::Mat4& result) const { - return evalInverse(Transform()).getMatrix(result); + Transform inverse; + evalInverse(inverse); + return inverse.getMatrix(result); } inline void Transform::evalFromRawMatrix(const Mat4& matrix) { From 8a2e3d5045e214c97c714c54c6bedf0ae7d2ab7f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 17:41:55 -0800 Subject: [PATCH 30/44] add animationSettings property to model entities --- examples/libraries/entityPropertyDialogBox.js | 3 +++ libraries/entities/src/EntityItemProperties.cpp | 13 +++++++++++-- libraries/entities/src/EntityItemProperties.h | 11 ++++++++++- libraries/entities/src/ModelEntityItem.cpp | 5 +++++ libraries/entities/src/ModelEntityItem.h | 3 +++ 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index ef597549f2..d4ece08bf4 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -52,6 +52,8 @@ EntityPropertyDialogBox = (function () { index++; array.push({ label: "Animation Frame:", value: properties.animationFrameIndex }); index++; + array.push({ label: "Animation Settings:", value: properties.animationSettings }); + index++; array.push({ label: "Textures:", value: properties.textures }); index++; array.push({ label: "Original Textures:\n" + properties.originalTextures, type: "header" }); @@ -240,6 +242,7 @@ EntityPropertyDialogBox = (function () { properties.animationIsPlaying = array[index++].value; properties.animationFPS = array[index++].value; properties.animationFrameIndex = array[index++].value; + properties.animationSettings = array[index++].value; properties.textures = array[index++].value; index++; // skip textureNames label } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index cb6d9c7bcd..e259c5c982 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -66,6 +66,7 @@ EntityItemProperties::EntityItemProperties() : _animationIsPlaying(ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING), _animationFrameIndex(ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX), _animationFPS(ModelEntityItem::DEFAULT_ANIMATION_FPS), + _animationSettings(""), _glowLevel(0.0f), _localRenderAlpha(1.0f), _isSpotlight(false), @@ -76,6 +77,8 @@ EntityItemProperties::EntityItemProperties() : _animationIsPlayingChanged(false), _animationFrameIndexChanged(false), _animationFPSChanged(false), + _animationSettingsChanged(false), + _glowLevelChanged(false), _localRenderAlphaChanged(false), _isSpotlightChanged(false), @@ -149,6 +152,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, animationIsPlaying); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FPS, animationFPS); + CHECK_PROPERTY_CHANGE(PROP_ANIMATION_SETTINGS, animationSettings); CHECK_PROPERTY_CHANGE(PROP_VISIBLE, visible); CHECK_PROPERTY_CHANGE(PROP_REGISTRATION_POINT, registrationPoint); CHECK_PROPERTY_CHANGE(PROP_ANGULAR_VELOCITY, angularVelocity); @@ -201,8 +205,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL); COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL); COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying); - COPY_PROPERTY_TO_QSCRIPTVALUE(animationFrameIndex); COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS); + COPY_PROPERTY_TO_QSCRIPTVALUE(animationFrameIndex); + COPY_PROPERTY_TO_QSCRIPTVALUE(animationSettings); COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); COPY_PROPERTY_TO_QSCRIPTVALUE(ignoreForCollisions); @@ -276,6 +281,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(animationIsPlaying, setAnimationIsPlaying); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFrameIndex, setAnimationFrameIndex); + COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(animationSettings, setAnimationSettings); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(glowLevel, setGlowLevel); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(localRenderAlpha, setLocalRenderAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(ignoreForCollisions, setIgnoreForCollisions); @@ -452,6 +458,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_CUTOFF, appendValue, properties.getCutoff()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, appendValue, properties.getLocked()); APPEND_ENTITY_PROPERTY(PROP_TEXTURES, appendValue, properties.getTextures()); + APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, appendValue, properties.getAnimationSettings()); } if (propertyCount > 0) { int endOfEntityItemData = packetData->getUncompressedByteOffset(); @@ -661,7 +668,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CUTOFF, float, setCutoff); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_TEXTURES, setTextures); - + READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_SETTINGS, setAnimationSettings); + return valid; } @@ -714,6 +722,7 @@ void EntityItemProperties::markAllChanged() { _animationIsPlayingChanged = true; _animationFrameIndexChanged = true; _animationFPSChanged = true; + _animationSettingsChanged = true; _glowLevelChanged = true; _localRenderAlphaChanged = true; _isSpotlightChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 6b22e8cba9..6cc205c1a2 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -80,8 +80,9 @@ enum EntityPropertyList { // used by Model entities PROP_TEXTURES, + PROP_ANIMATION_SETTINGS, - PROP_LAST_ITEM = PROP_CUTOFF + PROP_LAST_ITEM = PROP_ANIMATION_SETTINGS }; typedef PropertyFlags EntityPropertyFlags; @@ -178,6 +179,8 @@ public: float getAnimationFrameIndex() const { return _animationFrameIndex; } bool getAnimationIsPlaying() const { return _animationIsPlaying; } float getAnimationFPS() const { return _animationFPS; } + const QString& getAnimationSettings() const { return _animationSettings; } + float getGlowLevel() const { return _glowLevel; } float getLocalRenderAlpha() const { return _localRenderAlpha; } const QString& getScript() const { return _script; } @@ -189,6 +192,10 @@ public: void setAnimationFrameIndex(float value) { _animationFrameIndex = value; _animationFrameIndexChanged = true; } void setAnimationIsPlaying(bool value) { _animationIsPlaying = value; _animationIsPlayingChanged = true; } void setAnimationFPS(float value) { _animationFPS = value; _animationFPSChanged = true; } + void setAnimationSettings(const QString& value) + { _animationSettings = value; _animationSettingsChanged = true; } + + void setGlowLevel(float value) { _glowLevel = value; _glowLevelChanged = true; } void setLocalRenderAlpha(float value) { _localRenderAlpha = value; _localRenderAlphaChanged = true; } void setScript(const QString& value) { _script = value; _scriptChanged = true; } @@ -342,6 +349,7 @@ private: bool _animationIsPlaying; float _animationFrameIndex; float _animationFPS; + QString _animationSettings; float _glowLevel; float _localRenderAlpha; bool _isSpotlight; @@ -352,6 +360,7 @@ private: bool _animationIsPlayingChanged; bool _animationFrameIndexChanged; bool _animationFPSChanged; + bool _animationSettingsChanged; bool _glowLevelChanged; bool _localRenderAlphaChanged; bool _isSpotlightChanged; diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 265476b09d..095b1099b2 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -49,6 +49,7 @@ EntityItemProperties ModelEntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFPS, getAnimationFPS); COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel); COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationSettings, getAnimationSettings); return properties; } @@ -63,6 +64,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties, bool SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFPS, setAnimationFPS); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationSettings, setAnimationSettings); if (somethingChanged) { bool wantDebug = false; @@ -115,6 +117,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, setAnimationFrameIndex(animationFrameIndex); READ_ENTITY_PROPERTY_STRING(PROP_TEXTURES, setTextures); + READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_SETTINGS, setAnimationSettings); return bytesRead; } @@ -244,6 +247,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& requestedProperties += PROP_ANIMATION_FPS; requestedProperties += PROP_ANIMATION_FRAME_INDEX; requestedProperties += PROP_ANIMATION_PLAYING; + requestedProperties += PROP_ANIMATION_SETTINGS; requestedProperties += PROP_TEXTURES; return requestedProperties; @@ -266,6 +270,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, appendValue, getAnimationIsPlaying()); APPEND_ENTITY_PROPERTY(PROP_TEXTURES, appendValue, getTextures()); + APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, appendValue, getAnimationSettings()); } diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index aea9407e8b..4a581f2c0a 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -76,6 +76,7 @@ public: void setAnimationURL(const QString& url) { _animationURL = url; } static const float DEFAULT_ANIMATION_FRAME_INDEX; void setAnimationFrameIndex(float value) { _animationLoop.setFrameIndex(value); } + void setAnimationSettings(const QString& value) { _animationSettings = value; } static const bool DEFAULT_ANIMATION_IS_PLAYING; void setAnimationIsPlaying(bool value) { _animationLoop.setRunning(value); } @@ -90,6 +91,7 @@ public: bool getAnimationIsPlaying() const { return _animationLoop.isRunning(); } float getAnimationFrameIndex() const { return _animationLoop.getFrameIndex(); } float getAnimationFPS() const { return _animationLoop.getFPS(); } + const QString& getAnimationSettings() const { return _animationSettings; } static const QString DEFAULT_TEXTURES; const QString& getTextures() const { return _textures; } @@ -109,6 +111,7 @@ protected: quint64 _lastAnimated; QString _animationURL; AnimationLoop _animationLoop; + QString _animationSettings; QString _textures; // used on client side From 859c99b9de510040c074a81c650ebb51b7e9b901 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 18:15:35 -0800 Subject: [PATCH 31/44] Fix bug in the cache of GLBackend::TransformStage --- interface/src/gpu/GLBackend.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 774aaf6ae6..8921dc6d1c 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -432,7 +432,7 @@ void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { TransformPointer modelTransform = batch._transforms.get(batch._params[paramOffset]._uint); - if (modelTransform != _transform._model) { + if (_transform._model.isNull() || (modelTransform != _transform._model)) { _transform._model = modelTransform; _transform._invalidModel = true; } @@ -441,7 +441,7 @@ void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { TransformPointer viewTransform = batch._transforms.get(batch._params[paramOffset]._uint); - if (viewTransform != _transform._view) { + if (_transform._view.isNull() || (viewTransform != _transform._view)) { _transform._view = viewTransform; _transform._invalidView = true; } @@ -450,7 +450,7 @@ void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { TransformPointer projectionTransform = batch._transforms.get(batch._params[paramOffset]._uint); - if (projectionTransform != _transform._projection) { + if (_transform._projection.isNull() || (projectionTransform != _transform._projection)) { _transform._projection = projectionTransform; _transform._invalidProj = true; } From c9e8c21d8d77d95b9b551a7acd096ef6d08f0862 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 19:23:48 -0800 Subject: [PATCH 32/44] partial work on blending of animation settings --- .../entities/src/EntityItemProperties.cpp | 58 +++++++++++++++++++ libraries/entities/src/EntityItemProperties.h | 4 +- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index e259c5c982..8c17aeae6b 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -120,6 +121,63 @@ void EntityItemProperties::setSittingPoints(const QVector& sitting } } +void EntityItemProperties::setAnimationSettings(const QString& value) { + // the animations setting is a JSON string that may contain various animation settings. + // if it includes fps, frameIndex, or running, those values will be parsed out and + // will over ride the regular animation settings + + QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); + QJsonObject settingsAsJsonObject = settingsAsJson.object(); + QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); + if (settingsMap.contains("fps")) { + float fps = settingsMap["fps"].toFloat(); + setAnimationFPS(fps); + } + + if (settingsMap.contains("frameIndex")) { + float frameIndex = settingsMap["frameIndex"].toFloat(); + setAnimationFrameIndex(frameIndex); + } + + if (settingsMap.contains("running")) { + bool running = settingsMap["running"].toBool(); + setAnimationIsPlaying(running); + } + + _animationSettings = value; + _animationSettingsChanged = true; +} + +/** +QString EntityItemProperties::getAnimationSettings() const { + // the animations setting is a JSON string that may contain various animation settings. + // if it includes fps, frameIndex, or running, those values will be parsed out and + // will over ride the regular animation settings + QString value = _animationSettings; + + QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); + QJsonObject settingsAsJsonObject = settingsAsJson.object(); + QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); + if (settingsMap.contains("fps")) { + float fps = settingsMap["fps"].toFloat(); + setAnimationFPS(fps); + } + + if (settingsMap.contains("frameIndex")) { + float frameIndex = settingsMap["frameIndex"].toFloat(); + setAnimationFrameIndex(frameIndex); + } + + if (settingsMap.contains("running")) { + bool running = settingsMap["running"].toBool(); + setAnimationIsPlaying(running); + } + + _animationSettings = value; + _animationSettingsChanged = true; +} +**/ + void EntityItemProperties::debugDump() const { qDebug() << "EntityItemProperties..."; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 6cc205c1a2..5828a07122 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -192,9 +192,7 @@ public: void setAnimationFrameIndex(float value) { _animationFrameIndex = value; _animationFrameIndexChanged = true; } void setAnimationIsPlaying(bool value) { _animationIsPlaying = value; _animationIsPlayingChanged = true; } void setAnimationFPS(float value) { _animationFPS = value; _animationFPSChanged = true; } - void setAnimationSettings(const QString& value) - { _animationSettings = value; _animationSettingsChanged = true; } - + void setAnimationSettings(const QString& value); void setGlowLevel(float value) { _glowLevel = value; _glowLevelChanged = true; } void setLocalRenderAlpha(float value) { _localRenderAlpha = value; _localRenderAlphaChanged = true; } From 63a8608ac616bf712a3b196183988d91ae6429b4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Nov 2014 20:20:36 -0800 Subject: [PATCH 33/44] handle per model transforms, default scene mode off --- interface/src/Menu.cpp | 2 +- interface/src/Menu.h | 2 +- interface/src/entities/EntityTreeRenderer.cpp | 2 +- .../entities/RenderableModelEntityItem.cpp | 2 +- interface/src/renderer/Model.cpp | 69 +++++++++++++++++-- interface/src/renderer/Model.h | 6 +- 6 files changed, 74 insertions(+), 9 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c192d8f23c..e0feb4e349 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -438,7 +438,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisableLightEntities, 0, false); addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DontReduceMaterialSwitches, 0, false); - addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DontRenderEntitiesAsScene, 0, false); + addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::RenderEntitiesAsScene, 0, false); QMenu* entityCullingMenu = entitiesDebugMenu->addMenu("Culling"); addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontCullOutOfViewMeshParts, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 4f72ac138d..b745246780 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -377,7 +377,6 @@ namespace MenuOption { const QString DontCullOutOfViewMeshParts = "Don't Cull Out Of View Mesh Parts"; const QString DontCullTooSmallMeshParts = "Don't Cull Too Small Mesh Parts"; const QString DontReduceMaterialSwitches = "Don't Attempt to Reduce Material Switches"; - const QString DontRenderEntitiesAsScene = "Don't Render Entities as Scene"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableActivityLogger = "Disable Activity Logger"; @@ -448,6 +447,7 @@ namespace MenuOption { const QString ReloadAllScripts = "Reload All Scripts"; const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes"; const QString RenderDualContourSurfaces = "Render Dual Contour Surfaces"; + const QString RenderEntitiesAsScene = "Render Entities as Scene"; const QString RenderFocusIndicator = "Show Eye Focus"; const QString RenderHeadCollisionShapes = "Show Head Collision Shapes"; const QString RenderHeightfields = "Render Heightfields"; diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index f2ad41f045..99e4916c62 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -253,7 +253,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { } void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode) { - bool dontRenderAsScene = Menu::getInstance()->isOptionChecked(MenuOption::DontRenderEntitiesAsScene); + bool dontRenderAsScene = !Menu::getInstance()->isOptionChecked(MenuOption::RenderEntitiesAsScene); if (dontRenderAsScene) { OctreeRenderer::render(renderMode); diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 0864b34d0e..8d932b121d 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -172,7 +172,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // TODO: this is the majority of model render time. And rendering of a cube model vs the basic Box render // is significantly more expensive. Is there a way to call this that doesn't cost us as much? PerformanceTimer perfTimer("model->render"); - bool dontRenderAsScene = Menu::getInstance()->isOptionChecked(MenuOption::DontRenderEntitiesAsScene); + bool dontRenderAsScene = !Menu::getInstance()->isOptionChecked(MenuOption::RenderEntitiesAsScene); if (dontRenderAsScene) { _model->render(alpha, modelRenderMode, args); } else { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 60f72aad1b..8b3c656ae7 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1483,15 +1483,29 @@ void Model::deleteGeometry() { // Scene rendering support QVector Model::_modelsInScene; +gpu::Batch Model::_sceneRenderBatch; void Model::startScene() { _modelsInScene.clear(); } -void Model::endScene(RenderMode mode, RenderArgs* args) { +void Model::setupBatchTransform(gpu::Batch& batch) { + GLBATCH(glPushMatrix)(); + + // Capture the view matrix once for the rendering of this model + if (_transforms.empty()) { + _transforms.push_back(gpu::TransformPointer(new gpu::Transform())); + } + (*_transforms[0]) = gpu::Transform((*Application::getInstance()->getViewTransform())); + _transforms[0]->preTranslate(-_translation); + batch.setViewTransform(_transforms[0]); +} + +void Model::endScene(RenderMode mode, RenderArgs* args) { + PROFILE_RANGE(__FUNCTION__); - // first, do all the batch/GPU setup work.... // Let's introduce a gpu::Batch to capture all the calls to the graphics api - gpu::Batch batch; + _sceneRenderBatch.clear(); + gpu::Batch& batch = _sceneRenderBatch; GLBATCH(glDisable)(GL_COLOR_MATERIAL); @@ -1540,28 +1554,44 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { // now, for each model in the scene, render the mesh portions foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); + GLBATCH(glPopMatrix)(); } // render translucent meshes afterwards @@ -1577,28 +1607,44 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { int translucentParts = 0; const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); + GLBATCH(glPopMatrix)(); } GLBATCH(glDisable)(GL_ALPHA_TEST); @@ -1617,28 +1663,44 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args); + GLBATCH(glPopMatrix)(); } foreach(Model* model, _modelsInScene) { + model->setupBatchTransform(batch); translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); + GLBATCH(glPopMatrix)(); } } @@ -1668,7 +1730,6 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { { PROFILE_RANGE("render Batch"); ::gpu::GLBackend::renderBatch(batch); - batch.clear(); } // restore all the default material settings diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 70d4f689ac..8c74b1a222 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -284,7 +284,7 @@ private: gpu::Buffers _blendedVertexBuffers; gpu::Transforms _transforms; - gpu::Batch _renderBatch; + gpu::Batch _renderBatch; QVector > > _dilatedTextures; @@ -398,6 +398,8 @@ private: // Scene rendering support static QVector _modelsInScene; + static gpu::Batch _sceneRenderBatch; + static void endSceneSimple(RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); static void endSceneSplitPass(RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); @@ -406,6 +408,8 @@ private: bool renderCore(float alpha, RenderMode mode, RenderArgs* args); int renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL); + void setupBatchTransform(gpu::Batch& batch); + }; Q_DECLARE_METATYPE(QPointer) From e4355cd139582413a1dd8c3359660644bd17919c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 07:34:54 -0800 Subject: [PATCH 34/44] calculated animationSettings property to include older properties --- .../entities/src/EntityItemProperties.cpp | 38 +++++++++---------- libraries/entities/src/EntityItemProperties.h | 2 +- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 8c17aeae6b..61846d008e 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -148,7 +148,6 @@ void EntityItemProperties::setAnimationSettings(const QString& value) { _animationSettingsChanged = true; } -/** QString EntityItemProperties::getAnimationSettings() const { // the animations setting is a JSON string that may contain various animation settings. // if it includes fps, frameIndex, or running, those values will be parsed out and @@ -158,26 +157,22 @@ QString EntityItemProperties::getAnimationSettings() const { QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonObject settingsAsJsonObject = settingsAsJson.object(); QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); - if (settingsMap.contains("fps")) { - float fps = settingsMap["fps"].toFloat(); - setAnimationFPS(fps); - } - - if (settingsMap.contains("frameIndex")) { - float frameIndex = settingsMap["frameIndex"].toFloat(); - setAnimationFrameIndex(frameIndex); - } - - if (settingsMap.contains("running")) { - bool running = settingsMap["running"].toBool(); - setAnimationIsPlaying(running); - } - _animationSettings = value; - _animationSettingsChanged = true; -} -**/ + QVariant fpsValue(getAnimationFPS()); + settingsMap["fps"] = fpsValue; + QVariant frameIndexValue(getAnimationFrameIndex()); + settingsMap["frameIndex"] = frameIndexValue; + + QVariant runningValue(getAnimationIsPlaying()); + settingsMap["running"] = runningValue; + + settingsAsJsonObject = QJsonObject::fromVariantMap(settingsMap); + QJsonDocument newDocument(settingsAsJsonObject); + QByteArray jsonByteArray = newDocument.toJson(QJsonDocument::Compact); + QString jsonByteString(jsonByteArray); + return jsonByteString; +} void EntityItemProperties::debugDump() const { qDebug() << "EntityItemProperties..."; @@ -265,7 +260,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying); COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS); COPY_PROPERTY_TO_QSCRIPTVALUE(animationFrameIndex); - COPY_PROPERTY_TO_QSCRIPTVALUE(animationSettings); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(animationSettings,getAnimationSettings()); COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); COPY_PROPERTY_TO_QSCRIPTVALUE(ignoreForCollisions); @@ -340,6 +335,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFrameIndex, setAnimationFrameIndex); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(animationSettings, setAnimationSettings); + +qDebug() << "_animationSettingsChanged:" << _animationSettingsChanged; + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(glowLevel, setGlowLevel); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(localRenderAlpha, setLocalRenderAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(ignoreForCollisions, setIgnoreForCollisions); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 5828a07122..d6b8181c28 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -179,7 +179,7 @@ public: float getAnimationFrameIndex() const { return _animationFrameIndex; } bool getAnimationIsPlaying() const { return _animationIsPlaying; } float getAnimationFPS() const { return _animationFPS; } - const QString& getAnimationSettings() const { return _animationSettings; } + QString getAnimationSettings() const; float getGlowLevel() const { return _glowLevel; } float getLocalRenderAlpha() const { return _localRenderAlpha; } From 43f44f4131e4c4ecc588ec7395c4d9f23c19df3d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 07:52:00 -0800 Subject: [PATCH 35/44] suppress some potentially repeated log messages --- libraries/octree/src/Octree.cpp | 21 +++++++++++++++++++-- libraries/octree/src/OctreeSceneStats.cpp | 7 ++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 596dd7536c..4450689949 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -71,6 +72,10 @@ void Octree::recurseTreeWithPostOperation(RecurseOctreeOperation operation, void void Octree::recurseElementWithOperation(OctreeElement* element, RecurseOctreeOperation operation, void* extraData, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { + static QString repeatedMessage + = LogHandler::getInstance().addRepeatedMessageRegex( + "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); + qDebug() << "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return; } @@ -89,7 +94,11 @@ void Octree::recurseElementWithOperation(OctreeElement* element, RecurseOctreeOp void Octree::recurseElementWithPostOperation(OctreeElement* element, RecurseOctreeOperation operation, void* extraData, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { - qDebug() << "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!\n"; + static QString repeatedMessage + = LogHandler::getInstance().addRepeatedMessageRegex( + "Octree::recurseElementWithPostOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); + + qDebug() << "Octree::recurseElementWithPostOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return; } @@ -115,6 +124,10 @@ void Octree::recurseElementWithOperationDistanceSorted(OctreeElement* element, R const glm::vec3& point, void* extraData, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { + static QString repeatedMessage + = LogHandler::getInstance().addRepeatedMessageRegex( + "Octree::recurseElementWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); + qDebug() << "Octree::recurseElementWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return; } @@ -152,7 +165,11 @@ void Octree::recurseTreeWithOperator(RecurseOctreeOperator* operatorObject) { bool Octree::recurseElementWithOperator(OctreeElement* element, RecurseOctreeOperator* operatorObject, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { - qDebug() << "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; + static QString repeatedMessage + = LogHandler::getInstance().addRepeatedMessageRegex( + "Octree::recurseElementWithOperator() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); + + qDebug() << "Octree::recurseElementWithOperator() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return false; } diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 82a874a680..4b21890a22 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -854,8 +855,12 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, const int MAX_RESONABLE_FLIGHT_TIME = 200 * USECS_PER_SECOND; // 200 seconds is more than enough time for a packet to arrive const int MIN_RESONABLE_FLIGHT_TIME = 0; if (flightTime > MAX_RESONABLE_FLIGHT_TIME || flightTime < MIN_RESONABLE_FLIGHT_TIME) { + static QString repeatedMessage + = LogHandler::getInstance().addRepeatedMessageRegex( + "ignoring unreasonable packet... flightTime: -?\\d+ nodeClockSkewUsec: -?\\d+ usecs"); + qDebug() << "ignoring unreasonable packet... flightTime:" << flightTime - << " nodeClockSkewUsec:" << nodeClockSkewUsec << " usecs";; + << "nodeClockSkewUsec:" << nodeClockSkewUsec << "usecs";; return; // ignore any packets that are unreasonable } From ea0022501b67325beda648abc666e47229fd2909 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 08:13:30 -0800 Subject: [PATCH 36/44] only set animation properties if they actually changed --- examples/libraries/entityPropertyDialogBox.js | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index d4ece08bf4..d0d5add708 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -22,6 +22,8 @@ EntityPropertyDialogBox = (function () { var dimensionZ; var rescalePercentage; var editModelID = -1; + var previousAnimationFrameIndex; + var previousAnimationSettings; that.cleanup = function () { }; @@ -51,8 +53,10 @@ EntityPropertyDialogBox = (function () { array.push({ label: "Animation FPS:", value: properties.animationFPS }); index++; array.push({ label: "Animation Frame:", value: properties.animationFrameIndex }); + previousAnimationFrameIndex = properties.animationFrameIndex; index++; array.push({ label: "Animation Settings:", value: properties.animationSettings }); + previousAnimationSettings = properties.animationSettings; index++; array.push({ label: "Textures:", value: properties.textures }); index++; @@ -241,8 +245,21 @@ EntityPropertyDialogBox = (function () { properties.animationURL = array[index++].value; properties.animationIsPlaying = array[index++].value; properties.animationFPS = array[index++].value; - properties.animationFrameIndex = array[index++].value; - properties.animationSettings = array[index++].value; + + var newAnimationFrameIndex = array[index++].value; + var newAnimationSettings = array[index++].value; + + if (previousAnimationFrameIndex != newAnimationFrameIndex) { + properties.animationFrameIndex = newAnimationFrameIndex; + } else { + delete properties.animationFrameIndex; + } + + if (previousAnimationSettings != newAnimationSettings) { + properties.animationSettings = newAnimationSettings; + } else { + delete properties.animationSettings; + } properties.textures = array[index++].value; index++; // skip textureNames label } From 09a06c9d825dd8ef7b4778a325b20296b512f830 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 08:14:01 -0800 Subject: [PATCH 37/44] add debug streamer for xColor --- libraries/shared/src/SharedUtil.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index ac1b73e50b..69dfb4db35 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -34,6 +34,15 @@ struct xColor { unsigned char blue; }; +inline QDebug& operator<<(QDebug& dbg, const xColor& c) { + dbg.nospace() << "{type='xColor'" + ", red=" << c.red << + ", green=" << c.green << + ", blue=" << c.blue << + "}"; + return dbg; +} + static const float ZERO = 0.0f; static const float ONE = 1.0f; static const float ONE_HALF = 0.5f; From 55c177594bfe6d8f0abcc543dd37505002c5e820 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 08:37:54 -0800 Subject: [PATCH 38/44] only set animationIsPlaying if it changed --- examples/libraries/entityPropertyDialogBox.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index d0d5add708..da60e0c370 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -22,6 +22,7 @@ EntityPropertyDialogBox = (function () { var dimensionZ; var rescalePercentage; var editModelID = -1; + var previousAnimationIsPlaying; var previousAnimationFrameIndex; var previousAnimationSettings; @@ -49,6 +50,7 @@ EntityPropertyDialogBox = (function () { array.push({ label: "Animation URL:", value: properties.animationURL }); index++; array.push({ label: "Animation is playing:", value: properties.animationIsPlaying }); + previousAnimationIsPlaying = properties.animationIsPlaying; index++; array.push({ label: "Animation FPS:", value: properties.animationFPS }); index++; @@ -243,18 +245,24 @@ EntityPropertyDialogBox = (function () { if (properties.type == "Model") { properties.modelURL = array[index++].value; properties.animationURL = array[index++].value; - properties.animationIsPlaying = array[index++].value; + + var newAnimationIsPlaying = array[index++].value; + if (previousAnimationIsPlaying != newAnimationIsPlaying) { + properties.animationIsPlaying = newAnimationIsPlaying; + } else { + delete properties.animationIsPlaying; + } + properties.animationFPS = array[index++].value; var newAnimationFrameIndex = array[index++].value; - var newAnimationSettings = array[index++].value; - if (previousAnimationFrameIndex != newAnimationFrameIndex) { properties.animationFrameIndex = newAnimationFrameIndex; } else { delete properties.animationFrameIndex; } + var newAnimationSettings = array[index++].value; if (previousAnimationSettings != newAnimationSettings) { properties.animationSettings = newAnimationSettings; } else { From bc60c90308e70fb717d9ce61666cdc6e1d006c61 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 08:39:19 -0800 Subject: [PATCH 39/44] only actually set the properties if they were in the buffer --- libraries/entities/src/ModelEntityItem.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 095b1099b2..ee13ed171b 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -112,9 +112,15 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, animationFrameIndex); READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, animationIsPlaying); - setAnimationIsPlaying(animationIsPlaying); - setAnimationFPS(animationFPS); - setAnimationFrameIndex(animationFrameIndex); + if (propertyFlags.getHasProperty(PROP_ANIMATION_PLAYING)) { + setAnimationIsPlaying(animationIsPlaying); + } + if (propertyFlags.getHasProperty(PROP_ANIMATION_FPS)) { + setAnimationFPS(animationFPS); + } + if (propertyFlags.getHasProperty(PROP_ANIMATION_FRAME_INDEX)) { + setAnimationFrameIndex(animationFrameIndex); + } READ_ENTITY_PROPERTY_STRING(PROP_TEXTURES, setTextures); READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_SETTINGS, setAnimationSettings); From 701059d7976698a58347af0211ef97fc96e4eb25 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 08:58:33 -0800 Subject: [PATCH 40/44] removed some debug --- libraries/entities/src/EntityItemProperties.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 61846d008e..9e75350bd4 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -335,9 +335,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFrameIndex, setAnimationFrameIndex); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(animationSettings, setAnimationSettings); - -qDebug() << "_animationSettingsChanged:" << _animationSettingsChanged; - COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(glowLevel, setGlowLevel); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(localRenderAlpha, setLocalRenderAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(ignoreForCollisions, setIgnoreForCollisions); From 8ec12ea95435952faadb93bf602c4b1c18889272 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 08:59:06 -0800 Subject: [PATCH 41/44] add full animation settings support --- libraries/entities/src/ModelEntityItem.cpp | 93 ++++++++++++++++++++++ libraries/entities/src/ModelEntityItem.h | 19 ++++- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index ee13ed171b..d955f22478 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include #include @@ -405,3 +407,94 @@ void ModelEntityItem::debugDump() const { qDebug() << " model URL:" << getModelURL(); } +void ModelEntityItem::setAnimationSettings(const QString& value) { + // the animations setting is a JSON string that may contain various animation settings. + // if it includes fps, frameIndex, or running, those values will be parsed out and + // will over ride the regular animation settings + + QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); + QJsonObject settingsAsJsonObject = settingsAsJson.object(); + QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); + if (settingsMap.contains("fps")) { + float fps = settingsMap["fps"].toFloat(); + setAnimationFPS(fps); + } + + if (settingsMap.contains("frameIndex")) { + float frameIndex = settingsMap["frameIndex"].toFloat(); + setAnimationFrameIndex(frameIndex); + } + + if (settingsMap.contains("running")) { + bool running = settingsMap["running"].toBool(); + setAnimationIsPlaying(running); + } + + if (settingsMap.contains("firstFrame")) { + float firstFrame = settingsMap["firstFrame"].toFloat(); + setAnimationFirstFrame(firstFrame); + } + + if (settingsMap.contains("lastFrame")) { + float lastFrame = settingsMap["lastFrame"].toFloat(); + setAnimationLastFrame(lastFrame); + } + + if (settingsMap.contains("loop")) { + bool loop = settingsMap["loop"].toBool(); + setAnimationLoop(loop); + } + + if (settingsMap.contains("hold")) { + bool hold = settingsMap["hold"].toBool(); + setAnimationHold(hold); + } + + if (settingsMap.contains("startAutomatically")) { + bool startAutomatically = settingsMap["startAutomatically"].toBool(); + setAnimationStartAutomatically(startAutomatically); + } + + _animationSettings = value; +} + +QString ModelEntityItem::getAnimationSettings() const { + // the animations setting is a JSON string that may contain various animation settings. + // if it includes fps, frameIndex, or running, those values will be parsed out and + // will over ride the regular animation settings + QString value = _animationSettings; + + QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); + QJsonObject settingsAsJsonObject = settingsAsJson.object(); + QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); + + QVariant fpsValue(getAnimationFPS()); + settingsMap["fps"] = fpsValue; + + QVariant frameIndexValue(getAnimationFrameIndex()); + settingsMap["frameIndex"] = frameIndexValue; + + QVariant runningValue(getAnimationIsPlaying()); + settingsMap["running"] = runningValue; + + QVariant firstFrameValue(getAnimationFirstFrame()); + settingsMap["firstFrame"] = firstFrameValue; + + QVariant lastFrameValue(getAnimationLastFrame()); + settingsMap["lastFrame"] = lastFrameValue; + + QVariant loopValue(getAnimationLoop()); + settingsMap["loop"] = loopValue; + + QVariant holdValue(getAnimationHold()); + settingsMap["hold"] = holdValue; + + QVariant startAutomaticallyValue(getAnimationStartAutomatically()); + settingsMap["startAutomatically"] = startAutomaticallyValue; + + settingsAsJsonObject = QJsonObject::fromVariantMap(settingsMap); + QJsonDocument newDocument(settingsAsJsonObject); + QByteArray jsonByteArray = newDocument.toJson(QJsonDocument::Compact); + QString jsonByteString(jsonByteArray); + return jsonByteString; +} diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 4a581f2c0a..97ffed4076 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -76,13 +76,28 @@ public: void setAnimationURL(const QString& url) { _animationURL = url; } static const float DEFAULT_ANIMATION_FRAME_INDEX; void setAnimationFrameIndex(float value) { _animationLoop.setFrameIndex(value); } - void setAnimationSettings(const QString& value) { _animationSettings = value; } + void setAnimationSettings(const QString& value); static const bool DEFAULT_ANIMATION_IS_PLAYING; void setAnimationIsPlaying(bool value) { _animationLoop.setRunning(value); } static const float DEFAULT_ANIMATION_FPS; void setAnimationFPS(float value) { _animationLoop.setFPS(value); } + + void setAnimationLoop(bool loop) { _animationLoop.setLoop(loop); } + bool getAnimationLoop() const { return _animationLoop.getLoop(); } + + void setAnimationHold(bool hold) { _animationLoop.setHold(hold); } + bool getAnimationHold() const { return _animationLoop.getHold(); } + + void setAnimationStartAutomatically(bool startAutomatically) { _animationLoop.setStartAutomatically(startAutomatically); } + bool getAnimationStartAutomatically() const { return _animationLoop.getStartAutomatically(); } + + void setAnimationFirstFrame(float firstFrame) { _animationLoop.setFirstFrame(firstFrame); } + float getAnimationFirstFrame() const { return _animationLoop.getFirstFrame(); } + + void setAnimationLastFrame(float lastFrame) { _animationLoop.setLastFrame(lastFrame); } + float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); } void mapJoints(const QStringList& modelJointNames); QVector getAnimationFrame(); @@ -91,7 +106,7 @@ public: bool getAnimationIsPlaying() const { return _animationLoop.isRunning(); } float getAnimationFrameIndex() const { return _animationLoop.getFrameIndex(); } float getAnimationFPS() const { return _animationLoop.getFPS(); } - const QString& getAnimationSettings() const { return _animationSettings; } + QString getAnimationSettings() const; static const QString DEFAULT_TEXTURES; const QString& getTextures() const { return _textures; } From 42a73e280eee8dd412b553ce213aa70fc1a68f58 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 13 Nov 2014 09:29:37 -0800 Subject: [PATCH 42/44] remove the concert camera scripts from examples --- examples/concertCamera.js | 72 ---------------------------------- examples/concertCamera_kims.js | 72 ---------------------------------- examples/concertCamera_kyrs.js | 72 ---------------------------------- 3 files changed, 216 deletions(-) delete mode 100644 examples/concertCamera.js delete mode 100644 examples/concertCamera_kims.js delete mode 100644 examples/concertCamera_kyrs.js diff --git a/examples/concertCamera.js b/examples/concertCamera.js deleted file mode 100644 index 7ab7785345..0000000000 --- a/examples/concertCamera.js +++ /dev/null @@ -1,72 +0,0 @@ -// -// concertCamera.js -// -// Created by Philip Rosedale on June 24, 2014 -// Copyright 2014 High Fidelity, Inc. -// -// Move a camera through a series of pre-set locations by pressing number keys -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var oldMode; -var avatarPosition; - -var cameraNumber = 0; -var freeCamera = false; - -var cameraLocations = [ {x: 7971.9, y: 241.3, z: 7304.1}, {x: 7973.0, y: 241.3, z: 7304.1}, {x: 7975.5, y: 241.3, z: 7304.1}, {x: 7972.3, y: 241.3, z: 7303.3}, {x: 7971.0, y: 241.3, z: 7304.3}, {x: 7973.5, y: 240.7, z: 7302.5} ]; -var cameraLookAts = [ {x: 7971.1, y: 241.3, z: 7304.1}, {x: 7972.1, y: 241.3, z: 7304.1}, {x: 7972.1, y: 241.3, z: 7304.1}, {x: 7972.1, y: 241.3, z: 7304.1}, {x: 7972.1, y: 241.3, z: 7304.1}, {x: 7971.3, y: 241.3, z: 7304.2} ]; - -function saveCameraState() { - oldMode = Camera.mode; - avatarPosition = MyAvatar.position; - Camera.setModeShiftPeriod(0.0); - Camera.mode = "independent"; -} - -function restoreCameraState() { - Camera.stopLooking(); - Camera.mode = oldMode; -} - -function update(deltaTime) { - if (freeCamera) { - var delta = Vec3.subtract(MyAvatar.position, avatarPosition); - if (Vec3.length(delta) > 0.05) { - cameraNumber = 0; - freeCamera = false; - restoreCameraState(); - } - } -} - -function keyPressEvent(event) { - - var choice = parseInt(event.text); - - if ((choice > 0) && (choice <= cameraLocations.length)) { - print("camera " + choice); - if (!freeCamera) { - saveCameraState(); - freeCamera = true; - } - Camera.mode = "independent"; - Camera.setPosition(cameraLocations[choice - 1]); - Camera.keepLookingAt(cameraLookAts[choice - 1]); - } - if (event.text == "ESC") { - cameraNumber = 0; - freeCamera = false; - restoreCameraState(); - } - if (event.text == "0") { - // Show camera location in log - var cameraLocation = Camera.getPosition(); - print(cameraLocation.x + ", " + cameraLocation.y + ", " + cameraLocation.z); - } -} - -Script.update.connect(update); -Controller.keyPressEvent.connect(keyPressEvent); diff --git a/examples/concertCamera_kims.js b/examples/concertCamera_kims.js deleted file mode 100644 index ff4fb632de..0000000000 --- a/examples/concertCamera_kims.js +++ /dev/null @@ -1,72 +0,0 @@ -// -// concertCamera.js -// -// Created by Philip Rosedale on June 24, 2014 -// Copyright 2014 High Fidelity, Inc. -// -// Move a camera through a series of pre-set locations by pressing number keys -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var oldMode; -var avatarPosition; - -var cameraNumber = 0; -var freeCamera = false; - -var cameraLocations = [ {x: 8027.5, y: 237.5, z: 7305.7}, {x: 8027.5, y: 237.5, z: 7306.6}, {x: 8027.5, y: 237.5, z: 7308.0}, {x: 8027.5, y: 237.5, z: 7303.0}, {x: 8030.8, y: 238.6, z: 7311.4}, {x: 8030.9, y: 237.1, z: 7308.0} ]; -var cameraLookAts = [ {x: 8027.5, y: 237.5, z: 7304.0}, {x: 8027.5, y: 237.5, z: 7305.7}, {x: 8027.5, y: 237.5, z: 7304.0}, {x: 8027.5, y: 237.5, z: 7304.0}, {x: 8027.5, y: 237.5, z: 7304.0}, {x: 8027.5, y: 237.5, z: 7304.0} ]; - -function saveCameraState() { - oldMode = Camera.mode; - avatarPosition = MyAvatar.position; - Camera.setModeShiftPeriod(0.0); - Camera.mode = "independent"; -} - -function restoreCameraState() { - Camera.stopLooking(); - Camera.mode = oldMode; -} - -function update(deltaTime) { - if (freeCamera) { - var delta = Vec3.subtract(MyAvatar.position, avatarPosition); - if (Vec3.length(delta) > 0.05) { - cameraNumber = 0; - freeCamera = false; - restoreCameraState(); - } - } -} - -function keyPressEvent(event) { - - var choice = parseInt(event.text); - - if ((choice > 0) && (choice <= cameraLocations.length)) { - print("camera " + choice); - if (!freeCamera) { - saveCameraState(); - freeCamera = true; - } - Camera.mode = "independent"; - Camera.setPosition(cameraLocations[choice - 1]); - Camera.keepLookingAt(cameraLookAts[choice - 1]); - } - if (event.text == "ESC") { - cameraNumber = 0; - freeCamera = false; - restoreCameraState(); - } - if (event.text == "0") { - // Show camera location in log - var cameraLocation = Camera.getPosition(); - print(cameraLocation.x + ", " + cameraLocation.y + ", " + cameraLocation.z); - } -} - -Script.update.connect(update); -Controller.keyPressEvent.connect(keyPressEvent); diff --git a/examples/concertCamera_kyrs.js b/examples/concertCamera_kyrs.js deleted file mode 100644 index 4c7c893783..0000000000 --- a/examples/concertCamera_kyrs.js +++ /dev/null @@ -1,72 +0,0 @@ -// -// concertCamera.js -// -// Created by Philip Rosedale on June 24, 2014 -// Copyright 2014 High Fidelity, Inc. -// -// Move a camera through a series of pre-set locations by pressing number keys -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var oldMode; -var avatarPosition; - -var cameraNumber = 0; -var freeCamera = false; - -var cameraLocations = [ {x: 2921.5, y: 251.3, z: 8254.8}, {x: 2921.5, y: 251.3, z: 8254.4}, {x: 2921.5, y: 251.3, z: 8252.2}, {x: 2921.5, y: 251.3, z: 8247.2}, {x: 2921.4, y: 251.3, z: 8255.7} ]; -var cameraLookAts = [ {x: 2921.5, y: 251.3, z: 8255.7}, {x: 2921.5, y: 251.3, z: 8255.7}, {x: 2921.5, y: 251.3, z: 8255.7}, {x: 2921.5, y: 251.3, z: 8255.7}, {x: 2921.4 , y: 251.3, z: 8255.1} ]; - -function saveCameraState() { - oldMode = Camera.mode; - avatarPosition = MyAvatar.position; - Camera.setModeShiftPeriod(0.0); - Camera.mode = "independent"; -} - -function restoreCameraState() { - Camera.stopLooking(); - Camera.mode = oldMode; -} - -function update(deltaTime) { - if (freeCamera) { - var delta = Vec3.subtract(MyAvatar.position, avatarPosition); - if (Vec3.length(delta) > 0.05) { - cameraNumber = 0; - freeCamera = false; - restoreCameraState(); - } - } -} - -function keyPressEvent(event) { - - var choice = parseInt(event.text); - - if ((choice > 0) && (choice <= cameraLocations.length)) { - print("camera " + choice); - if (!freeCamera) { - saveCameraState(); - freeCamera = true; - } - Camera.mode = "independent"; - Camera.setPosition(cameraLocations[choice - 1]); - Camera.keepLookingAt(cameraLookAts[choice - 1]); - } - if (event.text == "ESC") { - cameraNumber = 0; - freeCamera = false; - restoreCameraState(); - } - if (event.text == "0") { - // Show camera location in log - var cameraLocation = Camera.getPosition(); - print(cameraLocation.x + ", " + cameraLocation.y + ", " + cameraLocation.z); - } -} - -Script.update.connect(update); -Controller.keyPressEvent.connect(keyPressEvent); From 8ad3ce7daf080e0903f6cf61a12bc51786b5e2b9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 09:32:59 -0800 Subject: [PATCH 43/44] bump packet version --- libraries/networking/src/PacketHeaders.cpp | 2 +- libraries/networking/src/PacketHeaders.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index b5cf84ee28..a5fdd86e3d 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -75,7 +75,7 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_SUPPORT_DIMENSIONS; + return VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 2e9ce697f0..466aebd36b 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -124,6 +124,7 @@ const PacketVersion VERSION_ROOT_ELEMENT_HAS_DATA = 2; const PacketVersion VERSION_ENTITIES_SUPPORT_SPLIT_MTU = 3; const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_SPLIT_MTU; const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4; +const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5; const PacketVersion VERSION_VOXELS_HAS_FILE_BREAKS = 1; #endif // hifi_PacketHeaders_h From 3e521e089b42aac2552cbb1e3354665baf927e2b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 09:48:15 -0800 Subject: [PATCH 44/44] fix unix build --- libraries/entities/src/EntityItemProperties.cpp | 2 +- libraries/entities/src/ModelEntityItem.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 9e75350bd4..0c184d5e35 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index d955f22478..52b8f7e643 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include #include #include