From 67535a386c3d2e4b5843918080c0b9a578766db5 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 6 Nov 2014 09:55:34 -0800 Subject: [PATCH 01/69] 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/69] 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/69] 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/69] 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/69] 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/69] 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 d083e75d2d44a2ca758c87f497a35662ac0066af Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 09:59:10 -0800 Subject: [PATCH 07/69] groundwork for better locally looped audio --- interface/src/Audio.cpp | 20 ++++--------------- interface/src/Audio.h | 2 +- libraries/audio/src/AbstractAudioInterface.h | 3 ++- .../audio/src/AudioScriptingInterface.cpp | 12 ----------- libraries/audio/src/AudioScriptingInterface.h | 1 - 5 files changed, 7 insertions(+), 31 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 726d1e609a..3289e64ed4 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1334,22 +1334,10 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float _drumSoundSample = 0; } -void Audio::handleAudioByteArray(const QByteArray& audioByteArray, const AudioInjectorOptions& injectorOptions) { - if (audioByteArray.size() > 0) { - QAudioFormat localFormat = _outputFormat; - - if (!injectorOptions.isStereo()) { - localFormat.setChannelCount(1); - } - - QAudioOutput* localSoundOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), localFormat, this); - - QIODevice* localIODevice = localSoundOutput->start(); - qDebug() << "Writing" << audioByteArray.size() << "to" << localIODevice; - localIODevice->write(audioByteArray); - } else { - qDebug() << "Audio::handleAudioByteArray called with an empty byte array. Sound is likely still downloading."; - } +QAudioOutput* Audio::newLocalOutputInterface(bool isStereo) { + QAudioFormat localFormat = _outputFormat; + localFormat.setChannelCount(isStereo ? 2 : 1); + return new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), localFormat); } void Audio::renderToolBox(int x, int y, bool boxed) { diff --git a/interface/src/Audio.h b/interface/src/Audio.h index ecbef026c4..02ea6db498 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -155,7 +155,7 @@ public slots: void selectAudioFilterBassCut(); void selectAudioFilterSmiley(); - virtual void handleAudioByteArray(const QByteArray& audioByteArray, const AudioInjectorOptions& options); + virtual QAudioOutput* newLocalOutputInterface(bool isStereo); void sendDownstreamAudioStatsPacket(); diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 1ee71ee32d..82710277b3 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -13,6 +13,7 @@ #define hifi_AbstractAudioInterface_h #include +#include #include "AudioInjectorOptions.h" @@ -24,7 +25,7 @@ public: virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0; virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0; public slots: - virtual void handleAudioByteArray(const QByteArray& audioByteArray, const AudioInjectorOptions& options) = 0; + virtual QAudioOutput* newLocalOutputInterface(bool isStereo) = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index 33afcdb095..318db1871b 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -37,18 +37,6 @@ void AudioScriptingInterface::stopAllInjectors() { } } -void AudioScriptingInterface::playLocalSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { - if (sound->isStereo()) { - const_cast(injectorOptions)->setIsStereo(true); - } - - // assume that localAudioInterface could be on a separate thread, use Qt::AutoConnection to handle properly - QMetaObject::invokeMethod(_localLoopbackInterface, "handleAudioByteArray", - Qt::AutoConnection, - Q_ARG(QByteArray, sound->getByteArray()), - Q_ARG(const AudioInjectorOptions&, *injectorOptions)); -} - AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { if (sound->isStereo()) { diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index 5cd0f9e99a..ffbef646ec 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -32,7 +32,6 @@ public slots: static float getLoudness(AudioInjector* injector); - void playLocalSound(Sound *sound, const AudioInjectorOptions* injectorOptions = NULL); AudioInjector* playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL); void stopInjector(AudioInjector* injector); From a8681cd5b65cf8ace44a62adda777a8548cbadcb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:24:21 -0800 Subject: [PATCH 08/69] changes to allow AudioInjectorOptions to operate as a hash from js --- libraries/audio/src/AudioInjector.cpp | 28 ++++---- libraries/audio/src/AudioInjectorOptions.cpp | 67 ++++++++++++------- libraries/audio/src/AudioInjectorOptions.h | 55 ++++----------- .../audio/src/AudioScriptingInterface.cpp | 6 +- libraries/audio/src/AudioScriptingInterface.h | 3 + libraries/avatars/src/Player.cpp | 10 +-- libraries/script-engine/src/ScriptEngine.cpp | 5 +- 7 files changed, 85 insertions(+), 89 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 45e1eb57e1..2d13568664 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -75,7 +75,7 @@ void AudioInjector::injectAudio() { packetStream << QUuid::createUuid(); // pack the stereo/mono type of the stream - packetStream << _options.isStereo(); + packetStream << _options.stereo; // pack the flag for loopback uchar loopbackFlag = (uchar) true; @@ -83,13 +83,13 @@ void AudioInjector::injectAudio() { // pack the position for injected audio int positionOptionOffset = injectAudioPacket.size(); - packetStream.writeRawData(reinterpret_cast(&_options.getPosition()), - sizeof(_options.getPosition())); + packetStream.writeRawData(reinterpret_cast(&_options.position), + sizeof(_options.position)); // pack our orientation for injected audio int orientationOptionOffset = injectAudioPacket.size(); - packetStream.writeRawData(reinterpret_cast(&_options.getOrientation()), - sizeof(_options.getOrientation())); + packetStream.writeRawData(reinterpret_cast(&_options.orientation), + sizeof(_options.orientation)); // pack zero for radius float radius = 0; @@ -97,23 +97,23 @@ void AudioInjector::injectAudio() { // pack 255 for attenuation byte int volumeOptionOffset = injectAudioPacket.size(); - quint8 volume = MAX_INJECTOR_VOLUME * _options.getVolume(); + quint8 volume = MAX_INJECTOR_VOLUME * _options.volume; packetStream << volume; - packetStream << _options.ignorePenumbra(); + packetStream << _options.ignorePenumbra; QElapsedTimer timer; timer.start(); int nextFrame = 0; int numPreAudioDataBytes = injectAudioPacket.size(); - bool shouldLoop = _options.getLoop(); + bool shouldLoop = _options.loop; // loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks quint16 outgoingInjectedAudioSequenceNumber = 0; while (_currentSendPosition < soundByteArray.size() && !_shouldStop) { - int bytesToCopy = std::min(((_options.isStereo()) ? 2 : 1) * NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, + int bytesToCopy = std::min(((_options.stereo) ? 2 : 1) * NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, soundByteArray.size() - _currentSendPosition); // Measure the loudness of this frame @@ -125,12 +125,12 @@ void AudioInjector::injectAudio() { _loudness /= (float)(bytesToCopy / sizeof(int16_t)); memcpy(injectAudioPacket.data() + positionOptionOffset, - &_options.getPosition(), - sizeof(_options.getPosition())); + &_options.position, + sizeof(_options.position)); memcpy(injectAudioPacket.data() + orientationOptionOffset, - &_options.getOrientation(), - sizeof(_options.getOrientation())); - volume = MAX_INJECTOR_VOLUME * _options.getVolume(); + &_options.orientation, + sizeof(_options.orientation)); + volume = MAX_INJECTOR_VOLUME * _options.volume; memcpy(injectAudioPacket.data() + volumeOptionOffset, &volume, sizeof(volume)); // resize the QByteArray to the right size diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index 670bea2fef..2a532b92b7 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -9,33 +9,54 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "AudioInjectorOptions.h" -AudioInjectorOptions::AudioInjectorOptions(QObject* parent) : - QObject(parent), - _position(0.0f, 0.0f, 0.0f), - _volume(1.0f), - _loop(false), - _orientation(glm::vec3(0.0f, 0.0f, 0.0f)), - _isStereo(false), - _ignorePenumbra(false) +AudioInjectorOptions::AudioInjectorOptions() : + position(0.0f, 0.0f, 0.0f), + volume(1.0f), + loop(false), + orientation(glm::vec3(0.0f, 0.0f, 0.0f)), + stereo(false), + ignorePenumbra(false) { + } -AudioInjectorOptions::AudioInjectorOptions(const AudioInjectorOptions& other) { - _position = other._position; - _volume = other._volume; - _loop = other._loop; - _orientation = other._orientation; - _isStereo = other._isStereo; - _ignorePenumbra = other._ignorePenumbra; +QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInjectorOptions& injectorOptions) { + QScriptValue obj = engine->newObject(); + obj.setProperty("position", vec3toScriptValue(engine, injectorOptions.position)); + obj.setProperty("volume", injectorOptions.volume); + obj.setProperty("loop", injectorOptions.loop); + obj.setProperty("orientation", quatToScriptValue(engine, injectorOptions.orientation)); + obj.setProperty("stereo", injectorOptions.stereo); + obj.setProperty("ignorePenumbra", injectorOptions.ignorePenumbra); + return obj; } -void AudioInjectorOptions::operator=(const AudioInjectorOptions& other) { - _position = other._position; - _volume = other._volume; - _loop = other._loop; - _orientation = other._orientation; - _isStereo = other._isStereo; - _ignorePenumbra = other._ignorePenumbra; -} \ No newline at end of file +void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOptions& injectorOptions) { + if (object.property("position").isValid()) { + vec3FromScriptValue(object.property("position"), injectorOptions.position); + } + + if (object.property("volume").isValid()) { + injectorOptions.volume = object.property("volume").toNumber(); + } + + if (object.property("loop").isValid()) { + injectorOptions.loop = object.property("loop").toBool(); + } + + if (object.property("orientation").isValid()) { + quatFromScriptValue(object.property("orientation"), injectorOptions.orientation); + } + + if (object.property("stereo").isValid()) { + injectorOptions.stereo = object.property("stereo").toBool(); + } + + if (object.property("ignorePenumbra").isValid()) { + injectorOptions.ignorePenumbra = object.property("ignorePenumbra").toBool(); + } + } \ No newline at end of file diff --git a/libraries/audio/src/AudioInjectorOptions.h b/libraries/audio/src/AudioInjectorOptions.h index 1ccd85be7e..c3e2da991a 100644 --- a/libraries/audio/src/AudioInjectorOptions.h +++ b/libraries/audio/src/AudioInjectorOptions.h @@ -12,54 +12,25 @@ #ifndef hifi_AudioInjectorOptions_h #define hifi_AudioInjectorOptions_h -#include +#include #include #include -#include - -class AudioInjectorOptions : public QObject { - Q_OBJECT - - Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation) - Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) - Q_PROPERTY(float volume READ getVolume WRITE setVolume) - Q_PROPERTY(bool loop READ getLoop WRITE setLoop) - Q_PROPERTY(bool isStereo READ isStereo WRITE setIsStereo) - Q_PROPERTY(bool ignorePenumbra READ ignorePenumbra WRITE setIgnorePenumbra) +class AudioInjectorOptions { public: - AudioInjectorOptions(QObject* parent = 0); - AudioInjectorOptions(const AudioInjectorOptions& other); - void operator=(const AudioInjectorOptions& other); - - const glm::vec3& getPosition() const { return _position; } - void setPosition(const glm::vec3& position) { _position = position; } - - float getVolume() const { return _volume; } - void setVolume(float volume) { _volume = volume; } - - bool getLoop() const { return _loop; } - void setLoop(bool loop) { _loop = loop; } - - const glm::quat& getOrientation() const { return _orientation; } - void setOrientation(const glm::quat& orientation) { _orientation = orientation; } - - const bool isStereo() const { return _isStereo; } - void setIsStereo(const bool isStereo) { _isStereo = isStereo; } - - const bool ignorePenumbra() const {return _ignorePenumbra; } - void setIgnorePenumbra(bool ignorePenumbra) { _ignorePenumbra = ignorePenumbra; } - -private: - glm::vec3 _position; - float _volume; - bool _loop; - glm::quat _orientation; - bool _isStereo; - bool _ignorePenumbra; + AudioInjectorOptions(); + glm::vec3 position; + float volume; + bool loop; + glm::quat orientation; + bool stereo; + bool ignorePenumbra; }; -Q_DECLARE_METATYPE(AudioInjectorOptions) +Q_DECLARE_METATYPE(AudioInjectorOptions); + +QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInjectorOptions& injectorOptions); +void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOptions& injectorOptions); #endif // hifi_AudioInjectorOptions_h diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index 318db1871b..bf2c16cc53 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -11,6 +11,10 @@ #include "AudioScriptingInterface.h" +void registerAudioMetaTypes(QScriptEngine* engine) { + qScriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue); +} + AudioScriptingInterface& AudioScriptingInterface::getInstance() { static AudioScriptingInterface staticInstance; return staticInstance; @@ -40,7 +44,7 @@ void AudioScriptingInterface::stopAllInjectors() { AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { if (sound->isStereo()) { - const_cast(injectorOptions)->setIsStereo(true); + const_cast(injectorOptions)->stereo = true; } AudioInjector* injector = new AudioInjector(sound, *injectorOptions); diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index ffbef646ec..a41ca645dd 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -44,4 +44,7 @@ private: QList< QPointer > _activeInjectors; AbstractAudioInterface* _localLoopbackInterface; }; + +void registerAudioMetaTypes(QScriptEngine* engine); + #endif // hifi_AudioScriptingInterface_h diff --git a/libraries/avatars/src/Player.cpp b/libraries/avatars/src/Player.cpp index 47d1b04421..709591b62b 100644 --- a/libraries/avatars/src/Player.cpp +++ b/libraries/avatars/src/Player.cpp @@ -166,8 +166,8 @@ void Player::pausePlayer() { void Player::setupAudioThread() { _audioThread = new QThread(); - _options.setPosition(_avatar->getPosition()); - _options.setOrientation(_avatar->getOrientation()); + _options.position = _avatar->getPosition(); + _options.orientation = _avatar->getOrientation(); _injector.reset(new AudioInjector(_recording->getAudio(), _options), &QObject::deleteLater); _injector->moveToThread(_audioThread); _audioThread->start(); @@ -292,8 +292,8 @@ void Player::play() { qDebug() << "WARNING: Player couldn't find head data."; } - _options.setPosition(_avatar->getPosition()); - _options.setOrientation(_avatar->getOrientation()); + _options.position = _avatar->getPosition(); + _options.orientation = _avatar->getOrientation(); _injector->setOptions(_options); } @@ -360,7 +360,7 @@ void Player::setCurrentTime(unsigned int currentTime) { } void Player::setVolume(float volume) { - _options.setVolume(volume); + _options.volume = volume; if (_injector) { _injector->setOptions(_options); } diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 7445822f55..2b1acf7592 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -234,7 +234,6 @@ bool ScriptEngine::setScriptContents(const QString& scriptContents, const QStrin return true; } -Q_SCRIPT_DECLARE_QMETAOBJECT(AudioInjectorOptions, QObject*) Q_SCRIPT_DECLARE_QMETAOBJECT(LocalVoxels, QString) void ScriptEngine::init() { @@ -254,6 +253,7 @@ void ScriptEngine::init() { registerMenuItemProperties(this); registerAnimationTypes(this); registerAvatarTypes(this); + registerAudioMetaTypes(this); Bitstream::registerTypes(this); qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValue); @@ -275,9 +275,6 @@ void ScriptEngine::init() { QScriptValue soundMetaObject = newQMetaObject(&Sound::staticMetaObject, soundConstructorValue); globalObject().setProperty("Sound", soundMetaObject); - QScriptValue injectionOptionValue = scriptValueFromQMetaObject(); - globalObject().setProperty("AudioInjectionOptions", injectionOptionValue); - QScriptValue localVoxelsValue = scriptValueFromQMetaObject(); globalObject().setProperty("LocalVoxels", localVoxelsValue); From 05174ffdf34862735e9bf5f05af12c4e24a7af5e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:26:53 -0800 Subject: [PATCH 09/69] update airGuitar.js to new AudioInjectionOptions format --- examples/airGuitar.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/airGuitar.js b/examples/airGuitar.js index c0e06add30..2c3d0409fa 100644 --- a/examples/airGuitar.js +++ b/examples/airGuitar.js @@ -132,15 +132,16 @@ function checkHands(deltaTime) { } function playChord(position, volume) { - var options = new AudioInjectionOptions(); - options.position = position; - options.volume = volume; if (Audio.isInjectorPlaying(soundPlaying)) { print("stopped sound"); Audio.stopInjector(soundPlaying); } + print("Played sound: " + whichChord + " at volume " + options.volume); - soundPlaying = Audio.playSound(chords[guitarSelector + whichChord], options); + soundPlaying = Audio.playSound(chords[guitarSelector + whichChord], { + position: position, + volume: volume + }); } function keyPressEvent(event) { From c684a1cf006e58751d809502c402735ad22d7373 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:28:33 -0800 Subject: [PATCH 10/69] update audioBall to new hash injector format --- examples/audioBall.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/audioBall.js b/examples/audioBall.js index 7e7126be06..ca666285a9 100644 --- a/examples/audioBall.js +++ b/examples/audioBall.js @@ -32,10 +32,10 @@ function updateEntity(deltaTime) { if (Math.random() < CHANCE_OF_PLAYING_SOUND) { // play a sound at the location of the entity - var options = new AudioInjectionOptions(); - options.position = entityPosition; - options.volume = 0.75; - Audio.playSound(sound, options); + Audio.playSound(sound, { + position: entityPosition, + volume: 0.75 + }); } var audioAverageLoudness = MyAvatar.audioAverageLoudness * FACTOR; From 12e15eab6a831d5ab019630d8e86b801a5f122de Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:29:29 -0800 Subject: [PATCH 11/69] update avatarCollision to new hash injector format --- examples/avatarCollision.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/avatarCollision.js b/examples/avatarCollision.js index 6c0886464c..4bd0adf69a 100644 --- a/examples/avatarCollision.js +++ b/examples/avatarCollision.js @@ -17,9 +17,11 @@ var SOUND_TRIGGER_CLEAR = 1000; // milliseconds var SOUND_TRIGGER_DELAY = 200; // milliseconds var soundExpiry = 0; var DateObj = new Date(); -var audioOptions = new AudioInjectionOptions(); -audioOptions.volume = 0.5; -audioOptions.position = { x: 0, y: 0, z: 0 }; + +var audioOptions = { + volume: 0.5, + position: { x: 0, y: 0, z: 0 } +} var hitSounds = new Array(); hitSounds[0] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit1.raw"); From d4b74e6ecf2380a85125af7dde5007ea037cfa1f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:30:16 -0800 Subject: [PATCH 12/69] update birdSongs to new injector hash format --- examples/birdSongs.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/birdSongs.js b/examples/birdSongs.js index 94e013d92b..b1ccbf8f3f 100644 --- a/examples/birdSongs.js +++ b/examples/birdSongs.js @@ -33,13 +33,13 @@ function maybePlaySound(deltaTime) { // Set the location and other info for the sound to play var whichBird = Math.floor(Math.random() * birds.length); //print("playing sound # " + whichBird); - var options = new AudioInjectionOptions(); var position = { x: lowerCorner.x + Math.random() * (upperCorner.x - lowerCorner.x), y: lowerCorner.y + Math.random() * (upperCorner.y - lowerCorner.y), z: lowerCorner.z + Math.random() * (upperCorner.z - lowerCorner.z) }; - options.position = position; - options.volume = BIRD_MASTER_VOLUME; - // + var options = { + position: position, + volume: BIRD_MASTER_VOLUME + }; var entityId = Entities.addEntity({ type: "Sphere", position: position, From ef2c181c9808c73e1125550d87ab7f74d1a2fda9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:55:07 -0800 Subject: [PATCH 13/69] repairs to audio classes for Sound* to QScriptValue --- libraries/audio/src/AudioInjector.cpp | 8 ++++++++ libraries/audio/src/AudioInjector.h | 3 +++ libraries/audio/src/AudioScriptingInterface.cpp | 10 ++++------ libraries/audio/src/AudioScriptingInterface.h | 2 +- libraries/audio/src/Sound.cpp | 9 +++++++++ libraries/audio/src/Sound.h | 6 ++++++ libraries/script-engine/src/ScriptEngine.cpp | 8 -------- 7 files changed, 31 insertions(+), 15 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 2d13568664..239d9eb596 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -21,6 +21,14 @@ #include "AudioInjector.h" +QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const &in) { + return engine->newQObject(in); +} + +void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out) { + out = qobject_cast(object.toQObject()); +} + AudioInjector::AudioInjector(QObject* parent) : QObject(parent), _sound(NULL), diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 68acd3b887..e53e2dbcad 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -50,4 +50,7 @@ private: Q_DECLARE_METATYPE(AudioInjector*) +QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const &in); +void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out); + #endif // hifi_AudioInjector_h diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index bf2c16cc53..7605b5d6af 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -13,6 +13,7 @@ void registerAudioMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue); + qScriptRegisterMetaType(engine, soundToScriptValue, soundFromScriptValue); } AudioScriptingInterface& AudioScriptingInterface::getInstance() { @@ -23,7 +24,7 @@ AudioScriptingInterface& AudioScriptingInterface::getInstance() { AudioScriptingInterface::AudioScriptingInterface() : _localLoopbackInterface(NULL) { - qRegisterMetaType("AudioInjectorOptions"); + } void AudioScriptingInterface::stopAllInjectors() { @@ -41,12 +42,9 @@ void AudioScriptingInterface::stopAllInjectors() { } } -AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { +AudioInjector* AudioScriptingInterface::playSound(Sound* sound, AudioInjectorOptions& injectorOptions) { - if (sound->isStereo()) { - const_cast(injectorOptions)->stereo = true; - } - AudioInjector* injector = new AudioInjector(sound, *injectorOptions); + AudioInjector* injector = new AudioInjector(sound, injectorOptions); QThread* injectorThread = new QThread(); diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index a41ca645dd..efcb0172c3 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -32,7 +32,7 @@ public slots: static float getLoudness(AudioInjector* injector); - AudioInjector* playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL); + AudioInjector* playSound(Sound* sound, AudioInjectorOptions& injectorOptions); void stopInjector(AudioInjector* injector); bool isInjectorPlaying(AudioInjector* injector); diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 2266385425..bb134ad198 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -29,6 +29,15 @@ #include "AudioEditBuffer.h" #include "Sound.h" + +QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const &in) { + return engine->newQObject(in); +} + +void soundFromScriptValue(const QScriptValue &object, Sound* &out) { + out = qobject_cast(object.toQObject()); +} + // procedural audio version of Sound Sound::Sound(float volume, float frequency, float duration, float decay, QObject* parent) : QObject(parent), diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index b8fdc6b458..ade3ad324f 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -14,6 +14,7 @@ #include #include +#include class Sound : public QObject { Q_OBJECT @@ -44,4 +45,9 @@ private slots: void replyError(QNetworkReply::NetworkError code); }; +Q_DECLARE_METATYPE(Sound*) + +QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const &in); +void soundFromScriptValue(const QScriptValue &object, Sound* &out); + #endif // hifi_Sound_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 2b1acf7592..3f89cdf9ba 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -74,14 +74,6 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) { out = qobject_cast(object.toQObject()); } -QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const &in) { - return engine->newQObject(in); -} - -void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out) { - out = qobject_cast(object.toQObject()); -} - QScriptValue inputControllerToScriptValue(QScriptEngine *engine, AbstractInputController* const &in) { return engine->newQObject(in); } From 853c0197a178189d4c232c365bf206ab5973edbc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:55:45 -0800 Subject: [PATCH 14/69] repairs to birdSongs for new hash injector format --- examples/birdSongs.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/examples/birdSongs.js b/examples/birdSongs.js index b1ccbf8f3f..680cb025ad 100644 --- a/examples/birdSongs.js +++ b/examples/birdSongs.js @@ -33,20 +33,22 @@ function maybePlaySound(deltaTime) { // Set the location and other info for the sound to play var whichBird = Math.floor(Math.random() * birds.length); //print("playing sound # " + whichBird); - var position = { x: lowerCorner.x + Math.random() * (upperCorner.x - lowerCorner.x), - y: lowerCorner.y + Math.random() * (upperCorner.y - lowerCorner.y), - z: lowerCorner.z + Math.random() * (upperCorner.z - lowerCorner.z) }; + var position = { + x: lowerCorner.x + Math.random() * (upperCorner.x - lowerCorner.x), + y: lowerCorner.y + Math.random() * (upperCorner.y - lowerCorner.y), + z: lowerCorner.z + Math.random() * (upperCorner.z - lowerCorner.z) + }; var options = { position: position, volume: BIRD_MASTER_VOLUME }; var entityId = Entities.addEntity({ - type: "Sphere", - position: position, - dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE }, - color: birds[whichBird].color, - lifetime: 10 - }); + type: "Sphere", + position: position, + dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE }, + color: birds[whichBird].color, + lifetime: 10 + }); if (useLights) { var lightId = Entities.addEntity({ From bfc25767edc1c7732fc6401f9a3f4d96471c0bfc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 10:57:07 -0800 Subject: [PATCH 15/69] repairs to bot_procedrual for hash injector options format --- examples/bot_procedural.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/bot_procedural.js b/examples/bot_procedural.js index f445162038..80f83fcdfa 100644 --- a/examples/bot_procedural.js +++ b/examples/bot_procedural.js @@ -134,13 +134,11 @@ function playRandomSound() { } function playRandomFootstepSound() { - - var whichSound = Math.floor((Math.random() * footstepSounds.length)); - var options = new AudioInjectionOptions(); - options.position = Avatar.position; - options.volume = 1.0; - Audio.playSound(footstepSounds[whichSound], options); - + var whichSound = Math.floor((Math.random() * footstepSounds.length)); + Audio.playSound(footstepSounds[whichSound], { + position: Avatar.position, + volume: 1.0 + }); } // ************************************ Facial Animation ********************************** From 3d1bb68c725f02ff18f45753dbbb011b2e04e03e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 11:04:33 -0800 Subject: [PATCH 16/69] fix for playSound argument to match QScriptValue conversion --- libraries/audio/src/AudioScriptingInterface.cpp | 2 +- libraries/audio/src/AudioScriptingInterface.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index 7605b5d6af..eee43ec18c 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -42,7 +42,7 @@ void AudioScriptingInterface::stopAllInjectors() { } } -AudioInjector* AudioScriptingInterface::playSound(Sound* sound, AudioInjectorOptions& injectorOptions) { +AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) { AudioInjector* injector = new AudioInjector(sound, injectorOptions); diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index efcb0172c3..2af690e772 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -32,7 +32,7 @@ public slots: static float getLoudness(AudioInjector* injector); - AudioInjector* playSound(Sound* sound, AudioInjectorOptions& injectorOptions); + AudioInjector* playSound(Sound* sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions()); void stopInjector(AudioInjector* injector); bool isInjectorPlaying(AudioInjector* injector); From 89ae8f53ba2d471f57df898cf2568e062b1bc495 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 11:05:35 -0800 Subject: [PATCH 17/69] use new AudioInjectionOptions format in botProceduralWayPoints --- examples/botProceduralWayPoints.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/botProceduralWayPoints.js b/examples/botProceduralWayPoints.js index fc9c0dda74..0f8b369470 100644 --- a/examples/botProceduralWayPoints.js +++ b/examples/botProceduralWayPoints.js @@ -172,13 +172,11 @@ function playRandomSound() { } function playRandomFootstepSound() { - - var whichSound = Math.floor((Math.random() * footstepSounds.length)); - var options = new AudioInjectionOptions(); - options.position = Avatar.position; - options.volume = 1.0; - Audio.playSound(footstepSounds[whichSound], options); - + var whichSound = Math.floor((Math.random() * footstepSounds.length)); + Audio.playSound(footstepSounds[whichSound], { + position: Avatar.position, + volume: 1.0 + }); } // Facial Animation From d81609f0459709959e5cb02c4f7cab335b0a1630 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 11:16:45 -0800 Subject: [PATCH 18/69] use hash in place of AudioInjectionOptions in other js files --- examples/clap.js | 8 +++---- examples/drumStick.js | 7 +++++-- examples/editVoxels.js | 8 ++++--- examples/entityBirds.js | 8 +++---- examples/entityScripts/playSoundOnClick.js | 9 ++++---- .../entityScripts/playSoundOnEnterOrLeave.js | 11 +++++----- examples/frisbee.js | 8 +++---- examples/grenadeLauncher.js | 5 +++-- examples/gun.js | 5 +++-- examples/headMove.js | 10 +++------ examples/inWorldTestTone.js | 8 +++---- examples/playSound.js | 11 +++++----- examples/playSoundLoop.js | 10 +++++---- examples/playSoundOrbit.js | 21 +++++++++---------- examples/playSoundWave.js | 9 ++++---- examples/radio.js | 10 +++++---- examples/spaceInvadersExample.js | 13 ++++++------ examples/toyball.js | 15 +++---------- examples/walk.js | 8 ++++--- 19 files changed, 89 insertions(+), 95 deletions(-) diff --git a/examples/clap.js b/examples/clap.js index 9cc79a1c92..bf71f13cea 100644 --- a/examples/clap.js +++ b/examples/clap.js @@ -89,11 +89,11 @@ function maybePlaySound(deltaTime) { } function playClap(volume, position) { - var options = new AudioInjectionOptions(); - options.position = position; - options.volume = 1.0; var clip = Math.floor(Math.random() * numberOfSounds); - Audio.playSound(claps[clip], options); + Audio.playSound(claps[clip], { + position: position, + volume: volume + }); } var FASTEST_CLAP_INTERVAL = 150.0; diff --git a/examples/drumStick.js b/examples/drumStick.js index d0560057c0..1af9ffc3dd 100644 --- a/examples/drumStick.js +++ b/examples/drumStick.js @@ -63,8 +63,11 @@ function checkSticks(deltaTime) { // Waiting for change in velocity direction or slowing to trigger drum sound if ((palmVelocity.y > 0.0) || (speed < STOP_SPEED)) { state[palm] = 0; - var options = new AudioInjectionOptions(); - options.position = Controller.getSpatialControlPosition(palm * 2 + 1); + + var options = { + position: Controller.getSpatialControlPosition(palm * 2 + 1); + } + if (strokeSpeed[palm] > 1.0) { strokeSpeed[palm] = 1.0; } options.volume = strokeSpeed[palm]; diff --git a/examples/editVoxels.js b/examples/editVoxels.js index e450f2d1d4..0747b9269f 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -68,9 +68,11 @@ var numColors = 9; var whichColor = 0; // Starting color is 'Copy' mode // Create sounds for for every script actions that require one -var audioOptions = new AudioInjectionOptions(); -audioOptions.volume = 1.0; -audioOptions.position = Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0 } ); // start with audio slightly above the avatar +// start with audio slightly above the avatar +var audioOptions = { + position: Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0 } ), + volume: 1.0 +}; function SoundArray() { this.audioOptions = audioOptions diff --git a/examples/entityBirds.js b/examples/entityBirds.js index bbc35a5f58..d18513ba49 100644 --- a/examples/entityBirds.js +++ b/examples/entityBirds.js @@ -135,10 +135,10 @@ function updateBirds(deltaTime) { // Tweeting behavior if (birds[i].tweeting == 0) { if (Math.random() < CHANCE_OF_TWEETING) { - var options = new AudioInjectionOptions(); - options.position = properties.position; - options.volume = 0.75; - Audio.playSound(birds[i].tweetSound, options); + Audio.playSound(birds[i].tweetSound, { + position: properties.position, + volume: 0.75 + }); birds[i].tweeting = 10; } } else { diff --git a/examples/entityScripts/playSoundOnClick.js b/examples/entityScripts/playSoundOnClick.js index b261bb269a..fea68db2c3 100644 --- a/examples/entityScripts/playSoundOnClick.js +++ b/examples/entityScripts/playSoundOnClick.js @@ -15,10 +15,9 @@ var bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); this.clickDownOnEntity = function(entityID, mouseEvent) { print("clickDownOnEntity()..."); - var options = new AudioInjectionOptions(); - var position = MyAvatar.position; - options.position = position; - options.volume = 0.5; - Audio.playSound(bird, options); + Audio.playSound(bird, { + position: MyAvatar.position, + volume: 0.5 + }); }; }) diff --git a/examples/entityScripts/playSoundOnEnterOrLeave.js b/examples/entityScripts/playSoundOnEnterOrLeave.js index 228a8a36d0..ab8bcbd2bd 100644 --- a/examples/entityScripts/playSoundOnEnterOrLeave.js +++ b/examples/entityScripts/playSoundOnEnterOrLeave.js @@ -14,12 +14,11 @@ (function(){ var bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); - function playSound(entityID) { - var options = new AudioInjectionOptions(); - var position = MyAvatar.position; - options.position = position; - options.volume = 0.5; - Audio.playSound(bird, options); + function playSound(entityID) { + Audio.playSound(bird, { + position: MyAvatar.position, + volume: 0.5 + }); }; this.enterEntity = function(entityID) { diff --git a/examples/frisbee.js b/examples/frisbee.js index c534a8b3fb..7e266de34b 100644 --- a/examples/frisbee.js +++ b/examples/frisbee.js @@ -177,10 +177,10 @@ function playSound(sound, position) { if (!SOUNDS_ENABLED) { return; } - var options = new AudioInjectionOptions(); - options.position = position; - options.volume = 1.0; - Audio.playSound(sound, options); + + Audio.playSound(sound,{ + position: position + }); } function cleanupFrisbees() { diff --git a/examples/grenadeLauncher.js b/examples/grenadeLauncher.js index bca067326a..e95d8dd79d 100644 --- a/examples/grenadeLauncher.js +++ b/examples/grenadeLauncher.js @@ -44,8 +44,9 @@ var targetLaunchSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/ var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst"; -var audioOptions = new AudioInjectionOptions(); -audioOptions.volume = 0.9; +var audioOptions { + volume: 0.9 +} var shotsFired = 0; diff --git a/examples/gun.js b/examples/gun.js index 385664226c..76084ce013 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -43,8 +43,9 @@ var targetLaunchSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/ var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst"; -var audioOptions = new AudioInjectionOptions(); -audioOptions.volume = 0.9; +var audioOptions = { + volume: 0.9 +} var shotsFired = 0; diff --git a/examples/headMove.js b/examples/headMove.js index b1f1c4ab7d..957686bb20 100644 --- a/examples/headMove.js +++ b/examples/headMove.js @@ -72,15 +72,11 @@ var WATCH_AVATAR_DISTANCE = 2.5; var sound = new Sound("http://public.highfidelity.io/sounds/Footsteps/FootstepW2Right-12db.wav"); function playSound() { - var options = new AudioInjectionOptions(); - var position = MyAvatar.position; - options.position = position; - options.volume = 1.0; - Audio.playSound(sound, options); + Audio.playSound(sound, { + position: MyAvatar.position + }); } - - function pullBack() { saveCameraState(); cameraPosition = Vec3.subtract(MyAvatar.position, Vec3.multiplyQbyV(Camera.getOrientation(), { x: 0, y: -hipsToEyes, z: -hipsToEyes * WATCH_AVATAR_DISTANCE })); diff --git a/examples/inWorldTestTone.js b/examples/inWorldTestTone.js index 590bb6c342..b3bf91d14d 100644 --- a/examples/inWorldTestTone.js +++ b/examples/inWorldTestTone.js @@ -19,11 +19,9 @@ var soundPlaying = false; function update(deltaTime) { if (!Audio.isInjectorPlaying(soundPlaying)) { - var options = new AudioInjectionOptions(); - options.position = { x:0, y:0, z:0 }; - options.volume = 1.0; - options.loop = true; - soundPlaying = Audio.playSound(sound, options); + soundPlaying = Audio.playSound(sound, { + loop: true + }); print("Started sound loop"); } } diff --git a/examples/playSound.js b/examples/playSound.js index 4130db5b16..efcda0b42b 100644 --- a/examples/playSound.js +++ b/examples/playSound.js @@ -15,12 +15,11 @@ var bird = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Animals/bushtit_1.raw"); function maybePlaySound(deltaTime) { if (Math.random() < 0.01) { - // Set the location and other info for the sound to play - var options = new AudioInjectionOptions(); - var position = MyAvatar.position; - options.position = position; - options.volume = 0.5; - Audio.playSound(bird, options); + // Set the location and other info for the sound to play + Audio.playSound(bird, { + position: MyAvatar.position, + volume: 0.5 + }); } } diff --git a/examples/playSoundLoop.js b/examples/playSoundLoop.js index 3122f13f37..b84c475d1a 100644 --- a/examples/playSoundLoop.js +++ b/examples/playSoundLoop.js @@ -20,10 +20,12 @@ var sound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+A.raw" //var sound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Cocktail+Party+Snippets/Bandcamp.wav"); var soundPlaying = false; -var options = new AudioInjectionOptions(); -options.position = Vec3.sum(Camera.getPosition(), Quat.getFront(MyAvatar.orientation)); -options.volume = 0.5; -options.loop = true; +var options = { + position: Vec3.sum(Camera.getPosition(), Quat.getFront(MyAvatar.orientation)), + volume: 0.5, + loop: true +} + var playing = false; var ball = false; diff --git a/examples/playSoundOrbit.js b/examples/playSoundOrbit.js index 2c44a4535a..d98f7d0768 100644 --- a/examples/playSoundOrbit.js +++ b/examples/playSoundOrbit.js @@ -19,24 +19,23 @@ var distance = 1; var debug = 0; function playSound() { - var options = new AudioInjectionOptions(); - currentTime += deltaTime; + currentTime += deltaTime; var s = distance * Math.sin(currentTime); var c = distance * Math.cos(currentTime); - var soundOffset = { x:s, y:0, z:c }; + var soundOffset = { x:s, y:0, z:c }; - if (debug) { - print("t=" + currentTime + "offset=" + soundOffset.x + "," + soundOffset.y + "," + soundOffset.z); - } + if (debug) { + print("t=" + currentTime + "offset=" + soundOffset.x + "," + soundOffset.y + "," + soundOffset.z); + } - var avatarPosition = MyAvatar.position; - var soundPosition = Vec3.sum(avatarPosition,soundOffset); + var avatarPosition = MyAvatar.position; + var soundPosition = Vec3.sum(avatarPosition,soundOffset); - options.position = soundPosition - options.volume = 1.0; - Audio.playSound(soundClip, options); + Audio.playSound(soundClip, { + position: soundPosition + }); } Script.setInterval(playSound, 250); diff --git a/examples/playSoundWave.js b/examples/playSoundWave.js index f152effb47..c5e69f5cd6 100644 --- a/examples/playSoundWave.js +++ b/examples/playSoundWave.js @@ -14,11 +14,10 @@ Script.include("libraries/globals.js"); var soundClip = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Cocktail%20Party%20Snippets/Walken1.wav"); function playSound() { - var options = new AudioInjectionOptions(); - var position = MyAvatar.position; - options.position = position; - options.volume = 0.5; - Audio.playSound(soundClip, options); + Audio.playSound(soundClip, { + position: MyAvatar.position, + volume: 0.5 + }); } Script.setInterval(playSound, 10000); diff --git a/examples/radio.js b/examples/radio.js index 293867398a..fc09fb184e 100644 --- a/examples/radio.js +++ b/examples/radio.js @@ -15,10 +15,12 @@ var modelURL = HIFI_PUBLIC_BUCKET + "models/entities/radio/Speakers.fbx"; var soundURL = HIFI_PUBLIC_BUCKET + "sounds/FamilyStereo.raw"; var AudioRotationOffset = Quat.fromPitchYawRollDegrees(0, -90, 0); -var audioOptions = new AudioInjectionOptions(); -audioOptions.volume = 0.5; -audioOptions.loop = true; -audioOptions.isStereo = true; +var audioOptions = { + volume: 0.5, + loop: true, + stereo: true +} + var injector = null; var sound = new Sound(soundURL, audioOptions.isStereo); diff --git a/examples/spaceInvadersExample.js b/examples/spaceInvadersExample.js index 8d69f066d6..dd5ac9e875 100644 --- a/examples/spaceInvadersExample.js +++ b/examples/spaceInvadersExample.js @@ -217,7 +217,8 @@ function update(deltaTime) { if (invaderStepOfCycle % stepsPerSound == 0) { // play the move sound - var options = new AudioInjectionOptions(); + var options = {}; + if (soundInMyHead) { options.position = { x: MyAvatar.position.x + 0.0, y: MyAvatar.position.y + 0.1, @@ -225,7 +226,7 @@ function update(deltaTime) { } else { options.position = getInvaderPosition(invadersPerRow / 2, numberOfRows / 2); } - options.volume = 1.0; + Audio.playSound(moveSounds[currentMoveSound], options); // get ready for next move sound @@ -330,7 +331,7 @@ function fireMissile() { lifetime: 5 }); - var options = new AudioInjectionOptions(); + var options = {} if (soundInMyHead) { options.position = { x: MyAvatar.position.x + 0.0, y: MyAvatar.position.y + 0.1, @@ -338,7 +339,7 @@ function fireMissile() { } else { options.position = missilePosition; } - options.volume = 1.0; + Audio.playSound(shootSound, options); missileFired = true; @@ -380,7 +381,7 @@ function deleteIfInvader(possibleInvaderEntity) { Entities.deleteEntity(myMissile); // play the hit sound - var options = new AudioInjectionOptions(); + var options = {}; if (soundInMyHead) { options.position = { x: MyAvatar.position.x + 0.0, y: MyAvatar.position.y + 0.1, @@ -388,7 +389,7 @@ function deleteIfInvader(possibleInvaderEntity) { } else { options.position = getInvaderPosition(row, column); } - options.volume = 1.0; + Audio.playSound(hitSound, options); } } diff --git a/examples/toyball.js b/examples/toyball.js index b41dd2bda5..1cd6de16eb 100644 --- a/examples/toyball.js +++ b/examples/toyball.js @@ -113,10 +113,7 @@ function checkControllerSide(whichSide) { inHand: true }; Entities.editEntity(closestEntity, properties); - var options = new AudioInjectionOptions(); - options.position = ballPosition; - options.volume = 1.0; - Audio.playSound(catchSound, options); + Audio.playSound(catchSound, { position: ballPosition }); return; // exit early } @@ -156,10 +153,7 @@ function checkControllerSide(whichSide) { } // Play a new ball sound - var options = new AudioInjectionOptions(); - options.position = ballPosition; - options.volume = 1.0; - Audio.playSound(newSound, options); + Audio.playSound(newSound, { position: ballPosition}); return; // exit early } @@ -207,10 +201,7 @@ function checkControllerSide(whichSide) { rightHandEntity = false; } - var options = new AudioInjectionOptions(); - options.position = ballPosition; - options.volume = 1.0; - Audio.playSound(throwSound, options); + Audio.playSound(throwSound, { position: ballPosition }); } } } diff --git a/examples/walk.js b/examples/walk.js index a9e8f401d6..ac0a2b1d39 100644 --- a/examples/walk.js +++ b/examples/walk.js @@ -285,9 +285,11 @@ function resetJoints() { // play footstep sound function playFootstep(side) { - var options = new AudioInjectionOptions(); - options.position = Camera.getPosition(); - options.volume = 0.5; + var options = { + position: Camera.getPosition(), + volume: 0.5 + } + var walkNumber = 2; // 0 to 2 if(side===DIRECTION_RIGHT && playFootStepSounds) { Audio.playSound(footsteps[walkNumber+1], options); From 1f452c8baa3050bd6eb5fa2ad1b8b36edc432630 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 11:17:45 -0800 Subject: [PATCH 19/69] replace AudioInjectionOptions with hash in playSoundOnEnterOrLeave --- examples/entityScripts/playSoundOnEnterOrLeave.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/entityScripts/playSoundOnEnterOrLeave.js b/examples/entityScripts/playSoundOnEnterOrLeave.js index ab8bcbd2bd..6ee961af0a 100644 --- a/examples/entityScripts/playSoundOnEnterOrLeave.js +++ b/examples/entityScripts/playSoundOnEnterOrLeave.js @@ -25,7 +25,7 @@ playSound(); }; - this.leaveEntity = function(entityID) { + this.leaveEntity = function(entityID) { playSound(); }; }) From d0e8c294dab7fb2549fc0aa02b0caa3e240fd872 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 11:22:16 -0800 Subject: [PATCH 20/69] handle passing of local audio interface to AudioInjector --- interface/src/Application.cpp | 2 +- libraries/audio/src/AudioInjector.h | 5 +++++ libraries/audio/src/AudioScriptingInterface.cpp | 3 ++- libraries/audio/src/AudioScriptingInterface.h | 6 ++---- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7f80407a6b..77cfcfd548 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -417,7 +417,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _trayIcon->show(); // set the local loopback interface for local sounds from audio scripts - AudioScriptingInterface::getInstance().setLocalLoopbackInterface(&_audio); + AudioScriptingInterface::getInstance().setLocalAudioInterface(&_audio); #ifdef HAVE_RTMIDI // setup the MIDIManager diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index e53e2dbcad..12e4c62d5d 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -21,6 +21,8 @@ #include "AudioInjectorOptions.h" #include "Sound.h" +class AbstractAudioInterface; + class AudioInjector : public QObject { Q_OBJECT public: @@ -29,6 +31,8 @@ public: bool isFinished() const { return _isFinished; } int getCurrentSendPosition() const { return _currentSendPosition; } + + void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; } public slots: void injectAudio(); void stop() { _shouldStop = true; } @@ -45,6 +49,7 @@ private: float _loudness; bool _isFinished; int _currentSendPosition; + AbstractAudioInterface* _localAudioInterface; }; diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index eee43ec18c..cb010ef11d 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -22,7 +22,7 @@ AudioScriptingInterface& AudioScriptingInterface::getInstance() { } AudioScriptingInterface::AudioScriptingInterface() : - _localLoopbackInterface(NULL) + _localAudioInterface(NULL) { } @@ -45,6 +45,7 @@ void AudioScriptingInterface::stopAllInjectors() { AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) { AudioInjector* injector = new AudioInjector(sound, injectorOptions); + injector->setLocalAudioInterface(_localAudioInterface); QThread* injectorThread = new QThread(); diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index 2af690e772..0017806b40 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -18,8 +18,6 @@ #include "AudioInjector.h" #include "Sound.h" -const AudioInjectorOptions DEFAULT_INJECTOR_OPTIONS; - class AudioScriptingInterface : public QObject { Q_OBJECT public: @@ -27,7 +25,7 @@ public: void stopAllInjectors(); - void setLocalLoopbackInterface(AbstractAudioInterface* audioInterface) { _localLoopbackInterface = audioInterface; } + void setLocalAudioInterface(AbstractAudioInterface* audioInterface) { _localAudioInterface = audioInterface; } public slots: static float getLoudness(AudioInjector* injector); @@ -42,7 +40,7 @@ public slots: private: AudioScriptingInterface(); QList< QPointer > _activeInjectors; - AbstractAudioInterface* _localLoopbackInterface; + AbstractAudioInterface* _localAudioInterface; }; void registerAudioMetaTypes(QScriptEngine* engine); From cd3877b5847301e213fb0dbe3a81a436666c097e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 14:14:43 -0800 Subject: [PATCH 21/69] handle local audio output via AudioInjector directly for control --- examples/lobby.js | 6 +++- interface/src/Audio.cpp | 9 ++++-- interface/src/Audio.h | 2 +- libraries/audio/src/AbstractAudioInterface.h | 2 +- libraries/audio/src/AudioInjector.cpp | 30 +++++++++++++++++++- libraries/audio/src/AudioInjector.h | 3 ++ libraries/audio/src/AudioInjectorOptions.cpp | 8 +++++- libraries/audio/src/AudioInjectorOptions.h | 1 + 8 files changed, 53 insertions(+), 8 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index 63ea1654a9..e6db57bdd5 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -37,7 +37,8 @@ var panelsCenterShift = Vec3.subtract(panelsCenter, orbCenter); var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8}; -var HELMET_ATTACHMENT_URL = "https://hifi-public.s3.amazonaws.com/models/attachments/IronManMaskOnly.fbx" +var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx" +var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw") function reticlePosition() { var RETICLE_DISTANCE = 1; @@ -87,6 +88,9 @@ function drawLobby() { // add an attachment on this avatar so other people see them in the lobby MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15); + + // start the drone sound + Audio.playSound(droneSound, { stereo: true, localOnly: true }); } } diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 3289e64ed4..58c3972bcb 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1334,10 +1334,13 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float _drumSoundSample = 0; } -QAudioOutput* Audio::newLocalOutputInterface(bool isStereo) { - QAudioFormat localFormat = _outputFormat; +QIODevice* Audio::newLocalOutputDevice(bool isStereo) { + QAudioFormat localFormat = _desiredOutputFormat; localFormat.setChannelCount(isStereo ? 2 : 1); - return new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), localFormat); + QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), + localFormat); + + return localOutput->start(); } void Audio::renderToolBox(int x, int y, bool boxed) { diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 02ea6db498..83688cf84a 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -155,7 +155,7 @@ public slots: void selectAudioFilterBassCut(); void selectAudioFilterSmiley(); - virtual QAudioOutput* newLocalOutputInterface(bool isStereo); + virtual QIODevice* newLocalOutputDevice(bool isStereo); void sendDownstreamAudioStatsPacket(); diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 82710277b3..e413bfc8f1 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -25,7 +25,7 @@ public: virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0; virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0; public slots: - virtual QAudioOutput* newLocalOutputInterface(bool isStereo) = 0; + virtual QIODevice* newLocalOutputDevice(bool isStereo) = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 239d9eb596..9b2720b90c 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -58,9 +58,37 @@ float AudioInjector::getLoudness() { return _loudness; } +void AudioInjector::injectAudio() { + if (_options.localOnly) { + injectLocally(); + } else { + injectToMixer(); + } +} + +void AudioInjector::injectLocally() { + if (_localAudioInterface) { + + QIODevice* localBuffer = NULL; + + QMetaObject::invokeMethod(_localAudioInterface, "newLocalOutputDevice", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QIODevice*, localBuffer), + Q_ARG(bool, _options.stereo)); + + if (localBuffer) { + // immediately write the byte array to the local device + localBuffer->write(_sound->getByteArray()); + } else { + qDebug() << "AudioInject::injectLocally did not get a valid QIODevice from _localAudioInterface"; + } + } else { + qDebug() << "AudioInject::injectLocally cannot inject locally with no local audio interface present."; + } +} + const uchar MAX_INJECTOR_VOLUME = 0xFF; -void AudioInjector::injectAudio() { +void AudioInjector::injectToMixer() { QByteArray soundByteArray = _sound->getByteArray(); if (_currentSendPosition < 0 || diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 12e4c62d5d..5a0a35d599 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -43,6 +43,9 @@ public slots: signals: void finished(); private: + void injectToMixer(); + void injectLocally(); + Sound* _sound; AudioInjectorOptions _options; bool _shouldStop; diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index 2a532b92b7..df435cf2cc 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -19,7 +19,8 @@ AudioInjectorOptions::AudioInjectorOptions() : loop(false), orientation(glm::vec3(0.0f, 0.0f, 0.0f)), stereo(false), - ignorePenumbra(false) + ignorePenumbra(false), + localOnly(false) { } @@ -32,6 +33,7 @@ QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInje obj.setProperty("orientation", quatToScriptValue(engine, injectorOptions.orientation)); obj.setProperty("stereo", injectorOptions.stereo); obj.setProperty("ignorePenumbra", injectorOptions.ignorePenumbra); + obj.setProperty("localOnly", injectorOptions.localOnly); return obj; } @@ -59,4 +61,8 @@ void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOpt if (object.property("ignorePenumbra").isValid()) { injectorOptions.ignorePenumbra = object.property("ignorePenumbra").toBool(); } + + if (object.property("localOnly").isValid()) { + injectorOptions.localOnly = object.property("localOnly").toBool(); + } } \ No newline at end of file diff --git a/libraries/audio/src/AudioInjectorOptions.h b/libraries/audio/src/AudioInjectorOptions.h index c3e2da991a..4fd3a0b7ae 100644 --- a/libraries/audio/src/AudioInjectorOptions.h +++ b/libraries/audio/src/AudioInjectorOptions.h @@ -26,6 +26,7 @@ public: glm::quat orientation; bool stereo; bool ignorePenumbra; + bool localOnly; }; Q_DECLARE_METATYPE(AudioInjectorOptions); From 83529c1fed313ebee6c7fed182cf097cb7dd672e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 14:45:33 -0800 Subject: [PATCH 22/69] fix QIODevice fail in AudioInjector by passing explicit size --- interface/src/Audio.cpp | 6 +++-- interface/src/Audio.h | 6 +---- libraries/audio/src/AbstractAudioInterface.h | 2 +- libraries/audio/src/AudioInjector.cpp | 25 +++++++++++++------- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 58c3972bcb..8fecb4ee8e 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1334,11 +1334,13 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float _drumSoundSample = 0; } -QIODevice* Audio::newLocalOutputDevice(bool isStereo) { +QIODevice* Audio::newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector) { QAudioFormat localFormat = _desiredOutputFormat; localFormat.setChannelCount(isStereo ? 2 : 1); + QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), - localFormat); + localFormat, this); + localOutput->setBufferSize(numBytes); return localOutput->start(); } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 83688cf84a..460be0a567 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -155,7 +155,7 @@ public slots: void selectAudioFilterBassCut(); void selectAudioFilterSmiley(); - virtual QIODevice* newLocalOutputDevice(bool isStereo); + virtual QIODevice* newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector); void sendDownstreamAudioStatsPacket(); @@ -256,10 +256,6 @@ private: float _iconColor; qint64 _iconPulseTimeReference; - /// Audio callback in class context. - inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight); - - bool _processSpatialAudio; /// Process received audio by spatial audio hooks unsigned int _spatialAudioStart; /// Start of spatial audio interval (in sample rate time base) unsigned int _spatialAudioFinish; /// End of spatial audio interval (in sample rate time base) diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index e413bfc8f1..5b42108430 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -25,7 +25,7 @@ public: virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0; virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0; public slots: - virtual QIODevice* newLocalOutputDevice(bool isStereo) = 0; + virtual QIODevice* newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector) = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 9b2720b90c..e83cd5350a 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -71,18 +71,27 @@ void AudioInjector::injectLocally() { QIODevice* localBuffer = NULL; - QMetaObject::invokeMethod(_localAudioInterface, "newLocalOutputDevice", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QIODevice*, localBuffer), - Q_ARG(bool, _options.stereo)); + const QByteArray& soundByteArray = _sound->getByteArray(); - if (localBuffer) { - // immediately write the byte array to the local device - localBuffer->write(_sound->getByteArray()); + if (soundByteArray.size() > 0) { + QMetaObject::invokeMethod(_localAudioInterface, "newLocalOutputDevice", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QIODevice*, localBuffer), + Q_ARG(bool, _options.stereo), + Q_ARG(int, soundByteArray.size()), + Q_ARG(QObject*, this)); + + if (localBuffer) { + // immediately write the byte array to the local device + qDebug() << "Writing" << localBuffer->write(soundByteArray) << "bytes to local audio device"; + } else { + qDebug() << "AudioInjector::injectLocally did not get a valid QIODevice from _localAudioInterface"; + } } else { - qDebug() << "AudioInject::injectLocally did not get a valid QIODevice from _localAudioInterface"; + qDebug() << "AudioInjector::injectLocally called without any data in Sound QByteArray"; } + } else { - qDebug() << "AudioInject::injectLocally cannot inject locally with no local audio interface present."; + qDebug() << "AudioInjector::injectLocally cannot inject locally with no local audio interface present."; } } From 0e30c65e60b85577d617cd95fbb3a7c99ef90b6a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 15:12:11 -0800 Subject: [PATCH 23/69] handle cleanup of local injection, volume --- examples/lobby.js | 6 ++++- interface/src/Application.cpp | 9 +++---- interface/src/Audio.cpp | 26 +++++++++++++++--- interface/src/Audio.h | 8 +++--- libraries/audio/src/AbstractAudioInterface.h | 4 ++- libraries/audio/src/AudioInjector.cpp | 28 +++++++++++++------- libraries/audio/src/AudioInjector.h | 4 +-- 7 files changed, 60 insertions(+), 25 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index e6db57bdd5..c921e744f1 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -39,6 +39,7 @@ var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8}; var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx" var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw") +var currentDrone; function reticlePosition() { var RETICLE_DISTANCE = 1; @@ -90,7 +91,7 @@ function drawLobby() { MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15); // start the drone sound - Audio.playSound(droneSound, { stereo: true, localOnly: true }); + currentDrone = Audio.playSound(droneSound, { stereo: true, localOnly: true }); } } @@ -121,6 +122,9 @@ function cleanupLobby() { Overlays.deleteOverlay(orbShell); Overlays.deleteOverlay(reticle); + currentDrone.stop(); + currentDrone = null; + panelWall = false; orbShell = false; reticle = false; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 77cfcfd548..d2d5ff2480 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -453,23 +453,22 @@ Application::~Application() { // ask the datagram processing thread to quit and wait until it is done _nodeThread->quit(); _nodeThread->wait(); + + // kill any audio injectors that are still around + AudioScriptingInterface::getInstance().stopAllInjectors(); // stop the audio process QMetaObject::invokeMethod(&_audio, "stop"); - + // ask the audio thread to quit and wait until it is done _audio.thread()->quit(); _audio.thread()->wait(); - - // kill any audio injectors that are still around - AudioScriptingInterface::getInstance().stopAllInjectors(); _octreeProcessor.terminate(); _voxelHideShowThread.terminate(); _voxelEditSender.terminate(); _entityEditSender.terminate(); - VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown Menu::getInstance()->deleteLater(); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 8fecb4ee8e..08a29a08ff 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -32,19 +32,21 @@ #include #include +#include + +#include #include #include #include #include #include -#include - -#include "Audio.h" #include "Menu.h" #include "Util.h" #include "PositionalAudioStream.h" +#include "Audio.h" + static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0; static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300; @@ -1334,17 +1336,33 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float _drumSoundSample = 0; } -QIODevice* Audio::newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector) { +QIODevice* Audio::newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector) { QAudioFormat localFormat = _desiredOutputFormat; localFormat.setChannelCount(isStereo ? 2 : 1); QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), localFormat, this); localOutput->setBufferSize(numBytes); + localOutput->setVolume(volume); + + // add this to our list of local injected outputs, we will need to clean it up when the injector says it is done + _injectedOutputInterfaces.insert(injector, localOutput); + + connect(injector, &AudioInjector::finished, this, &Audio::cleanupLocalOutputInterface); return localOutput->start(); } +void Audio::cleanupLocalOutputInterface() { + QAudioOutput* outputInterface = _injectedOutputInterfaces.value(sender()); + if (outputInterface) { + qDebug() << "Stopping a QAudioOutput interface since injector" << sender() << "is finished"; + + outputInterface->stop(); + outputInterface->deleteLater(); + } +} + void Audio::renderToolBox(int x, int y, bool boxed) { glEnable(GL_TEXTURE_2D); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 460be0a567..cc404723d8 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -155,7 +155,7 @@ public slots: void selectAudioFilterBassCut(); void selectAudioFilterSmiley(); - virtual QIODevice* newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector); + virtual QIODevice* newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector); void sendDownstreamAudioStatsPacket(); @@ -180,11 +180,11 @@ signals: void processInboundAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format); void processLocalAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format); +private slots: + void cleanupLocalOutputInterface(); private: void outputFormatChanged(); -private: - QByteArray firstInputFrame; QAudioInput* _audioInput; QAudioFormat _desiredInputFormat; @@ -365,6 +365,8 @@ private: AudioOutputIODevice _audioOutputIODevice; WeakRecorderPointer _recorder; + + QHash _injectedOutputInterfaces; }; diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 5b42108430..104abae554 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -17,6 +17,8 @@ #include "AudioInjectorOptions.h" +class AudioInjector; + class AbstractAudioInterface : public QObject { Q_OBJECT public: @@ -25,7 +27,7 @@ public: virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0; virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0; public slots: - virtual QIODevice* newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector) = 0; + virtual QIODevice* newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector) = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index e83cd5350a..a0914ca741 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -36,7 +36,8 @@ AudioInjector::AudioInjector(QObject* parent) : _shouldStop(false), _loudness(0.0f), _isFinished(false), - _currentSendPosition(0) + _currentSendPosition(0), + _localDevice(NULL) { } @@ -67,22 +68,21 @@ void AudioInjector::injectAudio() { } void AudioInjector::injectLocally() { - if (_localAudioInterface) { - - QIODevice* localBuffer = NULL; - + if (_localAudioInterface) { const QByteArray& soundByteArray = _sound->getByteArray(); if (soundByteArray.size() > 0) { QMetaObject::invokeMethod(_localAudioInterface, "newLocalOutputDevice", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QIODevice*, localBuffer), + Q_RETURN_ARG(QIODevice*, _localDevice), Q_ARG(bool, _options.stereo), + Q_ARG(qreal, _options.volume), Q_ARG(int, soundByteArray.size()), - Q_ARG(QObject*, this)); + Q_ARG(AudioInjector*, this)); - if (localBuffer) { + if (_localDevice) { // immediately write the byte array to the local device - qDebug() << "Writing" << localBuffer->write(soundByteArray) << "bytes to local audio device"; + qDebug() << "Writing" << soundByteArray.size() << "bytes to local audio device"; + _localDevice->write(soundByteArray); } else { qDebug() << "AudioInjector::injectLocally did not get a valid QIODevice from _localAudioInterface"; } @@ -220,3 +220,13 @@ void AudioInjector::injectToMixer() { _isFinished = true; emit finished(); } + +void AudioInjector::stop() { + _shouldStop = true; + + if (_localDevice) { + // we're only a local injector, so we can say we are finished and the AbstractAudioInterface should clean us up + _isFinished = true; + emit finished(); + } +} diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 5a0a35d599..98d391e494 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -35,7 +35,7 @@ public: void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; } public slots: void injectAudio(); - void stop() { _shouldStop = true; } + void stop(); void setOptions(AudioInjectorOptions& options); void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; } float getLoudness(); @@ -53,7 +53,7 @@ private: bool _isFinished; int _currentSendPosition; AbstractAudioInterface* _localAudioInterface; - + QIODevice* _localDevice; }; Q_DECLARE_METATYPE(AudioInjector*) From a5a02b5f8a5c6d80a43aa97bd543f08c708c5f27 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 16:34:00 -0800 Subject: [PATCH 24/69] add AudioInjectorLocalBuffer for more control --- examples/lobby.js | 3 +- interface/src/Audio.cpp | 32 ++++++++------ interface/src/Audio.h | 2 +- libraries/audio/src/AbstractAudioInterface.h | 3 +- libraries/audio/src/AudioInjector.cpp | 42 ++++++++++++------ libraries/audio/src/AudioInjector.h | 7 ++- .../audio/src/AudioInjectorLocalBuffer.cpp | 43 +++++++++++++++++++ .../audio/src/AudioInjectorLocalBuffer.h | 35 +++++++++++++++ 8 files changed, 136 insertions(+), 31 deletions(-) create mode 100644 libraries/audio/src/AudioInjectorLocalBuffer.cpp create mode 100644 libraries/audio/src/AudioInjectorLocalBuffer.h diff --git a/examples/lobby.js b/examples/lobby.js index c921e744f1..eb2611fd29 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -38,7 +38,8 @@ var panelsCenterShift = Vec3.subtract(panelsCenter, orbCenter); var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8}; var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx" -var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw") + +var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.raw") var currentDrone; function reticlePosition() { diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 08a29a08ff..a5f6bd897f 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1336,21 +1336,25 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float _drumSoundSample = 0; } -QIODevice* Audio::newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector) { - QAudioFormat localFormat = _desiredOutputFormat; - localFormat.setChannelCount(isStereo ? 2 : 1); +bool Audio::outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector) { + if (injector->getLocalBuffer()) { + QAudioFormat localFormat = _desiredOutputFormat; + localFormat.setChannelCount(isStereo ? 2 : 1); + + QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), + localFormat, this); + localOutput->setVolume(volume); + + // add this to our list of local injected outputs, we will need to clean it up when the injector says it is done + _injectedOutputInterfaces.insert(injector, localOutput); + + connect(injector, &AudioInjector::finished, this, &Audio::cleanupLocalOutputInterface); + + localOutput->start(injector->getLocalBuffer()); + return localOutput->state() == QAudio::ActiveState; + } - QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), - localFormat, this); - localOutput->setBufferSize(numBytes); - localOutput->setVolume(volume); - - // add this to our list of local injected outputs, we will need to clean it up when the injector says it is done - _injectedOutputInterfaces.insert(injector, localOutput); - - connect(injector, &AudioInjector::finished, this, &Audio::cleanupLocalOutputInterface); - - return localOutput->start(); + return false; } void Audio::cleanupLocalOutputInterface() { diff --git a/interface/src/Audio.h b/interface/src/Audio.h index cc404723d8..d6e26864e6 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -155,7 +155,7 @@ public slots: void selectAudioFilterBassCut(); void selectAudioFilterSmiley(); - virtual QIODevice* newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector); + virtual bool outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector); void sendDownstreamAudioStatsPacket(); diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 104abae554..b5a7be9849 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -18,6 +18,7 @@ #include "AudioInjectorOptions.h" class AudioInjector; +class AudioInjectorLocalBuffer; class AbstractAudioInterface : public QObject { Q_OBJECT @@ -27,7 +28,7 @@ public: virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0; virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0; public slots: - virtual QIODevice* newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector) = 0; + virtual bool outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector) = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index a0914ca741..ddd4f05630 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -37,7 +37,7 @@ AudioInjector::AudioInjector(QObject* parent) : _loudness(0.0f), _isFinished(false), _currentSendPosition(0), - _localDevice(NULL) + _localBuffer(NULL) { } @@ -47,10 +47,17 @@ AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorO _shouldStop(false), _loudness(0.0f), _isFinished(false), - _currentSendPosition(0) + _currentSendPosition(0), + _localBuffer(NULL) { } +AudioInjector::~AudioInjector() { + if (_localBuffer) { + _localBuffer->stop(); + } +} + void AudioInjector::setOptions(AudioInjectorOptions& options) { _options = options; } @@ -72,19 +79,25 @@ void AudioInjector::injectLocally() { const QByteArray& soundByteArray = _sound->getByteArray(); if (soundByteArray.size() > 0) { - QMetaObject::invokeMethod(_localAudioInterface, "newLocalOutputDevice", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QIODevice*, _localDevice), + bool successfulOutput = false; + + _localBuffer = new AudioInjectorLocalBuffer(_sound->getByteArray(), this); + _localBuffer->open(QIODevice::ReadOnly); + _localBuffer->setIsLooping(_options.loop); + + qDebug() << "Passing off AudioInjectorLocatBuffer to localAudioInterface"; + + QMetaObject::invokeMethod(_localAudioInterface, "outputLocalInjector", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, successfulOutput), Q_ARG(bool, _options.stereo), Q_ARG(qreal, _options.volume), - Q_ARG(int, soundByteArray.size()), Q_ARG(AudioInjector*, this)); - if (_localDevice) { - // immediately write the byte array to the local device - qDebug() << "Writing" << soundByteArray.size() << "bytes to local audio device"; - _localDevice->write(soundByteArray); - } else { - qDebug() << "AudioInjector::injectLocally did not get a valid QIODevice from _localAudioInterface"; + + + if (!successfulOutput) { + qDebug() << "AudioInjector::injectLocally could not output locally via _localAudioInterface"; } } else { qDebug() << "AudioInjector::injectLocally called without any data in Sound QByteArray"; @@ -224,8 +237,11 @@ void AudioInjector::injectToMixer() { void AudioInjector::stop() { _shouldStop = true; - if (_localDevice) { - // we're only a local injector, so we can say we are finished and the AbstractAudioInterface should clean us up + if (_localBuffer) { + // we're only a local injector, so we can say we are finished right away too + + _localBuffer->stop(); + _isFinished = true; emit finished(); } diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 98d391e494..607aeb500e 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -18,6 +18,7 @@ #include #include +#include "AudioInjectorLocalBuffer.h" #include "AudioInjectorOptions.h" #include "Sound.h" @@ -28,10 +29,14 @@ class AudioInjector : public QObject { public: AudioInjector(QObject* parent); AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions); + ~AudioInjector(); bool isFinished() const { return _isFinished; } int getCurrentSendPosition() const { return _currentSendPosition; } + AudioInjectorLocalBuffer* getLocalBuffer() const { return _localBuffer; } + bool isLocalOnly() const { return _options.localOnly; } + void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; } public slots: void injectAudio(); @@ -53,7 +58,7 @@ private: bool _isFinished; int _currentSendPosition; AbstractAudioInterface* _localAudioInterface; - QIODevice* _localDevice; + AudioInjectorLocalBuffer* _localBuffer; }; Q_DECLARE_METATYPE(AudioInjector*) diff --git a/libraries/audio/src/AudioInjectorLocalBuffer.cpp b/libraries/audio/src/AudioInjectorLocalBuffer.cpp new file mode 100644 index 0000000000..19c92276f9 --- /dev/null +++ b/libraries/audio/src/AudioInjectorLocalBuffer.cpp @@ -0,0 +1,43 @@ +// +// AudioInjectorLocalBuffer.cpp +// libraries/audio/src +// +// Created by Stephen Birarda on 2014-11-11. +// 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 "AudioInjectorLocalBuffer.h" + +AudioInjectorLocalBuffer::AudioInjectorLocalBuffer(const QByteArray& rawAudioArray, QObject* parent) : + QIODevice(parent), + _rawAudioArray(rawAudioArray), + _isLooping(false), + _isStopped(false) +{ + +} + +void AudioInjectorLocalBuffer::stop() { + _isStopped = true; + QIODevice::close(); +} + +qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) { + if (!_isStopped) { + int bytesToEnd = _rawAudioArray.size() - pos(); + + int bytesToRead = maxSize; + + if (maxSize > bytesToEnd) { + bytesToRead = bytesToEnd; + } + + memcpy(data, _rawAudioArray.data() + pos(), bytesToRead); + return bytesToRead; + } else { + return 0; + } +} \ No newline at end of file diff --git a/libraries/audio/src/AudioInjectorLocalBuffer.h b/libraries/audio/src/AudioInjectorLocalBuffer.h new file mode 100644 index 0000000000..6d234066ef --- /dev/null +++ b/libraries/audio/src/AudioInjectorLocalBuffer.h @@ -0,0 +1,35 @@ +// +// AudioInjectorLocalBuffer.h +// libraries/audio/src +// +// Created by Stephen Birarda on 2014-11-11. +// 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_AudioInjectorLocalBuffer_h +#define hifi_AudioInjectorLocalBuffer_h + +#include + +class AudioInjectorLocalBuffer : public QIODevice { + Q_OBJECT +public: + AudioInjectorLocalBuffer(const QByteArray& rawAudioArray, QObject* parent); + + void stop(); + + qint64 readData(char* data, qint64 maxSize); + qint64 writeData(const char* data, qint64 maxSize) { return 0; } + + void setIsLooping(bool isLooping) { _isLooping = isLooping; } + +private: + QByteArray _rawAudioArray; + bool _isLooping; + bool _isStopped; +}; + +#endif // hifi_AudioInjectorLocalBuffer_h \ No newline at end of file From cb5d5dd3a8ba3b879811361406b0d1422478c6cd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 16:57:25 -0800 Subject: [PATCH 25/69] handle looping via AudioInjectorLocalBuffer --- examples/lobby.js | 2 +- libraries/audio/src/AudioInjector.cpp | 4 +- .../audio/src/AudioInjectorLocalBuffer.cpp | 45 ++++++++++++++++--- .../audio/src/AudioInjectorLocalBuffer.h | 9 +++- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index eb2611fd29..682e8dbd80 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -92,7 +92,7 @@ function drawLobby() { MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15); // start the drone sound - currentDrone = Audio.playSound(droneSound, { stereo: true, localOnly: true }); + currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true }); } } diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index ddd4f05630..6716d525da 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -83,9 +83,7 @@ void AudioInjector::injectLocally() { _localBuffer = new AudioInjectorLocalBuffer(_sound->getByteArray(), this); _localBuffer->open(QIODevice::ReadOnly); - _localBuffer->setIsLooping(_options.loop); - - qDebug() << "Passing off AudioInjectorLocatBuffer to localAudioInterface"; + _localBuffer->setShouldLoop(_options.loop); QMetaObject::invokeMethod(_localAudioInterface, "outputLocalInjector", Qt::BlockingQueuedConnection, diff --git a/libraries/audio/src/AudioInjectorLocalBuffer.cpp b/libraries/audio/src/AudioInjectorLocalBuffer.cpp index 19c92276f9..bdf084091d 100644 --- a/libraries/audio/src/AudioInjectorLocalBuffer.cpp +++ b/libraries/audio/src/AudioInjectorLocalBuffer.cpp @@ -14,8 +14,9 @@ AudioInjectorLocalBuffer::AudioInjectorLocalBuffer(const QByteArray& rawAudioArray, QObject* parent) : QIODevice(parent), _rawAudioArray(rawAudioArray), - _isLooping(false), - _isStopped(false) + _shouldLoop(false), + _isStopped(false), + _currentOffset(0) { } @@ -27,17 +28,47 @@ void AudioInjectorLocalBuffer::stop() { qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) { if (!_isStopped) { - int bytesToEnd = _rawAudioArray.size() - pos(); - int bytesToRead = maxSize; + // first copy to the end of the raw audio + int bytesToEnd = _rawAudioArray.size() - _currentOffset; + + int bytesRead = maxSize; if (maxSize > bytesToEnd) { - bytesToRead = bytesToEnd; + bytesRead = bytesToEnd; } - memcpy(data, _rawAudioArray.data() + pos(), bytesToRead); - return bytesToRead; + memcpy(data, _rawAudioArray.data() + _currentOffset, bytesRead); + + // now check if we are supposed to loop and if we can copy more from the beginning + if (_shouldLoop && maxSize != bytesRead) { + bytesRead += recursiveReadFromFront(data + bytesRead, maxSize - bytesRead); + } else { + _currentOffset += bytesRead; + } + + return bytesRead; } else { return 0; } +} + +qint64 AudioInjectorLocalBuffer::recursiveReadFromFront(char* data, qint64 maxSize) { + // see how much we can get in this pass + int bytesRead = maxSize; + + if (bytesRead > _rawAudioArray.size()) { + bytesRead = _rawAudioArray.size(); + } + + // copy that amount + memcpy(data, _rawAudioArray.data(), bytesRead); + + // check if we need to call ourselves again and pull from the front again + if (bytesRead < maxSize) { + return bytesRead + recursiveReadFromFront(data, maxSize); + } else { + _currentOffset = bytesRead; + return bytesRead; + } } \ No newline at end of file diff --git a/libraries/audio/src/AudioInjectorLocalBuffer.h b/libraries/audio/src/AudioInjectorLocalBuffer.h index 6d234066ef..8b32c6fbc7 100644 --- a/libraries/audio/src/AudioInjectorLocalBuffer.h +++ b/libraries/audio/src/AudioInjectorLocalBuffer.h @@ -24,12 +24,17 @@ public: qint64 readData(char* data, qint64 maxSize); qint64 writeData(const char* data, qint64 maxSize) { return 0; } - void setIsLooping(bool isLooping) { _isLooping = isLooping; } + void setShouldLoop(bool shouldLoop) { _shouldLoop = shouldLoop; } private: + + qint64 recursiveReadFromFront(char* data, qint64 maxSize); + QByteArray _rawAudioArray; - bool _isLooping; + bool _shouldLoop; bool _isStopped; + + int _currentOffset; }; #endif // hifi_AudioInjectorLocalBuffer_h \ No newline at end of file From 04335862938ce81cd270ff2a344394307746fa8d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 16:59:15 -0800 Subject: [PATCH 26/69] switch lobby noise back to drone --- examples/lobby.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/lobby.js b/examples/lobby.js index 682e8dbd80..89a6b69776 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -39,7 +39,7 @@ var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8}; var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx" -var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.raw") +var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw") var currentDrone; function reticlePosition() { From 7f79f0946d57df39975911011966c6af2605de3e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 17:10:25 -0800 Subject: [PATCH 27/69] play a random musak song in lobby when it is shown --- examples/lobby.js | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index 89a6b69776..02d74a0cd7 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -40,7 +40,11 @@ var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8}; var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx" var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw") -var currentDrone; +var currentDrone = null; + +var latinSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.raw") +var elevatorSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/elevator.raw") +var currentMusak = null; function reticlePosition() { var RETICLE_DISTANCE = 1; @@ -93,6 +97,9 @@ function drawLobby() { // start the drone sound currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true }); + + // start one of our musak sounds + playRandomMusak(); } } @@ -118,13 +125,38 @@ function changeLobbyTextures() { Overlays.editOverlay(panelWall, textureProp); } +function playRandomMusak() { + chosenSound = null; + + if (latinSound.downloaded && elevatorSound.downloaded) { + chosenSound = Math.random < 0.5 ? latinSound : elevatorSound; + } else if (latinSound.downloaded) { + chosenSound = latinSound; + } else if (elevator.downloaded) { + chosenSound = elevatorSound; + } + + if (chosenSound) { + currentMusak = Audio.playSound(chosenSound, { stereo: true, localOnly: true }) + } else { + currentMusak = null; + } +} + function cleanupLobby() { Overlays.deleteOverlay(panelWall); Overlays.deleteOverlay(orbShell); Overlays.deleteOverlay(reticle); - currentDrone.stop(); - currentDrone = null; + if (currentDrone) { + currentDrone.stop(); + currentDrone = null; + } + + if (currentMusak) { + currentMusak.stop(); + currentMusak = null; + } panelWall = false; orbShell = false; From 9aa950e65740f6aecbe0008f2dd5a9ea12f1b5f8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 17:34:03 -0800 Subject: [PATCH 28/69] fix audio injector cleanup for local only injectors --- examples/lobby.js | 14 +++++--------- libraries/audio/src/AudioInjector.cpp | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index 02d74a0cd7..1b6596efa7 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -132,7 +132,7 @@ function playRandomMusak() { chosenSound = Math.random < 0.5 ? latinSound : elevatorSound; } else if (latinSound.downloaded) { chosenSound = latinSound; - } else if (elevator.downloaded) { + } else if (elevatorSound.downloaded) { chosenSound = elevatorSound; } @@ -148,15 +148,11 @@ function cleanupLobby() { Overlays.deleteOverlay(orbShell); Overlays.deleteOverlay(reticle); - if (currentDrone) { - currentDrone.stop(); - currentDrone = null; - } + Audio.stopInjector(currentDrone); + currentDrone = null; - if (currentMusak) { - currentMusak.stop(); - currentMusak = null; - } + Audio.stopInjector(currentMusak); + currentMusak = null; panelWall = false; orbShell = false; diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 6716d525da..fcd2127d4f 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -75,26 +75,25 @@ void AudioInjector::injectAudio() { } void AudioInjector::injectLocally() { + bool success = false; if (_localAudioInterface) { const QByteArray& soundByteArray = _sound->getByteArray(); if (soundByteArray.size() > 0) { - bool successfulOutput = false; - _localBuffer = new AudioInjectorLocalBuffer(_sound->getByteArray(), this); _localBuffer->open(QIODevice::ReadOnly); _localBuffer->setShouldLoop(_options.loop); QMetaObject::invokeMethod(_localAudioInterface, "outputLocalInjector", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, successfulOutput), + Q_RETURN_ARG(bool, success), Q_ARG(bool, _options.stereo), Q_ARG(qreal, _options.volume), Q_ARG(AudioInjector*, this)); - if (!successfulOutput) { + if (!success) { qDebug() << "AudioInjector::injectLocally could not output locally via _localAudioInterface"; } } else { @@ -104,6 +103,12 @@ void AudioInjector::injectLocally() { } else { qDebug() << "AudioInjector::injectLocally cannot inject locally with no local audio interface present."; } + + if (!success) { + // we never started so we are finished, call our stop method + stop(); + } + } const uchar MAX_INJECTOR_VOLUME = 0xFF; @@ -235,11 +240,8 @@ void AudioInjector::injectToMixer() { void AudioInjector::stop() { _shouldStop = true; - if (_localBuffer) { + if (_options.localOnly) { // we're only a local injector, so we can say we are finished right away too - - _localBuffer->stop(); - _isFinished = true; emit finished(); } From 8ac3aba2bdf4fefafd09685fc7c3404eca5d5d5c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 11 Nov 2014 17:54:02 -0800 Subject: [PATCH 29/69] Make text overlays apply alpha to text as well as background --- examples/overlaysExample.js | 3 ++- interface/src/ui/TextRenderer.cpp | 12 +++++++----- interface/src/ui/TextRenderer.h | 2 +- interface/src/ui/overlays/Text3DOverlay.cpp | 2 +- interface/src/ui/overlays/TextOverlay.cpp | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/examples/overlaysExample.js b/examples/overlaysExample.js index fef502c761..c7bc28db96 100644 --- a/examples/overlaysExample.js +++ b/examples/overlaysExample.js @@ -68,7 +68,8 @@ var text = Overlays.addOverlay("text", { color: { red: 255, green: 0, blue: 0}, topMargin: 4, leftMargin: 4, - text: "Here is some text.\nAnd a second line." + text: "Here is some text.\nAnd a second line.", + alpha: 0.7 }); // This will create an image overlay, which starts out as invisible diff --git a/interface/src/ui/TextRenderer.cpp b/interface/src/ui/TextRenderer.cpp index fed041d6ea..65725ab4ec 100644 --- a/interface/src/ui/TextRenderer.cpp +++ b/interface/src/ui/TextRenderer.cpp @@ -69,14 +69,16 @@ int TextRenderer::calculateHeight(const char* str) { return maxHeight; } -int TextRenderer::draw(int x, int y, const char* str) { +int TextRenderer::draw(int x, int y, const char* str, float alpha) { // Grab the current color float currentColor[4]; glGetFloatv(GL_CURRENT_COLOR, currentColor); - int compactColor = ((int( currentColor[0] * 255.f) & 0xFF)) | - ((int( currentColor[1] * 255.f) & 0xFF) << 8) | - ((int( currentColor[2] * 255.f) & 0xFF) << 16) | - ((int( currentColor[3] * 255.f) & 0xFF) << 24); + alpha = std::max(0.f, std::min(alpha, 1.f)); + currentColor[3] *= alpha; + int compactColor = ((int(currentColor[0] * 255.f) & 0xFF)) | + ((int(currentColor[1] * 255.f) & 0xFF) << 8) | + ((int(currentColor[2] * 255.f) & 0xFF) << 16) | + ((int(currentColor[3] * 255.f) & 0xFF) << 24); // TODO: Remove that code once we test for performance improvments //glEnable(GL_TEXTURE_2D); diff --git a/interface/src/ui/TextRenderer.h b/interface/src/ui/TextRenderer.h index bcb0ce8890..325420cf2a 100644 --- a/interface/src/ui/TextRenderer.h +++ b/interface/src/ui/TextRenderer.h @@ -63,7 +63,7 @@ public: int calculateHeight(const char* str); // also returns the height of the tallest character - int draw(int x, int y, const char* str); + int draw(int x, int y, const char* str, float alpha = 1.f); int computeWidth(char ch); int computeWidth(const char* str); diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index d8febbf0eb..072b52768a 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -112,7 +112,7 @@ void Text3DOverlay::render(RenderArgs* args) { QStringList lines = _text.split("\n"); int lineOffset = maxHeight; foreach(QString thisLine, lines) { - textRenderer->draw(0, lineOffset, qPrintable(thisLine)); + textRenderer->draw(0, lineOffset, qPrintable(thisLine), alpha); lineOffset += maxHeight; } diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 530b30a856..85ecca6d32 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -82,7 +82,7 @@ void TextOverlay::render(RenderArgs* args) { if (lineOffset == 0) { lineOffset = textRenderer->calculateHeight(qPrintable(thisLine)); } - lineOffset += textRenderer->draw(x, y + lineOffset, qPrintable(thisLine)); + lineOffset += textRenderer->draw(x, y + lineOffset, qPrintable(thisLine), alpha); const int lineGap = 2; lineOffset += lineGap; From 9a45a707649d81140adf21af2b14a5f3467739c0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 20:47:40 -0800 Subject: [PATCH 30/69] repairs to Sound script conversion typos --- libraries/audio/src/Sound.cpp | 4 ++-- libraries/audio/src/Sound.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index bb134ad198..4c520f27ce 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -30,11 +30,11 @@ #include "Sound.h" -QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const &in) { +QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const& in) { return engine->newQObject(in); } -void soundFromScriptValue(const QScriptValue &object, Sound* &out) { +void soundFromScriptValue(const QScriptValue& object, Sound*& out) { out = qobject_cast(object.toQObject()); } diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index ade3ad324f..f7b51891f0 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -47,7 +47,7 @@ private slots: Q_DECLARE_METATYPE(Sound*) -QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const &in); -void soundFromScriptValue(const QScriptValue &object, Sound* &out); +QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const& in); +void soundFromScriptValue(const QScriptValue& object, Sound*& out); #endif // hifi_Sound_h From ed9a2bf676010e7d374b5973ac0a16f68a51c7d7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 11 Nov 2014 20:48:34 -0800 Subject: [PATCH 31/69] fix for AudioInjector QScriptValue conversion typos --- libraries/audio/src/AudioInjector.cpp | 4 ++-- libraries/audio/src/AudioInjector.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index fcd2127d4f..1743504883 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -21,11 +21,11 @@ #include "AudioInjector.h" -QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const &in) { +QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const& in) { return engine->newQObject(in); } -void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out) { +void injectorFromScriptValue(const QScriptValue& object, AudioInjector*& out) { out = qobject_cast(object.toQObject()); } diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 607aeb500e..13188c5977 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -63,7 +63,7 @@ private: Q_DECLARE_METATYPE(AudioInjector*) -QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const &in); -void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out); +QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const& in); +void injectorFromScriptValue(const QScriptValue& object, AudioInjector*& out); #endif // hifi_AudioInjector_h From b716a512c69a8ae68b913c4c1a1940a0ec354fdd Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 00:26:44 -0800 Subject: [PATCH 32/69] 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 33/69] 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 34/69] 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 35/69] 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 36/69] 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 37/69] 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 38/69] 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 39/69] 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 40/69] 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 41/69] 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 42/69] 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 43/69] 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 44/69] 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 45/69] 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 46/69] 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 47/69] 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 48/69] 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 49/69] 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 50/69] 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 51/69] 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 52/69] 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 53/69] 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 54/69] 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 55/69] 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 56/69] 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 57/69] 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 58/69] 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 59/69] 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 60/69] 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 61/69] 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 62/69] 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 63/69] 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 64/69] 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 65/69] 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 66/69] 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 67/69] 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 68/69] 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 69/69] 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