From 660d9237e6e77fbefa8d4845132fc01e3b65eba8 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sat, 28 Feb 2015 13:07:16 -0800 Subject: [PATCH 01/56] First version of the Shader and the magical shader program --- libraries/gpu/src/gpu/Context.h | 20 +- libraries/gpu/src/gpu/GLBackend.h | 11 + libraries/gpu/src/gpu/GLBackendShader.cpp | 275 ++++++++++++++++++ libraries/gpu/src/gpu/Resource.h | 3 +- libraries/gpu/src/gpu/Shader.cpp | 67 +++++ libraries/gpu/src/gpu/Shader.h | 126 ++++++++ libraries/gpu/src/gpu/Texture.h | 4 +- .../model/src/model/SkyFromAtmosphere.slf | 108 +++++++ .../model/src/model/SkyFromAtmosphere.slv | 68 +++++ libraries/model/src/model/SkyFromSpace.slf | 114 ++++++++ libraries/model/src/model/SkyFromSpace.slv | 43 +++ libraries/model/src/model/Stage.cpp | 10 + libraries/model/src/model/Stage.h | 4 + 13 files changed, 845 insertions(+), 8 deletions(-) create mode 100755 libraries/gpu/src/gpu/GLBackendShader.cpp create mode 100755 libraries/gpu/src/gpu/Shader.cpp create mode 100755 libraries/gpu/src/gpu/Shader.h create mode 100755 libraries/model/src/model/SkyFromAtmosphere.slf create mode 100755 libraries/model/src/model/SkyFromAtmosphere.slv create mode 100755 libraries/model/src/model/SkyFromSpace.slf create mode 100755 libraries/model/src/model/SkyFromSpace.slv diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 8955010f50..632c5f96de 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -15,6 +15,7 @@ #include "Resource.h" #include "Texture.h" +#include "Shader.h" namespace gpu { @@ -46,14 +47,15 @@ public: template< typename T > static void setGPUObject(const Buffer& buffer, T* bo) { - buffer.setGPUObject(reinterpret_cast(bo)); + // buffer.setGPUObject(reinterpret_cast(bo)); + buffer.setGPUObject(bo); } template< typename T > static T* getGPUObject(const Buffer& buffer) { return reinterpret_cast(buffer.getGPUObject()); } - void syncGPUObject(const Buffer& buffer); + //void syncGPUObject(const Buffer& buffer); template< typename T > static void setGPUObject(const Texture& texture, T* to) { @@ -64,7 +66,19 @@ public: return reinterpret_cast(texture.getGPUObject()); } - void syncGPUObject(const Texture& texture); + //void syncGPUObject(const Texture& texture); + + + template< typename T > + static void setGPUObject(const Shader& shader, T* so) { + shader.setGPUObject(reinterpret_cast(so)); + } + template< typename T > + static T* getGPUObject(const Shader& shader) { + return reinterpret_cast(shader.getGPUObject()); + } + + // void syncGPUObject(const Shader& shader); protected: diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 49d139d727..161ce1dad6 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -60,6 +60,17 @@ public: static void syncGPUObject(const Texture& texture); static GLuint getTextureID(const TexturePointer& texture); + class GLShader : public GPUObject { + public: + GLuint _shader; + GLuint _program; + + GLShader(); + ~GLShader(); + }; + static GLShader* syncGPUObject(const Shader& shader); + static GLuint getShaderID(const ShaderPointer& shader); + static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS; static const int MAX_NUM_INPUT_BUFFERS = 16; diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp new file mode 100755 index 0000000000..e37643e2f2 --- /dev/null +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -0,0 +1,275 @@ +// +// GLBackendShader.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 2/28/2015. +// 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 "GLBackendShared.h" + + +GLBackend::GLShader::GLShader() : + _shader(0), + _program(0) +{} + +GLBackend::GLShader::~GLShader() { + if (_shader != 0) { + glDeleteShader(_shader); + } + if (_program != 0) { + glDeleteProgram(_program); + } +} + +bool compileShader(const Shader& shader, GLBackend::GLShader& object) { + // Any GLSLprogram ? normally yes... + const std::string& shaderSource = shader.getSource().getCode(); + if (shaderSource.empty()) { + qDebug() << "GLShader::compileShader - no GLSL shader source code ? so failed to create"; + return false; + } + + // Shader domain + const GLenum SHADER_DOMAINS[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER }; + GLenum shaderDomain = SHADER_DOMAINS[shader.getType()]; + + // Create the shader object + GLuint glshader = glCreateShader(shaderDomain); + if (!glshader) { + qDebug() << "GLShader::compileShader - failed to create the gl shader & gl program object"; + return false; + } + + // Assign the source + const GLchar* srcstr = shaderSource.c_str(); + glShaderSource(glshader, 1, &srcstr, NULL); + + // Compile ! + glCompileShader(glshader); + + // check if shader compiled + GLint compiled = 0; + glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled); + + // if compilation fails + if (!compiled) + { + // save the source code to a temp file so we can debug easily + /* std::ofstream filestream; + filestream.open( "debugshader.glsl" ); + if ( filestream.is_open() ) + { + filestream << shaderSource->source; + filestream.close(); + } + */ + + GLint infoLength = 0; + glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength); + + char* temp = new char[infoLength] ; + glGetShaderInfoLog( glshader, infoLength, NULL, temp); + + qDebug() << "GLShader::compileShader - failed to compile the gl shader object:"; + qDebug() << temp; + + /* + filestream.open( "debugshader.glsl.info.txt" ); + if ( filestream.is_open() ) + { + filestream << String( temp ); + filestream.close(); + } + */ + delete[] temp; + + glDeleteShader( glshader); + return false; + } + + // so far so good, program is almost done, need to link: + GLuint glprogram = glCreateProgram(); + if (!glprogram) { + qDebug() << "GLShader::compileShader - failed to create the gl shader & gl program object"; + return false; + } + + glProgramParameteri(glprogram, GL_PROGRAM_SEPARABLE, GL_TRUE); + glAttachShader(glprogram, glshader); + glLinkProgram(glprogram); + + GLint linked = 0; + glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); + + if (!linked) + { + /* + // save the source code to a temp file so we can debug easily + std::ofstream filestream; + filestream.open( "debugshader.glsl" ); + if ( filestream.is_open() ) + { + filestream << shaderSource->source; + filestream.close(); + } + */ + + GLint infoLength = 0; + glGetProgramiv( glprogram, GL_INFO_LOG_LENGTH, &infoLength ); + + char* temp = new char[infoLength] ; + glGetProgramInfoLog( glprogram, infoLength, NULL, temp); + + qDebug() << "GLShader::compileShader - failed to LINK the gl program object :"; + qDebug() << temp; + + /* + filestream.open( "debugshader.glsl.info.txt" ); + if ( filestream.is_open() ) + { + filestream << String( temp ); + filestream.close(); + } + */ + delete[] temp; + + glDeleteShader( glshader); + glDeleteProgram( glprogram); + return false; + } + + // So far so good, the shader is created successfully + object._shader = glshader; + object._program = glprogram; + + return true; +} + +bool compileProgram(const Shader& program, GLBackend::GLShader& object) { + if(!program.isProgram()) { + return false; + } + + // Let's go through every shaders and make sure they are ready to go + std::vector< GLuint > shaderObjects; + for (auto subShader : program.getShaders()) { + GLuint so = GLBackend::getShaderID(subShader); + if (!so) { + qDebug() << "GLShader::compileProgram - One of the shaders of the program is not compiled?"; + return false; + } + shaderObjects.push_back(so); + } + + // so far so good, program is almost done, need to link: + GLuint glprogram = glCreateProgram(); + if (!glprogram) { + qDebug() << "GLShader::compileProgram - failed to create the gl program object"; + return false; + } + + // glProgramParameteri(glprogram, GL_PROGRAM_, GL_TRUE); + // Create the program from the sub shaders + for (auto so : shaderObjects) { + glAttachShader(glprogram, so); + } + + // Link! + glLinkProgram(glprogram); + + GLint linked = 0; + glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); + + if (!linked) + { + /* + // save the source code to a temp file so we can debug easily + std::ofstream filestream; + filestream.open( "debugshader.glsl" ); + if ( filestream.is_open() ) + { + filestream << shaderSource->source; + filestream.close(); + } + */ + + GLint infoLength = 0; + glGetProgramiv( glprogram, GL_INFO_LOG_LENGTH, &infoLength ); + + char* temp = new char[infoLength] ; + glGetProgramInfoLog( glprogram, infoLength, NULL, temp); + + qDebug() << "GLShader::compileProgram - failed to LINK the gl program object :"; + qDebug() << temp; + + /* + filestream.open( "debugshader.glsl.info.txt" ); + if ( filestream.is_open() ) + { + filestream << String( temp ); + filestream.close(); + } + */ + delete[] temp; + + glDeleteProgram( glprogram); + return false; + } + + // So far so good, the program is created successfully + object._shader = 0; + object._program = glprogram; + + return true; +} + +GLBackend::GLShader* GLBackend::syncGPUObject(const Shader& shader) { + GLShader* object = Backend::getGPUObject(shader); + + // If GPU object already created then good + if (object) { + return object; + } + + // need to have a gpu object? + + // GO through the process of allocating the correct storage and/or update the content + if (shader.isProgram()) { + GLShader tempObject; + if (compileProgram(shader, tempObject)) { + object = new GLShader(tempObject); + Backend::setGPUObject(shader, object); + } + } else if (shader.isDomain()) { + GLShader tempObject; + if (compileShader(shader, tempObject)) { + object = new GLShader(tempObject); + Backend::setGPUObject(shader, object); + } + } + + return object; +} + + + +GLuint GLBackend::getShaderID(const ShaderPointer& shader) { + if (!shader) { + return 0; + } + GLShader* object = GLBackend::syncGPUObject(*shader); + if (object) { + if (shader->isProgram()) { + return object->_program; + } else { + return object->_shader; + } + } else { + return 0; + } +} + diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index a75c3e8d7c..225e3fd927 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -140,12 +140,11 @@ protected: Sysmem* _sysmem = NULL; - mutable GPUObject* _gpuObject = NULL; // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = NULL; void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; }; diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp new file mode 100755 index 0000000000..87365e245e --- /dev/null +++ b/libraries/gpu/src/gpu/Shader.cpp @@ -0,0 +1,67 @@ +// +// Shader.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 2/27/2015. +// 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 "Shader.h" +#include +#include + +using namespace gpu; + +Shader::Shader(Type type, const Source& source): + _source(source), + _type(type) +{ +} + +Shader::Shader(Type type, Pointer& vertex, Pointer& pixel): + _type(type) +{ + _shaders.resize(2); + _shaders[VERTEX] = vertex; + _shaders[PIXEL] = pixel; +} + + +Shader::~Shader() +{ +} + +/* +Program::Program(): + _storage(), + _type(GRAPHICS) +{ +} + +Program::~Program() +{ +} +*/ + +Shader* Shader::createVertex(const Source& source) { + Shader* shader = new Shader(VERTEX, source); + return shader; +} + +Shader* Shader::createPixel(const Source& source) { + Shader* shader = new Shader(PIXEL, source); + return shader; +} + +Shader* Shader::createProgram(Pointer& vertexShader, Pointer& pixelShader) { + if (vertexShader && vertexShader->getType() == VERTEX) { + if (pixelShader && pixelShader->getType() == PIXEL) { + Shader* shader = new Shader(PROGRAM, vertexShader, pixelShader); + return shader; + } + } + return nullptr; +} diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h new file mode 100755 index 0000000000..57177639ae --- /dev/null +++ b/libraries/gpu/src/gpu/Shader.h @@ -0,0 +1,126 @@ +// +// Shader.h +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 2/27/2015. +// 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_Shader_h +#define hifi_gpu_Shader_h + +#include "Resource.h" +#include + +namespace gpu { + +class Shader { +public: + + typedef QSharedPointer< Shader > Pointer; + typedef std::vector< Pointer > Shaders; + + class Source { + public: + enum Language { + GLSL = 0, + }; + + Source() {} + Source(const std::string& code, Language lang = GLSL) : _code(code), _lang(lang) {} + Source(const Source& source) : _code(source._code), _lang(source._lang) {} + virtual ~Source() {} + + virtual const std::string& getCode() const { return _code; } + + protected: + std::string _code; + Language _lang = GLSL; + }; + + enum Type { + VERTEX = 0, + PIXEL, + GEOMETRY, + NUM_DOMAINS, + + PROGRAM, + }; + + static Shader* createVertex(const Source& source); + static Shader* createPixel(const Source& source); + + static Shader* createProgram(Pointer& vertexShader, Pointer& pixelShader); + + + ~Shader(); + + Type getType() const { return _type; } + bool isProgram() const { return getType() > NUM_DOMAINS; } + bool isDomain() const { return getType() < NUM_DOMAINS; } + + const Source& getSource() const { return _source; } + + const Shaders& getShaders() const { return _shaders; } + +protected: + Shader(Type type, const Source& source); + Shader(Type type, Pointer& vertex, Pointer& pixel); + + Shader(const Shader& shader); // deep copy of the sysmem shader + Shader& operator=(const Shader& shader); // deep copy of the sysmem texture + + // Source contains the actual source code or nothing if the shader is a program + Source _source; + + // if shader is composed of sub shaders, here they are + Shaders _shaders; + + // The type of the shader, the master key + Type _type; + + // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = NULL; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } + GPUObject* getGPUObject() const { return _gpuObject; } + friend class Backend; +}; + +typedef Shader::Pointer ShaderPointer; +typedef std::vector< ShaderPointer > Shaders; + +/* +class Program { +public: + + enum Type { + GRAPHICS = 0, + + NUM_TYPES, + }; + + + Program(); + Program(const Program& program); // deep copy of the sysmem shader + Program& operator=(const Program& program); // deep copy of the sysmem texture + ~Program(); + +protected: + Shaders _shaders; + Type _type; + + // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = NULL; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } + GPUObject* getGPUObject() const { return _gpuObject; } + friend class Backend; +}; + +typedef QSharedPointer ShaderPointer; +*/ +}; + + +#endif diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 61923999b9..3eed52c686 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -207,12 +207,10 @@ protected: Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices); - mutable GPUObject* _gpuObject = NULL; - // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = NULL; void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; }; diff --git a/libraries/model/src/model/SkyFromAtmosphere.slf b/libraries/model/src/model/SkyFromAtmosphere.slf new file mode 100755 index 0000000000..02036d0d7c --- /dev/null +++ b/libraries/model/src/model/SkyFromAtmosphere.slf @@ -0,0 +1,108 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> + +// +// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: +// +// NVIDIA Statement on the Software +// +// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are +// detailed. +// +// No Warranty +// +// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL +// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +// Limitation of Liability +// +// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR +// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT +// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY +// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH +// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS. +// + +// +// Atmospheric scattering fragment shader +// +// Author: Sean O'Neil +// +// Copyright (c) 2004 Sean O'Neil +// + +uniform vec3 v3CameraPos; // The camera's current position +uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels +uniform float fInnerRadius; // The inner (planetary) radius +uniform float fKrESun; // Kr * ESun +uniform float fKmESun; // Km * ESun +uniform float fKr4PI; // Kr * 4 * PI +uniform float fKm4PI; // Km * 4 * PI +uniform float fScale; // 1 / (fOuterRadius - fInnerRadius) +uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found) +uniform float fScaleOverScaleDepth; // fScale / fScaleDepth + +const int nSamples = 2; +const float fSamples = 2.0; + +uniform vec3 v3LightPos; +uniform float g; +uniform float g2; + +varying vec3 position; + +float scale(float fCos) +{ + float x = 1.0 - fCos; + return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); +} + +void main (void) +{ + // Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere) + vec3 v3Pos = position; + vec3 v3Ray = v3Pos - v3CameraPos; + float fFar = length(v3Ray); + v3Ray /= fFar; + + // Calculate the ray's starting position, then calculate its scattering offset + vec3 v3Start = v3CameraPos; + float fHeight = length(v3Start); + float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight)); + float fStartAngle = dot(v3Ray, v3Start) / fHeight; + float fStartOffset = fDepth * scale(fStartAngle); + + // Initialize the scattering loop variables + //gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0); + float fSampleLength = fFar / fSamples; + float fScaledLength = fSampleLength * fScale; + vec3 v3SampleRay = v3Ray * fSampleLength; + vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; + + // Now loop through the sample rays + vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); + for(int i=0; i +<$VERSION_HEADER$> + +// +// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: +// +// NVIDIA Statement on the Software +// +// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are +// detailed. +// +// No Warranty +// +// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL +// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +// Limitation of Liability +// +// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR +// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT +// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY +// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH +// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS. +// + +// +// Atmospheric scattering vertex shader +// +// Author: Sean O'Neil +// +// Copyright (c) 2004 Sean O'Neil +// + +uniform vec3 v3CameraPos; // The camera's current position +uniform vec3 v3LightPos; // The direction vector to the light source +uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels +uniform float fOuterRadius; // The outer (atmosphere) radius +uniform float fInnerRadius; // The inner (planetary) radius +uniform float fKrESun; // Kr * ESun +uniform float fKmESun; // Km * ESun +uniform float fKr4PI; // Kr * 4 * PI +uniform float fKm4PI; // Km * 4 * PI +uniform float fScale; // 1 / (fOuterRadius - fInnerRadius) +uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found) +uniform float fScaleOverScaleDepth; // fScale / fScaleDepth + + +const int nSamples = 2; +const float fSamples = 2.0; + +varying vec3 position; + + +float scale(float fCos) +{ + float x = 1.0 - fCos; + return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); +} + +void main(void) +{ + // Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere) + position = gl_Vertex.xyz * fOuterRadius; + + gl_Position = gl_ModelViewProjectionMatrix * vec4(position, 1.0); +} diff --git a/libraries/model/src/model/SkyFromSpace.slf b/libraries/model/src/model/SkyFromSpace.slf new file mode 100755 index 0000000000..5f6ce80efa --- /dev/null +++ b/libraries/model/src/model/SkyFromSpace.slf @@ -0,0 +1,114 @@ +#version 120 + +// +// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: +// +// NVIDIA Statement on the Software +// +// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are +// detailed. +// +// No Warranty +// +// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL +// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +// Limitation of Liability +// +// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR +// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT +// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY +// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH +// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS. +// + +// +// Atmospheric scattering fragment shader +// +// Author: Sean O'Neil +// +// Copyright (c) 2004 Sean O'Neil +// + +uniform vec3 v3CameraPos; // The camera's current position +uniform vec3 v3LightPos; // The direction vector to the light source +uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels +uniform float fCameraHeight2; // fCameraHeight^2 +uniform float fOuterRadius; // The outer (atmosphere) radius +uniform float fOuterRadius2; // fOuterRadius^2 +uniform float fInnerRadius; // The inner (planetary) radius +uniform float fKrESun; // Kr * ESun +uniform float fKmESun; // Km * ESun +uniform float fKr4PI; // Kr * 4 * PI +uniform float fKm4PI; // Km * 4 * PI +uniform float fScale; // 1 / (fOuterRadius - fInnerRadius) +uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found) +uniform float fScaleOverScaleDepth; // fScale / fScaleDepth + +uniform float g; +uniform float g2; + +const int nSamples = 2; +const float fSamples = 2.0; + +varying vec3 position; + +float scale(float fCos) +{ + float x = 1.0 - fCos; + return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); +} + + +void main (void) +{ + // Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere) + vec3 v3Pos = position; + vec3 v3Ray = v3Pos - v3CameraPos; + float fFar = length(v3Ray); + v3Ray /= fFar; + + // Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere) + float B = 2.0 * dot(v3CameraPos, v3Ray); + float C = fCameraHeight2 - fOuterRadius2; + float fDet = max(0.0, B*B - 4.0 * C); + float fNear = 0.5 * (-B - sqrt(fDet)); + + // Calculate the ray's starting position, then calculate its scattering offset + vec3 v3Start = v3CameraPos + v3Ray * fNear; + fFar -= fNear; + float fStartAngle = dot(v3Ray, v3Start) / fOuterRadius; + float fStartDepth = exp(-1.0 / fScaleDepth); + float fStartOffset = fStartDepth * scale(fStartAngle); + + // Initialize the scattering loop variables + //gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0); + float fSampleLength = fFar / fSamples; + float fScaledLength = fSampleLength * fScale; + vec3 v3SampleRay = v3Ray * fSampleLength; + vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; + + // Now loop through the sample rays + vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); + for(int i=0; i #include +#include "SkyFromAtmosphere_vert.h" +#include "SkyFromAtmosphere_frag.h" + using namespace model; @@ -150,6 +153,13 @@ SunSkyStage::SunSkyStage() : setDayTime(12.0f); // Begining of march setYearTime(60.0f); + + _skyShader = gpu::ShaderPointer( + gpu::Shader::createProgram( + gpu::ShaderPointer(gpu::Shader::createVertex(std::string(SkyFromAtmosphere_vert))), + gpu::ShaderPointer(gpu::Shader::createPixel(std::string(SkyFromAtmosphere_frag))) + ) + ); } SunSkyStage::~SunSkyStage() { diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index 762e2d9717..4de0edb96b 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -11,6 +11,8 @@ #ifndef hifi_model_Stage_h #define hifi_model_Stage_h +#include "gpu/Shader.h" + #include "Light.h" namespace model { @@ -143,6 +145,8 @@ public: protected: LightPointer _sunLight; + gpu::ShaderPointer _skyShader; + float _dayTime; int _yearTime; From cb737d64d3a858f45e6a2a58978e9ddd4e0fff07 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sun, 1 Mar 2015 15:20:32 -0800 Subject: [PATCH 02/56] Testing the gpu::Shader compilation and building steps, ready to be used for real --- libraries/gpu/src/gpu/GLBackend.cpp | 14 ++- libraries/gpu/src/gpu/GLBackend.h | 4 +- libraries/gpu/src/gpu/GLBackendShader.cpp | 120 ++++++++++----------- libraries/gpu/src/gpu/GLBackendTexture.cpp | 11 +- libraries/model/src/model/Stage.cpp | 4 + 5 files changed, 78 insertions(+), 75 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index fd91e0df0c..64bcb006a5 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -1015,11 +1015,11 @@ GLBackend::GLBuffer::~GLBuffer() { } } -void GLBackend::syncGPUObject(const Buffer& buffer) { +GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) { GLBuffer* object = Backend::getGPUObject(buffer); if (object && (object->_stamp == buffer.getSysmem().getStamp())) { - return; + return object; } // need to have a gpu object? @@ -1040,12 +1040,18 @@ void GLBackend::syncGPUObject(const Buffer& buffer) { object->_size = buffer.getSysmem().getSize(); //} CHECK_GL_ERROR(); + + return object; } GLuint GLBackend::getBufferID(const Buffer& buffer) { - GLBackend::syncGPUObject(buffer); - return Backend::getGPUObject(buffer)->_buffer; + GLBuffer* bo = GLBackend::syncGPUObject(buffer); + if (bo) { + return bo->_buffer; + } else { + return 0; + } } diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 161ce1dad6..81271851bb 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -44,7 +44,7 @@ public: GLBuffer(); ~GLBuffer(); }; - static void syncGPUObject(const Buffer& buffer); + static GLBuffer* syncGPUObject(const Buffer& buffer); static GLuint getBufferID(const Buffer& buffer); class GLTexture : public GPUObject { @@ -57,7 +57,7 @@ public: GLTexture(); ~GLTexture(); }; - static void syncGPUObject(const Texture& texture); + static GLTexture* syncGPUObject(const Texture& texture); static GLuint getTextureID(const TexturePointer& texture); class GLShader : public GPUObject { diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index e37643e2f2..4d84d33a5f 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -25,12 +25,12 @@ GLBackend::GLShader::~GLShader() { } } -bool compileShader(const Shader& shader, GLBackend::GLShader& object) { +GLBackend::GLShader* compileShader(const Shader& shader) { // Any GLSLprogram ? normally yes... const std::string& shaderSource = shader.getSource().getCode(); if (shaderSource.empty()) { qDebug() << "GLShader::compileShader - no GLSL shader source code ? so failed to create"; - return false; + return nullptr; } // Shader domain @@ -40,8 +40,8 @@ bool compileShader(const Shader& shader, GLBackend::GLShader& object) { // Create the shader object GLuint glshader = glCreateShader(shaderDomain); if (!glshader) { - qDebug() << "GLShader::compileShader - failed to create the gl shader & gl program object"; - return false; + qDebug() << "GLShader::compileShader - failed to create the gl shader object"; + return nullptr; } // Assign the source @@ -56,13 +56,11 @@ bool compileShader(const Shader& shader, GLBackend::GLShader& object) { glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled); // if compilation fails - if (!compiled) - { + if (!compiled) { // save the source code to a temp file so we can debug easily /* std::ofstream filestream; - filestream.open( "debugshader.glsl" ); - if ( filestream.is_open() ) - { + filestream.open("debugshader.glsl"); + if (filestream.is_open()) { filestream << shaderSource->source; filestream.close(); } @@ -72,30 +70,31 @@ bool compileShader(const Shader& shader, GLBackend::GLShader& object) { glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength); char* temp = new char[infoLength] ; - glGetShaderInfoLog( glshader, infoLength, NULL, temp); + glGetShaderInfoLog(glshader, infoLength, NULL, temp); qDebug() << "GLShader::compileShader - failed to compile the gl shader object:"; qDebug() << temp; /* - filestream.open( "debugshader.glsl.info.txt" ); - if ( filestream.is_open() ) - { - filestream << String( temp ); + filestream.open("debugshader.glsl.info.txt"); + if (filestream.is_open()) { + filestream << std::string(temp); filestream.close(); } */ delete[] temp; - glDeleteShader( glshader); - return false; + glDeleteShader(glshader); + return nullptr; } + GLuint glprogram = 0; +#ifdef SEPARATE_PROGRAM // so far so good, program is almost done, need to link: GLuint glprogram = glCreateProgram(); if (!glprogram) { qDebug() << "GLShader::compileShader - failed to create the gl shader & gl program object"; - return false; + return nullptr; } glProgramParameteri(glprogram, GL_PROGRAM_SEPARABLE, GL_TRUE); @@ -105,53 +104,52 @@ bool compileShader(const Shader& shader, GLBackend::GLShader& object) { GLint linked = 0; glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); - if (!linked) - { + if (!linked) { /* // save the source code to a temp file so we can debug easily std::ofstream filestream; - filestream.open( "debugshader.glsl" ); - if ( filestream.is_open() ) - { + filestream.open("debugshader.glsl"); + if (filestream.is_open()) { filestream << shaderSource->source; filestream.close(); } */ GLint infoLength = 0; - glGetProgramiv( glprogram, GL_INFO_LOG_LENGTH, &infoLength ); + glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength); char* temp = new char[infoLength] ; - glGetProgramInfoLog( glprogram, infoLength, NULL, temp); + glGetProgramInfoLog(glprogram, infoLength, NULL, temp); qDebug() << "GLShader::compileShader - failed to LINK the gl program object :"; qDebug() << temp; /* - filestream.open( "debugshader.glsl.info.txt" ); - if ( filestream.is_open() ) - { - filestream << String( temp ); + filestream.open("debugshader.glsl.info.txt"); + if (filestream.is_open()) { + filestream << String(temp); filestream.close(); } */ delete[] temp; - glDeleteShader( glshader); - glDeleteProgram( glprogram); - return false; + glDeleteShader(glshader); + glDeleteProgram(glprogram); + return nullptr; } +#endif // So far so good, the shader is created successfully - object._shader = glshader; - object._program = glprogram; + GLBackend::GLShader* object = new GLBackend::GLShader(); + object->_shader = glshader; + object->_program = glprogram; - return true; + return object; } -bool compileProgram(const Shader& program, GLBackend::GLShader& object) { +GLBackend::GLShader* compileProgram(const Shader& program) { if(!program.isProgram()) { - return false; + return nullptr; } // Let's go through every shaders and make sure they are ready to go @@ -160,7 +158,7 @@ bool compileProgram(const Shader& program, GLBackend::GLShader& object) { GLuint so = GLBackend::getShaderID(subShader); if (!so) { qDebug() << "GLShader::compileProgram - One of the shaders of the program is not compiled?"; - return false; + return nullptr; } shaderObjects.push_back(so); } @@ -169,7 +167,7 @@ bool compileProgram(const Shader& program, GLBackend::GLShader& object) { GLuint glprogram = glCreateProgram(); if (!glprogram) { qDebug() << "GLShader::compileProgram - failed to create the gl program object"; - return false; + return nullptr; } // glProgramParameteri(glprogram, GL_PROGRAM_, GL_TRUE); @@ -184,47 +182,45 @@ bool compileProgram(const Shader& program, GLBackend::GLShader& object) { GLint linked = 0; glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); - if (!linked) - { + if (!linked) { /* // save the source code to a temp file so we can debug easily std::ofstream filestream; - filestream.open( "debugshader.glsl" ); - if ( filestream.is_open() ) - { + filestream.open("debugshader.glsl"); + if (filestream.is_open()) { filestream << shaderSource->source; filestream.close(); } */ GLint infoLength = 0; - glGetProgramiv( glprogram, GL_INFO_LOG_LENGTH, &infoLength ); + glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength); char* temp = new char[infoLength] ; - glGetProgramInfoLog( glprogram, infoLength, NULL, temp); + glGetProgramInfoLog(glprogram, infoLength, NULL, temp); qDebug() << "GLShader::compileProgram - failed to LINK the gl program object :"; qDebug() << temp; /* - filestream.open( "debugshader.glsl.info.txt" ); - if ( filestream.is_open() ) - { - filestream << String( temp ); + filestream.open("debugshader.glsl.info.txt"); + if (filestream.is_open()) { + filestream << std::string(temp); filestream.close(); } */ delete[] temp; - glDeleteProgram( glprogram); - return false; + glDeleteProgram(glprogram); + return nullptr; } // So far so good, the program is created successfully - object._shader = 0; - object._program = glprogram; + GLBackend::GLShader* object = new GLBackend::GLShader(); + object->_shader = 0; + object->_program = glprogram; - return true; + return object; } GLBackend::GLShader* GLBackend::syncGPUObject(const Shader& shader) { @@ -234,20 +230,17 @@ GLBackend::GLShader* GLBackend::syncGPUObject(const Shader& shader) { if (object) { return object; } - // need to have a gpu object? - - // GO through the process of allocating the correct storage and/or update the content if (shader.isProgram()) { - GLShader tempObject; - if (compileProgram(shader, tempObject)) { - object = new GLShader(tempObject); + GLShader* tempObject = compileProgram(shader); + if (tempObject) { + object = tempObject; Backend::setGPUObject(shader, object); } } else if (shader.isDomain()) { - GLShader tempObject; - if (compileShader(shader, tempObject)) { - object = new GLShader(tempObject); + GLShader* tempObject = compileShader(shader); + if (tempObject) { + object = tempObject; Backend::setGPUObject(shader, object); } } @@ -256,7 +249,6 @@ GLBackend::GLShader* GLBackend::syncGPUObject(const Shader& shader) { } - GLuint GLBackend::getShaderID(const ShaderPointer& shader) { if (!shader) { return 0; diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 0b2dffd6f7..6875abbc33 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -223,7 +223,7 @@ public: }; -void GLBackend::syncGPUObject(const Texture& texture) { +GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { GLTexture* object = Backend::getGPUObject(texture); // If GPU object already created and in sync @@ -232,14 +232,14 @@ void GLBackend::syncGPUObject(const Texture& texture) { // If gpu object info is in sync with sysmem version if (object->_contentStamp >= texture.getDataStamp()) { // Then all good, GPU object is ready to be used - return; + return object; } else { // Need to update the content of the GPU object from the source sysmem of the texture needUpdate = true; } } else if (!texture.isDefined()) { // NO texture definition yet so let's avoid thinking - return; + return nullptr; } // need to have a gpu object? @@ -320,6 +320,8 @@ void GLBackend::syncGPUObject(const Texture& texture) { qDebug() << "GLBackend::syncGPUObject(const Texture&) case for Texture Type " << texture.getType() << " not supported"; } CHECK_GL_ERROR(); + + return object; } @@ -328,8 +330,7 @@ GLuint GLBackend::getTextureID(const TexturePointer& texture) { if (!texture) { return 0; } - GLBackend::syncGPUObject(*texture); - GLTexture* object = Backend::getGPUObject(*texture); + GLTexture* object = GLBackend::syncGPUObject(*texture); if (object) { return object->_texture; } else { diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 10dea9ab3f..9a68779caf 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -15,6 +15,7 @@ #include "SkyFromAtmosphere_vert.h" #include "SkyFromAtmosphere_frag.h" +#include "gpu/GLBackend.h" using namespace model; @@ -215,5 +216,8 @@ void SunSkyStage::updateGraphicsObject() const { double originAlt = _earthSunModel.getAltitude(); _sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f)); + GLuint program = gpu::GLBackend::getShaderID(_skyShader); + + } From 3d558dae6435c0749bd84c51571bd0d94c627f54 Mon Sep 17 00:00:00 2001 From: Virendra Singh Date: Tue, 3 Mar 2015 01:51:35 +0530 Subject: [PATCH 03/56] MassProperties of a 3D mesh --- libraries/physics/src/MassProperties.cpp | 195 +++++++++++++++++++++++ libraries/physics/src/MassProperties.h | 60 +++++++ 2 files changed, 255 insertions(+) create mode 100644 libraries/physics/src/MassProperties.cpp create mode 100644 libraries/physics/src/MassProperties.h diff --git a/libraries/physics/src/MassProperties.cpp b/libraries/physics/src/MassProperties.cpp new file mode 100644 index 0000000000..ec4066ce9f --- /dev/null +++ b/libraries/physics/src/MassProperties.cpp @@ -0,0 +1,195 @@ +// +// MassProperties.cpp +// libraries/physics/src +// +// Created by Virendra Singh 2015.02.28 +// 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 "MassProperties.h" +using namespace massproperties; + +Tetrahedron::Tetrahedron(Vertex p1, Vertex p2, Vertex p3, Vertex p4) :\ +_w(p1), +_x(p2), +_y(p3), +_z(p4){ + + computeVolumeAndInertia(); +} +Tetrahedron::~Tetrahedron(){ + +} + +Vertex Tetrahedron::getX(){ + return _x; +} + +Vertex Tetrahedron::getY(){ + return _y; +} +Vertex Tetrahedron::getZ(){ + return _z; +} + +Vertex Tetrahedron::getw(){ + return _w; +} + +Vertex Tetrahedron::getCentroid(){ + Vertex com; + com.x = (_x.x + _y.x + _z.x + _w.x) / 4.0f; + com.y = (_x.y + _y.y + _z.y + _w.y) / 4.0f; + com.z = (_x.z + _y.z + _z.z + _w.z) / 4.0f; + return com; +} + +vector Tetrahedron::getVolumeAndInertia(){ + return _volumeAndInertia; +} + +void Tetrahedron::computeVolumeAndInertia(){ + double A = glm::distance2(_w, _x); + double B = glm::distance2(_w, _y); + double C = glm::distance2(_x, _y); + double a = glm::distance2(_y, _z); + double b = glm::distance2(_x, _z); + double c = glm::distance2(_w, _z); + double squaredVol = (4 * a * b * c) - (a*glm::pow((b + c - A), 2.0)) - (b*glm::pow((c + a - B), 2.0)) - + (c*glm::pow((a + b - C), 2.0)) + ((a + b - C)*(a + c - B)*(b + c - A)); + + double volume = glm::sqrt(squaredVol);// volume of tetrahedron + _volumeAndInertia.push_back(volume); + + //centroid is used for calculating inertia tensor relative to center of mass. + // translatw the tetrahedron to its center of mass using parallel axis theorem + Vertex com = getCentroid(); + Vertex p0 = _w - com; + Vertex p1 = _x - com; + Vertex p2 = _y - com; + Vertex p3 = _z - com; + + //Calculate inertia tensor based on Tonon's Formulae given in the paper mentioned below. + //http://docsdrive.com/pdfs/sciencepublications/jmssp/2005/8-11.pdf + //Explicit exact formulas for the 3-D tetrahedron inertia tensor in terms of its vertex coordinates - F.Tonon + + double inertia_a = (volume * 6.0 / 60.0) * ( + p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + + p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + + p2.y*p2.y + p2.y*p3.y + + p3.y*p3.y + + p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + + p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + + p2.z*p2.z + p2.z*p3.z + + p3.z*p3.z); + _volumeAndInertia.push_back(inertia_a); + + double inertia_b = (volume * 6.0 / 60.0) * ( + p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + + p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + + p2.x*p2.x + p2.x*p3.x + + p3.x*p3.x + + p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + + p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + + p2.z*p2.z + p2.z*p3.z + + p3.z*p3.z); + _volumeAndInertia.push_back(inertia_b); + + double inertia_c = (volume * 6.0 / 60.0) * ( + p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + + p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + + p2.x*p2.x + p2.x*p3.x + + p3.x*p3.x + + p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + + p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + + p2.y*p2.y + p2.y*p3.y + + p3.y*p3.y); + _volumeAndInertia.push_back(inertia_c); + + double inertia_aa = (volume * 6.0 / 60.0) * (2.0 * (p0.y*p0.z + p1.y*p1.z + p2.y*p2.z + p3.y*p3.z) + + p0.y*p1.z + p0.y*p2.z + p0.y*p3.z + + p1.y*p0.z + p1.y*p2.z + p1.y*p3.z + + p2.y*p0.z + p2.y*p1.z + p2.y*p3.z + + p3.y*p0.z + p3.y*p1.z + p3.y*p2.z); + _volumeAndInertia.push_back(inertia_aa); + + double inertia_bb = (volume * 6.0 / 60.0) * (2.0 * (p0.x*p0.z + p1.x*p1.z + p2.x*p2.z + p3.x*p3.z) + + p0.x*p1.z + p0.x*p2.z + p0.x*p3.z + + p1.x*p0.z + p1.x*p2.z + p1.x*p3.z + + p2.x*p0.z + p2.x*p1.z + p2.x*p3.z + + p3.x*p0.z + p3.x*p1.z + p3.x*p2.z); + _volumeAndInertia.push_back(inertia_bb); + + double inertia_cc = (volume * 6.0 / 60.0) * (2.0 * (p0.x*p0.y + p1.x*p1.y + p2.x*p2.y + p3.x*p3.y) + + p0.x*p1.y + p0.x*p2.y + p0.x*p3.y + + p1.x*p0.y + p1.x*p2.y + p1.x*p3.y + + p2.x*p0.y + p2.x*p1.y + p2.x*p3.y + + p3.x*p0.y + p3.x*p1.y + p3.x*p2.y); + _volumeAndInertia.push_back(inertia_cc); +} + +//class to compute volume, mass, center of mass, and inertia tensor of a mesh. +//origin is the default reference point for generating the tetrahedron from each triangle of the mesh. We can provide another reference +//point by passing it as 3rd parameter to the constructor + +MassProperties::MassProperties(vector *vertices, Triangle *triangles, Vertex referencepoint = glm::vec3(0.0,0.0,0.0)):\ +_vertices(vertices), +_triangles(triangles), +_referencePoint(referencepoint), +_trianglesCount(0), +_tetrahedraCount(0), +_verticesCount(0){ + + if (_triangles){ + _trianglesCount = _triangles->size() / 3; + } + + if (_vertices){ + _verticesCount = _vertices->size(); + } + generateTetrahedra(); +} + +MassProperties::~MassProperties(){ + if (_vertices){ + _vertices->clear(); + } + if (_triangles){ + _triangles->clear(); + } + delete _vertices; + delete _triangles; +} + +void MassProperties::generateTetrahedra(){ + for (int i = 0; i < _trianglesCount * 3; i += 3){ + Vertex p1 = _vertices->at(_triangles->at(i)); + Vertex p2 = _vertices->at(_triangles->at(i + 1)); + Vertex p3 = _vertices->at(_triangles->at(i + 2)); + Tetrahedron t(_referencePoint, p1, p2, p3); + _tetrahedra.push_back(t); + } +} + +int MassProperties::getTriangleCount() const{ + return _trianglesCount; +} + +int MassProperties::getVerticesCount() const{ + return _verticesCount; +} + +int MassProperties::getTetrahedraCount() const{ + return _tetrahedra.size(); +} + +vector MassProperties::getTetrahedra() const{ + return _tetrahedra; +} +vector MassProperties::getVolumeAndInertia(){ + vector volumeAndInertia; + return volumeAndInertia; +} \ No newline at end of file diff --git a/libraries/physics/src/MassProperties.h b/libraries/physics/src/MassProperties.h new file mode 100644 index 0000000000..f5a2f0a0c7 --- /dev/null +++ b/libraries/physics/src/MassProperties.h @@ -0,0 +1,60 @@ +// +// MassProperties.h +// libraries/physics/src +// +// Created by Virendra Singh 2015.02.28 +// 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 +#include +#include +#include +using namespace std; +namespace massproperties{ + typedef glm::vec3 Vertex; + typedef vector Triangle; + + //Tetrahedron class containing the base triangle and the apex. + class Tetrahedron{ + private: + Vertex _w; //apex + Vertex _x; + Vertex _y; + Vertex _z; + vector _volumeAndInertia; + public: + Tetrahedron(Vertex p1, Vertex p2, Vertex p3, Vertex p4); + ~Tetrahedron(); + Vertex getX(); + Vertex getY(); + Vertex getZ(); + Vertex getw(); + Vertex getCentroid(); + void computeVolumeAndInertia(); + vector getVolumeAndInertia(); + }; + + class MassProperties{ + private: + int _trianglesCount; + int _tetrahedraCount; + int _verticesCount; + vector *_vertices; + Vertex _referencePoint; + Triangle *_triangles; + vector _tetrahedra; + void generateTetrahedra(); + public: + MassProperties(vector *vertices, Triangle *triangles, Vertex refewrencepoint); + ~MassProperties(); + int getTriangleCount() const; + int getVerticesCount() const; + int getTetrahedraCount() const; + vector getTetrahedra() const; + vector getVolumeAndInertia(); + }; +} \ No newline at end of file From 7a129235c26af553f0fe5991e493b32e5516f6e4 Mon Sep 17 00:00:00 2001 From: Virendra Singh Date: Wed, 4 Mar 2015 01:12:20 +0530 Subject: [PATCH 04/56] Mass properties unit tests --- libraries/physics/src/MassProperties.cpp | 279 ++++++++++++---------- libraries/physics/src/MassProperties.h | 89 +++---- tests/physics/src/MassPropertiesTests.cpp | 133 +++++++++++ tests/physics/src/MassPropertiesTests.h | 20 ++ tests/physics/src/main.cpp | 14 +- 5 files changed, 369 insertions(+), 166 deletions(-) create mode 100644 tests/physics/src/MassPropertiesTests.cpp create mode 100644 tests/physics/src/MassPropertiesTests.h diff --git a/libraries/physics/src/MassProperties.cpp b/libraries/physics/src/MassProperties.cpp index ec4066ce9f..4d2e668f95 100644 --- a/libraries/physics/src/MassProperties.cpp +++ b/libraries/physics/src/MassProperties.cpp @@ -12,123 +12,119 @@ #include "MassProperties.h" using namespace massproperties; -Tetrahedron::Tetrahedron(Vertex p1, Vertex p2, Vertex p3, Vertex p4) :\ +Tetrahedron::Tetrahedron(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) :\ _w(p1), _x(p2), _y(p3), _z(p4){ - - computeVolumeAndInertia(); + computeVolume(); + computeInertia(); } Tetrahedron::~Tetrahedron(){ } -Vertex Tetrahedron::getX(){ - return _x; +Vertex Tetrahedron::getX() const{ + return _x; } -Vertex Tetrahedron::getY(){ - return _y; +Vertex Tetrahedron::getY() const{ + return _y; } -Vertex Tetrahedron::getZ(){ - return _z; +Vertex Tetrahedron::getZ() const{ + return _z; } -Vertex Tetrahedron::getw(){ - return _w; +Vertex Tetrahedron::getw() const{ + return _w; } -Vertex Tetrahedron::getCentroid(){ - Vertex com; - com.x = (_x.x + _y.x + _z.x + _w.x) / 4.0f; - com.y = (_x.y + _y.y + _z.y + _w.y) / 4.0f; - com.z = (_x.z + _y.z + _z.z + _w.z) / 4.0f; - return com; +Vertex Tetrahedron::getCentroid() const{ + Vertex com; + com.x = (_x.x + _y.x + _z.x + _w.x) / 4.0f; + com.y = (_x.y + _y.y + _z.y + _w.y) / 4.0f; + com.z = (_x.z + _y.z + _z.z + _w.z) / 4.0f; + return com; } -vector Tetrahedron::getVolumeAndInertia(){ - return _volumeAndInertia; +vector Tetrahedron::getVolumeAndInertia() const{ + return _volumeAndInertia; } -void Tetrahedron::computeVolumeAndInertia(){ - double A = glm::distance2(_w, _x); - double B = glm::distance2(_w, _y); - double C = glm::distance2(_x, _y); - double a = glm::distance2(_y, _z); - double b = glm::distance2(_x, _z); - double c = glm::distance2(_w, _z); - double squaredVol = (4 * a * b * c) - (a*glm::pow((b + c - A), 2.0)) - (b*glm::pow((c + a - B), 2.0)) - - (c*glm::pow((a + b - C), 2.0)) + ((a + b - C)*(a + c - B)*(b + c - A)); +void Tetrahedron::computeVolume(){ + glm::mat4 tet = { glm::vec4(_x.x, _y.x, _z.x, _w.x), glm::vec4(_x.y, _y.y, _z.y, _w.y), glm::vec4(_x.z, _y.z, _z.z, _w.z), glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) }; + _volume = glm::determinant(tet) / 6.0f; + _volumeAndInertia.push_back(_volume); + std::cout << "volume : " << _volume << std::endl; +} - double volume = glm::sqrt(squaredVol);// volume of tetrahedron - _volumeAndInertia.push_back(volume); +void Tetrahedron::computeInertia(){ + + //centroid is used for calculating inertia tensor relative to center of mass. + // translate the tetrahedron to its center of mass using P = P - centroid + Vertex com = getCentroid(); + Vertex p0 = _w - com; + Vertex p1 = _x - com; + Vertex p2 = _y - com; + Vertex p3 = _z - com; - //centroid is used for calculating inertia tensor relative to center of mass. - // translatw the tetrahedron to its center of mass using parallel axis theorem - Vertex com = getCentroid(); - Vertex p0 = _w - com; - Vertex p1 = _x - com; - Vertex p2 = _y - com; - Vertex p3 = _z - com; + //Calculate inertia tensor based on Tonon's Formulae given in the paper mentioned below. + //http://docsdrive.com/pdfs/sciencepublications/jmssp/2005/8-11.pdf + //Explicit exact formulas for the 3-D tetrahedron inertia tensor in terms of its vertex coordinates - F.Tonon - //Calculate inertia tensor based on Tonon's Formulae given in the paper mentioned below. - //http://docsdrive.com/pdfs/sciencepublications/jmssp/2005/8-11.pdf - //Explicit exact formulas for the 3-D tetrahedron inertia tensor in terms of its vertex coordinates - F.Tonon + double inertia_a = (_volume * 6.0 / 60.0) * ( + p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + + p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + + p2.y*p2.y + p2.y*p3.y + + p3.y*p3.y + + p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + + p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + + p2.z*p2.z + p2.z*p3.z + + p3.z*p3.z); + _volumeAndInertia.push_back(inertia_a); - double inertia_a = (volume * 6.0 / 60.0) * ( - p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + - p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + - p2.y*p2.y + p2.y*p3.y + - p3.y*p3.y + - p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + - p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + - p2.z*p2.z + p2.z*p3.z + - p3.z*p3.z); - _volumeAndInertia.push_back(inertia_a); + double inertia_b = (_volume * 6.0 / 60.0) * ( + p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + + p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + + p2.x*p2.x + p2.x*p3.x + + p3.x*p3.x + + p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + + p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + + p2.z*p2.z + p2.z*p3.z + + p3.z*p3.z); + _volumeAndInertia.push_back(inertia_b); - double inertia_b = (volume * 6.0 / 60.0) * ( - p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + - p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + - p2.x*p2.x + p2.x*p3.x + - p3.x*p3.x + - p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + - p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + - p2.z*p2.z + p2.z*p3.z + - p3.z*p3.z); - _volumeAndInertia.push_back(inertia_b); + double inertia_c = (_volume * 6.0 / 60.0) * ( + p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + + p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + + p2.x*p2.x + p2.x*p3.x + + p3.x*p3.x + + p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + + p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + + p2.y*p2.y + p2.y*p3.y + + p3.y*p3.y); + _volumeAndInertia.push_back(inertia_c); - double inertia_c = (volume * 6.0 / 60.0) * ( - p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + - p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + - p2.x*p2.x + p2.x*p3.x + - p3.x*p3.x + - p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + - p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + - p2.y*p2.y + p2.y*p3.y + - p3.y*p3.y); - _volumeAndInertia.push_back(inertia_c); + double inertia_aa = (_volume * 6.0 / 120.0) * (2.0 * (p0.y*p0.z + p1.y*p1.z + p2.y*p2.z + p3.y*p3.z) + + p0.y*p1.z + p0.y*p2.z + p0.y*p3.z + + p1.y*p0.z + p1.y*p2.z + p1.y*p3.z + + p2.y*p0.z + p2.y*p1.z + p2.y*p3.z + + p3.y*p0.z + p3.y*p1.z + p3.y*p2.z); + _volumeAndInertia.push_back(inertia_aa); - double inertia_aa = (volume * 6.0 / 60.0) * (2.0 * (p0.y*p0.z + p1.y*p1.z + p2.y*p2.z + p3.y*p3.z) + - p0.y*p1.z + p0.y*p2.z + p0.y*p3.z + - p1.y*p0.z + p1.y*p2.z + p1.y*p3.z + - p2.y*p0.z + p2.y*p1.z + p2.y*p3.z + - p3.y*p0.z + p3.y*p1.z + p3.y*p2.z); - _volumeAndInertia.push_back(inertia_aa); + double inertia_bb = (_volume * 6.0 / 120.0) * (2.0 * (p0.x*p0.z + p1.x*p1.z + p2.x*p2.z + p3.x*p3.z) + + p0.x*p1.z + p0.x*p2.z + p0.x*p3.z + + p1.x*p0.z + p1.x*p2.z + p1.x*p3.z + + p2.x*p0.z + p2.x*p1.z + p2.x*p3.z + + p3.x*p0.z + p3.x*p1.z + p3.x*p2.z); + _volumeAndInertia.push_back(inertia_bb); - double inertia_bb = (volume * 6.0 / 60.0) * (2.0 * (p0.x*p0.z + p1.x*p1.z + p2.x*p2.z + p3.x*p3.z) + - p0.x*p1.z + p0.x*p2.z + p0.x*p3.z + - p1.x*p0.z + p1.x*p2.z + p1.x*p3.z + - p2.x*p0.z + p2.x*p1.z + p2.x*p3.z + - p3.x*p0.z + p3.x*p1.z + p3.x*p2.z); - _volumeAndInertia.push_back(inertia_bb); - - double inertia_cc = (volume * 6.0 / 60.0) * (2.0 * (p0.x*p0.y + p1.x*p1.y + p2.x*p2.y + p3.x*p3.y) + - p0.x*p1.y + p0.x*p2.y + p0.x*p3.y + - p1.x*p0.y + p1.x*p2.y + p1.x*p3.y + - p2.x*p0.y + p2.x*p1.y + p2.x*p3.y + - p3.x*p0.y + p3.x*p1.y + p3.x*p2.y); - _volumeAndInertia.push_back(inertia_cc); + double inertia_cc = (_volume * 6.0 / 120.0) * (2.0 * (p0.x*p0.y + p1.x*p1.y + p2.x*p2.y + p3.x*p3.y) + + p0.x*p1.y + p0.x*p2.y + p0.x*p3.y + + p1.x*p0.y + p1.x*p2.y + p1.x*p3.y + + p2.x*p0.y + p2.x*p1.y + p2.x*p3.y + + p3.x*p0.y + p3.x*p1.y + p3.x*p2.y); + _volumeAndInertia.push_back(inertia_cc); } //class to compute volume, mass, center of mass, and inertia tensor of a mesh. @@ -141,55 +137,98 @@ _triangles(triangles), _referencePoint(referencepoint), _trianglesCount(0), _tetrahedraCount(0), -_verticesCount(0){ +_verticesCount(0), +_centerOfMass(glm::vec3(0.0, 0.0, 0.0)){ - if (_triangles){ - _trianglesCount = _triangles->size() / 3; - } + if (_triangles){ + _trianglesCount = _triangles->size() / 3; + } - if (_vertices){ - _verticesCount = _vertices->size(); - } - generateTetrahedra(); + if (_vertices){ + _verticesCount = _vertices->size(); + } + generateTetrahedra(); } MassProperties::~MassProperties(){ - if (_vertices){ - _vertices->clear(); - } - if (_triangles){ - _triangles->clear(); - } - delete _vertices; - delete _triangles; + if (_vertices){ + _vertices->clear(); + } + if (_triangles){ + _triangles->clear(); + } } -void MassProperties::generateTetrahedra(){ - for (int i = 0; i < _trianglesCount * 3; i += 3){ - Vertex p1 = _vertices->at(_triangles->at(i)); - Vertex p2 = _vertices->at(_triangles->at(i + 1)); - Vertex p3 = _vertices->at(_triangles->at(i + 2)); - Tetrahedron t(_referencePoint, p1, p2, p3); - _tetrahedra.push_back(t); - } +void MassProperties::generateTetrahedra() { + std::cout << "apex : " << _referencePoint.x << " " << _referencePoint.y << " " << _referencePoint.z << std::endl; + for (int i = 0; i < _trianglesCount * 3; i += 3){ + Vertex p1 = _vertices->at(_triangles->at(i)); + Vertex p2 = _vertices->at(_triangles->at(i + 1)); + Vertex p3 = _vertices->at(_triangles->at(i + 2)); + Tetrahedron t(_referencePoint, p1, p2, p3); + _tetrahedra.push_back(t); + } } int MassProperties::getTriangleCount() const{ - return _trianglesCount; + return _trianglesCount; } int MassProperties::getVerticesCount() const{ - return _verticesCount; + return _verticesCount; +} + +Vertex MassProperties::getCenterOfMass() const{ + return _centerOfMass; } int MassProperties::getTetrahedraCount() const{ - return _tetrahedra.size(); + return _tetrahedra.size(); } vector MassProperties::getTetrahedra() const{ - return _tetrahedra; + return _tetrahedra; } -vector MassProperties::getVolumeAndInertia(){ - vector volumeAndInertia; - return volumeAndInertia; + +vector MassProperties::getMassProperties(){ + vector volumeAndInertia; + double volume = 0.0; + double inertia_a = 0.0; + double inertia_b = 0.0; + double inertia_c = 0.0; + double inertia_aa = 0.0; + double inertia_bb = 0.0; + double inertia_cc = 0.0; + glm::vec3 centerOfMass; + + //Translate accumulated center of mass from each tetrahedron to mesh center of mass using parallel axis theorem + for each (Tetrahedron tet in _tetrahedra){ + vector tetMassProperties = tet.getVolumeAndInertia(); + volume += tetMassProperties.at(0); //volume + centerOfMass += tet.getCentroid() * (float)tetMassProperties.at(0); + } + + if (volume != 0){ + _centerOfMass = (centerOfMass / (float)volume); + } + + //Translate the moment of inertia from each tetrahedron to mesh center of mass using parallel axis theorem + for each (Tetrahedron tet in _tetrahedra){ + vector tetMassProperties = tet.getVolumeAndInertia(); + const double dist = glm::distance(_centerOfMass, tet.getCentroid()); + inertia_a += tetMassProperties.at(1) + (dist * dist * tetMassProperties.at(0)); + inertia_b += tetMassProperties.at(2) + (dist * dist * tetMassProperties.at(0)); + inertia_c += tetMassProperties.at(3) + (dist * dist * tetMassProperties.at(0)); + inertia_aa += tetMassProperties.at(4) + (dist * dist * tetMassProperties.at(0)); + inertia_bb += tetMassProperties.at(5) + (dist * dist * tetMassProperties.at(0)); + inertia_cc += tetMassProperties.at(6) + (dist * dist * tetMassProperties.at(0)); + } + volumeAndInertia.push_back(volume); + volumeAndInertia.push_back(inertia_a); + volumeAndInertia.push_back(inertia_b); + volumeAndInertia.push_back(inertia_c); + volumeAndInertia.push_back(inertia_aa); + volumeAndInertia.push_back(inertia_bb); + volumeAndInertia.push_back(inertia_cc); + return volumeAndInertia; } \ No newline at end of file diff --git a/libraries/physics/src/MassProperties.h b/libraries/physics/src/MassProperties.h index f5a2f0a0c7..240e0e53f7 100644 --- a/libraries/physics/src/MassProperties.h +++ b/libraries/physics/src/MassProperties.h @@ -8,6 +8,8 @@ // 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_MassProperties_h +#define hifi_MassProperties_h #include #include @@ -15,46 +17,51 @@ #include using namespace std; namespace massproperties{ - typedef glm::vec3 Vertex; - typedef vector Triangle; + typedef glm::vec3 Vertex; + typedef vector Triangle; - //Tetrahedron class containing the base triangle and the apex. - class Tetrahedron{ - private: - Vertex _w; //apex - Vertex _x; - Vertex _y; - Vertex _z; - vector _volumeAndInertia; - public: - Tetrahedron(Vertex p1, Vertex p2, Vertex p3, Vertex p4); - ~Tetrahedron(); - Vertex getX(); - Vertex getY(); - Vertex getZ(); - Vertex getw(); - Vertex getCentroid(); - void computeVolumeAndInertia(); - vector getVolumeAndInertia(); - }; + //Tetrahedron class containing the base triangle and the apex. + class Tetrahedron{ + private: + Vertex _w; //apex + Vertex _x; + Vertex _y; + Vertex _z; + double _volume; + vector _volumeAndInertia; + void computeInertia(); + void computeVolume(); + public: + Tetrahedron(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4); + ~Tetrahedron(); + Vertex getX() const; + Vertex getY() const; + Vertex getZ() const; + Vertex getw() const; + Vertex getCentroid() const; + vector getVolumeAndInertia() const; + }; - class MassProperties{ - private: - int _trianglesCount; - int _tetrahedraCount; - int _verticesCount; - vector *_vertices; - Vertex _referencePoint; - Triangle *_triangles; - vector _tetrahedra; - void generateTetrahedra(); - public: - MassProperties(vector *vertices, Triangle *triangles, Vertex refewrencepoint); - ~MassProperties(); - int getTriangleCount() const; - int getVerticesCount() const; - int getTetrahedraCount() const; - vector getTetrahedra() const; - vector getVolumeAndInertia(); - }; -} \ No newline at end of file + class MassProperties{ + private: + int _trianglesCount; + int _tetrahedraCount; + int _verticesCount; + vector *_vertices; + Vertex _referencePoint; + Vertex _centerOfMass; + Triangle *_triangles; + vector _tetrahedra; + void generateTetrahedra(); + public: + MassProperties(vector *vertices, Triangle *triangles, Vertex refewrencepoint); + ~MassProperties(); + int getTriangleCount() const; + int getVerticesCount() const; + int getTetrahedraCount() const; + Vertex getCenterOfMass() const; + vector getTetrahedra() const; + vector getMassProperties(); + }; +} +#endif // hifi_MassProperties_h \ No newline at end of file diff --git a/tests/physics/src/MassPropertiesTests.cpp b/tests/physics/src/MassPropertiesTests.cpp new file mode 100644 index 0000000000..83a8443cf9 --- /dev/null +++ b/tests/physics/src/MassPropertiesTests.cpp @@ -0,0 +1,133 @@ +// +// MassPropertiesTests.cpp +// tests/physics/src +// +// Created by Virendra Singh on 2015.03.02 +// 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 +#include +#include + +#include "MassPropertiesTests.h" + +void MassPropertiesTests::testWithTetrahedron(){ + glm::vec3 p0(8.33220, -11.86875, 0.93355); + glm::vec3 p1(0.75523, 5.00000, 16.37072); + glm::vec3 p2(52.61236, 5.00000, -5.38580); + glm::vec3 p3(2.00000, 5.00000, 3.00000); + glm::vec3 centroid(15.92492, 0.782813, 3.72962); + double volume = 1873.233236; + double inertia_a = 43520.33257; + double inertia_b = 194711.28938; + double inertia_c = 191168.76173; + double inertia_aa = 4417.66150; + double inertia_bb = -46343.16662; + double inertia_cc = 11996.20119; + massproperties::Tetrahedron tet(p0, p1, p2, p3); + glm::vec3 diff = centroid - tet.getCentroid(); + vector voumeAndInertia = tet.getVolumeAndInertia(); + std::cout << std::setprecision(12); + //test if centroid is correct + if (diff.x > epsilion || diff.y > epsilion || diff.z > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Centroid is incorrect : Expected = " << centroid.x << " " << + centroid.y << " " << centroid.z << ", actual = " << tet.getCentroid().x << " " << tet.getCentroid().y << + " " << tet.getCentroid().z << std::endl; + } + + //test if volume is correct + if (abs(volume - voumeAndInertia.at(0)) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << " " << + ", actual = " << voumeAndInertia.at(0) << std::endl; + } + + //test if moment of inertia with respect to x axis is correct + if (abs(inertia_a - (voumeAndInertia.at(1))) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to x axis is incorrect : Expected = " << + inertia_a << " " << ", actual = " << (voumeAndInertia.at(1)) << std::endl; + } + + //test if moment of inertia with respect to y axis is correct + if (abs(inertia_b - (voumeAndInertia.at(2))) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to y axis is incorrect : Expected = " << + inertia_b << " " << ", actual = " << (voumeAndInertia.at(2)) << std::endl; + } + + //test if moment of inertia with respect to z axis is correct + if (abs(inertia_c - (voumeAndInertia.at(3))) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to z axis is incorrect : Expected = " << + inertia_c << " " << ", actual = " << (voumeAndInertia.at(3)) << std::endl; + } + + //test if product of inertia with respect to x axis is correct + if (abs(inertia_aa - (voumeAndInertia.at(4))) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to x axis is incorrect : Expected = " << + inertia_aa << " " << ", actual = " << (voumeAndInertia.at(4)) << std::endl; + } + + //test if product of inertia with respect to y axis is correct + if (abs(inertia_bb - (voumeAndInertia.at(5))) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to y axis is incorrect : Expected = " << + inertia_bb << " " << ", actual = " << (voumeAndInertia.at(5)) << std::endl; + } + + //test if product of inertia with respect to z axis is correct + if (abs(inertia_cc - (voumeAndInertia.at(6))) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to z axis is incorrect : Expected = " << + inertia_cc << " " << ", actual = " << (voumeAndInertia.at(6)) << std::endl; + } + +} + +void MassPropertiesTests::testWithUnitCube(){ + massproperties::Vertex p0(1.0, -1.0, -1.0); + massproperties::Vertex p1(1.0, -1.0, 1.0); + massproperties::Vertex p2(-1.0, -1.0, 1.0); + massproperties::Vertex p3(-1.0, -1.0, -1.0); + massproperties::Vertex p4(1.0, 1.0, -1.0); + massproperties::Vertex p5(1.0, 1.0, 1.0); + massproperties::Vertex p6(-1.0, 1.0, 1.0); + massproperties::Vertex p7(-1.0, 1.0, -1.0); + vector vertices; + vertices.push_back(p0); + vertices.push_back(p1); + vertices.push_back(p2); + vertices.push_back(p3); + vertices.push_back(p4); + vertices.push_back(p5); + vertices.push_back(p6); + vertices.push_back(p7); + std::cout << std::setprecision(5); + vector triangles = { 1 - 1, 2 - 1, 3 - 1, 1 - 1, 3 - 1, 4 - 1, 5 - 1, 8 - 1, 7 - 1, 5 - 1, 7 - 1, 6 - 1, 1 - 1, 5 - 1, 6 - 1, 1 - 1, + 6 - 1, 2 - 1, 2 - 1, 6 - 1, 7 - 1, 2 - 1, 7 - 1, 3 - 1, 3 - 1, 7 - 1, 8 - 1, 3 - 1, 8 - 1, 4 - 1, 5 - 1, 1 - 1, 4 - 1, 5 - 1, 4 - 1, 8 - 1 }; + glm::vec3 centerOfMass(0.0, 0.0, 0.0); + double volume =8.0; + double side = 2.0; + double inertia = (volume * side * side) / 6.0; //inertia of a unit cube is (mass * side * side) /6 + + //test with origin as reference point + massproperties::MassProperties massProp1(&vertices, &triangles, {}); + vector volumeAndInertia1 = massProp1.getMassProperties(); + if (abs(centerOfMass.x - massProp1.getCenterOfMass().x) > epsilion || abs(centerOfMass.y - massProp1.getCenterOfMass().y) > epsilion || + abs(centerOfMass.z - massProp1.getCenterOfMass().z) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << " " << + centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getCenterOfMass().x << " " << massProp1.getCenterOfMass().y << + " " << massProp1.getCenterOfMass().z << std::endl; + } + + if (abs(inertia - (volumeAndInertia1.at(1))) > epsilion || abs(inertia - (volumeAndInertia1.at(2))) > epsilion || + abs(inertia - (volumeAndInertia1.at(3))) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment is incorrect : Expected = " << inertia << " " << + inertia << " " << inertia << ", actual = " << (volumeAndInertia1.at(1)) << " " << (volumeAndInertia1.at(2)) << + " " << (volumeAndInertia1.at(3)) << std::endl; + } +} + +void MassPropertiesTests::runAllTests(){ + testWithTetrahedron(); + testWithUnitCube(); +} \ No newline at end of file diff --git a/tests/physics/src/MassPropertiesTests.h b/tests/physics/src/MassPropertiesTests.h new file mode 100644 index 0000000000..583ac25126 --- /dev/null +++ b/tests/physics/src/MassPropertiesTests.h @@ -0,0 +1,20 @@ +// +// MassPropertiesTests.h +// tests/physics/src +// +// Created by Virendra Singh on 2015.03.02 +// 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_MassPropertiesTests_h +#define hifi_MassPropertiesTests_h +#define epsilion 0.02 +namespace MassPropertiesTests{ + void testWithTetrahedron(); + void testWithUnitCube(); + void runAllTests(); +} +#endif // hifi_MassPropertiesTests_h \ No newline at end of file diff --git a/tests/physics/src/main.cpp b/tests/physics/src/main.cpp index bcf26f4115..eed58dbbdb 100644 --- a/tests/physics/src/main.cpp +++ b/tests/physics/src/main.cpp @@ -8,17 +8,21 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include "ShapeColliderTests.h" #include "VerletShapeTests.h" #include "ShapeInfoTests.h" #include "ShapeManagerTests.h" #include "BulletUtilTests.h" +#include "MassPropertiesTests.h" int main(int argc, char** argv) { - ShapeColliderTests::runAllTests(); - VerletShapeTests::runAllTests(); - ShapeInfoTests::runAllTests(); - ShapeManagerTests::runAllTests(); - BulletUtilTests::runAllTests(); + //ShapeColliderTests::runAllTests(); + //VerletShapeTests::runAllTests(); + //ShapeInfoTests::runAllTests(); + //ShapeManagerTests::runAllTests(); + // BulletUtilTests::runAllTests(); + MassPropertiesTests::runAllTests(); + getch(); return 0; } From 4627d2e7b5112984edd80a250a30a9cbcb131d5e Mon Sep 17 00:00:00 2001 From: Virendra Singh Date: Wed, 4 Mar 2015 03:52:59 +0530 Subject: [PATCH 05/56] Parallel axis theorem correction --- libraries/physics/src/MassProperties.cpp | 44 ++++---- tests/physics/src/MassPropertiesTests.cpp | 117 ++++++++++++++++++++-- tests/physics/src/MassPropertiesTests.h | 1 + tests/physics/src/main.cpp | 14 ++- 4 files changed, 141 insertions(+), 35 deletions(-) diff --git a/libraries/physics/src/MassProperties.cpp b/libraries/physics/src/MassProperties.cpp index 4d2e668f95..c6264ee220 100644 --- a/libraries/physics/src/MassProperties.cpp +++ b/libraries/physics/src/MassProperties.cpp @@ -52,10 +52,10 @@ vector Tetrahedron::getVolumeAndInertia() const{ } void Tetrahedron::computeVolume(){ - glm::mat4 tet = { glm::vec4(_x.x, _y.x, _z.x, _w.x), glm::vec4(_x.y, _y.y, _z.y, _w.y), glm::vec4(_x.z, _y.z, _z.z, _w.z), glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) }; + glm::mat4 tet = { glm::vec4(_x.x, _y.x, _z.x, _w.x), glm::vec4(_x.y, _y.y, _z.y, _w.y), glm::vec4(_x.z, _y.z, _z.z, _w.z), + glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) }; _volume = glm::determinant(tet) / 6.0f; _volumeAndInertia.push_back(_volume); - std::cout << "volume : " << _volume << std::endl; } void Tetrahedron::computeInertia(){ @@ -128,8 +128,8 @@ void Tetrahedron::computeInertia(){ } //class to compute volume, mass, center of mass, and inertia tensor of a mesh. -//origin is the default reference point for generating the tetrahedron from each triangle of the mesh. We can provide another reference -//point by passing it as 3rd parameter to the constructor +//origin is the default reference point for generating the tetrahedron from each triangle of the mesh. We can provide +//another reference point by passing it as 3rd parameter to the constructor MassProperties::MassProperties(vector *vertices, Triangle *triangles, Vertex referencepoint = glm::vec3(0.0,0.0,0.0)):\ _vertices(vertices), @@ -160,7 +160,6 @@ MassProperties::~MassProperties(){ } void MassProperties::generateTetrahedra() { - std::cout << "apex : " << _referencePoint.x << " " << _referencePoint.y << " " << _referencePoint.z << std::endl; for (int i = 0; i < _trianglesCount * 3; i += 3){ Vertex p1 = _vertices->at(_triangles->at(i)); Vertex p2 = _vertices->at(_triangles->at(i + 1)); @@ -200,6 +199,8 @@ vector MassProperties::getMassProperties(){ double inertia_bb = 0.0; double inertia_cc = 0.0; glm::vec3 centerOfMass; + glm::mat3 globalInertia(0.0); + glm::mat3 globalProductInertia(0.0); //Translate accumulated center of mass from each tetrahedron to mesh center of mass using parallel axis theorem for each (Tetrahedron tet in _tetrahedra){ @@ -215,20 +216,27 @@ vector MassProperties::getMassProperties(){ //Translate the moment of inertia from each tetrahedron to mesh center of mass using parallel axis theorem for each (Tetrahedron tet in _tetrahedra){ vector tetMassProperties = tet.getVolumeAndInertia(); - const double dist = glm::distance(_centerOfMass, tet.getCentroid()); - inertia_a += tetMassProperties.at(1) + (dist * dist * tetMassProperties.at(0)); - inertia_b += tetMassProperties.at(2) + (dist * dist * tetMassProperties.at(0)); - inertia_c += tetMassProperties.at(3) + (dist * dist * tetMassProperties.at(0)); - inertia_aa += tetMassProperties.at(4) + (dist * dist * tetMassProperties.at(0)); - inertia_bb += tetMassProperties.at(5) + (dist * dist * tetMassProperties.at(0)); - inertia_cc += tetMassProperties.at(6) + (dist * dist * tetMassProperties.at(0)); + glm::mat3 identity; + glm::vec3 diff = _centerOfMass - tet.getCentroid(); + float diffDot = glm::dot(diff, diff); + glm::mat3 outerDiff = glm::outerProduct(diff, diff); + + //3x3 of local inertia tensors of each tetrahedron. Inertia tensors are the diagonal elements + glm::mat3 localMomentInertia = { Vertex(tetMassProperties.at(1), 0.0f, 0.0f), Vertex(0.0f, tetMassProperties.at(2), 0.0f), + Vertex(0.0f, 0.0f, tetMassProperties.at(3)) }; + glm::mat3 localProductInertia = { Vertex(tetMassProperties.at(4), 0.0f, 0.0f), Vertex(0.0f, tetMassProperties.at(5), 0.0f), + Vertex(0.0f, 0.0f, tetMassProperties.at(6)) }; + + //Parallel axis theorem J = I * m[(R.R)*Identity - RxR] where x is outer cross product + globalInertia += localMomentInertia + (float)tetMassProperties.at(0) * ((diffDot*identity) - outerDiff); + globalProductInertia += localProductInertia + (float)tetMassProperties.at(0) * ((diffDot * identity) - outerDiff); } volumeAndInertia.push_back(volume); - volumeAndInertia.push_back(inertia_a); - volumeAndInertia.push_back(inertia_b); - volumeAndInertia.push_back(inertia_c); - volumeAndInertia.push_back(inertia_aa); - volumeAndInertia.push_back(inertia_bb); - volumeAndInertia.push_back(inertia_cc); + volumeAndInertia.push_back(globalInertia[0][0]); + volumeAndInertia.push_back(globalInertia[1][1]); + volumeAndInertia.push_back(globalInertia[2][2]); + volumeAndInertia.push_back(globalProductInertia[0][0]); + volumeAndInertia.push_back(globalProductInertia[1][1]); + volumeAndInertia.push_back(globalProductInertia[2][2]); return volumeAndInertia; } \ No newline at end of file diff --git a/tests/physics/src/MassPropertiesTests.cpp b/tests/physics/src/MassPropertiesTests.cpp index 83a8443cf9..f36a494b35 100644 --- a/tests/physics/src/MassPropertiesTests.cpp +++ b/tests/physics/src/MassPropertiesTests.cpp @@ -47,7 +47,7 @@ void MassPropertiesTests::testWithTetrahedron(){ //test if moment of inertia with respect to x axis is correct if (abs(inertia_a - (voumeAndInertia.at(1))) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to x axis is incorrect : Expected = " << + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to x axis is incorrect : Expected = " << inertia_a << " " << ", actual = " << (voumeAndInertia.at(1)) << std::endl; } @@ -83,7 +83,7 @@ void MassPropertiesTests::testWithTetrahedron(){ } -void MassPropertiesTests::testWithUnitCube(){ +void MassPropertiesTests::testWithCube(){ massproperties::Vertex p0(1.0, -1.0, -1.0); massproperties::Vertex p1(1.0, -1.0, 1.0); massproperties::Vertex p2(-1.0, -1.0, 1.0); @@ -101,11 +101,11 @@ void MassPropertiesTests::testWithUnitCube(){ vertices.push_back(p5); vertices.push_back(p6); vertices.push_back(p7); - std::cout << std::setprecision(5); - vector triangles = { 1 - 1, 2 - 1, 3 - 1, 1 - 1, 3 - 1, 4 - 1, 5 - 1, 8 - 1, 7 - 1, 5 - 1, 7 - 1, 6 - 1, 1 - 1, 5 - 1, 6 - 1, 1 - 1, - 6 - 1, 2 - 1, 2 - 1, 6 - 1, 7 - 1, 2 - 1, 7 - 1, 3 - 1, 3 - 1, 7 - 1, 8 - 1, 3 - 1, 8 - 1, 4 - 1, 5 - 1, 1 - 1, 4 - 1, 5 - 1, 4 - 1, 8 - 1 }; + std::cout << std::setprecision(10); + vector triangles = { 0, 1, 2, 0, 2, 3, 4, 7, 6, 4, 6, 5, 0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2, 2, 6, + 7, 2, 7, 3, 4, 0, 3, 4, 3, 7 }; glm::vec3 centerOfMass(0.0, 0.0, 0.0); - double volume =8.0; + double volume = 8.0; double side = 2.0; double inertia = (volume * side * side) / 6.0; //inertia of a unit cube is (mass * side * side) /6 @@ -115,19 +115,118 @@ void MassPropertiesTests::testWithUnitCube(){ if (abs(centerOfMass.x - massProp1.getCenterOfMass().x) > epsilion || abs(centerOfMass.y - massProp1.getCenterOfMass().y) > epsilion || abs(centerOfMass.z - massProp1.getCenterOfMass().z) > epsilion){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << " " << - centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getCenterOfMass().x << " " << massProp1.getCenterOfMass().y << - " " << massProp1.getCenterOfMass().z << std::endl; + centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getCenterOfMass().x << " " << + massProp1.getCenterOfMass().y << " " << massProp1.getCenterOfMass().z << std::endl; } - if (abs(inertia - (volumeAndInertia1.at(1))) > epsilion || abs(inertia - (volumeAndInertia1.at(2))) > epsilion || + if (abs(volume - volumeAndInertia1.at(0)) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << + ", actual = " << volumeAndInertia1.at(0) << std::endl; + } + + if (abs(inertia - (volumeAndInertia1.at(1))) > epsilion || abs(inertia - (volumeAndInertia1.at(2))) > epsilion || abs(inertia - (volumeAndInertia1.at(3))) > epsilion){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment is incorrect : Expected = " << inertia << " " << inertia << " " << inertia << ", actual = " << (volumeAndInertia1.at(1)) << " " << (volumeAndInertia1.at(2)) << " " << (volumeAndInertia1.at(3)) << std::endl; } + + //test with {2,2,2} as reference point + massproperties::MassProperties massProp2(&vertices, &triangles, { 2, 2, 2 }); + vector volumeAndInertia2 = massProp2.getMassProperties(); + if (abs(centerOfMass.x - massProp2.getCenterOfMass().x) > epsilion || abs(centerOfMass.y - massProp2.getCenterOfMass().y) > epsilion || + abs(centerOfMass.z - massProp2.getCenterOfMass().z) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << + " " << centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp2.getCenterOfMass().x << " " << + massProp2.getCenterOfMass().y << " " << massProp2.getCenterOfMass().z << std::endl; + } + + if (abs(volume - volumeAndInertia2.at(0)) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << + ", actual = " << volumeAndInertia2.at(0) << std::endl; + } + + if (abs(inertia - (volumeAndInertia2.at(1))) > epsilion || abs(inertia - (volumeAndInertia2.at(2))) > epsilion || + abs(inertia - (volumeAndInertia2.at(3))) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment is incorrect : Expected = " << inertia << " " << + inertia << " " << inertia << ", actual = " << (volumeAndInertia2.at(1)) << " " << (volumeAndInertia2.at(2)) << + " " << (volumeAndInertia2.at(3)) << std::endl; + } } +void MassPropertiesTests::testWithUnitCube() +{ + massproperties::Vertex p0(0, 0, 1); + massproperties::Vertex p1(1, 0, 1); + massproperties::Vertex p2(0, 1, 1); + massproperties::Vertex p3(1, 1, 1); + massproperties::Vertex p4(0, 0, 0); + massproperties::Vertex p5(1, 0, 0); + massproperties::Vertex p6(0, 1, 0); + massproperties::Vertex p7(1, 1, 0); + vector vertices; + vertices.push_back(p0); + vertices.push_back(p1); + vertices.push_back(p2); + vertices.push_back(p3); + vertices.push_back(p4); + vertices.push_back(p5); + vertices.push_back(p6); + vertices.push_back(p7); + vector triangles = { 0, 1, 2, 1, 3, 2, 2, 3, 7, 2, 7, 6, 1, 7, 3, 1, 5, 7, 6, 7, 4, 7, 5, 4, 0, 4, 1, + 1, 4, 5, 2, 6, 4, 0, 2, 4 }; + glm::vec3 centerOfMass(0.5, 0.5, 0.5); + double volume = 1.0; + double side = 1.0; + double inertia = (volume * side * side) / 6.0; //inertia of a unit cube is (mass * side * side) /6 + std::cout << std::setprecision(10); + + //test with origin as reference point + massproperties::MassProperties massProp1(&vertices, &triangles, {}); + vector volumeAndInertia1 = massProp1.getMassProperties(); + if (abs(centerOfMass.x - massProp1.getCenterOfMass().x) > epsilion || abs(centerOfMass.y - massProp1.getCenterOfMass().y) > epsilion || + abs(centerOfMass.z - massProp1.getCenterOfMass().z) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << + " " << centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getCenterOfMass().x << " " << + massProp1.getCenterOfMass().y << " " << massProp1.getCenterOfMass().z << std::endl; + } + + if (abs(volume - volumeAndInertia1.at(0)) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << + ", actual = " << volumeAndInertia1.at(0) << std::endl; + } + + if (abs(inertia - (volumeAndInertia1.at(1))) > epsilion || abs(inertia - (volumeAndInertia1.at(2))) > epsilion || + abs(inertia - (volumeAndInertia1.at(3))) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment is incorrect : Expected = " << inertia << " " << + inertia << " " << inertia << ", actual = " << (volumeAndInertia1.at(1)) << " " << (volumeAndInertia1.at(2)) << + " " << (volumeAndInertia1.at(3)) << std::endl; + } + + //test with {2,1,2} as reference point + massproperties::MassProperties massProp2(&vertices, &triangles, { 2, 1, 2 }); + vector volumeAndInertia2 = massProp2.getMassProperties(); + if (abs(centerOfMass.x - massProp2.getCenterOfMass().x) > epsilion || abs(centerOfMass.y - massProp2.getCenterOfMass().y) > epsilion || + abs(centerOfMass.z - massProp2.getCenterOfMass().z) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << " " << + centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp2.getCenterOfMass().x << " " << + massProp2.getCenterOfMass().y << " " << massProp2.getCenterOfMass().z << std::endl; + } + + if (abs(volume - volumeAndInertia2.at(0)) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << + ", actual = " << volumeAndInertia2.at(0) << std::endl; + } + + if (abs(inertia - (volumeAndInertia2.at(1))) > epsilion || abs(inertia - (volumeAndInertia2.at(2))) > epsilion || + abs(inertia - (volumeAndInertia2.at(3))) > epsilion){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment is incorrect : Expected = " << inertia << " " << + inertia << " " << inertia << ", actual = " << (volumeAndInertia2.at(1)) << " " << (volumeAndInertia2.at(2)) << + " " << (volumeAndInertia2.at(3)) << std::endl; + } +} void MassPropertiesTests::runAllTests(){ testWithTetrahedron(); testWithUnitCube(); + testWithCube(); } \ No newline at end of file diff --git a/tests/physics/src/MassPropertiesTests.h b/tests/physics/src/MassPropertiesTests.h index 583ac25126..21ab3ccb0a 100644 --- a/tests/physics/src/MassPropertiesTests.h +++ b/tests/physics/src/MassPropertiesTests.h @@ -15,6 +15,7 @@ namespace MassPropertiesTests{ void testWithTetrahedron(); void testWithUnitCube(); + void testWithCube(); void runAllTests(); } #endif // hifi_MassPropertiesTests_h \ No newline at end of file diff --git a/tests/physics/src/main.cpp b/tests/physics/src/main.cpp index eed58dbbdb..d42b5d1241 100644 --- a/tests/physics/src/main.cpp +++ b/tests/physics/src/main.cpp @@ -8,7 +8,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include #include "ShapeColliderTests.h" #include "VerletShapeTests.h" #include "ShapeInfoTests.h" @@ -17,12 +16,11 @@ #include "MassPropertiesTests.h" int main(int argc, char** argv) { - //ShapeColliderTests::runAllTests(); - //VerletShapeTests::runAllTests(); - //ShapeInfoTests::runAllTests(); - //ShapeManagerTests::runAllTests(); - // BulletUtilTests::runAllTests(); - MassPropertiesTests::runAllTests(); - getch(); + ShapeColliderTests::runAllTests(); + VerletShapeTests::runAllTests(); + ShapeInfoTests::runAllTests(); + ShapeManagerTests::runAllTests(); + BulletUtilTests::runAllTests(); + MassPropertiesTests::runAllTests(); return 0; } From 1facbbb844c8941883fb1ce26e9f7980dccbfad4 Mon Sep 17 00:00:00 2001 From: Virendra Singh Date: Wed, 4 Mar 2015 08:21:39 +0530 Subject: [PATCH 06/56] Removed MSVC specific for each blocks --- libraries/physics/src/MassProperties.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/MassProperties.cpp b/libraries/physics/src/MassProperties.cpp index c6264ee220..deaa37587d 100644 --- a/libraries/physics/src/MassProperties.cpp +++ b/libraries/physics/src/MassProperties.cpp @@ -203,7 +203,7 @@ vector MassProperties::getMassProperties(){ glm::mat3 globalProductInertia(0.0); //Translate accumulated center of mass from each tetrahedron to mesh center of mass using parallel axis theorem - for each (Tetrahedron tet in _tetrahedra){ + for(Tetrahedron tet : _tetrahedra){ vector tetMassProperties = tet.getVolumeAndInertia(); volume += tetMassProperties.at(0); //volume centerOfMass += tet.getCentroid() * (float)tetMassProperties.at(0); @@ -214,7 +214,7 @@ vector MassProperties::getMassProperties(){ } //Translate the moment of inertia from each tetrahedron to mesh center of mass using parallel axis theorem - for each (Tetrahedron tet in _tetrahedra){ + for(Tetrahedron tet : _tetrahedra){ vector tetMassProperties = tet.getVolumeAndInertia(); glm::mat3 identity; glm::vec3 diff = _centerOfMass - tet.getCentroid(); From 4366525da46ae7e81df17d5ddf45a1a9604926ae Mon Sep 17 00:00:00 2001 From: Virendra Singh Date: Wed, 4 Mar 2015 08:51:44 +0530 Subject: [PATCH 07/56] Removed unused variables --- libraries/physics/src/MassProperties.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libraries/physics/src/MassProperties.cpp b/libraries/physics/src/MassProperties.cpp index deaa37587d..e579f2d358 100644 --- a/libraries/physics/src/MassProperties.cpp +++ b/libraries/physics/src/MassProperties.cpp @@ -192,12 +192,6 @@ vector MassProperties::getTetrahedra() const{ vector MassProperties::getMassProperties(){ vector volumeAndInertia; double volume = 0.0; - double inertia_a = 0.0; - double inertia_b = 0.0; - double inertia_c = 0.0; - double inertia_aa = 0.0; - double inertia_bb = 0.0; - double inertia_cc = 0.0; glm::vec3 centerOfMass; glm::mat3 globalInertia(0.0); glm::mat3 globalProductInertia(0.0); From 42867bf98d089cdeb6e5c4a4f663a8c5fd5d7159 Mon Sep 17 00:00:00 2001 From: Virendra Singh Date: Fri, 6 Mar 2015 11:10:38 +0530 Subject: [PATCH 08/56] code revamp --- libraries/physics/src/MassProperties.cpp | 236 ------------------ libraries/physics/src/MassProperties.h | 67 ----- libraries/physics/src/MeshInfo.cpp | 160 ++++++++++++ libraries/physics/src/MeshInfo.h | 34 +++ tests/physics/src/MassPropertiesTests.cpp | 232 ----------------- tests/physics/src/MeshInfoTests.cpp | 198 +++++++++++++++ ...{MassPropertiesTests.h => MeshInfoTests.h} | 11 +- tests/physics/src/main.cpp | 4 +- 8 files changed, 399 insertions(+), 543 deletions(-) delete mode 100644 libraries/physics/src/MassProperties.cpp delete mode 100644 libraries/physics/src/MassProperties.h create mode 100644 libraries/physics/src/MeshInfo.cpp create mode 100644 libraries/physics/src/MeshInfo.h delete mode 100644 tests/physics/src/MassPropertiesTests.cpp create mode 100644 tests/physics/src/MeshInfoTests.cpp rename tests/physics/src/{MassPropertiesTests.h => MeshInfoTests.h} (66%) diff --git a/libraries/physics/src/MassProperties.cpp b/libraries/physics/src/MassProperties.cpp deleted file mode 100644 index e579f2d358..0000000000 --- a/libraries/physics/src/MassProperties.cpp +++ /dev/null @@ -1,236 +0,0 @@ -// -// MassProperties.cpp -// libraries/physics/src -// -// Created by Virendra Singh 2015.02.28 -// 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 "MassProperties.h" -using namespace massproperties; - -Tetrahedron::Tetrahedron(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) :\ -_w(p1), -_x(p2), -_y(p3), -_z(p4){ - computeVolume(); - computeInertia(); -} -Tetrahedron::~Tetrahedron(){ - -} - -Vertex Tetrahedron::getX() const{ - return _x; -} - -Vertex Tetrahedron::getY() const{ - return _y; -} -Vertex Tetrahedron::getZ() const{ - return _z; -} - -Vertex Tetrahedron::getw() const{ - return _w; -} - -Vertex Tetrahedron::getCentroid() const{ - Vertex com; - com.x = (_x.x + _y.x + _z.x + _w.x) / 4.0f; - com.y = (_x.y + _y.y + _z.y + _w.y) / 4.0f; - com.z = (_x.z + _y.z + _z.z + _w.z) / 4.0f; - return com; -} - -vector Tetrahedron::getVolumeAndInertia() const{ - return _volumeAndInertia; -} - -void Tetrahedron::computeVolume(){ - glm::mat4 tet = { glm::vec4(_x.x, _y.x, _z.x, _w.x), glm::vec4(_x.y, _y.y, _z.y, _w.y), glm::vec4(_x.z, _y.z, _z.z, _w.z), - glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) }; - _volume = glm::determinant(tet) / 6.0f; - _volumeAndInertia.push_back(_volume); -} - -void Tetrahedron::computeInertia(){ - - //centroid is used for calculating inertia tensor relative to center of mass. - // translate the tetrahedron to its center of mass using P = P - centroid - Vertex com = getCentroid(); - Vertex p0 = _w - com; - Vertex p1 = _x - com; - Vertex p2 = _y - com; - Vertex p3 = _z - com; - - //Calculate inertia tensor based on Tonon's Formulae given in the paper mentioned below. - //http://docsdrive.com/pdfs/sciencepublications/jmssp/2005/8-11.pdf - //Explicit exact formulas for the 3-D tetrahedron inertia tensor in terms of its vertex coordinates - F.Tonon - - double inertia_a = (_volume * 6.0 / 60.0) * ( - p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + - p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + - p2.y*p2.y + p2.y*p3.y + - p3.y*p3.y + - p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + - p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + - p2.z*p2.z + p2.z*p3.z + - p3.z*p3.z); - _volumeAndInertia.push_back(inertia_a); - - double inertia_b = (_volume * 6.0 / 60.0) * ( - p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + - p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + - p2.x*p2.x + p2.x*p3.x + - p3.x*p3.x + - p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + - p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + - p2.z*p2.z + p2.z*p3.z + - p3.z*p3.z); - _volumeAndInertia.push_back(inertia_b); - - double inertia_c = (_volume * 6.0 / 60.0) * ( - p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + - p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + - p2.x*p2.x + p2.x*p3.x + - p3.x*p3.x + - p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + - p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + - p2.y*p2.y + p2.y*p3.y + - p3.y*p3.y); - _volumeAndInertia.push_back(inertia_c); - - double inertia_aa = (_volume * 6.0 / 120.0) * (2.0 * (p0.y*p0.z + p1.y*p1.z + p2.y*p2.z + p3.y*p3.z) + - p0.y*p1.z + p0.y*p2.z + p0.y*p3.z + - p1.y*p0.z + p1.y*p2.z + p1.y*p3.z + - p2.y*p0.z + p2.y*p1.z + p2.y*p3.z + - p3.y*p0.z + p3.y*p1.z + p3.y*p2.z); - _volumeAndInertia.push_back(inertia_aa); - - double inertia_bb = (_volume * 6.0 / 120.0) * (2.0 * (p0.x*p0.z + p1.x*p1.z + p2.x*p2.z + p3.x*p3.z) + - p0.x*p1.z + p0.x*p2.z + p0.x*p3.z + - p1.x*p0.z + p1.x*p2.z + p1.x*p3.z + - p2.x*p0.z + p2.x*p1.z + p2.x*p3.z + - p3.x*p0.z + p3.x*p1.z + p3.x*p2.z); - _volumeAndInertia.push_back(inertia_bb); - - double inertia_cc = (_volume * 6.0 / 120.0) * (2.0 * (p0.x*p0.y + p1.x*p1.y + p2.x*p2.y + p3.x*p3.y) + - p0.x*p1.y + p0.x*p2.y + p0.x*p3.y + - p1.x*p0.y + p1.x*p2.y + p1.x*p3.y + - p2.x*p0.y + p2.x*p1.y + p2.x*p3.y + - p3.x*p0.y + p3.x*p1.y + p3.x*p2.y); - _volumeAndInertia.push_back(inertia_cc); -} - -//class to compute volume, mass, center of mass, and inertia tensor of a mesh. -//origin is the default reference point for generating the tetrahedron from each triangle of the mesh. We can provide -//another reference point by passing it as 3rd parameter to the constructor - -MassProperties::MassProperties(vector *vertices, Triangle *triangles, Vertex referencepoint = glm::vec3(0.0,0.0,0.0)):\ -_vertices(vertices), -_triangles(triangles), -_referencePoint(referencepoint), -_trianglesCount(0), -_tetrahedraCount(0), -_verticesCount(0), -_centerOfMass(glm::vec3(0.0, 0.0, 0.0)){ - - if (_triangles){ - _trianglesCount = _triangles->size() / 3; - } - - if (_vertices){ - _verticesCount = _vertices->size(); - } - generateTetrahedra(); -} - -MassProperties::~MassProperties(){ - if (_vertices){ - _vertices->clear(); - } - if (_triangles){ - _triangles->clear(); - } -} - -void MassProperties::generateTetrahedra() { - for (int i = 0; i < _trianglesCount * 3; i += 3){ - Vertex p1 = _vertices->at(_triangles->at(i)); - Vertex p2 = _vertices->at(_triangles->at(i + 1)); - Vertex p3 = _vertices->at(_triangles->at(i + 2)); - Tetrahedron t(_referencePoint, p1, p2, p3); - _tetrahedra.push_back(t); - } -} - -int MassProperties::getTriangleCount() const{ - return _trianglesCount; -} - -int MassProperties::getVerticesCount() const{ - return _verticesCount; -} - -Vertex MassProperties::getCenterOfMass() const{ - return _centerOfMass; -} - -int MassProperties::getTetrahedraCount() const{ - return _tetrahedra.size(); -} - -vector MassProperties::getTetrahedra() const{ - return _tetrahedra; -} - -vector MassProperties::getMassProperties(){ - vector volumeAndInertia; - double volume = 0.0; - glm::vec3 centerOfMass; - glm::mat3 globalInertia(0.0); - glm::mat3 globalProductInertia(0.0); - - //Translate accumulated center of mass from each tetrahedron to mesh center of mass using parallel axis theorem - for(Tetrahedron tet : _tetrahedra){ - vector tetMassProperties = tet.getVolumeAndInertia(); - volume += tetMassProperties.at(0); //volume - centerOfMass += tet.getCentroid() * (float)tetMassProperties.at(0); - } - - if (volume != 0){ - _centerOfMass = (centerOfMass / (float)volume); - } - - //Translate the moment of inertia from each tetrahedron to mesh center of mass using parallel axis theorem - for(Tetrahedron tet : _tetrahedra){ - vector tetMassProperties = tet.getVolumeAndInertia(); - glm::mat3 identity; - glm::vec3 diff = _centerOfMass - tet.getCentroid(); - float diffDot = glm::dot(diff, diff); - glm::mat3 outerDiff = glm::outerProduct(diff, diff); - - //3x3 of local inertia tensors of each tetrahedron. Inertia tensors are the diagonal elements - glm::mat3 localMomentInertia = { Vertex(tetMassProperties.at(1), 0.0f, 0.0f), Vertex(0.0f, tetMassProperties.at(2), 0.0f), - Vertex(0.0f, 0.0f, tetMassProperties.at(3)) }; - glm::mat3 localProductInertia = { Vertex(tetMassProperties.at(4), 0.0f, 0.0f), Vertex(0.0f, tetMassProperties.at(5), 0.0f), - Vertex(0.0f, 0.0f, tetMassProperties.at(6)) }; - - //Parallel axis theorem J = I * m[(R.R)*Identity - RxR] where x is outer cross product - globalInertia += localMomentInertia + (float)tetMassProperties.at(0) * ((diffDot*identity) - outerDiff); - globalProductInertia += localProductInertia + (float)tetMassProperties.at(0) * ((diffDot * identity) - outerDiff); - } - volumeAndInertia.push_back(volume); - volumeAndInertia.push_back(globalInertia[0][0]); - volumeAndInertia.push_back(globalInertia[1][1]); - volumeAndInertia.push_back(globalInertia[2][2]); - volumeAndInertia.push_back(globalProductInertia[0][0]); - volumeAndInertia.push_back(globalProductInertia[1][1]); - volumeAndInertia.push_back(globalProductInertia[2][2]); - return volumeAndInertia; -} \ No newline at end of file diff --git a/libraries/physics/src/MassProperties.h b/libraries/physics/src/MassProperties.h deleted file mode 100644 index 240e0e53f7..0000000000 --- a/libraries/physics/src/MassProperties.h +++ /dev/null @@ -1,67 +0,0 @@ -// -// MassProperties.h -// libraries/physics/src -// -// Created by Virendra Singh 2015.02.28 -// 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_MassProperties_h -#define hifi_MassProperties_h - -#include -#include -#include -#include -using namespace std; -namespace massproperties{ - typedef glm::vec3 Vertex; - typedef vector Triangle; - - //Tetrahedron class containing the base triangle and the apex. - class Tetrahedron{ - private: - Vertex _w; //apex - Vertex _x; - Vertex _y; - Vertex _z; - double _volume; - vector _volumeAndInertia; - void computeInertia(); - void computeVolume(); - public: - Tetrahedron(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4); - ~Tetrahedron(); - Vertex getX() const; - Vertex getY() const; - Vertex getZ() const; - Vertex getw() const; - Vertex getCentroid() const; - vector getVolumeAndInertia() const; - }; - - class MassProperties{ - private: - int _trianglesCount; - int _tetrahedraCount; - int _verticesCount; - vector *_vertices; - Vertex _referencePoint; - Vertex _centerOfMass; - Triangle *_triangles; - vector _tetrahedra; - void generateTetrahedra(); - public: - MassProperties(vector *vertices, Triangle *triangles, Vertex refewrencepoint); - ~MassProperties(); - int getTriangleCount() const; - int getVerticesCount() const; - int getTetrahedraCount() const; - Vertex getCenterOfMass() const; - vector getTetrahedra() const; - vector getMassProperties(); - }; -} -#endif // hifi_MassProperties_h \ No newline at end of file diff --git a/libraries/physics/src/MeshInfo.cpp b/libraries/physics/src/MeshInfo.cpp new file mode 100644 index 0000000000..b406cff269 --- /dev/null +++ b/libraries/physics/src/MeshInfo.cpp @@ -0,0 +1,160 @@ +// +// MeshInfo.cpp +// libraries/physics/src +// +// Created by Virendra Singh 2015.02.28 +// 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 "MeshInfo.h" +#include df +using namespace meshinfo; + +//class to compute volume, mass, center of mass, and inertia tensor of a mesh. +//origin is the default reference point for generating the tetrahedron from each triangle of the mesh. + +MeshInfo::MeshInfo(vector *vertices, vector *triangles) :\ +_vertices(vertices), +_triangles(triangles), +_centerOfMass(Vertex(0.0, 0.0, 0.0)){ +} + +MeshInfo::~MeshInfo(){ + + _vertices = NULL; + _triangles = NULL; + +} + +inline Vertex MeshInfo::getCentroid(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const{ + Vertex com; + com.x = (p1.x + p2.x + p3.x + p4.x) / 4.0f; + com.y = (p2.y + p2.y + p3.y + p4.y) / 4.0f; + com.z = (p2.z + p2.z + p3.z + p4.z) / 4.0f; + return com; +} + +inline float MeshInfo::getVolume(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const{ + glm::mat4 tet = { glm::vec4(p1.x, p2.x, p3.x, p4.x), glm::vec4(p1.y, p2.y, p3.y, p4.y), glm::vec4(p1.z, p2.z, p3.z, p4.z), + glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) }; + return glm::determinant(tet) / 6.0f; +} + +Vertex MeshInfo::getMeshCentroid() const{ + return _centerOfMass; +} + +vector MeshInfo::computeMassProperties(){ + vector volumeAndInertia = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + Vertex p0(0.0, 0.0, 0.0); + float meshVolume = 0.0f; + glm::mat3 globalMomentOfInertia(0.0); + glm::mat3 globalProductOfInertia(0.0); + + //First we need need the center of mass of the mesh in order to translate the tetrahedron inertia to center of mass of the mesh. + for (int i = 0; i < _triangles->size(); i += 3){ + Vertex p1 = _vertices->at(_triangles->at(i)); + Vertex p2 = _vertices->at(_triangles->at(i + 1)); + Vertex p3 = _vertices->at(_triangles->at(i + 2)); + float volume = getVolume(p1, p2, p3, p0); + Vertex com = getCentroid(p0, p1, p2, p3); + //Translate accumulated center of mass from each tetrahedron to mesh's center of mass using parallel axis theorem + meshVolume += volume; + _centerOfMass += com * volume; + } + if (meshVolume == 0){ + return volumeAndInertia; + } + _centerOfMass = (_centerOfMass / (float)meshVolume); + + //Translate the moment of inertia from each tetrahedron to mesh's center of mass using parallel axis theorem + for (int i = 0; i < _triangles->size(); i += 3){ + Vertex p1 = _vertices->at(_triangles->at(i)); + Vertex p2 = _vertices->at(_triangles->at(i + 1)); + Vertex p3 = _vertices->at(_triangles->at(i + 2)); + float volume = getVolume(p1, p2, p3, p0); + Vertex com = getCentroid(p0, p1, p2, p3); + glm::mat3 identity; + Vertex diff = _centerOfMass - com; + float diffDot = glm::dot(diff, diff); + glm::mat3 outerDiff = glm::outerProduct(diff, diff); + //centroid is used for calculating inertia tensor relative to center of mass. + // translate the tetrahedron to its center of mass using P = P - centroid + p0 = p0 - com; + p1 = p1 - com; + p2 = p2 - com; + p3 = p3 - com; + + //Calculate inertia tensor based on Tonon's Formulae given in the paper mentioned below. + //http://docsdrive.com/pdfs/sciencepublications/jmssp/2005/8-11.pdf + //Explicit exact formulas for the 3-D tetrahedron inertia tensor in terms of its vertex coordinates - F.Tonon + + float inertia_a = (volume * 6.0 / 60.0) * ( + p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + + p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + + p2.y*p2.y + p2.y*p3.y + + p3.y*p3.y + + p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + + p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + + p2.z*p2.z + p2.z*p3.z + + p3.z*p3.z); + + float inertia_b = (volume * 6.0 / 60.0) * ( + p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + + p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + + p2.x*p2.x + p2.x*p3.x + + p3.x*p3.x + + p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + + p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + + p2.z*p2.z + p2.z*p3.z + + p3.z*p3.z); + + float inertia_c = (volume * 6.0 / 60.0) * ( + p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + + p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + + p2.x*p2.x + p2.x*p3.x + + p3.x*p3.x + + p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + + p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + + p2.y*p2.y + p2.y*p3.y + + p3.y*p3.y); + + float inertia_aa = (volume * 6.0 / 120.0) * (2.0 * (p0.y*p0.z + p1.y*p1.z + p2.y*p2.z + p3.y*p3.z) + + p0.y*p1.z + p0.y*p2.z + p0.y*p3.z + + p1.y*p0.z + p1.y*p2.z + p1.y*p3.z + + p2.y*p0.z + p2.y*p1.z + p2.y*p3.z + + p3.y*p0.z + p3.y*p1.z + p3.y*p2.z); + + float inertia_bb = (volume * 6.0 / 120.0) * (2.0 * (p0.x*p0.z + p1.x*p1.z + p2.x*p2.z + p3.x*p3.z) + + p0.x*p1.z + p0.x*p2.z + p0.x*p3.z + + p1.x*p0.z + p1.x*p2.z + p1.x*p3.z + + p2.x*p0.z + p2.x*p1.z + p2.x*p3.z + + p3.x*p0.z + p3.x*p1.z + p3.x*p2.z); + + float inertia_cc = (volume * 6.0 / 120.0) * (2.0 * (p0.x*p0.y + p1.x*p1.y + p2.x*p2.y + p3.x*p3.y) + + p0.x*p1.y + p0.x*p2.y + p0.x*p3.y + + p1.x*p0.y + p1.x*p2.y + p1.x*p3.y + + p2.x*p0.y + p2.x*p1.y + p2.x*p3.y + + p3.x*p0.y + p3.x*p1.y + p3.x*p2.y); + //3x3 of local inertia tensors of each tetrahedron. Inertia tensors are the diagonal elements + glm::mat3 localMomentInertia = { Vertex(inertia_a, 0.0f, 0.0f), Vertex(0.0f, inertia_b, 0.0f), + Vertex(0.0f, 0.0f, inertia_c) }; + glm::mat3 localProductInertia = { Vertex(inertia_aa, 0.0f, 0.0f), Vertex(0.0f, inertia_bb, 0.0f), + Vertex(0.0f, 0.0f, inertia_cc) }; + + //Parallel axis theorem J = I * m[(R.R)*Identity - RxR] where x is outer cross product + globalMomentOfInertia += localMomentInertia + volume * ((diffDot*identity) - outerDiff); + globalProductOfInertia += localProductInertia + volume * ((diffDot * identity) - outerDiff); + } + volumeAndInertia.push_back(meshVolume); + volumeAndInertia.push_back(globalMomentOfInertia[0][0]); + volumeAndInertia.push_back(globalMomentOfInertia[1][1]); + volumeAndInertia.push_back(globalMomentOfInertia[2][2]); + volumeAndInertia.push_back(globalProductOfInertia[0][0]); + volumeAndInertia.push_back(globalProductOfInertia[1][1]); + volumeAndInertia.push_back(globalProductOfInertia[2][2]); + return volumeAndInertia; +} \ No newline at end of file diff --git a/libraries/physics/src/MeshInfo.h b/libraries/physics/src/MeshInfo.h new file mode 100644 index 0000000000..b400ef9cf0 --- /dev/null +++ b/libraries/physics/src/MeshInfo.h @@ -0,0 +1,34 @@ +// +// MeshInfo.h +// libraries/physics/src +// +// Created by Virendra Singh 2015.02.28 +// 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_MeshInfo_h +#define hifi_MeshInfo_h +#include +#include +#include +using namespace std; +namespace meshinfo{ + typedef glm::vec3 Vertex; + class MeshInfo{ + private: + inline float getVolume(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const; + vector computeVolumeAndInertia(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const; + public: + vector *_vertices; + Vertex _centerOfMass; + vector *_triangles; + MeshInfo(vector *vertices, vector *triangles); + ~MeshInfo(); + inline Vertex getCentroid(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const; + Vertex getMeshCentroid() const; + vector computeMassProperties(); + }; +} +#endif // hifi_MeshInfo_h \ No newline at end of file diff --git a/tests/physics/src/MassPropertiesTests.cpp b/tests/physics/src/MassPropertiesTests.cpp deleted file mode 100644 index f36a494b35..0000000000 --- a/tests/physics/src/MassPropertiesTests.cpp +++ /dev/null @@ -1,232 +0,0 @@ -// -// MassPropertiesTests.cpp -// tests/physics/src -// -// Created by Virendra Singh on 2015.03.02 -// 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 -#include -#include - -#include "MassPropertiesTests.h" - -void MassPropertiesTests::testWithTetrahedron(){ - glm::vec3 p0(8.33220, -11.86875, 0.93355); - glm::vec3 p1(0.75523, 5.00000, 16.37072); - glm::vec3 p2(52.61236, 5.00000, -5.38580); - glm::vec3 p3(2.00000, 5.00000, 3.00000); - glm::vec3 centroid(15.92492, 0.782813, 3.72962); - double volume = 1873.233236; - double inertia_a = 43520.33257; - double inertia_b = 194711.28938; - double inertia_c = 191168.76173; - double inertia_aa = 4417.66150; - double inertia_bb = -46343.16662; - double inertia_cc = 11996.20119; - massproperties::Tetrahedron tet(p0, p1, p2, p3); - glm::vec3 diff = centroid - tet.getCentroid(); - vector voumeAndInertia = tet.getVolumeAndInertia(); - std::cout << std::setprecision(12); - //test if centroid is correct - if (diff.x > epsilion || diff.y > epsilion || diff.z > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Centroid is incorrect : Expected = " << centroid.x << " " << - centroid.y << " " << centroid.z << ", actual = " << tet.getCentroid().x << " " << tet.getCentroid().y << - " " << tet.getCentroid().z << std::endl; - } - - //test if volume is correct - if (abs(volume - voumeAndInertia.at(0)) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << " " << - ", actual = " << voumeAndInertia.at(0) << std::endl; - } - - //test if moment of inertia with respect to x axis is correct - if (abs(inertia_a - (voumeAndInertia.at(1))) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to x axis is incorrect : Expected = " << - inertia_a << " " << ", actual = " << (voumeAndInertia.at(1)) << std::endl; - } - - //test if moment of inertia with respect to y axis is correct - if (abs(inertia_b - (voumeAndInertia.at(2))) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to y axis is incorrect : Expected = " << - inertia_b << " " << ", actual = " << (voumeAndInertia.at(2)) << std::endl; - } - - //test if moment of inertia with respect to z axis is correct - if (abs(inertia_c - (voumeAndInertia.at(3))) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to z axis is incorrect : Expected = " << - inertia_c << " " << ", actual = " << (voumeAndInertia.at(3)) << std::endl; - } - - //test if product of inertia with respect to x axis is correct - if (abs(inertia_aa - (voumeAndInertia.at(4))) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to x axis is incorrect : Expected = " << - inertia_aa << " " << ", actual = " << (voumeAndInertia.at(4)) << std::endl; - } - - //test if product of inertia with respect to y axis is correct - if (abs(inertia_bb - (voumeAndInertia.at(5))) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to y axis is incorrect : Expected = " << - inertia_bb << " " << ", actual = " << (voumeAndInertia.at(5)) << std::endl; - } - - //test if product of inertia with respect to z axis is correct - if (abs(inertia_cc - (voumeAndInertia.at(6))) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to z axis is incorrect : Expected = " << - inertia_cc << " " << ", actual = " << (voumeAndInertia.at(6)) << std::endl; - } - -} - -void MassPropertiesTests::testWithCube(){ - massproperties::Vertex p0(1.0, -1.0, -1.0); - massproperties::Vertex p1(1.0, -1.0, 1.0); - massproperties::Vertex p2(-1.0, -1.0, 1.0); - massproperties::Vertex p3(-1.0, -1.0, -1.0); - massproperties::Vertex p4(1.0, 1.0, -1.0); - massproperties::Vertex p5(1.0, 1.0, 1.0); - massproperties::Vertex p6(-1.0, 1.0, 1.0); - massproperties::Vertex p7(-1.0, 1.0, -1.0); - vector vertices; - vertices.push_back(p0); - vertices.push_back(p1); - vertices.push_back(p2); - vertices.push_back(p3); - vertices.push_back(p4); - vertices.push_back(p5); - vertices.push_back(p6); - vertices.push_back(p7); - std::cout << std::setprecision(10); - vector triangles = { 0, 1, 2, 0, 2, 3, 4, 7, 6, 4, 6, 5, 0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2, 2, 6, - 7, 2, 7, 3, 4, 0, 3, 4, 3, 7 }; - glm::vec3 centerOfMass(0.0, 0.0, 0.0); - double volume = 8.0; - double side = 2.0; - double inertia = (volume * side * side) / 6.0; //inertia of a unit cube is (mass * side * side) /6 - - //test with origin as reference point - massproperties::MassProperties massProp1(&vertices, &triangles, {}); - vector volumeAndInertia1 = massProp1.getMassProperties(); - if (abs(centerOfMass.x - massProp1.getCenterOfMass().x) > epsilion || abs(centerOfMass.y - massProp1.getCenterOfMass().y) > epsilion || - abs(centerOfMass.z - massProp1.getCenterOfMass().z) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << " " << - centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getCenterOfMass().x << " " << - massProp1.getCenterOfMass().y << " " << massProp1.getCenterOfMass().z << std::endl; - } - - if (abs(volume - volumeAndInertia1.at(0)) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << - ", actual = " << volumeAndInertia1.at(0) << std::endl; - } - - if (abs(inertia - (volumeAndInertia1.at(1))) > epsilion || abs(inertia - (volumeAndInertia1.at(2))) > epsilion || - abs(inertia - (volumeAndInertia1.at(3))) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment is incorrect : Expected = " << inertia << " " << - inertia << " " << inertia << ", actual = " << (volumeAndInertia1.at(1)) << " " << (volumeAndInertia1.at(2)) << - " " << (volumeAndInertia1.at(3)) << std::endl; - } - - //test with {2,2,2} as reference point - massproperties::MassProperties massProp2(&vertices, &triangles, { 2, 2, 2 }); - vector volumeAndInertia2 = massProp2.getMassProperties(); - if (abs(centerOfMass.x - massProp2.getCenterOfMass().x) > epsilion || abs(centerOfMass.y - massProp2.getCenterOfMass().y) > epsilion || - abs(centerOfMass.z - massProp2.getCenterOfMass().z) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << - " " << centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp2.getCenterOfMass().x << " " << - massProp2.getCenterOfMass().y << " " << massProp2.getCenterOfMass().z << std::endl; - } - - if (abs(volume - volumeAndInertia2.at(0)) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << - ", actual = " << volumeAndInertia2.at(0) << std::endl; - } - - if (abs(inertia - (volumeAndInertia2.at(1))) > epsilion || abs(inertia - (volumeAndInertia2.at(2))) > epsilion || - abs(inertia - (volumeAndInertia2.at(3))) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment is incorrect : Expected = " << inertia << " " << - inertia << " " << inertia << ", actual = " << (volumeAndInertia2.at(1)) << " " << (volumeAndInertia2.at(2)) << - " " << (volumeAndInertia2.at(3)) << std::endl; - } -} - -void MassPropertiesTests::testWithUnitCube() -{ - massproperties::Vertex p0(0, 0, 1); - massproperties::Vertex p1(1, 0, 1); - massproperties::Vertex p2(0, 1, 1); - massproperties::Vertex p3(1, 1, 1); - massproperties::Vertex p4(0, 0, 0); - massproperties::Vertex p5(1, 0, 0); - massproperties::Vertex p6(0, 1, 0); - massproperties::Vertex p7(1, 1, 0); - vector vertices; - vertices.push_back(p0); - vertices.push_back(p1); - vertices.push_back(p2); - vertices.push_back(p3); - vertices.push_back(p4); - vertices.push_back(p5); - vertices.push_back(p6); - vertices.push_back(p7); - vector triangles = { 0, 1, 2, 1, 3, 2, 2, 3, 7, 2, 7, 6, 1, 7, 3, 1, 5, 7, 6, 7, 4, 7, 5, 4, 0, 4, 1, - 1, 4, 5, 2, 6, 4, 0, 2, 4 }; - glm::vec3 centerOfMass(0.5, 0.5, 0.5); - double volume = 1.0; - double side = 1.0; - double inertia = (volume * side * side) / 6.0; //inertia of a unit cube is (mass * side * side) /6 - std::cout << std::setprecision(10); - - //test with origin as reference point - massproperties::MassProperties massProp1(&vertices, &triangles, {}); - vector volumeAndInertia1 = massProp1.getMassProperties(); - if (abs(centerOfMass.x - massProp1.getCenterOfMass().x) > epsilion || abs(centerOfMass.y - massProp1.getCenterOfMass().y) > epsilion || - abs(centerOfMass.z - massProp1.getCenterOfMass().z) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << - " " << centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getCenterOfMass().x << " " << - massProp1.getCenterOfMass().y << " " << massProp1.getCenterOfMass().z << std::endl; - } - - if (abs(volume - volumeAndInertia1.at(0)) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << - ", actual = " << volumeAndInertia1.at(0) << std::endl; - } - - if (abs(inertia - (volumeAndInertia1.at(1))) > epsilion || abs(inertia - (volumeAndInertia1.at(2))) > epsilion || - abs(inertia - (volumeAndInertia1.at(3))) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment is incorrect : Expected = " << inertia << " " << - inertia << " " << inertia << ", actual = " << (volumeAndInertia1.at(1)) << " " << (volumeAndInertia1.at(2)) << - " " << (volumeAndInertia1.at(3)) << std::endl; - } - - //test with {2,1,2} as reference point - massproperties::MassProperties massProp2(&vertices, &triangles, { 2, 1, 2 }); - vector volumeAndInertia2 = massProp2.getMassProperties(); - if (abs(centerOfMass.x - massProp2.getCenterOfMass().x) > epsilion || abs(centerOfMass.y - massProp2.getCenterOfMass().y) > epsilion || - abs(centerOfMass.z - massProp2.getCenterOfMass().z) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << " " << - centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp2.getCenterOfMass().x << " " << - massProp2.getCenterOfMass().y << " " << massProp2.getCenterOfMass().z << std::endl; - } - - if (abs(volume - volumeAndInertia2.at(0)) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << - ", actual = " << volumeAndInertia2.at(0) << std::endl; - } - - if (abs(inertia - (volumeAndInertia2.at(1))) > epsilion || abs(inertia - (volumeAndInertia2.at(2))) > epsilion || - abs(inertia - (volumeAndInertia2.at(3))) > epsilion){ - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment is incorrect : Expected = " << inertia << " " << - inertia << " " << inertia << ", actual = " << (volumeAndInertia2.at(1)) << " " << (volumeAndInertia2.at(2)) << - " " << (volumeAndInertia2.at(3)) << std::endl; - } -} -void MassPropertiesTests::runAllTests(){ - testWithTetrahedron(); - testWithUnitCube(); - testWithCube(); -} \ No newline at end of file diff --git a/tests/physics/src/MeshInfoTests.cpp b/tests/physics/src/MeshInfoTests.cpp new file mode 100644 index 0000000000..69a6964128 --- /dev/null +++ b/tests/physics/src/MeshInfoTests.cpp @@ -0,0 +1,198 @@ +// +// MeshInfoTests.cpp +// tests/physics/src +// +// Created by Virendra Singh on 2015.03.02 +// 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 +#include +#include + +#include "MeshInfoTests.h" +const double epsilon = 0.02; +void MeshInfoTests::testWithTetrahedron(){ + glm::vec3 p0(8.33220, -11.86875, 0.93355); + glm::vec3 p1(0.75523, 5.00000, 16.37072); + glm::vec3 p2(52.61236, 5.00000, -5.38580); + glm::vec3 p3(2.00000, 5.00000, 3.00000); + glm::vec3 centroid(15.92492, 0.782813, 3.72962); + + //translate the tetrahedron so that its apex is on origin + glm::vec3 p11 = p1 - p0; + glm::vec3 p22 = p2 - p0; + glm::vec3 p33 = p3 - p0; + vector vertices = { p11, p22, p33 }; + vector triangles = { 0, 1, 2 }; + + float volume = 1873.233236; + float inertia_a = 43520.33257; + float inertia_b = 194711.28938; + float inertia_c = 191168.76173; + float inertia_aa = 4417.66150; + float inertia_bb = -46343.16662; + float inertia_cc = 11996.20119; + + meshinfo::MeshInfo meshinfo(&vertices,&triangles); + glm::vec3 tetCenterOfMass = meshinfo.getCentroid(p0, p1, p2, p3); + glm::vec3 diff = centroid - tetCenterOfMass; + vector voumeAndInertia = meshinfo.computeMassProperties(); + std::cout << std::setprecision(12); + //test if centroid is correct + if (diff.x > epsilon || diff.y > epsilon || diff.z > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Centroid is incorrect : Expected = " << centroid.x << " " << + centroid.y << " " << centroid.z << ", actual = " << tetCenterOfMass.x << " " << tetCenterOfMass.y << + " " << tetCenterOfMass.z << std::endl; + } + + //test if volume is correct + if (abs(volume - voumeAndInertia.at(0)) > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << " " << + ", actual = " << voumeAndInertia.at(0) << std::endl; + } + + //test if moment of inertia with respect to x axis is correct + if (abs(inertia_a - (voumeAndInertia.at(1))) > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to x axis is incorrect : Expected = " << + inertia_a << " " << ", actual = " << (voumeAndInertia.at(1)) << std::endl; + } + + //test if moment of inertia with respect to y axis is correct + if (abs(inertia_b - (voumeAndInertia.at(2))) > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to y axis is incorrect : Expected = " << + inertia_b << " " << ", actual = " << (voumeAndInertia.at(2)) << std::endl; + } + + //test if moment of inertia with respect to z axis is correct + if (abs(inertia_c - (voumeAndInertia.at(3))) > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to z axis is incorrect : Expected = " << + inertia_c << " " << ", actual = " << (voumeAndInertia.at(3)) << std::endl; + } + + //test if product of inertia with respect to x axis is correct + if (abs(inertia_aa - (voumeAndInertia.at(4))) > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to x axis is incorrect : Expected = " << + inertia_aa << " " << ", actual = " << (voumeAndInertia.at(4)) << std::endl; + } + + //test if product of inertia with respect to y axis is correct + if (abs(inertia_bb - (voumeAndInertia.at(5))) > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to y axis is incorrect : Expected = " << + inertia_bb << " " << ", actual = " << (voumeAndInertia.at(5)) << std::endl; + } + + //test if product of inertia with respect to z axis is correct + if (abs(inertia_cc - (voumeAndInertia.at(6))) > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to z axis is incorrect : Expected = " << + inertia_cc << " " << ", actual = " << (voumeAndInertia.at(6)) << std::endl; + } + +} + +void MeshInfoTests::testWithCube(){ + glm::vec3 p0(1.0, -1.0, -1.0); + glm::vec3 p1(1.0, -1.0, 1.0); + glm::vec3 p2(-1.0, -1.0, 1.0); + glm::vec3 p3(-1.0, -1.0, -1.0); + glm::vec3 p4(1.0, 1.0, -1.0); + glm::vec3 p5(1.0, 1.0, 1.0); + glm::vec3 p6(-1.0, 1.0, 1.0); + glm::vec3 p7(-1.0, 1.0, -1.0); + vector vertices; + vertices.push_back(p0); + vertices.push_back(p1); + vertices.push_back(p2); + vertices.push_back(p3); + vertices.push_back(p4); + vertices.push_back(p5); + vertices.push_back(p6); + vertices.push_back(p7); + std::cout << std::setprecision(10); + vector triangles = { 0, 1, 2, 0, 2, 3, 4, 7, 6, 4, 6, 5, 0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2, 2, 6, + 7, 2, 7, 3, 4, 0, 3, 4, 3, 7 }; + glm::vec3 centerOfMass(0.0, 0.0, 0.0); + double volume = 8.0; + double side = 2.0; + double inertia = (volume * side * side) / 6.0; //inertia of a unit cube is (mass * side * side) /6 + + //test with origin as reference point + meshinfo::MeshInfo massProp1(&vertices, &triangles); + vector volumeAndInertia1 = massProp1.computeMassProperties(); + if (abs(centerOfMass.x - massProp1.getMeshCentroid().x) > epsilon || abs(centerOfMass.y - massProp1.getMeshCentroid().y) > epsilon || + abs(centerOfMass.z - massProp1.getMeshCentroid().z) > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << " " << + centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getMeshCentroid().x << " " << + massProp1.getMeshCentroid().y << " " << massProp1.getMeshCentroid().z << std::endl; + } + + if (abs(volume - volumeAndInertia1.at(0)) > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << + ", actual = " << volumeAndInertia1.at(0) << std::endl; + } + + if (abs(inertia - (volumeAndInertia1.at(1))) > epsilon || abs(inertia - (volumeAndInertia1.at(2))) > epsilon || + abs(inertia - (volumeAndInertia1.at(3))) > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia is incorrect : Expected = " << inertia << " " << + inertia << " " << inertia << ", actual = " << (volumeAndInertia1.at(1)) << " " << (volumeAndInertia1.at(2)) << + " " << (volumeAndInertia1.at(3)) << std::endl; + } +} + +void MeshInfoTests::testWithUnitCube() +{ + glm::vec3 p0(0, 0, 1); + glm::vec3 p1(1, 0, 1); + glm::vec3 p2(0, 1, 1); + glm::vec3 p3(1, 1, 1); + glm::vec3 p4(0, 0, 0); + glm::vec3 p5(1, 0, 0); + glm::vec3 p6(0, 1, 0); + glm::vec3 p7(1, 1, 0); + vector vertices; + vertices.push_back(p0); + vertices.push_back(p1); + vertices.push_back(p2); + vertices.push_back(p3); + vertices.push_back(p4); + vertices.push_back(p5); + vertices.push_back(p6); + vertices.push_back(p7); + vector triangles = { 0, 1, 2, 1, 3, 2, 2, 3, 7, 2, 7, 6, 1, 7, 3, 1, 5, 7, 6, 7, 4, 7, 5, 4, 0, 4, 1, + 1, 4, 5, 2, 6, 4, 0, 2, 4 }; + glm::vec3 centerOfMass(0.5, 0.5, 0.5); + double volume = 1.0; + double side = 1.0; + double inertia = (volume * side * side) / 6.0; //inertia of a unit cube is (mass * side * side) /6 + std::cout << std::setprecision(10); + + //test with origin as reference point + meshinfo::MeshInfo massProp1(&vertices, &triangles); + vector volumeAndInertia1 = massProp1.computeMassProperties(); + if (abs(centerOfMass.x - massProp1.getMeshCentroid().x) > epsilon || abs(centerOfMass.y - massProp1.getMeshCentroid().y) > epsilon || + abs(centerOfMass.z - massProp1.getMeshCentroid().z) > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << + " " << centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getMeshCentroid().x << " " << + massProp1.getMeshCentroid().y << " " << massProp1.getMeshCentroid().z << std::endl; + } + + if (abs(volume - volumeAndInertia1.at(0)) > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << + ", actual = " << volumeAndInertia1.at(0) << std::endl; + } + + if (abs(inertia - (volumeAndInertia1.at(1))) > epsilon || abs(inertia - (volumeAndInertia1.at(2))) > epsilon || + abs(inertia - (volumeAndInertia1.at(3))) > epsilon){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia is incorrect : Expected = " << inertia << " " << + inertia << " " << inertia << ", actual = " << (volumeAndInertia1.at(1)) << " " << (volumeAndInertia1.at(2)) << + " " << (volumeAndInertia1.at(3)) << std::endl; + } +} +void MeshInfoTests::runAllTests(){ + testWithTetrahedron(); + testWithUnitCube(); + testWithCube(); +} \ No newline at end of file diff --git a/tests/physics/src/MassPropertiesTests.h b/tests/physics/src/MeshInfoTests.h similarity index 66% rename from tests/physics/src/MassPropertiesTests.h rename to tests/physics/src/MeshInfoTests.h index 21ab3ccb0a..d4c954b802 100644 --- a/tests/physics/src/MassPropertiesTests.h +++ b/tests/physics/src/MeshInfoTests.h @@ -1,5 +1,5 @@ // -// MassPropertiesTests.h +// MeshInfoTests.h // tests/physics/src // // Created by Virendra Singh on 2015.03.02 @@ -9,13 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_MassPropertiesTests_h -#define hifi_MassPropertiesTests_h -#define epsilion 0.02 -namespace MassPropertiesTests{ +#ifndef hifi_MeshInfoTests_h +#define hifi_MeshInfoTests_h +namespace MeshInfoTests{ void testWithTetrahedron(); void testWithUnitCube(); void testWithCube(); void runAllTests(); } -#endif // hifi_MassPropertiesTests_h \ No newline at end of file +#endif // hifi_MeshInfoTests_h \ No newline at end of file diff --git a/tests/physics/src/main.cpp b/tests/physics/src/main.cpp index d42b5d1241..e7dae7aca5 100644 --- a/tests/physics/src/main.cpp +++ b/tests/physics/src/main.cpp @@ -13,7 +13,7 @@ #include "ShapeInfoTests.h" #include "ShapeManagerTests.h" #include "BulletUtilTests.h" -#include "MassPropertiesTests.h" +#include "MeshInfoTests.h" int main(int argc, char** argv) { ShapeColliderTests::runAllTests(); @@ -21,6 +21,6 @@ int main(int argc, char** argv) { ShapeInfoTests::runAllTests(); ShapeManagerTests::runAllTests(); BulletUtilTests::runAllTests(); - MassPropertiesTests::runAllTests(); + MeshInfoTests::runAllTests(); return 0; } From 84e05e361eed107117b6dd0b290282425f85d17b Mon Sep 17 00:00:00 2001 From: Virendra Singh Date: Fri, 6 Mar 2015 22:07:35 +0530 Subject: [PATCH 09/56] Accuracy improved to 0.01 --- libraries/physics/src/MeshInfo.cpp | 221 ++++++++++++++-------------- libraries/physics/src/MeshInfo.h | 18 +-- tests/physics/src/MeshInfoTests.cpp | 126 ++++++++-------- 3 files changed, 184 insertions(+), 181 deletions(-) diff --git a/libraries/physics/src/MeshInfo.cpp b/libraries/physics/src/MeshInfo.cpp index b406cff269..0d9149cb44 100644 --- a/libraries/physics/src/MeshInfo.cpp +++ b/libraries/physics/src/MeshInfo.cpp @@ -24,137 +24,138 @@ _centerOfMass(Vertex(0.0, 0.0, 0.0)){ MeshInfo::~MeshInfo(){ - _vertices = NULL; - _triangles = NULL; + _vertices = NULL; + _triangles = NULL; } inline Vertex MeshInfo::getCentroid(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const{ - Vertex com; - com.x = (p1.x + p2.x + p3.x + p4.x) / 4.0f; - com.y = (p2.y + p2.y + p3.y + p4.y) / 4.0f; - com.z = (p2.z + p2.z + p3.z + p4.z) / 4.0f; - return com; + Vertex com; + com.x = (p1.x + p2.x + p3.x + p4.x) / 4.0f; + com.y = (p1.y + p2.y + p3.y + p4.y) / 4.0f; + com.z = (p1.z + p2.z + p3.z + p4.z) / 4.0f; + return com; } inline float MeshInfo::getVolume(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const{ - glm::mat4 tet = { glm::vec4(p1.x, p2.x, p3.x, p4.x), glm::vec4(p1.y, p2.y, p3.y, p4.y), glm::vec4(p1.z, p2.z, p3.z, p4.z), - glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) }; - return glm::determinant(tet) / 6.0f; + glm::mat4 tet = { glm::vec4(p1.x, p2.x, p3.x, p4.x), glm::vec4(p1.y, p2.y, p3.y, p4.y), glm::vec4(p1.z, p2.z, p3.z, p4.z), + glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) }; + return glm::determinant(tet) / 6.0f; } Vertex MeshInfo::getMeshCentroid() const{ - return _centerOfMass; + return _centerOfMass; } vector MeshInfo::computeMassProperties(){ - vector volumeAndInertia = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - Vertex p0(0.0, 0.0, 0.0); - float meshVolume = 0.0f; - glm::mat3 globalMomentOfInertia(0.0); - glm::mat3 globalProductOfInertia(0.0); + vector volumeAndInertia = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + Vertex origin(0.0, 0.0, 0.0); + float meshVolume = 0.0f; + glm::mat3 globalMomentOfInertia(0.0); + glm::mat3 globalProductOfInertia(0.0); - //First we need need the center of mass of the mesh in order to translate the tetrahedron inertia to center of mass of the mesh. - for (int i = 0; i < _triangles->size(); i += 3){ - Vertex p1 = _vertices->at(_triangles->at(i)); - Vertex p2 = _vertices->at(_triangles->at(i + 1)); - Vertex p3 = _vertices->at(_triangles->at(i + 2)); - float volume = getVolume(p1, p2, p3, p0); - Vertex com = getCentroid(p0, p1, p2, p3); - //Translate accumulated center of mass from each tetrahedron to mesh's center of mass using parallel axis theorem - meshVolume += volume; - _centerOfMass += com * volume; - } - if (meshVolume == 0){ - return volumeAndInertia; - } - _centerOfMass = (_centerOfMass / (float)meshVolume); + //First we need need the center of mass of the mesh in order to translate the tetrahedron inertia to center of mass of the mesh. + for (unsigned int i = 0; i < _triangles->size(); i += 3){ + Vertex p1 = _vertices->at(_triangles->at(i)); + Vertex p2 = _vertices->at(_triangles->at(i + 1)); + Vertex p3 = _vertices->at(_triangles->at(i + 2)); + float volume = getVolume(p1, p2, p3, origin); + Vertex com = getCentroid(origin, p1, p2, p3); + //Translate accumulated center of mass from each tetrahedron to mesh's center of mass using parallel axis theorem + meshVolume += volume; + _centerOfMass += com * volume; + } + if (meshVolume == 0){ + return volumeAndInertia; + } + _centerOfMass = (_centerOfMass / (float)meshVolume); - //Translate the moment of inertia from each tetrahedron to mesh's center of mass using parallel axis theorem - for (int i = 0; i < _triangles->size(); i += 3){ - Vertex p1 = _vertices->at(_triangles->at(i)); - Vertex p2 = _vertices->at(_triangles->at(i + 1)); - Vertex p3 = _vertices->at(_triangles->at(i + 2)); - float volume = getVolume(p1, p2, p3, p0); - Vertex com = getCentroid(p0, p1, p2, p3); - glm::mat3 identity; - Vertex diff = _centerOfMass - com; - float diffDot = glm::dot(diff, diff); - glm::mat3 outerDiff = glm::outerProduct(diff, diff); - //centroid is used for calculating inertia tensor relative to center of mass. - // translate the tetrahedron to its center of mass using P = P - centroid - p0 = p0 - com; - p1 = p1 - com; - p2 = p2 - com; - p3 = p3 - com; + //Translate the moment of inertia from each tetrahedron to mesh's center of mass using parallel axis theorem + for (unsigned int i = 0; i < _triangles->size(); i += 3){ + Vertex p1 = _vertices->at(_triangles->at(i)); + Vertex p2 = _vertices->at(_triangles->at(i + 1)); + Vertex p3 = _vertices->at(_triangles->at(i + 2)); + float volume = getVolume(p1, p2, p3, origin); + Vertex com = getCentroid(origin, p1, p2, p3); + glm::mat3 identity; + Vertex diff = _centerOfMass - com; + float diffDot = glm::dot(diff, diff); + glm::mat3 outerDiff = glm::outerProduct(diff, diff); + //centroid is used for calculating inertia tensor relative to center of mass. + // translate the tetrahedron to its center of mass using P = P - centroid + Vertex p0 = origin - com; + p1 = p1 - com; + p2 = p2 - com; + p3 = p3 - com; - //Calculate inertia tensor based on Tonon's Formulae given in the paper mentioned below. - //http://docsdrive.com/pdfs/sciencepublications/jmssp/2005/8-11.pdf - //Explicit exact formulas for the 3-D tetrahedron inertia tensor in terms of its vertex coordinates - F.Tonon + //Calculate inertia tensor based on Tonon's Formulae given in the paper mentioned below. + //http://docsdrive.com/pdfs/sciencepublications/jmssp/2005/8-11.pdf + //Explicit exact formulas for the 3-D tetrahedron inertia tensor in terms of its vertex coordinates - F.Tonon - float inertia_a = (volume * 6.0 / 60.0) * ( - p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + - p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + - p2.y*p2.y + p2.y*p3.y + - p3.y*p3.y + - p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + - p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + - p2.z*p2.z + p2.z*p3.z + - p3.z*p3.z); + float inertia_a = (volume * 6.0f / 60.0f) * ( + p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + + p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + + p2.y*p2.y + p2.y*p3.y + + p3.y*p3.y + + p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + + p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + + p2.z*p2.z + p2.z*p3.z + + p3.z*p3.z); - float inertia_b = (volume * 6.0 / 60.0) * ( - p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + - p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + - p2.x*p2.x + p2.x*p3.x + - p3.x*p3.x + - p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + - p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + - p2.z*p2.z + p2.z*p3.z + - p3.z*p3.z); + float inertia_b = (volume * 6.0f / 60.0f) * ( + p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + + p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + + p2.x*p2.x + p2.x*p3.x + + p3.x*p3.x + + p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z + + p1.z*p1.z + p1.z*p2.z + p1.z*p3.z + + p2.z*p2.z + p2.z*p3.z + + p3.z*p3.z); - float inertia_c = (volume * 6.0 / 60.0) * ( - p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + - p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + - p2.x*p2.x + p2.x*p3.x + - p3.x*p3.x + - p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + - p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + - p2.y*p2.y + p2.y*p3.y + - p3.y*p3.y); + float inertia_c = (volume * 6.0f / 60.0f) * ( + p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + + p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + + p2.x*p2.x + p2.x*p3.x + + p3.x*p3.x + + p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + + p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + + p2.y*p2.y + p2.y*p3.y + + p3.y*p3.y); - float inertia_aa = (volume * 6.0 / 120.0) * (2.0 * (p0.y*p0.z + p1.y*p1.z + p2.y*p2.z + p3.y*p3.z) + - p0.y*p1.z + p0.y*p2.z + p0.y*p3.z + - p1.y*p0.z + p1.y*p2.z + p1.y*p3.z + - p2.y*p0.z + p2.y*p1.z + p2.y*p3.z + - p3.y*p0.z + p3.y*p1.z + p3.y*p2.z); + float inertia_aa = (volume * 6.0f / 120.0f) * (2.0f * (p0.y*p0.z + p1.y*p1.z + p2.y*p2.z + p3.y*p3.z) + + p0.y*p1.z + p0.y*p2.z + p0.y*p3.z + + p1.y*p0.z + p1.y*p2.z + p1.y*p3.z + + p2.y*p0.z + p2.y*p1.z + p2.y*p3.z + + p3.y*p0.z + p3.y*p1.z + p3.y*p2.z); - float inertia_bb = (volume * 6.0 / 120.0) * (2.0 * (p0.x*p0.z + p1.x*p1.z + p2.x*p2.z + p3.x*p3.z) + - p0.x*p1.z + p0.x*p2.z + p0.x*p3.z + - p1.x*p0.z + p1.x*p2.z + p1.x*p3.z + - p2.x*p0.z + p2.x*p1.z + p2.x*p3.z + - p3.x*p0.z + p3.x*p1.z + p3.x*p2.z); + float inertia_bb = (volume * 6.0f / 120.0f) * (2.0f * (p0.x*p0.z + p1.x*p1.z + p2.x*p2.z + p3.x*p3.z) + + p0.x*p1.z + p0.x*p2.z + p0.x*p3.z + + p1.x*p0.z + p1.x*p2.z + p1.x*p3.z + + p2.x*p0.z + p2.x*p1.z + p2.x*p3.z + + p3.x*p0.z + p3.x*p1.z + p3.x*p2.z); - float inertia_cc = (volume * 6.0 / 120.0) * (2.0 * (p0.x*p0.y + p1.x*p1.y + p2.x*p2.y + p3.x*p3.y) + - p0.x*p1.y + p0.x*p2.y + p0.x*p3.y + - p1.x*p0.y + p1.x*p2.y + p1.x*p3.y + - p2.x*p0.y + p2.x*p1.y + p2.x*p3.y + - p3.x*p0.y + p3.x*p1.y + p3.x*p2.y); - //3x3 of local inertia tensors of each tetrahedron. Inertia tensors are the diagonal elements - glm::mat3 localMomentInertia = { Vertex(inertia_a, 0.0f, 0.0f), Vertex(0.0f, inertia_b, 0.0f), - Vertex(0.0f, 0.0f, inertia_c) }; - glm::mat3 localProductInertia = { Vertex(inertia_aa, 0.0f, 0.0f), Vertex(0.0f, inertia_bb, 0.0f), - Vertex(0.0f, 0.0f, inertia_cc) }; + float inertia_cc = (volume * 6.0f / 120.0f) * (2.0f * (p0.x*p0.y + p1.x*p1.y + p2.x*p2.y + p3.x*p3.y) + + p0.x*p1.y + p0.x*p2.y + p0.x*p3.y + + p1.x*p0.y + p1.x*p2.y + p1.x*p3.y + + p2.x*p0.y + p2.x*p1.y + p2.x*p3.y + + p3.x*p0.y + p3.x*p1.y + p3.x*p2.y); - //Parallel axis theorem J = I * m[(R.R)*Identity - RxR] where x is outer cross product - globalMomentOfInertia += localMomentInertia + volume * ((diffDot*identity) - outerDiff); - globalProductOfInertia += localProductInertia + volume * ((diffDot * identity) - outerDiff); - } - volumeAndInertia.push_back(meshVolume); - volumeAndInertia.push_back(globalMomentOfInertia[0][0]); - volumeAndInertia.push_back(globalMomentOfInertia[1][1]); - volumeAndInertia.push_back(globalMomentOfInertia[2][2]); - volumeAndInertia.push_back(globalProductOfInertia[0][0]); - volumeAndInertia.push_back(globalProductOfInertia[1][1]); - volumeAndInertia.push_back(globalProductOfInertia[2][2]); - return volumeAndInertia; + //3x3 of local inertia tensors of each tetrahedron. Inertia tensors are the diagonal elements + glm::mat3 localMomentInertia = { Vertex(inertia_a, 0.0f, 0.0f), Vertex(0.0f, inertia_b, 0.0f), + Vertex(0.0f, 0.0f, inertia_c) }; + glm::mat3 localProductInertia = { Vertex(inertia_aa, 0.0f, 0.0f), Vertex(0.0f, inertia_bb, 0.0f), + Vertex(0.0f, 0.0f, inertia_cc) }; + + //Parallel axis theorem J = I * m[(R.R)*Identity - RxR] where x is outer cross product + globalMomentOfInertia += localMomentInertia + volume * ((diffDot*identity) - outerDiff); + globalProductOfInertia += localProductInertia + volume * ((diffDot * identity) - outerDiff); + } + volumeAndInertia[0] = meshVolume; + volumeAndInertia[1] = globalMomentOfInertia[0][0]; + volumeAndInertia[2] = globalMomentOfInertia[1][1]; + volumeAndInertia[3] = globalMomentOfInertia[2][2]; + volumeAndInertia[4] = globalProductOfInertia[0][0]; + volumeAndInertia[5] = globalProductOfInertia[1][1]; + volumeAndInertia[6] = globalProductOfInertia[2][2]; + return volumeAndInertia; } \ No newline at end of file diff --git a/libraries/physics/src/MeshInfo.h b/libraries/physics/src/MeshInfo.h index b400ef9cf0..d267c75ae6 100644 --- a/libraries/physics/src/MeshInfo.h +++ b/libraries/physics/src/MeshInfo.h @@ -16,18 +16,18 @@ using namespace std; namespace meshinfo{ typedef glm::vec3 Vertex; - class MeshInfo{ - private: - inline float getVolume(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const; - vector computeVolumeAndInertia(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const; + class MeshInfo{ + private: + inline float getVolume(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const; + vector computeVolumeAndInertia(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const; public: - vector *_vertices; - Vertex _centerOfMass; - vector *_triangles; + vector *_vertices; + Vertex _centerOfMass; + vector *_triangles; MeshInfo(vector *vertices, vector *triangles); ~MeshInfo(); - inline Vertex getCentroid(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const; - Vertex getMeshCentroid() const; + inline Vertex getCentroid(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const; + Vertex getMeshCentroid() const; vector computeMassProperties(); }; } diff --git a/tests/physics/src/MeshInfoTests.cpp b/tests/physics/src/MeshInfoTests.cpp index 69a6964128..73364b207e 100644 --- a/tests/physics/src/MeshInfoTests.cpp +++ b/tests/physics/src/MeshInfoTests.cpp @@ -14,7 +14,7 @@ #include #include "MeshInfoTests.h" -const double epsilon = 0.02; +const float epsilon = 0.01f; void MeshInfoTests::testWithTetrahedron(){ glm::vec3 p0(8.33220, -11.86875, 0.93355); glm::vec3 p1(0.75523, 5.00000, 16.37072); @@ -22,71 +22,73 @@ void MeshInfoTests::testWithTetrahedron(){ glm::vec3 p3(2.00000, 5.00000, 3.00000); glm::vec3 centroid(15.92492, 0.782813, 3.72962); - //translate the tetrahedron so that its apex is on origin - glm::vec3 p11 = p1 - p0; - glm::vec3 p22 = p2 - p0; - glm::vec3 p33 = p3 - p0; - vector vertices = { p11, p22, p33 }; - vector triangles = { 0, 1, 2 }; + //translate the tetrahedron so that its apex is on origin + glm::vec3 p11 = p1 - p0; + glm::vec3 p22 = p2 - p0; + glm::vec3 p33 = p3 - p0; + vector vertices = { p11, p22, p33 }; + vector triangles = { 0, 1, 2 }; - float volume = 1873.233236; - float inertia_a = 43520.33257; - float inertia_b = 194711.28938; - float inertia_c = 191168.76173; - float inertia_aa = 4417.66150; - float inertia_bb = -46343.16662; - float inertia_cc = 11996.20119; + float volume = 1873.233236f; + float inertia_a = 43520.33257f; + //actual should be 194711.28938f. But for some reason it becomes 194711.296875 during + //runtime due to how floating points are stored. + float inertia_b = 194711.289f; + float inertia_c = 191168.76173f; + float inertia_aa = 4417.66150f; + float inertia_bb = -46343.16662f; + float inertia_cc = 11996.20119f; - meshinfo::MeshInfo meshinfo(&vertices,&triangles); - glm::vec3 tetCenterOfMass = meshinfo.getCentroid(p0, p1, p2, p3); - glm::vec3 diff = centroid - tetCenterOfMass; - vector voumeAndInertia = meshinfo.computeMassProperties(); + meshinfo::MeshInfo meshinfo(&vertices,&triangles); + glm::vec3 tetCenterOfMass = meshinfo.getCentroid(p0, p1, p2, p3); + glm::vec3 diff = centroid - tetCenterOfMass; + vector voumeAndInertia = meshinfo.computeMassProperties(); std::cout << std::setprecision(12); //test if centroid is correct - if (diff.x > epsilon || diff.y > epsilon || diff.z > epsilon){ + if (diff.x > epsilon || diff.y > epsilon || diff.z > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Centroid is incorrect : Expected = " << centroid.x << " " << - centroid.y << " " << centroid.z << ", actual = " << tetCenterOfMass.x << " " << tetCenterOfMass.y << - " " << tetCenterOfMass.z << std::endl; + centroid.y << " " << centroid.z << ", actual = " << tetCenterOfMass.x << " " << tetCenterOfMass.y << + " " << tetCenterOfMass.z << std::endl; } //test if volume is correct - if (abs(volume - voumeAndInertia.at(0)) > epsilon){ + if (abs(volume - voumeAndInertia.at(0)) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << " " << ", actual = " << voumeAndInertia.at(0) << std::endl; } //test if moment of inertia with respect to x axis is correct - if (abs(inertia_a - (voumeAndInertia.at(1))) > epsilon){ + if (abs(inertia_a - (voumeAndInertia.at(1))) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to x axis is incorrect : Expected = " << - inertia_a << " " << ", actual = " << (voumeAndInertia.at(1)) << std::endl; + inertia_a << " " << ", actual = " << voumeAndInertia.at(1) << std::endl; } //test if moment of inertia with respect to y axis is correct - if (abs(inertia_b - (voumeAndInertia.at(2))) > epsilon){ + if (abs(inertia_b - voumeAndInertia.at(2)) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to y axis is incorrect : Expected = " << inertia_b << " " << ", actual = " << (voumeAndInertia.at(2)) << std::endl; } //test if moment of inertia with respect to z axis is correct - if (abs(inertia_c - (voumeAndInertia.at(3))) > epsilon){ + if (abs(inertia_c - (voumeAndInertia.at(3))) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to z axis is incorrect : Expected = " << inertia_c << " " << ", actual = " << (voumeAndInertia.at(3)) << std::endl; } //test if product of inertia with respect to x axis is correct - if (abs(inertia_aa - (voumeAndInertia.at(4))) > epsilon){ + if (abs(inertia_aa - (voumeAndInertia.at(4))) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to x axis is incorrect : Expected = " << inertia_aa << " " << ", actual = " << (voumeAndInertia.at(4)) << std::endl; } //test if product of inertia with respect to y axis is correct - if (abs(inertia_bb - (voumeAndInertia.at(5))) > epsilon){ + if (abs(inertia_bb - (voumeAndInertia.at(5))) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to y axis is incorrect : Expected = " << inertia_bb << " " << ", actual = " << (voumeAndInertia.at(5)) << std::endl; } //test if product of inertia with respect to z axis is correct - if (abs(inertia_cc - (voumeAndInertia.at(6))) > epsilon){ + if (abs(inertia_cc - (voumeAndInertia.at(6))) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to z axis is incorrect : Expected = " << inertia_cc << " " << ", actual = " << (voumeAndInertia.at(6)) << std::endl; } @@ -94,15 +96,15 @@ void MeshInfoTests::testWithTetrahedron(){ } void MeshInfoTests::testWithCube(){ - glm::vec3 p0(1.0, -1.0, -1.0); - glm::vec3 p1(1.0, -1.0, 1.0); - glm::vec3 p2(-1.0, -1.0, 1.0); - glm::vec3 p3(-1.0, -1.0, -1.0); - glm::vec3 p4(1.0, 1.0, -1.0); - glm::vec3 p5(1.0, 1.0, 1.0); - glm::vec3 p6(-1.0, 1.0, 1.0); - glm::vec3 p7(-1.0, 1.0, -1.0); - vector vertices; + glm::vec3 p0(1.0, -1.0, -1.0); + glm::vec3 p1(1.0, -1.0, 1.0); + glm::vec3 p2(-1.0, -1.0, 1.0); + glm::vec3 p3(-1.0, -1.0, -1.0); + glm::vec3 p4(1.0, 1.0, -1.0); + glm::vec3 p5(1.0, 1.0, 1.0); + glm::vec3 p6(-1.0, 1.0, 1.0); + glm::vec3 p7(-1.0, 1.0, -1.0); + vector vertices; vertices.push_back(p0); vertices.push_back(p1); vertices.push_back(p2); @@ -120,22 +122,22 @@ void MeshInfoTests::testWithCube(){ double inertia = (volume * side * side) / 6.0; //inertia of a unit cube is (mass * side * side) /6 //test with origin as reference point - meshinfo::MeshInfo massProp1(&vertices, &triangles); + meshinfo::MeshInfo massProp1(&vertices, &triangles); vector volumeAndInertia1 = massProp1.computeMassProperties(); - if (abs(centerOfMass.x - massProp1.getMeshCentroid().x) > epsilon || abs(centerOfMass.y - massProp1.getMeshCentroid().y) > epsilon || - abs(centerOfMass.z - massProp1.getMeshCentroid().z) > epsilon){ + if (abs(centerOfMass.x - massProp1.getMeshCentroid().x) > epsilon || abs(centerOfMass.y - massProp1.getMeshCentroid().y) > epsilon || + abs(centerOfMass.z - massProp1.getMeshCentroid().z) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << " " << - centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getMeshCentroid().x << " " << - massProp1.getMeshCentroid().y << " " << massProp1.getMeshCentroid().z << std::endl; + centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getMeshCentroid().x << " " << + massProp1.getMeshCentroid().y << " " << massProp1.getMeshCentroid().z << std::endl; } - if (abs(volume - volumeAndInertia1.at(0)) > epsilon){ + if (abs(volume - volumeAndInertia1.at(0)) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << ", actual = " << volumeAndInertia1.at(0) << std::endl; } - if (abs(inertia - (volumeAndInertia1.at(1))) > epsilon || abs(inertia - (volumeAndInertia1.at(2))) > epsilon || - abs(inertia - (volumeAndInertia1.at(3))) > epsilon){ + if (abs(inertia - (volumeAndInertia1.at(1))) > epsilon || abs(inertia - (volumeAndInertia1.at(2))) > epsilon || + abs(inertia - (volumeAndInertia1.at(3))) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia is incorrect : Expected = " << inertia << " " << inertia << " " << inertia << ", actual = " << (volumeAndInertia1.at(1)) << " " << (volumeAndInertia1.at(2)) << " " << (volumeAndInertia1.at(3)) << std::endl; @@ -144,15 +146,15 @@ void MeshInfoTests::testWithCube(){ void MeshInfoTests::testWithUnitCube() { - glm::vec3 p0(0, 0, 1); - glm::vec3 p1(1, 0, 1); - glm::vec3 p2(0, 1, 1); - glm::vec3 p3(1, 1, 1); - glm::vec3 p4(0, 0, 0); - glm::vec3 p5(1, 0, 0); - glm::vec3 p6(0, 1, 0); - glm::vec3 p7(1, 1, 0); - vector vertices; + glm::vec3 p0(0, 0, 1); + glm::vec3 p1(1, 0, 1); + glm::vec3 p2(0, 1, 1); + glm::vec3 p3(1, 1, 1); + glm::vec3 p4(0, 0, 0); + glm::vec3 p5(1, 0, 0); + glm::vec3 p6(0, 1, 0); + glm::vec3 p7(1, 1, 0); + vector vertices; vertices.push_back(p0); vertices.push_back(p1); vertices.push_back(p2); @@ -172,20 +174,20 @@ void MeshInfoTests::testWithUnitCube() //test with origin as reference point meshinfo::MeshInfo massProp1(&vertices, &triangles); vector volumeAndInertia1 = massProp1.computeMassProperties(); - if (abs(centerOfMass.x - massProp1.getMeshCentroid().x) > epsilon || abs(centerOfMass.y - massProp1.getMeshCentroid().y) > epsilon || - abs(centerOfMass.z - massProp1.getMeshCentroid().z) > epsilon){ + if (abs(centerOfMass.x - massProp1.getMeshCentroid().x) > epsilon || abs(centerOfMass.y - massProp1.getMeshCentroid().y) > + epsilon || abs(centerOfMass.z - massProp1.getMeshCentroid().z) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << - " " << centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getMeshCentroid().x << " " << - massProp1.getMeshCentroid().y << " " << massProp1.getMeshCentroid().z << std::endl; + " " << centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getMeshCentroid().x << " " << + massProp1.getMeshCentroid().y << " " << massProp1.getMeshCentroid().z << std::endl; } - if (abs(volume - volumeAndInertia1.at(0)) > epsilon){ + if (abs(volume - volumeAndInertia1.at(0)) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << ", actual = " << volumeAndInertia1.at(0) << std::endl; } - if (abs(inertia - (volumeAndInertia1.at(1))) > epsilon || abs(inertia - (volumeAndInertia1.at(2))) > epsilon || - abs(inertia - (volumeAndInertia1.at(3))) > epsilon){ + if (abs(inertia - (volumeAndInertia1.at(1))) > epsilon || abs(inertia - (volumeAndInertia1.at(2))) > epsilon || + abs(inertia - (volumeAndInertia1.at(3))) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia is incorrect : Expected = " << inertia << " " << inertia << " " << inertia << ", actual = " << (volumeAndInertia1.at(1)) << " " << (volumeAndInertia1.at(2)) << " " << (volumeAndInertia1.at(3)) << std::endl; From c097c6aad2e4c19ef4ec586d5dde7c9fa7077b08 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 6 Mar 2015 10:41:53 -0800 Subject: [PATCH 10/56] Adding the self introspection of shaders --- libraries/gpu/src/gpu/Format.h | 28 +- libraries/gpu/src/gpu/GLBackend.h | 4 + libraries/gpu/src/gpu/GLBackendShader.cpp | 331 ++++++++++++++++++++++ libraries/gpu/src/gpu/Shader.cpp | 21 +- libraries/gpu/src/gpu/Shader.h | 72 +++-- libraries/model/src/model/Stage.cpp | 7 +- libraries/render-utils/src/Model.cpp | 9 + 7 files changed, 428 insertions(+), 44 deletions(-) diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index cbf90384ce..73c3c92c0a 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -53,6 +53,8 @@ enum Type { NUINT8, NUM_TYPES, + + BOOL = UINT8, }; // Array providing the size in bytes for a given scalar type static const int TYPE_SIZE[NUM_TYPES] = { @@ -81,9 +83,9 @@ enum Dimension { VEC2, VEC3, VEC4, + MAT2, MAT3, MAT4, - NUM_DIMENSIONS, }; // Count (of scalars) in an Element for a given Dimension @@ -92,8 +94,9 @@ static const int DIMENSION_COUNT[NUM_DIMENSIONS] = { 2, 3, 4, + 4, 9, - 16 + 16, }; // Semantic of an Element @@ -118,6 +121,27 @@ enum Semantic { SRGBA, SBGRA, + UNIFORM, + + TEXTURE, + BUFFER, + + SAMPLER_1D, + SAMPLER_2D, + SAMPLER_2D_MS, + SAMPLER_3D, + SAMPLER_CUBE, + SAMPLER_1D_ARRAY, + SAMPLER_2D_ARRAY, + SAMPLER_2D_MS_ARRAY, + SAMPLER_3D_ARRAY, + SAMPLER_CUBE_ARRAY, + SAMPLER_2D_SHADOW, + SAMPLER_2D_SHADOW_ARRAY, + SAMPLER_CUBE_SHADOW, + SAMPLER_CUBE_SHADOW_ARRAY, + + NUM_SEMANTICS, }; diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 81271851bb..535d7a3e1f 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -33,6 +33,7 @@ public: static void checkGLError(); + static bool makeShader(Shader& shader); class GLBuffer : public GPUObject { @@ -65,6 +66,9 @@ public: GLuint _shader; GLuint _program; + GLuint _transformCameraSlot = -1; + GLuint _transformObjectSlot = -1; + GLShader(); ~GLShader(); }; diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 4d84d33a5f..724f1ad019 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -10,6 +10,9 @@ // #include "GLBackendShared.h" +#include "Format.h" + +using namespace gpu; GLBackend::GLShader::GLShader() : _shader(0), @@ -25,6 +28,78 @@ GLBackend::GLShader::~GLShader() { } } + +void makeBindings(GLBackend::GLShader* shader) { + if(!shader || !shader->_program) { + return; + } + GLuint glprogram = shader->_program; + GLint loc = -1; + + //Check for gpu specific attribute bindings + loc = glGetAttribLocation(glprogram, "position"); + if (loc >= 0) { + glBindAttribLocation(glprogram, gpu::Stream::POSITION, "position"); + } + + loc = glGetAttribLocation(glprogram, "normal"); + if (loc >= 0) { + glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "normal"); + } + + loc = glGetAttribLocation(glprogram, "color"); + if (loc >= 0) { + glBindAttribLocation(glprogram, gpu::Stream::COLOR, "color"); + } + + loc = glGetAttribLocation(glprogram, "texcoord"); + if (loc >= 0) { + glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "texcoord"); + } + + loc = glGetAttribLocation(glprogram, "tangent"); + if (loc >= 0) { + glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "tangent"); + } + + loc = glGetAttribLocation(glprogram, "texcoord1"); + if (loc >= 0) { + glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD1, "texcoord1"); + } + + loc = glGetAttribLocation(glprogram, "clusterIndices"); + if (loc >= 0) { + glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "clusterIndices"); + } + + loc = glGetAttribLocation(glprogram, "clusterWeights"); + if (loc >= 0) { + glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "clusterWeights"); + } + + //Check for gpu specific uniform bindings + loc = glGetUniformBlockIndex(glprogram, "transformObjectBuffer"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT); + shader->_transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT; + } + + loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT); + shader->_transformCameraSlot = gpu::TRANSFORM_OBJECT_SLOT; + } + + // Link again + glLinkProgram(glprogram); + + GLint linked = 0; + glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); + if (!linked) { + qDebug() << "GLShader::makeBindings - failed to link after assigning bindings?"; + } +} + GLBackend::GLShader* compileShader(const Shader& shader) { // Any GLSLprogram ? normally yes... const std::string& shaderSource = shader.getSource().getCode(); @@ -144,6 +219,8 @@ GLBackend::GLShader* compileShader(const Shader& shader) { object->_shader = glshader; object->_program = glprogram; + makeBindings(object); + return object; } @@ -220,6 +297,8 @@ GLBackend::GLShader* compileProgram(const Shader& program) { object->_shader = 0; object->_program = glprogram; + makeBindings(object); + return object; } @@ -265,3 +344,255 @@ GLuint GLBackend::getShaderID(const ShaderPointer& shader) { } } +Element getFormatFromGLUniform(GLenum gltype) { + switch (gltype) { + case GL_FLOAT: return Element(SCALAR, gpu::FLOAT, UNIFORM); + case GL_FLOAT_VEC2: return Element(VEC2, gpu::FLOAT, UNIFORM); + case GL_FLOAT_VEC3: return Element(VEC3, gpu::FLOAT, UNIFORM); + case GL_FLOAT_VEC4: return Element(VEC4, gpu::FLOAT, UNIFORM); + + case GL_DOUBLE: return Element(SCALAR, gpu::FLOAT, UNIFORM); + case GL_DOUBLE_VEC2: return Element(VEC2, gpu::FLOAT, UNIFORM); + case GL_DOUBLE_VEC3: return Element(VEC3, gpu::FLOAT, UNIFORM); + case GL_DOUBLE_VEC4: return Element(VEC4, gpu::FLOAT, UNIFORM); + + case GL_INT: return Element(SCALAR, gpu::INT32, UNIFORM); + case GL_INT_VEC2: return Element(VEC2, gpu::INT32, UNIFORM); + case GL_INT_VEC3: return Element(VEC3, gpu::INT32, UNIFORM); + case GL_INT_VEC4: return Element(VEC4, gpu::INT32, UNIFORM); + + case GL_UNSIGNED_INT: return Element(SCALAR, gpu::UINT32, UNIFORM); + case GL_UNSIGNED_INT_VEC2: return Element(VEC2, gpu::UINT32, UNIFORM); + case GL_UNSIGNED_INT_VEC3: return Element(VEC3, gpu::UINT32, UNIFORM); + case GL_UNSIGNED_INT_VEC4: return Element(VEC4, gpu::UINT32, UNIFORM); + + case GL_BOOL: return Element(SCALAR, gpu::BOOL, UNIFORM); + case GL_BOOL_VEC2: return Element(VEC2, gpu::BOOL, UNIFORM); + case GL_BOOL_VEC3: return Element(VEC3, gpu::BOOL, UNIFORM); + case GL_BOOL_VEC4: return Element(VEC4, gpu::BOOL, UNIFORM); + + + case GL_FLOAT_MAT2: return Element(gpu::MAT2, gpu::FLOAT, UNIFORM); + case GL_FLOAT_MAT3: return Element(MAT3, gpu::FLOAT, UNIFORM); + case GL_FLOAT_MAT4: return Element(MAT4, gpu::FLOAT, UNIFORM); + +/* {GL_FLOAT_MAT2x3 mat2x3}, + {GL_FLOAT_MAT2x4 mat2x4}, + {GL_FLOAT_MAT3x2 mat3x2}, + {GL_FLOAT_MAT3x4 mat3x4}, + {GL_FLOAT_MAT4x2 mat4x2}, + {GL_FLOAT_MAT4x3 mat4x3}, + {GL_DOUBLE_MAT2 dmat2}, + {GL_DOUBLE_MAT3 dmat3}, + {GL_DOUBLE_MAT4 dmat4}, + {GL_DOUBLE_MAT2x3 dmat2x3}, + {GL_DOUBLE_MAT2x4 dmat2x4}, + {GL_DOUBLE_MAT3x2 dmat3x2}, + {GL_DOUBLE_MAT3x4 dmat3x4}, + {GL_DOUBLE_MAT4x2 dmat4x2}, + {GL_DOUBLE_MAT4x3 dmat4x3}, + */ + + case GL_SAMPLER_1D: return Element(SCALAR, gpu::FLOAT, SAMPLER_1D); + case GL_SAMPLER_2D: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D); + case GL_SAMPLER_2D_MULTISAMPLE: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_MS); + case GL_SAMPLER_3D: return Element(SCALAR, gpu::FLOAT, SAMPLER_3D); + case GL_SAMPLER_CUBE: return Element(SCALAR, gpu::FLOAT, SAMPLER_CUBE); + + case GL_SAMPLER_1D_ARRAY: return Element(SCALAR, gpu::FLOAT, SAMPLER_1D_ARRAY); + case GL_SAMPLER_2D_ARRAY: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_ARRAY); + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_MS_ARRAY); + + case GL_SAMPLER_2D_SHADOW: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_SHADOW); + case GL_SAMPLER_CUBE_SHADOW: return Element(SCALAR, gpu::FLOAT, SAMPLER_CUBE_SHADOW); + + case GL_SAMPLER_2D_ARRAY_SHADOW: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_SHADOW_ARRAY); + +// {GL_SAMPLER_1D_SHADOW sampler1DShadow}, + // {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow}, + +// {GL_SAMPLER_BUFFER samplerBuffer}, +// {GL_SAMPLER_2D_RECT sampler2DRect}, + // {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow}, + + case GL_INT_SAMPLER_1D: return Element(SCALAR, gpu::INT32, SAMPLER_1D); + case GL_INT_SAMPLER_2D: return Element(SCALAR, gpu::INT32, SAMPLER_2D); + case GL_INT_SAMPLER_2D_MULTISAMPLE: return Element(SCALAR, gpu::INT32, SAMPLER_2D_MS); + case GL_INT_SAMPLER_3D: return Element(SCALAR, gpu::INT32, SAMPLER_3D); + case GL_INT_SAMPLER_CUBE: return Element(SCALAR, gpu::INT32, SAMPLER_CUBE); + + case GL_INT_SAMPLER_1D_ARRAY: return Element(SCALAR, gpu::INT32, SAMPLER_1D_ARRAY); + case GL_INT_SAMPLER_2D_ARRAY: return Element(SCALAR, gpu::INT32, SAMPLER_2D_ARRAY); + case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return Element(SCALAR, gpu::INT32, SAMPLER_2D_MS_ARRAY); + + // {GL_INT_SAMPLER_BUFFER isamplerBuffer}, + // {GL_INT_SAMPLER_2D_RECT isampler2DRect}, + + case GL_UNSIGNED_INT_SAMPLER_1D: return Element(SCALAR, gpu::UINT32, SAMPLER_1D); + case GL_UNSIGNED_INT_SAMPLER_2D: return Element(SCALAR, gpu::UINT32, SAMPLER_2D); + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return Element(SCALAR, gpu::UINT32, SAMPLER_2D_MS); + case GL_UNSIGNED_INT_SAMPLER_3D: return Element(SCALAR, gpu::UINT32, SAMPLER_3D); + case GL_UNSIGNED_INT_SAMPLER_CUBE: return Element(SCALAR, gpu::UINT32, SAMPLER_CUBE); + + case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return Element(SCALAR, gpu::UINT32, SAMPLER_1D_ARRAY); + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return Element(SCALAR, gpu::UINT32, SAMPLER_2D_ARRAY); + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return Element(SCALAR, gpu::UINT32, SAMPLER_2D_MS_ARRAY); + +// {GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer}, +// {GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect}, +/* + {GL_IMAGE_1D image1D}, + {GL_IMAGE_2D image2D}, + {GL_IMAGE_3D image3D}, + {GL_IMAGE_2D_RECT image2DRect}, + {GL_IMAGE_CUBE imageCube}, + {GL_IMAGE_BUFFER imageBuffer}, + {GL_IMAGE_1D_ARRAY image1DArray}, + {GL_IMAGE_2D_ARRAY image2DArray}, + {GL_IMAGE_2D_MULTISAMPLE image2DMS}, + {GL_IMAGE_2D_MULTISAMPLE_ARRAY image2DMSArray}, + {GL_INT_IMAGE_1D iimage1D}, + {GL_INT_IMAGE_2D iimage2D}, + {GL_INT_IMAGE_3D iimage3D}, + {GL_INT_IMAGE_2D_RECT iimage2DRect}, + {GL_INT_IMAGE_CUBE iimageCube}, + {GL_INT_IMAGE_BUFFER iimageBuffer}, + {GL_INT_IMAGE_1D_ARRAY iimage1DArray}, + {GL_INT_IMAGE_2D_ARRAY iimage2DArray}, + {GL_INT_IMAGE_2D_MULTISAMPLE iimage2DMS}, + {GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY iimage2DMSArray}, + {GL_UNSIGNED_INT_IMAGE_1D uimage1D}, + {GL_UNSIGNED_INT_IMAGE_2D uimage2D}, + {GL_UNSIGNED_INT_IMAGE_3D uimage3D}, + {GL_UNSIGNED_INT_IMAGE_2D_RECT uimage2DRect}, + {GL_UNSIGNED_INT_IMAGE_CUBE uimageCube},+ [0] {_name="fInnerRadius" _location=0 _element={_semantic=15 '\xf' _dimension=0 '\0' _type=0 '\0' } } gpu::Shader::Slot + + {GL_UNSIGNED_INT_IMAGE_BUFFER uimageBuffer}, + {GL_UNSIGNED_INT_IMAGE_1D_ARRAY uimage1DArray}, + {GL_UNSIGNED_INT_IMAGE_2D_ARRAY uimage2DArray}, + {GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS}, + {GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY uimage2DMSArray}, + {GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint} +*/ + default: + return Element(); + } + +}; + + +int makeUniformSlots(GLuint glprogram, Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) { + GLint uniformsCount = 0; + + glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount); + + for (int i = 0; i < uniformsCount; i++) { + const GLint NAME_LENGTH = 256; + GLchar name[NAME_LENGTH]; + GLint length = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name); + + auto element = getFormatFromGLUniform(type); + uniforms.insert(Shader::Slot(name, i, element)); + } + + return uniformsCount; +} + +int makeUniformBlockSlots(GLuint glprogram, Shader::SlotSet& buffers) { + GLint buffersCount = 0; + + glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount); + + for (int i = 0; i < buffersCount; i++) { + const GLint NAME_LENGTH = 256; + GLchar name[NAME_LENGTH]; + GLint length = 0; + GLint size = 0; + GLenum type = 0; + GLint binding = -1; + glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_BINDING, &binding); + glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &size); + glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length); + glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, name); + + Element element(SCALAR, gpu::FLOAT, BUFFER); + buffers.insert(Shader::Slot(name, binding, element)); + } + + return buffersCount; +} + +int makeInputSlots(GLuint glprogram, Shader::SlotSet& inputs) { + GLint inputsCount = 0; + + glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount); + + for (int i = 0; i < inputsCount; i++) { + const GLint NAME_LENGTH = 256; + GLchar name[NAME_LENGTH]; + GLint length = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name); + + auto element = getFormatFromGLUniform(type); + inputs.insert(Shader::Slot(name, i, element)); + } + + return inputsCount; +} + +int makeOutputSlots(GLuint glprogram, Shader::SlotSet& outputs) { + /* GLint outputsCount = 0; + + glGetProgramiv(glprogram, GL_ACTIVE_, &outputsCount); + + for (int i = 0; i < inputsCount; i++) { + const GLint NAME_LENGTH = 256; + GLchar name[NAME_LENGTH]; + GLint length = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name); + + auto element = getFormatFromGLUniform(type); + outputs.insert(Shader::Slot(name, i, element)); + } + */ + return 0; //inputsCount; +} + +bool GLBackend::makeShader(Shader& shader) { + + // First make sure the SHader has been compiled + GLShader* object = GLBackend::syncGPUObject(shader); + if (!object) { + return false; + } + + if (object->_program) { + Shader::SlotSet uniforms; + Shader::SlotSet textures; + Shader::SlotSet samplers; + makeUniformSlots(object->_program, uniforms, textures, samplers); + + Shader::SlotSet buffers; + makeUniformBlockSlots(object->_program, buffers); + + Shader::SlotSet inputs; + makeInputSlots(object->_program, inputs); + + Shader::SlotSet outputs; + makeOutputSlots(object->_program, outputs); + + shader.defineSlots(uniforms, buffers, textures, samplers, inputs, outputs); + + } else if (object->_shader) { + + } + + return true; +} diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp index 87365e245e..164778b0e2 100755 --- a/libraries/gpu/src/gpu/Shader.cpp +++ b/libraries/gpu/src/gpu/Shader.cpp @@ -33,18 +33,6 @@ Shader::Shader(Type type, Pointer& vertex, Pointer& pixel): Shader::~Shader() { } - -/* -Program::Program(): - _storage(), - _type(GRAPHICS) -{ -} - -Program::~Program() -{ -} -*/ Shader* Shader::createVertex(const Source& source) { Shader* shader = new Shader(VERTEX, source); @@ -65,3 +53,12 @@ Shader* Shader::createProgram(Pointer& vertexShader, Pointer& pixelShader) { } return nullptr; } + +void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& buffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) { + _uniforms = uniforms; + _buffers = buffers; + _textures = textures; + _samplers = samplers; + _inputs = inputs; + _outputs = outputs; +} diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index 57177639ae..3a374d91c8 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -13,6 +13,7 @@ #include "Resource.h" #include +#include namespace gpu { @@ -40,6 +41,24 @@ public: Language _lang = GLSL; }; + class Slot { + public: + + std::string _name; + uint16 _location; + Element _element; + + Slot(const std::string& name, uint16 location, const Element& element) : _name(name), _location(location), _element(element) {} + + + class Less { + public: + bool operator() (const Slot& x, const Slot& y) const { return x._name < y._name; } + }; + }; + typedef std::set SlotSet; + + enum Type { VERTEX = 0, PIXEL, @@ -65,6 +84,22 @@ public: const Shaders& getShaders() const { return _shaders; } + // Access the exposed uniform, input and output slot + const SlotSet& getUniforms() const { return _uniforms; } + const SlotSet& getBuffers() const { return _buffers; } + const SlotSet& getTextures() const { return _textures; } + const SlotSet& getSamplers() const { return _samplers; } + const SlotSet& getInputs() const { return _inputs; } + const SlotSet& getOutputs() const { return _outputs; } + + // Define the list of uniforms, inputs and outputs for the shader + // This call is intendend to build the list of exposed slots in order + // to correctly bind resource to the shader. + // These can be build "manually" from knowledge of the atual shader code + // or automatically by calling "Context::makeShader()", this is the preferred way + void defineSlots(const SlotSet& uniforms, const SlotSet& buffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs); + + protected: Shader(Type type, const Source& source); Shader(Type type, Pointer& vertex, Pointer& pixel); @@ -78,6 +113,14 @@ protected: // if shader is composed of sub shaders, here they are Shaders _shaders; + // List of exposed uniform, input and output slots + SlotSet _uniforms; + SlotSet _buffers; + SlotSet _textures; + SlotSet _samplers; + SlotSet _inputs; + SlotSet _outputs; + // The type of the shader, the master key Type _type; @@ -91,35 +134,6 @@ protected: typedef Shader::Pointer ShaderPointer; typedef std::vector< ShaderPointer > Shaders; -/* -class Program { -public: - - enum Type { - GRAPHICS = 0, - - NUM_TYPES, - }; - - - Program(); - Program(const Program& program); // deep copy of the sysmem shader - Program& operator=(const Program& program); // deep copy of the sysmem texture - ~Program(); - -protected: - Shaders _shaders; - Type _type; - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = NULL; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; -}; - -typedef QSharedPointer ShaderPointer; -*/ }; diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 9a68779caf..1ebb2e6ece 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -216,8 +216,13 @@ void SunSkyStage::updateGraphicsObject() const { double originAlt = _earthSunModel.getAltitude(); _sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f)); - GLuint program = gpu::GLBackend::getShaderID(_skyShader); + GLuint program = gpu::GLBackend::getShaderID(_skyShader); + static int firstTime = 0; + if (firstTime == 0) { + firstTime++; + gpu::GLBackend::makeShader(*_skyShader); + } } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index c7e5b71b22..3fcf181812 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -299,6 +299,15 @@ void Model::init() { _program.addShaderFromSourceCode(QGLShader::Fragment, model_frag); initProgram(_program, _locations); + + auto defaultShader = gpu::ShaderPointer( + gpu::Shader::createProgram( + gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert))), + gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_frag))) + ) + ); + gpu::GLBackend::makeShader(*defaultShader); + _normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); _normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); initProgram(_normalMapProgram, _normalMapLocations); From 22d9ff278815c88afbbbff56a7b721468ea5501b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 6 Mar 2015 14:36:08 -0800 Subject: [PATCH 11/56] Show/hide menu bar in non-VR fullscreen --- interface/src/Application.cpp | 53 +++++++++++++++++++++++++++++++++-- interface/src/Application.h | 3 ++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6484e364bc..0e989e8e12 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -459,6 +459,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // enable mouse tracking; otherwise, we only get drag events _glWidget->setMouseTracking(true); + _fullscreenMenuWidget->setParent(_glWidget); + _toolWindow = new ToolWindow(); _toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint); _toolWindow->setWindowTitle("Tools"); @@ -1258,6 +1260,18 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { return; } + if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen) + && !Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { + // Show/hide menu bar in fullscreen + if (event->globalY() > _menuBarHeight) { + _fullscreenMenuWidget->setFixedHeight(0); + Menu::getInstance()->setFixedHeight(0); + } else { + _fullscreenMenuWidget->setFixedHeight(_menuBarHeight); + Menu::getInstance()->setFixedHeight(_menuBarHeight); + } + } + _entities.mouseMoveEvent(event, deviceID); _controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts @@ -1523,14 +1537,47 @@ void Application::setFullscreen(bool fullscreen) { if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { if (fullscreen) { - // Menu show() after hide() doesn't work with Rift VR display so set height instead. + // Menu hide() disables menu commands, and show() after hide() doesn't work with Rift VR display. + // So set height instead. _window->menuBar()->setMaximumHeight(0); } else { _window->menuBar()->setMaximumHeight(QWIDGETSIZE_MAX); } + } else { + if (fullscreen) { + // Move menu to a QWidget floating above _glWidget so that show/hide doesn't adjust viewport. + _menuBarHeight = Menu::getInstance()->height(); + Menu::getInstance()->setParent(_fullscreenMenuWidget); + Menu::getInstance()->setFixedWidth(_window->windowHandle()->screen()->size().width()); + _fullscreenMenuWidget->show(); + } else { + // Restore menu to being part of MainWindow. + _fullscreenMenuWidget->hide(); + _window->setMenuBar(Menu::getInstance()); + _window->menuBar()->setMaximumHeight(QWIDGETSIZE_MAX); + } } - _window->setWindowState(fullscreen ? (_window->windowState() | Qt::WindowFullScreen) : - (_window->windowState() & ~Qt::WindowFullScreen)); + + // Work around Qt bug that prevents floating menus being shown when in fullscreen mode. + // https://bugreports.qt.io/browse/QTBUG-41883 + // Known issue: Top-level menu items don't highlight when cursor hovers. This is probably a side-effect of the work-around. + // TODO: Remove this work-around once the bug has been fixed and restore the following lines. + //_window->setWindowState(fullscreen ? (_window->windowState() | Qt::WindowFullScreen) : + // (_window->windowState() & ~Qt::WindowFullScreen)); + _window->hide(); + if (fullscreen) { + _window->setWindowState(_window->windowState() | Qt::WindowFullScreen); + // The next line produces the following warning in the log: + // [WARNING][03 / 06 12:17 : 58] QWidget::setMinimumSize: (/ MainWindow) Negative sizes + // (0, -1) are not possible + // This is better than the alternative which is to have the window slightly less than fullscreen with a visible line + // of pixels for the remainder of the screen. + _window->setContentsMargins(0, 0, 0, -1); + } else { + _window->setWindowState(_window->windowState() & ~Qt::WindowFullScreen); + _window->setContentsMargins(0, 0, 0, 0); + } + if (!_aboutToQuit) { _window->show(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 91a5f7547b..17551ef3db 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -584,6 +584,9 @@ private: QTimer _settingsTimer; GLCanvas* _glWidget = new GLCanvas(); // our GLCanvas has a couple extra features + + QWidget* _fullscreenMenuWidget = new QWidget(); + int _menuBarHeight; }; #endif // hifi_Application_h From 032896f75c69f0bb9b1aa1f4f537034996e94036 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 6 Mar 2015 14:57:27 -0800 Subject: [PATCH 12/56] Fix starting up fullscreen --- interface/src/Application.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0e989e8e12..410d9c629f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -460,6 +460,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _glWidget->setMouseTracking(true); _fullscreenMenuWidget->setParent(_glWidget); + _menuBarHeight = Menu::getInstance()->height(); + if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) { + setFullscreen(true); // Initialize menu bar show/hide + } _toolWindow = new ToolWindow(); _toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint); From 23a6326aa175e696e1b8f611dcd99e9e66a11499 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sun, 8 Mar 2015 10:53:29 -0700 Subject: [PATCH 13/56] testing the shader features in Model and refining the shader making workflow --- libraries/gpu/src/gpu/Context.cpp | 11 + libraries/gpu/src/gpu/Context.h | 9 + libraries/gpu/src/gpu/Format.h | 22 +- libraries/gpu/src/gpu/GLBackend.h | 2 +- libraries/gpu/src/gpu/GLBackendShader.cpp | 244 ++++++++++++++-------- libraries/gpu/src/gpu/Resource.h | 12 ++ libraries/gpu/src/gpu/Shader.cpp | 9 + libraries/gpu/src/gpu/Shader.h | 43 +++- libraries/model/src/model/Stage.cpp | 3 +- libraries/render-utils/src/Model.cpp | 91 +++++++- libraries/render-utils/src/Model.h | 1 + 11 files changed, 326 insertions(+), 121 deletions(-) diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 85227e0557..54387e8f71 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -10,3 +10,14 @@ // #include "Context.h" +// this include should disappear! as soon as the gpu::Context is in place +#include "GLBackend.h" + +using namespace gpu; + +bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) { + if (shader.isProgram()) { + return GLBackend::makeProgram(shader, bindings); + } + return false; +} \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 632c5f96de..ecff65fd8d 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -92,8 +92,17 @@ public: void enqueueBatch(Batch& batch); + + protected: + // This function can only be called by "static Shader::makeProgram()" + // makeProgramShader(...) make a program shader ready to be used in a Batch. + // It compiles the sub shaders, link them and defines the Slots and their bindings. + // If the shader passed is not a program, nothing happens. + static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet()); + + friend class Shader; }; diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 73c3c92c0a..8a754bb564 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -122,24 +122,10 @@ enum Semantic { SBGRA, UNIFORM, - - TEXTURE, - BUFFER, - - SAMPLER_1D, - SAMPLER_2D, - SAMPLER_2D_MS, - SAMPLER_3D, - SAMPLER_CUBE, - SAMPLER_1D_ARRAY, - SAMPLER_2D_ARRAY, - SAMPLER_2D_MS_ARRAY, - SAMPLER_3D_ARRAY, - SAMPLER_CUBE_ARRAY, - SAMPLER_2D_SHADOW, - SAMPLER_2D_SHADOW_ARRAY, - SAMPLER_CUBE_SHADOW, - SAMPLER_CUBE_SHADOW_ARRAY, + UNIFORM_BUFFER, + SAMPLER, + SAMPLER_MULTISAMPLE, + SAMPLER_SHADOW, NUM_SEMANTICS, diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 535d7a3e1f..974bb6fb8b 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -33,7 +33,7 @@ public: static void checkGLError(); - static bool makeShader(Shader& shader); + static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet()); class GLBuffer : public GPUObject { diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 724f1ad019..5136461f5c 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -28,7 +28,6 @@ GLBackend::GLShader::~GLShader() { } } - void makeBindings(GLBackend::GLShader* shader) { if(!shader || !shader->_program) { return; @@ -36,7 +35,7 @@ void makeBindings(GLBackend::GLShader* shader) { GLuint glprogram = shader->_program; GLint loc = -1; - //Check for gpu specific attribute bindings + //Check for gpu specific attribute slotBindings loc = glGetAttribLocation(glprogram, "position"); if (loc >= 0) { glBindAttribLocation(glprogram, gpu::Stream::POSITION, "position"); @@ -77,7 +76,18 @@ void makeBindings(GLBackend::GLShader* shader) { glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "clusterWeights"); } - //Check for gpu specific uniform bindings + // Link again to take into account the assigned attrib location + glLinkProgram(glprogram); + + GLint linked = 0; + glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); + if (!linked) { + qDebug() << "GLShader::makeBindings - failed to link after assigning slotBindings?"; + } + + // now assign the ubo binding, then DON't relink! + + //Check for gpu specific uniform slotBindings loc = glGetUniformBlockIndex(glprogram, "transformObjectBuffer"); if (loc >= 0) { glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT); @@ -90,14 +100,6 @@ void makeBindings(GLBackend::GLShader* shader) { shader->_transformCameraSlot = gpu::TRANSFORM_OBJECT_SLOT; } - // Link again - glLinkProgram(glprogram); - - GLint linked = 0; - glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); - if (!linked) { - qDebug() << "GLShader::makeBindings - failed to link after assigning bindings?"; - } } GLBackend::GLShader* compileShader(const Shader& shader) { @@ -344,37 +346,45 @@ GLuint GLBackend::getShaderID(const ShaderPointer& shader) { } } -Element getFormatFromGLUniform(GLenum gltype) { +class ElementResource { +public: + gpu::Element _element; + uint16 _resource; + + ElementResource(Element&& elem, uint16 resource) : _element(elem), _resource(resource) {} +}; + +ElementResource getFormatFromGLUniform(GLenum gltype) { switch (gltype) { - case GL_FLOAT: return Element(SCALAR, gpu::FLOAT, UNIFORM); - case GL_FLOAT_VEC2: return Element(VEC2, gpu::FLOAT, UNIFORM); - case GL_FLOAT_VEC3: return Element(VEC3, gpu::FLOAT, UNIFORM); - case GL_FLOAT_VEC4: return Element(VEC4, gpu::FLOAT, UNIFORM); + case GL_FLOAT: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER); - case GL_DOUBLE: return Element(SCALAR, gpu::FLOAT, UNIFORM); - case GL_DOUBLE_VEC2: return Element(VEC2, gpu::FLOAT, UNIFORM); - case GL_DOUBLE_VEC3: return Element(VEC3, gpu::FLOAT, UNIFORM); - case GL_DOUBLE_VEC4: return Element(VEC4, gpu::FLOAT, UNIFORM); + case GL_DOUBLE: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_DOUBLE_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_DOUBLE_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_DOUBLE_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER); - case GL_INT: return Element(SCALAR, gpu::INT32, UNIFORM); - case GL_INT_VEC2: return Element(VEC2, gpu::INT32, UNIFORM); - case GL_INT_VEC3: return Element(VEC3, gpu::INT32, UNIFORM); - case GL_INT_VEC4: return Element(VEC4, gpu::INT32, UNIFORM); + case GL_INT: return ElementResource(Element(SCALAR, gpu::INT32, UNIFORM), Resource::BUFFER); + case GL_INT_VEC2: return ElementResource(Element(VEC2, gpu::INT32, UNIFORM), Resource::BUFFER); + case GL_INT_VEC3: return ElementResource(Element(VEC3, gpu::INT32, UNIFORM), Resource::BUFFER); + case GL_INT_VEC4: return ElementResource(Element(VEC4, gpu::INT32, UNIFORM), Resource::BUFFER); - case GL_UNSIGNED_INT: return Element(SCALAR, gpu::UINT32, UNIFORM); - case GL_UNSIGNED_INT_VEC2: return Element(VEC2, gpu::UINT32, UNIFORM); - case GL_UNSIGNED_INT_VEC3: return Element(VEC3, gpu::UINT32, UNIFORM); - case GL_UNSIGNED_INT_VEC4: return Element(VEC4, gpu::UINT32, UNIFORM); + case GL_UNSIGNED_INT: return ElementResource(Element(SCALAR, gpu::UINT32, UNIFORM), Resource::BUFFER); + case GL_UNSIGNED_INT_VEC2: return ElementResource(Element(VEC2, gpu::UINT32, UNIFORM), Resource::BUFFER); + case GL_UNSIGNED_INT_VEC3: return ElementResource(Element(VEC3, gpu::UINT32, UNIFORM), Resource::BUFFER); + case GL_UNSIGNED_INT_VEC4: return ElementResource(Element(VEC4, gpu::UINT32, UNIFORM), Resource::BUFFER); - case GL_BOOL: return Element(SCALAR, gpu::BOOL, UNIFORM); - case GL_BOOL_VEC2: return Element(VEC2, gpu::BOOL, UNIFORM); - case GL_BOOL_VEC3: return Element(VEC3, gpu::BOOL, UNIFORM); - case GL_BOOL_VEC4: return Element(VEC4, gpu::BOOL, UNIFORM); + case GL_BOOL: return ElementResource(Element(SCALAR, gpu::BOOL, UNIFORM), Resource::BUFFER); + case GL_BOOL_VEC2: return ElementResource(Element(VEC2, gpu::BOOL, UNIFORM), Resource::BUFFER); + case GL_BOOL_VEC3: return ElementResource(Element(VEC3, gpu::BOOL, UNIFORM), Resource::BUFFER); + case GL_BOOL_VEC4: return ElementResource(Element(VEC4, gpu::BOOL, UNIFORM), Resource::BUFFER); - case GL_FLOAT_MAT2: return Element(gpu::MAT2, gpu::FLOAT, UNIFORM); - case GL_FLOAT_MAT3: return Element(MAT3, gpu::FLOAT, UNIFORM); - case GL_FLOAT_MAT4: return Element(MAT4, gpu::FLOAT, UNIFORM); + case GL_FLOAT_MAT2: return ElementResource(Element(gpu::MAT2, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_MAT3: return ElementResource(Element(MAT3, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_MAT4: return ElementResource(Element(MAT4, gpu::FLOAT, UNIFORM), Resource::BUFFER); /* {GL_FLOAT_MAT2x3 mat2x3}, {GL_FLOAT_MAT2x4 mat2x4}, @@ -393,20 +403,20 @@ Element getFormatFromGLUniform(GLenum gltype) { {GL_DOUBLE_MAT4x3 dmat4x3}, */ - case GL_SAMPLER_1D: return Element(SCALAR, gpu::FLOAT, SAMPLER_1D); - case GL_SAMPLER_2D: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D); - case GL_SAMPLER_2D_MULTISAMPLE: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_MS); - case GL_SAMPLER_3D: return Element(SCALAR, gpu::FLOAT, SAMPLER_3D); - case GL_SAMPLER_CUBE: return Element(SCALAR, gpu::FLOAT, SAMPLER_CUBE); + case GL_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D); + case GL_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D); + case GL_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); + case GL_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_3D); + case GL_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_CUBE); - case GL_SAMPLER_1D_ARRAY: return Element(SCALAR, gpu::FLOAT, SAMPLER_1D_ARRAY); - case GL_SAMPLER_2D_ARRAY: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_ARRAY); - case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_MS_ARRAY); + case GL_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D_ARRAY); + case GL_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D_ARRAY); + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); - case GL_SAMPLER_2D_SHADOW: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_SHADOW); - case GL_SAMPLER_CUBE_SHADOW: return Element(SCALAR, gpu::FLOAT, SAMPLER_CUBE_SHADOW); + case GL_SAMPLER_2D_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D); + case GL_SAMPLER_CUBE_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_CUBE); - case GL_SAMPLER_2D_ARRAY_SHADOW: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_SHADOW_ARRAY); + case GL_SAMPLER_2D_ARRAY_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D_ARRAY); // {GL_SAMPLER_1D_SHADOW sampler1DShadow}, // {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow}, @@ -415,28 +425,28 @@ Element getFormatFromGLUniform(GLenum gltype) { // {GL_SAMPLER_2D_RECT sampler2DRect}, // {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow}, - case GL_INT_SAMPLER_1D: return Element(SCALAR, gpu::INT32, SAMPLER_1D); - case GL_INT_SAMPLER_2D: return Element(SCALAR, gpu::INT32, SAMPLER_2D); - case GL_INT_SAMPLER_2D_MULTISAMPLE: return Element(SCALAR, gpu::INT32, SAMPLER_2D_MS); - case GL_INT_SAMPLER_3D: return Element(SCALAR, gpu::INT32, SAMPLER_3D); - case GL_INT_SAMPLER_CUBE: return Element(SCALAR, gpu::INT32, SAMPLER_CUBE); + case GL_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D); + case GL_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D); + case GL_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); + case GL_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_3D); + case GL_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_CUBE); - case GL_INT_SAMPLER_1D_ARRAY: return Element(SCALAR, gpu::INT32, SAMPLER_1D_ARRAY); - case GL_INT_SAMPLER_2D_ARRAY: return Element(SCALAR, gpu::INT32, SAMPLER_2D_ARRAY); - case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return Element(SCALAR, gpu::INT32, SAMPLER_2D_MS_ARRAY); + case GL_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D_ARRAY); + case GL_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D_ARRAY); + case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); // {GL_INT_SAMPLER_BUFFER isamplerBuffer}, // {GL_INT_SAMPLER_2D_RECT isampler2DRect}, - case GL_UNSIGNED_INT_SAMPLER_1D: return Element(SCALAR, gpu::UINT32, SAMPLER_1D); - case GL_UNSIGNED_INT_SAMPLER_2D: return Element(SCALAR, gpu::UINT32, SAMPLER_2D); - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return Element(SCALAR, gpu::UINT32, SAMPLER_2D_MS); - case GL_UNSIGNED_INT_SAMPLER_3D: return Element(SCALAR, gpu::UINT32, SAMPLER_3D); - case GL_UNSIGNED_INT_SAMPLER_CUBE: return Element(SCALAR, gpu::UINT32, SAMPLER_CUBE); + case GL_UNSIGNED_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D); + case GL_UNSIGNED_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D); + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); + case GL_UNSIGNED_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_3D); + case GL_UNSIGNED_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_CUBE); - case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return Element(SCALAR, gpu::UINT32, SAMPLER_1D_ARRAY); - case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return Element(SCALAR, gpu::UINT32, SAMPLER_2D_ARRAY); - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return Element(SCALAR, gpu::UINT32, SAMPLER_2D_MS_ARRAY); + case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D_ARRAY); + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D_ARRAY); + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); // {GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer}, // {GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect}, @@ -475,13 +485,13 @@ Element getFormatFromGLUniform(GLenum gltype) { {GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint} */ default: - return Element(); + return ElementResource(Element(), Resource::BUFFER); } }; -int makeUniformSlots(GLuint glprogram, Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) { +int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) { GLint uniformsCount = 0; glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount); @@ -493,19 +503,56 @@ int makeUniformSlots(GLuint glprogram, Shader::SlotSet& uniforms, Shader::SlotSe GLint size = 0; GLenum type = 0; glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name); + GLint location = glGetUniformLocation(glprogram, name); + const GLint INVALID_UNIFORM_LOCATION = -1; - auto element = getFormatFromGLUniform(type); - uniforms.insert(Shader::Slot(name, i, element)); + // Try to make sense of the gltype + auto elementResource = getFormatFromGLUniform(type); + + // The uniform as a standard var type + if (location != INVALID_UNIFORM_LOCATION) { + if (elementResource._resource == Resource::BUFFER) { + uniforms.insert(Shader::Slot(name, location, elementResource._element, elementResource._resource)); + } else { + // For texture/Sampler, the location is the actual binding value + GLint binding = -1; + glGetUniformiv(glprogram, location, &binding); + + auto requestedBinding = slotBindings.find(std::string(name)); + if (requestedBinding != slotBindings.end()) { + if (binding != (*requestedBinding)._location) { + binding = (*requestedBinding)._location; + glUniform1i(location, binding); + } + } + + textures.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); + samplers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); + } + } } return uniformsCount; } -int makeUniformBlockSlots(GLuint glprogram, Shader::SlotSet& buffers) { - GLint buffersCount = 0; +const GLint UNUSED_SLOT = -1; +bool isUnusedSlot(GLint binding) { + return (binding == UNUSED_SLOT); +} +int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) { + GLint buffersCount = 0; glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount); + // fast exit + if (buffersCount == 0) { + return 0; + } + + GLint maxNumUniformBufferSlots = 0; + glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxNumUniformBufferSlots); + std::vector uniformBufferSlotMap(maxNumUniformBufferSlots, -1); + for (int i = 0; i < buffersCount; i++) { const GLint NAME_LENGTH = 256; GLchar name[NAME_LENGTH]; @@ -513,19 +560,46 @@ int makeUniformBlockSlots(GLuint glprogram, Shader::SlotSet& buffers) { GLint size = 0; GLenum type = 0; GLint binding = -1; - glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_BINDING, &binding); - glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &size); + glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length); glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, name); + glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_BINDING, &binding); + glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &size); + + GLuint blockIndex = glGetUniformBlockIndex(glprogram, name); - Element element(SCALAR, gpu::FLOAT, BUFFER); - buffers.insert(Shader::Slot(name, binding, element)); + // CHeck if there is a requested binding for this block + auto requestedBinding = slotBindings.find(std::string(name)); + if (requestedBinding != slotBindings.end()) { + // If yes force it + if (binding != (*requestedBinding)._location) { + binding = (*requestedBinding)._location; + glUniformBlockBinding(glprogram, blockIndex, binding); + } + } else if (binding == 0) { + // If no binding was assigned then just do it finding a free slot + auto slotIt = std::find_if(uniformBufferSlotMap.begin(), uniformBufferSlotMap.end(), isUnusedSlot); + if (slotIt != uniformBufferSlotMap.end()) { + binding = slotIt - uniformBufferSlotMap.begin(); + glUniformBlockBinding(glprogram, blockIndex, binding); + } else { + // This should neve happen, an active ubo cannot find an available slot among the max available?! + binding = -1; + } + } + // If binding is valid record it + if (binding >= 0) { + uniformBufferSlotMap[binding] = blockIndex; + } + + Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER); + buffers.insert(Shader::Slot(name, binding, element, Resource::BUFFER)); } return buffersCount; } -int makeInputSlots(GLuint glprogram, Shader::SlotSet& inputs) { +int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) { GLint inputsCount = 0; glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount); @@ -538,14 +612,16 @@ int makeInputSlots(GLuint glprogram, Shader::SlotSet& inputs) { GLenum type = 0; glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name); - auto element = getFormatFromGLUniform(type); - inputs.insert(Shader::Slot(name, i, element)); + GLint binding = glGetAttribLocation(glprogram, name); + + auto elementResource = getFormatFromGLUniform(type); + inputs.insert(Shader::Slot(name, binding, elementResource._element, -1)); } return inputsCount; } -int makeOutputSlots(GLuint glprogram, Shader::SlotSet& outputs) { +int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs) { /* GLint outputsCount = 0; glGetProgramiv(glprogram, GL_ACTIVE_, &outputsCount); @@ -565,28 +641,28 @@ int makeOutputSlots(GLuint glprogram, Shader::SlotSet& outputs) { return 0; //inputsCount; } -bool GLBackend::makeShader(Shader& shader) { +bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) { - // First make sure the SHader has been compiled + // First make sure the Shader has been compiled GLShader* object = GLBackend::syncGPUObject(shader); if (!object) { return false; } if (object->_program) { + Shader::SlotSet buffers; + makeUniformBlockSlots(object->_program, slotBindings, buffers); + Shader::SlotSet uniforms; Shader::SlotSet textures; Shader::SlotSet samplers; - makeUniformSlots(object->_program, uniforms, textures, samplers); - - Shader::SlotSet buffers; - makeUniformBlockSlots(object->_program, buffers); + makeUniformSlots(object->_program, slotBindings, uniforms, textures, samplers); Shader::SlotSet inputs; - makeInputSlots(object->_program, inputs); + makeInputSlots(object->_program, slotBindings, inputs); Shader::SlotSet outputs; - makeOutputSlots(object->_program, outputs); + makeOutputSlots(object->_program, slotBindings, outputs); shader.defineSlots(uniforms, buffers, textures, samplers, inputs, outputs); diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index 225e3fd927..3da25ae78f 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -38,6 +38,18 @@ public: // The size in bytes of data stored in the resource virtual Size getSize() const = 0; + enum Type { + BUFFER = 0, + TEXTURE_1D, + TEXTURE_2D, + TEXTURE_3D, + TEXTURE_CUBE, + TEXTURE_1D_ARRAY, + TEXTURE_2D_ARRAY, + TEXTURE_3D_ARRAY, + TEXTURE_CUBE_ARRAY, + }; + protected: Resource() {} diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp index 164778b0e2..59838fae9c 100755 --- a/libraries/gpu/src/gpu/Shader.cpp +++ b/libraries/gpu/src/gpu/Shader.cpp @@ -13,6 +13,8 @@ #include #include +#include "Context.h" + using namespace gpu; Shader::Shader(Type type, const Source& source): @@ -62,3 +64,10 @@ void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& buffers, const _inputs = inputs; _outputs = outputs; } + +bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings) { + if (shader.isProgram()) { + return Context::makeProgram(shader, bindings); + } + return false; +} diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index 3a374d91c8..9a5bec313b 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -45,18 +45,28 @@ public: public: std::string _name; - uint16 _location; + uint32 _location; Element _element; + uint16 _resourceType; - Slot(const std::string& name, uint16 location, const Element& element) : _name(name), _location(location), _element(element) {} + Slot(const std::string& name, uint16 location, const Element& element, uint16 resourceType = Resource::BUFFER) : + _name(name), _location(location), _element(element), _resourceType(resourceType) {} - - class Less { - public: - bool operator() (const Slot& x, const Slot& y) const { return x._name < y._name; } - }; }; - typedef std::set SlotSet; + + class Binding { + public: + std::string _name; + uint32 _location; + Binding(const std::string&& name, uint32 loc = 0) : _name(name), _location(loc) {} + }; + + template class Less { + public: + bool operator() (const T& x, const T& y) const { return x._name < y._name; } + }; + typedef std::set> SlotSet; + typedef std::set> BindingSet; enum Type { @@ -89,6 +99,7 @@ public: const SlotSet& getBuffers() const { return _buffers; } const SlotSet& getTextures() const { return _textures; } const SlotSet& getSamplers() const { return _samplers; } + const SlotSet& getInputs() const { return _inputs; } const SlotSet& getOutputs() const { return _outputs; } @@ -96,9 +107,23 @@ public: // This call is intendend to build the list of exposed slots in order // to correctly bind resource to the shader. // These can be build "manually" from knowledge of the atual shader code - // or automatically by calling "Context::makeShader()", this is the preferred way + // or automatically by calling "makeShader()", this is the preferred way void defineSlots(const SlotSet& uniforms, const SlotSet& buffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs); + // makeProgram(...) make a program shader ready to be used in a Batch. + // It compiles the sub shaders, link them and defines the Slots and their bindings. + // If the shader passed is not a program, nothing happens. + // + // It is possible to provide a set of slot bindings (from the name of the slot to a unit number) allowing + // to make sure slots with the same semantics can be always bound on the same location from shader to shader. + // For example, the "diffuseMap" can always be bound to texture unit #1 for different shaders by specifying a Binding("diffuseMap", 1) + // + // As of now (03/2015), the call to makeProgram is in fact calling gpu::Context::makeProgram and does rely + // on the underneath gpu::Context::Backend available. Since we only support glsl, this means that it relies + // on a glContext and the driver to compile the glsl shader. + // Hoppefully in a few years the shader compilation will be completely abstracted in a separate shader compiler library + // independant of the graphics api in use underneath (looking at you opengl & vulkan). + static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet()); protected: Shader(Type type, const Source& source); diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 1ebb2e6ece..d470d841bc 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -15,6 +15,7 @@ #include "SkyFromAtmosphere_vert.h" #include "SkyFromAtmosphere_frag.h" +#include "gpu/Context.h" #include "gpu/GLBackend.h" using namespace model; @@ -221,7 +222,7 @@ void SunSkyStage::updateGraphicsObject() const { static int firstTime = 0; if (firstTime == 0) { firstTime++; - gpu::GLBackend::makeShader(*_skyShader); + gpu::Shader::makeProgram(*_skyShader); } } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 50ae3fd882..8f8f19c72a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -299,18 +299,93 @@ void Model::initJointTransforms() { void Model::init() { if (!_program.isLinked()) { +/* + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), 1)); + slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1)); + slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2)); + slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), 3)); + + // Vertex shaders + auto modelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert))); + auto modelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_normal_map_vert))); + auto modelLightmapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_vert))); + auto modelLightmapNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert))); + auto modelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_shadow_vert))); + auto skinModelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_vert))); + auto skinModelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_normal_map_vert))); + auto skinModelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_shadow_vert))); + + // Pixel shaders + auto modelPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_frag))); + auto modelNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_map_frag))); + auto modelSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_specular_map_frag))); + auto modelNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_specular_map_frag))); + auto modelTranslucentPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_translucent_frag))); + auto modelShadowPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_shadow_frag))); + auto modelLightmapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_frag))); + auto modelLightmapNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag))); + auto modelLightmapSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag))); + auto modelLightmapNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag))); + + + bool makeResult = false; + + // Programs + auto program = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelPixel)); + makeResult = gpu::Shader::makeProgram(*program, slotBindings); + + auto normalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalMapPixel)); + makeResult = gpu::Shader::makeProgram(*normalMapProgram, slotBindings); + + auto specularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*specularMapProgram, slotBindings); + + auto normalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*normalSpecularMapProgram, slotBindings); + + auto translucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelTranslucentPixel)); + makeResult = gpu::Shader::makeProgram(*translucentProgram, slotBindings); + + auto shadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelShadowVertex, modelShadowPixel)); + makeResult = gpu::Shader::makeProgram(*shadowProgram, slotBindings); + + auto lightmapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapPixel)); + makeResult = gpu::Shader::makeProgram(*lightmapProgram, slotBindings); + + auto lightmapNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalMapPixel)); + makeResult = gpu::Shader::makeProgram(*lightmapNormalMapProgram, slotBindings); + + auto lightmapSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*lightmapSpecularMapProgram, slotBindings); + + auto lightmapNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*lightmapNormalSpecularMapProgram, slotBindings); + + auto skinProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelPixel)); + makeResult = gpu::Shader::makeProgram(*skinProgram, slotBindings); + + auto skinNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalMapPixel)); + makeResult = gpu::Shader::makeProgram(*skinNormalMapProgram, slotBindings); + + auto skinSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*skinSpecularMapProgram, slotBindings); + + auto skinNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*skinNormalSpecularMapProgram, slotBindings); + + auto skinShadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelShadowVertex, modelShadowPixel)); + makeResult = gpu::Shader::makeProgram(*skinShadowProgram, slotBindings); + + auto skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel)); + makeResult = gpu::Shader::makeProgram(*skinTranslucentProgram, slotBindings); +*/ + _program.addShaderFromSourceCode(QGLShader::Vertex, model_vert); _program.addShaderFromSourceCode(QGLShader::Fragment, model_frag); initProgram(_program, _locations); - - auto defaultShader = gpu::ShaderPointer( - gpu::Shader::createProgram( - gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert))), - gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_frag))) - ) - ); - gpu::GLBackend::makeShader(*defaultShader); _normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); _normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 303fa770ad..453d721962 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -309,6 +309,7 @@ private: int _blendNumber; int _appliedBlendNumber; + static ProgramObject _program; static ProgramObject _normalMapProgram; static ProgramObject _specularMapProgram; From cc85f468d6268cff98cd2741670bde7696b82f1e Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 9 Mar 2015 11:14:42 -0700 Subject: [PATCH 14/56] splitting the code of GLBackend into separate .cpp, adding the PIpeline,adn the state to gpu --- libraries/gpu/src/gpu/Batch.cpp | 10 +- libraries/gpu/src/gpu/Batch.h | 9 +- libraries/gpu/src/gpu/Context.h | 20 +- libraries/gpu/src/gpu/GLBackend.cpp | 447 +------------------ libraries/gpu/src/gpu/GLBackend.h | 28 +- libraries/gpu/src/gpu/GLBackendBuffer.cpp | 66 +++ libraries/gpu/src/gpu/GLBackendInput.cpp | 223 +++++++++ libraries/gpu/src/gpu/GLBackendPipeline.cpp | 95 ++++ libraries/gpu/src/gpu/GLBackendShader.cpp | 1 + libraries/gpu/src/gpu/GLBackendTransform.cpp | 156 +++++++ libraries/gpu/src/gpu/Pipeline.cpp | 34 ++ libraries/gpu/src/gpu/Pipeline.h | 53 +++ libraries/gpu/src/gpu/State.cpp | 20 + libraries/gpu/src/gpu/State.h | 88 ++++ libraries/model/src/model/Stage.cpp | 11 +- libraries/model/src/model/Stage.h | 4 +- libraries/render-utils/src/Model.cpp | 2 +- 17 files changed, 803 insertions(+), 464 deletions(-) create mode 100755 libraries/gpu/src/gpu/GLBackendBuffer.cpp create mode 100755 libraries/gpu/src/gpu/GLBackendInput.cpp create mode 100755 libraries/gpu/src/gpu/GLBackendPipeline.cpp create mode 100755 libraries/gpu/src/gpu/GLBackendTransform.cpp create mode 100755 libraries/gpu/src/gpu/Pipeline.cpp create mode 100755 libraries/gpu/src/gpu/Pipeline.h create mode 100755 libraries/gpu/src/gpu/State.cpp create mode 100755 libraries/gpu/src/gpu/State.h diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index ddbc76fce6..9ca0eeaebf 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -25,7 +25,8 @@ Batch::Batch() : _buffers(), _textures(), _streamFormats(), - _transforms() + _transforms(), + _pipelines() { } @@ -42,6 +43,7 @@ void Batch::clear() { _textures.clear(); _streamFormats.clear(); _transforms.clear(); + _pipelines.clear(); } uint32 Batch::cacheResource(Resource* res) { @@ -159,6 +161,12 @@ void Batch::setProjectionTransform(const Mat4& proj) { _params.push_back(cacheData(sizeof(Mat4), &proj)); } +void Batch::setPipeline(const PipelinePointer& pipeline) { + ADD_COMMAND(setPipeline); + + _params.push_back(_pipelines.cache(pipeline)); +} + void Batch::setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size) { ADD_COMMAND(setUniformBuffer); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 310cd9fe16..54a6339ae3 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -21,6 +21,8 @@ #include "Stream.h" #include "Texture.h" +#include "Pipeline.h" + #if defined(NSIGHT_FOUND) #include "nvToolsExt.h" class ProfileRange { @@ -96,7 +98,9 @@ public: void setViewTransform(const Transform& view); void setProjectionTransform(const Mat4& proj); - // Shader Stage + // Pipeline Stage + void setPipeline(const PipelinePointer& pipeline); + void setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size); void setUniformBuffer(uint32 slot, const BufferView& view); // not a command, just a shortcut from a BufferView @@ -164,6 +168,7 @@ public: COMMAND_setViewTransform, COMMAND_setProjectionTransform, + COMMAND_setPipeline, COMMAND_setUniformBuffer, COMMAND_setUniformTexture, @@ -281,6 +286,7 @@ public: typedef Cache::Vector TextureCaches; typedef Cache::Vector StreamFormatCaches; typedef Cache::Vector TransformCaches; + typedef Cache::Vector PipelineCaches; typedef unsigned char Byte; typedef std::vector Bytes; @@ -320,6 +326,7 @@ public: TextureCaches _textures; StreamFormatCaches _streamFormats; TransformCaches _transforms; + PipelineCaches _pipelines; protected: }; diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index ecff65fd8d..1e239f0c56 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -16,6 +16,7 @@ #include "Resource.h" #include "Texture.h" #include "Shader.h" +#include "Pipeline.h" namespace gpu { @@ -47,7 +48,6 @@ public: template< typename T > static void setGPUObject(const Buffer& buffer, T* bo) { - // buffer.setGPUObject(reinterpret_cast(bo)); buffer.setGPUObject(bo); } template< typename T > @@ -55,30 +55,32 @@ public: return reinterpret_cast(buffer.getGPUObject()); } - //void syncGPUObject(const Buffer& buffer); - template< typename T > static void setGPUObject(const Texture& texture, T* to) { - texture.setGPUObject(reinterpret_cast(to)); + texture.setGPUObject(to); } template< typename T > static T* getGPUObject(const Texture& texture) { return reinterpret_cast(texture.getGPUObject()); } - - //void syncGPUObject(const Texture& texture); - template< typename T > static void setGPUObject(const Shader& shader, T* so) { - shader.setGPUObject(reinterpret_cast(so)); + shader.setGPUObject(so); } template< typename T > static T* getGPUObject(const Shader& shader) { return reinterpret_cast(shader.getGPUObject()); } - // void syncGPUObject(const Shader& shader); + template< typename T > + static void setGPUObject(const Pipeline& pipeline, T* po) { + pipeline.setGPUObject(po); + } + template< typename T > + static T* getGPUObject(const Pipeline& pipeline) { + return reinterpret_cast(pipeline.getGPUObject()); + } protected: diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 6314d179ed..4831ecdd4c 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -25,6 +25,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_setViewTransform), (&::gpu::GLBackend::do_setProjectionTransform), + (&::gpu::GLBackend::do_setPipeline), (&::gpu::GLBackend::do_setUniformBuffer), (&::gpu::GLBackend::do_setUniformTexture), @@ -71,7 +72,8 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = GLBackend::GLBackend() : _input(), - _transform() + _transform(), + _pipeline() { initTransform(); } @@ -134,6 +136,7 @@ void GLBackend::checkGLError() { void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { updateInput(); updateTransform(); + updatePipeline(); Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = _primitiveToGLmode[primitiveType]; @@ -147,6 +150,7 @@ void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { updateInput(); updateTransform(); + updatePipeline(); Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = _primitiveToGLmode[primitiveType]; @@ -167,389 +171,6 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) { CHECK_GL_ERROR(); } -void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) { - Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint); - - if (format != _input._format) { - _input._format = format; - _input._invalidFormat = true; - } -} - -void GLBackend::do_setInputBuffer(Batch& batch, uint32 paramOffset) { - Offset stride = batch._params[paramOffset + 0]._uint; - Offset offset = batch._params[paramOffset + 1]._uint; - BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); - uint32 channel = batch._params[paramOffset + 3]._uint; - - if (channel < getNumInputBuffers()) { - _input._buffers[channel] = buffer; - _input._bufferOffsets[channel] = offset; - _input._bufferStrides[channel] = stride; - _input._buffersState.set(channel); - } -} - -#define SUPPORT_LEGACY_OPENGL -#if defined(SUPPORT_LEGACY_OPENGL) -static const int NUM_CLASSIC_ATTRIBS = Stream::TANGENT; -static const GLenum attributeSlotToClassicAttribName[NUM_CLASSIC_ATTRIBS] = { - GL_VERTEX_ARRAY, - GL_NORMAL_ARRAY, - GL_COLOR_ARRAY, - GL_TEXTURE_COORD_ARRAY -}; -#endif - -void GLBackend::updateInput() { - if (_input._invalidFormat || _input._buffersState.any()) { - - if (_input._invalidFormat) { - InputStageState::ActivationCache newActivation; - - // Check expected activation - if (_input._format) { - const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); - for (Stream::Format::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) { - const Stream::Attribute& attrib = (*it).second; - newActivation.set(attrib._slot); - } - } - - // Manage Activation what was and what is expected now - for (unsigned int i = 0; i < newActivation.size(); i++) { - bool newState = newActivation[i]; - if (newState != _input._attributeActivation[i]) { -#if defined(SUPPORT_LEGACY_OPENGL) - if (i < NUM_CLASSIC_ATTRIBS) { - if (newState) { - glEnableClientState(attributeSlotToClassicAttribName[i]); - } - else { - glDisableClientState(attributeSlotToClassicAttribName[i]); - } - } else { -#else - { -#endif - if (newState) { - glEnableVertexAttribArray(i); - } else { - glDisableVertexAttribArray(i); - } - } - CHECK_GL_ERROR(); - - _input._attributeActivation.flip(i); - } - } - } - - // now we need to bind the buffers and assign the attrib pointers - if (_input._format) { - const Buffers& buffers = _input._buffers; - const Offsets& offsets = _input._bufferOffsets; - const Offsets& strides = _input._bufferStrides; - - const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); - - for (Stream::Format::ChannelMap::const_iterator channelIt = _input._format->getChannels().begin(); - channelIt != _input._format->getChannels().end(); - channelIt++) { - const Stream::Format::ChannelMap::value_type::second_type& channel = (*channelIt).second; - if ((*channelIt).first < buffers.size()) { - int bufferNum = (*channelIt).first; - - if (_input._buffersState.test(bufferNum) || _input._invalidFormat) { - GLuint vbo = gpu::GLBackend::getBufferID((*buffers[bufferNum])); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - CHECK_GL_ERROR(); - _input._buffersState[bufferNum] = false; - - for (unsigned int i = 0; i < channel._slots.size(); i++) { - const Stream::Attribute& attrib = attributes.at(channel._slots[i]); - GLuint slot = attrib._slot; - GLuint count = attrib._element.getDimensionCount(); - GLenum type = _elementTypeToGLType[attrib._element.getType()]; - GLuint stride = strides[bufferNum]; - GLuint pointer = attrib._offset + offsets[bufferNum]; - #if defined(SUPPORT_LEGACY_OPENGL) - if (slot < NUM_CLASSIC_ATTRIBS) { - switch (slot) { - case Stream::POSITION: - glVertexPointer(count, type, stride, reinterpret_cast(pointer)); - break; - case Stream::NORMAL: - glNormalPointer(type, stride, reinterpret_cast(pointer)); - break; - case Stream::COLOR: - glColorPointer(count, type, stride, reinterpret_cast(pointer)); - break; - case Stream::TEXCOORD: - glTexCoordPointer(count, type, stride, reinterpret_cast(pointer)); - break; - }; - } else { - #else - { - #endif - GLboolean isNormalized = attrib._element.isNormalized(); - glVertexAttribPointer(slot, count, type, isNormalized, stride, - reinterpret_cast(pointer)); - } - CHECK_GL_ERROR(); - } - } - } - } - } - // everything format related should be in sync now - _input._invalidFormat = false; - } - -/* TODO: Fancy version GL4.4 - if (_needInputFormatUpdate) { - - InputActivationCache newActivation; - - // Assign the vertex format required - if (_inputFormat) { - const StreamFormat::AttributeMap& attributes = _inputFormat->getAttributes(); - for (StreamFormat::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) { - const StreamFormat::Attribute& attrib = (*it).second; - newActivation.set(attrib._slot); - glVertexAttribFormat( - attrib._slot, - attrib._element.getDimensionCount(), - _elementTypeToGLType[attrib._element.getType()], - attrib._element.isNormalized(), - attrib._stride); - } - CHECK_GL_ERROR(); - } - - // Manage Activation what was and what is expected now - for (int i = 0; i < newActivation.size(); i++) { - bool newState = newActivation[i]; - if (newState != _inputAttributeActivation[i]) { - if (newState) { - glEnableVertexAttribArray(i); - } else { - glDisableVertexAttribArray(i); - } - _inputAttributeActivation.flip(i); - } - } - CHECK_GL_ERROR(); - - _needInputFormatUpdate = false; - } - - if (_needInputStreamUpdate) { - if (_inputStream) { - const Stream::Buffers& buffers = _inputStream->getBuffers(); - const Stream::Offsets& offsets = _inputStream->getOffsets(); - const Stream::Strides& strides = _inputStream->getStrides(); - - for (int i = 0; i < buffers.size(); i++) { - GLuint vbo = gpu::GLBackend::getBufferID((*buffers[i])); - glBindVertexBuffer(i, vbo, offsets[i], strides[i]); - } - - CHECK_GL_ERROR(); - } - _needInputStreamUpdate = false; - } -*/ -} - - -void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { - _input._indexBufferType = (Type) batch._params[paramOffset + 2]._uint; - BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint); - _input._indexBufferOffset = batch._params[paramOffset + 0]._uint; - _input._indexBuffer = indexBuffer; - if (indexBuffer) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer)); - } else { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - CHECK_GL_ERROR(); -} - -// Transform Stage - -void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { - _transform._model = batch._transforms.get(batch._params[paramOffset]._uint); - _transform._invalidModel = true; -} - -void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { - _transform._view = batch._transforms.get(batch._params[paramOffset]._uint); - _transform._invalidView = true; -} - -void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { - memcpy(&_transform._projection, batch.editData(batch._params[paramOffset]._uint), sizeof(Mat4)); - _transform._invalidProj = true; -} - -void GLBackend::initTransform() { -#if defined(Q_OS_WIN) - glGenBuffers(1, &_transform._transformObjectBuffer); - glGenBuffers(1, &_transform._transformCameraBuffer); - - glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformObjectBuffer); - glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW); - - glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformCameraBuffer); - glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW); - - - glBindBuffer(GL_UNIFORM_BUFFER, 0); -#else -#endif -} - -void GLBackend::killTransform() { -#if defined(Q_OS_WIN) - glDeleteBuffers(1, &_transform._transformObjectBuffer); - glDeleteBuffers(1, &_transform._transformCameraBuffer); -#else -#endif -} -void GLBackend::updateTransform() { - // Check all the dirty flags and update the state accordingly - if (_transform._invalidProj) { - _transform._transformCamera._projection = _transform._projection; - } - - if (_transform._invalidView) { - _transform._view.getInverseMatrix(_transform._transformCamera._view); - _transform._view.getMatrix(_transform._transformCamera._viewInverse); - } - - if (_transform._invalidModel) { - _transform._model.getMatrix(_transform._transformObject._model); - _transform._model.getInverseMatrix(_transform._transformObject._modelInverse); - } - - if (_transform._invalidView || _transform._invalidProj) { - Mat4 viewUntranslated = _transform._transformCamera._view; - viewUntranslated[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f); - _transform._transformCamera._projectionViewUntranslated = _transform._transformCamera._projection * viewUntranslated; - } - - if (_transform._invalidView || _transform._invalidProj) { -#if defined(Q_OS_WIN) - glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, 0); - glBindBuffer(GL_ARRAY_BUFFER, _transform._transformCameraBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - CHECK_GL_ERROR(); -#endif - } - - if (_transform._invalidModel) { -#if defined(Q_OS_WIN) - glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, 0); - glBindBuffer(GL_ARRAY_BUFFER, _transform._transformObjectBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - CHECK_GL_ERROR(); -#endif - } - -#if defined(Q_OS_WIN) - glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._transformObjectBuffer); - glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, _transform._transformCameraBuffer); - CHECK_GL_ERROR(); -#endif - - -#if defined(Q_OS_MAC) || defined(Q_OS_LINUX) - // Do it again for fixed pipeline until we can get rid of it - if (_transform._invalidProj) { - if (_transform._lastMode != GL_PROJECTION) { - glMatrixMode(GL_PROJECTION); - _transform._lastMode = GL_PROJECTION; - } - glLoadMatrixf(reinterpret_cast< const GLfloat* >(&_transform._projection)); - - CHECK_GL_ERROR(); - } - - if (_transform._invalidModel || _transform._invalidView) { - if (!_transform._model.isIdentity()) { - if (_transform._lastMode != GL_MODELVIEW) { - glMatrixMode(GL_MODELVIEW); - _transform._lastMode = GL_MODELVIEW; - } - Transform::Mat4 modelView; - if (!_transform._view.isIdentity()) { - Transform mvx; - Transform::inverseMult(mvx, _transform._view, _transform._model); - mvx.getMatrix(modelView); - } else { - _transform._model.getMatrix(modelView); - } - glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); - } else { - if (!_transform._view.isIdentity()) { - if (_transform._lastMode != GL_MODELVIEW) { - glMatrixMode(GL_MODELVIEW); - _transform._lastMode = GL_MODELVIEW; - } - Transform::Mat4 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? - // glLoadIdentity(); - } - } - CHECK_GL_ERROR(); - } -#endif - - // Flags are clean - _transform._invalidView = _transform._invalidProj = _transform._invalidModel = false; -} - -void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { - GLuint slot = batch._params[paramOffset + 3]._uint; - BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); - GLintptr rangeStart = batch._params[paramOffset + 1]._uint; - GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint; -#if defined(Q_OS_MAC) - GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart); - glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data); - - // NOT working so we ll stick to the uniform float array until we move to core profile - // GLuint bo = getBufferID(*uniformBuffer); - //glUniformBufferEXT(_shader._program, slot, bo); -#elif defined(Q_OS_WIN) - GLuint bo = getBufferID(*uniformBuffer); - glBindBufferRange(GL_UNIFORM_BUFFER, slot, bo, rangeStart, rangeSize); -#else - GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart); - glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data); -#endif - CHECK_GL_ERROR(); -} - -void GLBackend::do_setUniformTexture(Batch& batch, uint32 paramOffset) { - GLuint slot = batch._params[paramOffset + 1]._uint; - TexturePointer uniformTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); - - GLuint to = getTextureID(uniformTexture); - glActiveTexture(GL_TEXTURE0 + slot); - glBindTexture(GL_TEXTURE_2D, to); - - CHECK_GL_ERROR(); -} - - // 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 @@ -740,8 +361,10 @@ void Batch::_glUseProgram(GLuint program) { } void GLBackend::do_glUseProgram(Batch& batch, uint32 paramOffset) { - _shader._program = batch._params[paramOffset]._uint; - glUseProgram(_shader._program); + _pipeline._program = batch._params[paramOffset]._uint; + // for this call we still want to execute the glUseProgram in the order of the glCOmmand to avoid any issue + _pipeline._invalidProgram = false; + glUseProgram(_pipeline._program); CHECK_GL_ERROR(); } @@ -998,55 +621,3 @@ void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) { CHECK_GL_ERROR(); } -GLBackend::GLBuffer::GLBuffer() : - _stamp(0), - _buffer(0), - _size(0) -{} - -GLBackend::GLBuffer::~GLBuffer() { - if (_buffer != 0) { - glDeleteBuffers(1, &_buffer); - } -} - -GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) { - GLBuffer* object = Backend::getGPUObject(buffer); - - if (object && (object->_stamp == buffer.getSysmem().getStamp())) { - return object; - } - - // need to have a gpu object? - if (!object) { - object = new GLBuffer(); - glGenBuffers(1, &object->_buffer); - CHECK_GL_ERROR(); - Backend::setGPUObject(buffer, object); - } - - // Now let's update the content of the bo with the sysmem version - // TODO: in the future, be smarter about when to actually upload the glBO version based on the data that did change - //if () { - glBindBuffer(GL_ARRAY_BUFFER, object->_buffer); - glBufferData(GL_ARRAY_BUFFER, buffer.getSysmem().getSize(), buffer.getSysmem().readData(), GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - object->_stamp = buffer.getSysmem().getStamp(); - object->_size = buffer.getSysmem().getSize(); - //} - CHECK_GL_ERROR(); - - return object; -} - - - -GLuint GLBackend::getBufferID(const Buffer& buffer) { - GLBuffer* bo = GLBackend::syncGPUObject(buffer); - if (bo) { - return bo->_buffer; - } else { - return 0; - } -} - diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 974bb6fb8b..2fd27862f9 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -75,6 +75,16 @@ public: static GLShader* syncGPUObject(const Shader& shader); static GLuint getShaderID(const ShaderPointer& shader); + + class GLPipeline : public GPUObject { + public: + GLShader* _program; + + GLPipeline(); + ~GLPipeline(); + }; + static GLPipeline* syncGPUObject(const Pipeline& pipeline); + static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS; static const int MAX_NUM_INPUT_BUFFERS = 16; @@ -160,18 +170,24 @@ protected: _lastMode(GL_TEXTURE) {} } _transform; - // Shader Stage + // Pipeline Stage + void do_setPipeline(Batch& batch, uint32 paramOffset); void do_setUniformBuffer(Batch& batch, uint32 paramOffset); void do_setUniformTexture(Batch& batch, uint32 paramOffset); - void updateShader(); - struct ShaderStageState { + void updatePipeline(); + struct PipelineStageState { + PipelinePointer _pipeline; GLuint _program; + bool _invalidProgram; - ShaderStageState() : - _program(0) {} - } _shader; + PipelineStageState() : + _pipeline(), + _program(0), + _invalidProgram(false) + {} + } _pipeline; // TODO: As long as we have gl calls explicitely issued from interface diff --git a/libraries/gpu/src/gpu/GLBackendBuffer.cpp b/libraries/gpu/src/gpu/GLBackendBuffer.cpp new file mode 100755 index 0000000000..12eab21686 --- /dev/null +++ b/libraries/gpu/src/gpu/GLBackendBuffer.cpp @@ -0,0 +1,66 @@ +// +// GLBackendBuffer.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// 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 "GLBackendShared.h" + +using namespace gpu; + +GLBackend::GLBuffer::GLBuffer() : + _stamp(0), + _buffer(0), + _size(0) +{} + +GLBackend::GLBuffer::~GLBuffer() { + if (_buffer != 0) { + glDeleteBuffers(1, &_buffer); + } +} + +GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) { + GLBuffer* object = Backend::getGPUObject(buffer); + + if (object && (object->_stamp == buffer.getSysmem().getStamp())) { + return object; + } + + // need to have a gpu object? + if (!object) { + object = new GLBuffer(); + glGenBuffers(1, &object->_buffer); + CHECK_GL_ERROR(); + Backend::setGPUObject(buffer, object); + } + + // Now let's update the content of the bo with the sysmem version + // TODO: in the future, be smarter about when to actually upload the glBO version based on the data that did change + //if () { + glBindBuffer(GL_ARRAY_BUFFER, object->_buffer); + glBufferData(GL_ARRAY_BUFFER, buffer.getSysmem().getSize(), buffer.getSysmem().readData(), GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + object->_stamp = buffer.getSysmem().getStamp(); + object->_size = buffer.getSysmem().getSize(); + //} + CHECK_GL_ERROR(); + + return object; +} + + + +GLuint GLBackend::getBufferID(const Buffer& buffer) { + GLBuffer* bo = GLBackend::syncGPUObject(buffer); + if (bo) { + return bo->_buffer; + } else { + return 0; + } +} + diff --git a/libraries/gpu/src/gpu/GLBackendInput.cpp b/libraries/gpu/src/gpu/GLBackendInput.cpp new file mode 100755 index 0000000000..982d2656a0 --- /dev/null +++ b/libraries/gpu/src/gpu/GLBackendInput.cpp @@ -0,0 +1,223 @@ +// +// GLBackendInput.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// 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 "GLBackendShared.h" + +using namespace gpu; + +void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) { + Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint); + + if (format != _input._format) { + _input._format = format; + _input._invalidFormat = true; + } +} + +void GLBackend::do_setInputBuffer(Batch& batch, uint32 paramOffset) { + Offset stride = batch._params[paramOffset + 0]._uint; + Offset offset = batch._params[paramOffset + 1]._uint; + BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); + uint32 channel = batch._params[paramOffset + 3]._uint; + + if (channel < getNumInputBuffers()) { + _input._buffers[channel] = buffer; + _input._bufferOffsets[channel] = offset; + _input._bufferStrides[channel] = stride; + _input._buffersState.set(channel); + } +} + +#define SUPPORT_LEGACY_OPENGL +#if defined(SUPPORT_LEGACY_OPENGL) +static const int NUM_CLASSIC_ATTRIBS = Stream::TANGENT; +static const GLenum attributeSlotToClassicAttribName[NUM_CLASSIC_ATTRIBS] = { + GL_VERTEX_ARRAY, + GL_NORMAL_ARRAY, + GL_COLOR_ARRAY, + GL_TEXTURE_COORD_ARRAY +}; +#endif + +void GLBackend::updateInput() { + if (_input._invalidFormat || _input._buffersState.any()) { + + if (_input._invalidFormat) { + InputStageState::ActivationCache newActivation; + + // Check expected activation + if (_input._format) { + const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); + for (Stream::Format::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) { + const Stream::Attribute& attrib = (*it).second; + newActivation.set(attrib._slot); + } + } + + // Manage Activation what was and what is expected now + for (unsigned int i = 0; i < newActivation.size(); i++) { + bool newState = newActivation[i]; + if (newState != _input._attributeActivation[i]) { +#if defined(SUPPORT_LEGACY_OPENGL) + if (i < NUM_CLASSIC_ATTRIBS) { + if (newState) { + glEnableClientState(attributeSlotToClassicAttribName[i]); + } + else { + glDisableClientState(attributeSlotToClassicAttribName[i]); + } + } else { +#else + { +#endif + if (newState) { + glEnableVertexAttribArray(i); + } else { + glDisableVertexAttribArray(i); + } + } + CHECK_GL_ERROR(); + + _input._attributeActivation.flip(i); + } + } + } + + // now we need to bind the buffers and assign the attrib pointers + if (_input._format) { + const Buffers& buffers = _input._buffers; + const Offsets& offsets = _input._bufferOffsets; + const Offsets& strides = _input._bufferStrides; + + const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); + + for (Stream::Format::ChannelMap::const_iterator channelIt = _input._format->getChannels().begin(); + channelIt != _input._format->getChannels().end(); + channelIt++) { + const Stream::Format::ChannelMap::value_type::second_type& channel = (*channelIt).second; + if ((*channelIt).first < buffers.size()) { + int bufferNum = (*channelIt).first; + + if (_input._buffersState.test(bufferNum) || _input._invalidFormat) { + GLuint vbo = gpu::GLBackend::getBufferID((*buffers[bufferNum])); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + CHECK_GL_ERROR(); + _input._buffersState[bufferNum] = false; + + for (unsigned int i = 0; i < channel._slots.size(); i++) { + const Stream::Attribute& attrib = attributes.at(channel._slots[i]); + GLuint slot = attrib._slot; + GLuint count = attrib._element.getDimensionCount(); + GLenum type = _elementTypeToGLType[attrib._element.getType()]; + GLuint stride = strides[bufferNum]; + GLuint pointer = attrib._offset + offsets[bufferNum]; + #if defined(SUPPORT_LEGACY_OPENGL) + if (slot < NUM_CLASSIC_ATTRIBS) { + switch (slot) { + case Stream::POSITION: + glVertexPointer(count, type, stride, reinterpret_cast(pointer)); + break; + case Stream::NORMAL: + glNormalPointer(type, stride, reinterpret_cast(pointer)); + break; + case Stream::COLOR: + glColorPointer(count, type, stride, reinterpret_cast(pointer)); + break; + case Stream::TEXCOORD: + glTexCoordPointer(count, type, stride, reinterpret_cast(pointer)); + break; + }; + } else { + #else + { + #endif + GLboolean isNormalized = attrib._element.isNormalized(); + glVertexAttribPointer(slot, count, type, isNormalized, stride, + reinterpret_cast(pointer)); + } + CHECK_GL_ERROR(); + } + } + } + } + } + // everything format related should be in sync now + _input._invalidFormat = false; + } + +/* TODO: Fancy version GL4.4 + if (_needInputFormatUpdate) { + + InputActivationCache newActivation; + + // Assign the vertex format required + if (_inputFormat) { + const StreamFormat::AttributeMap& attributes = _inputFormat->getAttributes(); + for (StreamFormat::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) { + const StreamFormat::Attribute& attrib = (*it).second; + newActivation.set(attrib._slot); + glVertexAttribFormat( + attrib._slot, + attrib._element.getDimensionCount(), + _elementTypeToGLType[attrib._element.getType()], + attrib._element.isNormalized(), + attrib._stride); + } + CHECK_GL_ERROR(); + } + + // Manage Activation what was and what is expected now + for (int i = 0; i < newActivation.size(); i++) { + bool newState = newActivation[i]; + if (newState != _inputAttributeActivation[i]) { + if (newState) { + glEnableVertexAttribArray(i); + } else { + glDisableVertexAttribArray(i); + } + _inputAttributeActivation.flip(i); + } + } + CHECK_GL_ERROR(); + + _needInputFormatUpdate = false; + } + + if (_needInputStreamUpdate) { + if (_inputStream) { + const Stream::Buffers& buffers = _inputStream->getBuffers(); + const Stream::Offsets& offsets = _inputStream->getOffsets(); + const Stream::Strides& strides = _inputStream->getStrides(); + + for (int i = 0; i < buffers.size(); i++) { + GLuint vbo = gpu::GLBackend::getBufferID((*buffers[i])); + glBindVertexBuffer(i, vbo, offsets[i], strides[i]); + } + + CHECK_GL_ERROR(); + } + _needInputStreamUpdate = false; + } +*/ +} + + +void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { + _input._indexBufferType = (Type) batch._params[paramOffset + 2]._uint; + BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint); + _input._indexBufferOffset = batch._params[paramOffset + 0]._uint; + _input._indexBuffer = indexBuffer; + if (indexBuffer) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer)); + } else { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + CHECK_GL_ERROR(); +} diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp new file mode 100755 index 0000000000..eba904ae4f --- /dev/null +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -0,0 +1,95 @@ +// +// GLBackendPipeline.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// 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 "GLBackendShared.h" + +#include "Format.h" + +using namespace gpu; + +GLBackend::GLPipeline::GLPipeline() : + _program(nullptr) +{} + +GLBackend::GLPipeline::~GLPipeline() { + _program = nullptr; +} + +GLBackend::GLPipeline* GLBackend::syncGPUObject(const Pipeline& pipeline) { + GLPipeline* object = Backend::getGPUObject(pipeline); + + // If GPU object already created then good + if (object) { + return object; + } + + return nullptr; +} + +void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) { + PipelinePointer pipeline = batch._pipelines.get(batch._params[paramOffset + 0]._uint); + + if (pipeline == _pipeline._pipeline) { + return; + } + + auto pipelineObject = syncGPUObject((*pipeline)); + if (!pipelineObject) { + return; + } + + _pipeline._pipeline = pipeline; + _pipeline._program = pipelineObject->_program->_program; + _pipeline._invalidProgram = true; +} + +void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { + GLuint slot = batch._params[paramOffset + 3]._uint; + BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); + GLintptr rangeStart = batch._params[paramOffset + 1]._uint; + GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint; +#if defined(Q_OS_MAC) + GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart); + glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data); + + // NOT working so we ll stick to the uniform float array until we move to core profile + // GLuint bo = getBufferID(*uniformBuffer); + //glUniformBufferEXT(_shader._program, slot, bo); +#elif defined(Q_OS_WIN) + GLuint bo = getBufferID(*uniformBuffer); + glBindBufferRange(GL_UNIFORM_BUFFER, slot, bo, rangeStart, rangeSize); +#else + GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart); + glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data); +#endif + CHECK_GL_ERROR(); +} + +void GLBackend::do_setUniformTexture(Batch& batch, uint32 paramOffset) { + GLuint slot = batch._params[paramOffset + 1]._uint; + TexturePointer uniformTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); + + GLuint to = getTextureID(uniformTexture); + glActiveTexture(GL_TEXTURE0 + slot); + glBindTexture(GL_TEXTURE_2D, to); + + CHECK_GL_ERROR(); +} + + +void GLBackend::updatePipeline() { + if (_pipeline._invalidProgram) { + glUseProgram(_pipeline._program); + CHECK_GL_ERROR(); + + _pipeline._invalidProgram = true; + } +} + diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 5136461f5c..8adce580a5 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -672,3 +672,4 @@ bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindin return true; } + diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp new file mode 100755 index 0000000000..6e928bcf09 --- /dev/null +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -0,0 +1,156 @@ +// +// GLBackendTransform.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// 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 "GLBackendShared.h" + +#include "Format.h" + +using namespace gpu; + +// Transform Stage + +void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { + _transform._model = batch._transforms.get(batch._params[paramOffset]._uint); + _transform._invalidModel = true; +} + +void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { + _transform._view = batch._transforms.get(batch._params[paramOffset]._uint); + _transform._invalidView = true; +} + +void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { + memcpy(&_transform._projection, batch.editData(batch._params[paramOffset]._uint), sizeof(Mat4)); + _transform._invalidProj = true; +} + +void GLBackend::initTransform() { +#if defined(Q_OS_WIN) + glGenBuffers(1, &_transform._transformObjectBuffer); + glGenBuffers(1, &_transform._transformCameraBuffer); + + glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformObjectBuffer); + glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW); + + glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformCameraBuffer); + glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW); + + + glBindBuffer(GL_UNIFORM_BUFFER, 0); +#else +#endif +} + +void GLBackend::killTransform() { +#if defined(Q_OS_WIN) + glDeleteBuffers(1, &_transform._transformObjectBuffer); + glDeleteBuffers(1, &_transform._transformCameraBuffer); +#else +#endif +} +void GLBackend::updateTransform() { + // Check all the dirty flags and update the state accordingly + if (_transform._invalidProj) { + _transform._transformCamera._projection = _transform._projection; + } + + if (_transform._invalidView) { + _transform._view.getInverseMatrix(_transform._transformCamera._view); + _transform._view.getMatrix(_transform._transformCamera._viewInverse); + } + + if (_transform._invalidModel) { + _transform._model.getMatrix(_transform._transformObject._model); + _transform._model.getInverseMatrix(_transform._transformObject._modelInverse); + } + + if (_transform._invalidView || _transform._invalidProj) { + Mat4 viewUntranslated = _transform._transformCamera._view; + viewUntranslated[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f); + _transform._transformCamera._projectionViewUntranslated = _transform._transformCamera._projection * viewUntranslated; + } + + if (_transform._invalidView || _transform._invalidProj) { +#if defined(Q_OS_WIN) + glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, 0); + glBindBuffer(GL_ARRAY_BUFFER, _transform._transformCameraBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + CHECK_GL_ERROR(); +#endif + } + + if (_transform._invalidModel) { +#if defined(Q_OS_WIN) + glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, 0); + glBindBuffer(GL_ARRAY_BUFFER, _transform._transformObjectBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + CHECK_GL_ERROR(); +#endif + } + +#if defined(Q_OS_WIN) + glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._transformObjectBuffer); + glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, _transform._transformCameraBuffer); + CHECK_GL_ERROR(); +#endif + + +#if defined(Q_OS_MAC) || defined(Q_OS_LINUX) + // Do it again for fixed pipeline until we can get rid of it + if (_transform._invalidProj) { + if (_transform._lastMode != GL_PROJECTION) { + glMatrixMode(GL_PROJECTION); + _transform._lastMode = GL_PROJECTION; + } + glLoadMatrixf(reinterpret_cast< const GLfloat* >(&_transform._projection)); + + CHECK_GL_ERROR(); + } + + if (_transform._invalidModel || _transform._invalidView) { + if (!_transform._model.isIdentity()) { + if (_transform._lastMode != GL_MODELVIEW) { + glMatrixMode(GL_MODELVIEW); + _transform._lastMode = GL_MODELVIEW; + } + Transform::Mat4 modelView; + if (!_transform._view.isIdentity()) { + Transform mvx; + Transform::inverseMult(mvx, _transform._view, _transform._model); + mvx.getMatrix(modelView); + } else { + _transform._model.getMatrix(modelView); + } + glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); + } else { + if (!_transform._view.isIdentity()) { + if (_transform._lastMode != GL_MODELVIEW) { + glMatrixMode(GL_MODELVIEW); + _transform._lastMode = GL_MODELVIEW; + } + Transform::Mat4 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? + // glLoadIdentity(); + } + } + CHECK_GL_ERROR(); + } +#endif + + // Flags are clean + _transform._invalidView = _transform._invalidProj = _transform._invalidModel = false; +} + + diff --git a/libraries/gpu/src/gpu/Pipeline.cpp b/libraries/gpu/src/gpu/Pipeline.cpp new file mode 100755 index 0000000000..931d330c2b --- /dev/null +++ b/libraries/gpu/src/gpu/Pipeline.cpp @@ -0,0 +1,34 @@ +// +// Pipeline.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// 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 "Pipeline.h" +#include +#include + +using namespace gpu; + +Pipeline::Pipeline(): + _program(), + _states() +{ +} + +Pipeline::~Pipeline() +{ +} + +Pipeline* Pipeline::create(const ShaderPointer& program, const States& states) { + Pipeline* pipeline = new Pipeline(); + pipeline->_program = program; + pipeline->_states = states; + + return pipeline; +} diff --git a/libraries/gpu/src/gpu/Pipeline.h b/libraries/gpu/src/gpu/Pipeline.h new file mode 100755 index 0000000000..c2fc944bb7 --- /dev/null +++ b/libraries/gpu/src/gpu/Pipeline.h @@ -0,0 +1,53 @@ +// +// Pipeline.h +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// 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_Pipeline_h +#define hifi_gpu_Pipeline_h + +#include "Resource.h" +#include +#include + +#include "Shader.h" +#include "State.h" + +namespace gpu { + +class Pipeline { +public: + static Pipeline* create(const ShaderPointer& program, const States& states); + ~Pipeline(); + + const ShaderPointer& getProgram() const { return _program; } + + const States& getStates() const { return _states; } + +protected: + ShaderPointer _program; + States _states; + + Pipeline(); + Pipeline(const Pipeline& pipeline); // deep copy of the sysmem shader + Pipeline& operator=(const Pipeline& pipeline); // deep copy of the sysmem texture + + // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = NULL; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } + GPUObject* getGPUObject() const { return _gpuObject; } + friend class Backend; +}; + +typedef QSharedPointer< Pipeline > PipelinePointer; +typedef std::vector< PipelinePointer > Pipelines; + +}; + + +#endif diff --git a/libraries/gpu/src/gpu/State.cpp b/libraries/gpu/src/gpu/State.cpp new file mode 100755 index 0000000000..0b8edb7cd2 --- /dev/null +++ b/libraries/gpu/src/gpu/State.cpp @@ -0,0 +1,20 @@ +// +// State.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// 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 "State.h" +#include + +using namespace gpu; + + +State::~State() +{ +} diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h new file mode 100755 index 0000000000..92ef4c1c8d --- /dev/null +++ b/libraries/gpu/src/gpu/State.h @@ -0,0 +1,88 @@ +// +// Pipeline.h +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// 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_State_h +#define hifi_gpu_State_h + +#include "Format.h" +#include +#include + + +namespace gpu { + +class GPUObject; + +class State { +public: + State() {} + virtual ~State(); + + // Work in progress, not used + /* + enum Field { + FILL_MODE, + CULL_MODE, + DEPTH_BIAS, + DEPTH_BIAS_CLAMP, + DEPTH_BIASSLOPE_SCALE, + + FRONT_CLOCKWISE, + DEPTH_CLIP_ENABLE, + SCISSR_ENABLE, + MULTISAMPLE_ENABLE, + ANTIALISED_LINE_ENABLE, + + DEPTH_ENABLE, + DEPTH_WRITE_MASK, + DEPTH_FUNCTION, + + STENCIL_ENABLE, + STENCIL_READ_MASK, + STENCIL_WRITE_MASK, + STENCIL_FUNCTION_FRONT, + STENCIL_FUNCTION_BACK, + STENCIL_REFERENCE, + + BLEND_INDEPENDANT_ENABLE, + BLEND_ENABLE, + BLEND_SOURCE, + BLEND_DESTINATION, + BLEND_OPERATION, + BLEND_SOURCE_ALPHA, + BLEND_DESTINATION_ALPHA, + BLEND_OPERATION_ALPHA, + BLEND_WRITE_MASK, + BLEND_FACTOR, + + SAMPLE_MASK, + + ALPHA_TO_COVERAGE_ENABLE, + }; + */ + +protected: + State(const State& state); + State& operator=(const State& state); + + // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = NULL; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } + GPUObject* getGPUObject() const { return _gpuObject; } + friend class Backend; +}; + +typedef QSharedPointer< State > StatePointer; +typedef std::vector< StatePointer > States; + +}; + + +#endif diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index d470d841bc..e4786df792 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -15,8 +15,6 @@ #include "SkyFromAtmosphere_vert.h" #include "SkyFromAtmosphere_frag.h" -#include "gpu/Context.h" -#include "gpu/GLBackend.h" using namespace model; @@ -156,12 +154,14 @@ SunSkyStage::SunSkyStage() : // Begining of march setYearTime(60.0f); - _skyShader = gpu::ShaderPointer( + auto skyShader = gpu::ShaderPointer( gpu::Shader::createProgram( gpu::ShaderPointer(gpu::Shader::createVertex(std::string(SkyFromAtmosphere_vert))), gpu::ShaderPointer(gpu::Shader::createPixel(std::string(SkyFromAtmosphere_frag))) ) ); + _skyPipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, gpu::States())); + } SunSkyStage::~SunSkyStage() { @@ -217,12 +217,11 @@ void SunSkyStage::updateGraphicsObject() const { double originAlt = _earthSunModel.getAltitude(); _sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f)); - - GLuint program = gpu::GLBackend::getShaderID(_skyShader); static int firstTime = 0; if (firstTime == 0) { firstTime++; - gpu::Shader::makeProgram(*_skyShader); + bool result = gpu::Shader::makeProgram(*(_skyPipeline->getProgram())); + } } diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index 4de0edb96b..61914b5a6b 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -11,7 +11,7 @@ #ifndef hifi_model_Stage_h #define hifi_model_Stage_h -#include "gpu/Shader.h" +#include "gpu/Pipeline.h" #include "Light.h" @@ -145,7 +145,7 @@ public: protected: LightPointer _sunLight; - gpu::ShaderPointer _skyShader; + gpu::PipelinePointer _skyPipeline; float _dayTime; int _yearTime; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 8f8f19c72a..80781c3522 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -299,7 +299,7 @@ void Model::initJointTransforms() { void Model::init() { if (!_program.isLinked()) { -/* +/* //Work in progress not used yet gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), 1)); slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0)); From ee5409b0a8c4a9e8e6d4d7b89872ed6a90ddec6a Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 9 Mar 2015 14:25:59 -0700 Subject: [PATCH 15/56] fixing compilation on macosx --- libraries/gpu/src/gpu/GLBackendShader.cpp | 616 +++++++++++----------- libraries/model/src/model/Stage.cpp | 9 +- 2 files changed, 316 insertions(+), 309 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 8adce580a5..9bcc278d8e 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -29,13 +29,13 @@ GLBackend::GLShader::~GLShader() { } void makeBindings(GLBackend::GLShader* shader) { - if(!shader || !shader->_program) { - return; - } - GLuint glprogram = shader->_program; - GLint loc = -1; - - //Check for gpu specific attribute slotBindings + if(!shader || !shader->_program) { + return; + } + GLuint glprogram = shader->_program; + GLint loc = -1; + + //Check for gpu specific attribute slotBindings loc = glGetAttribLocation(glprogram, "position"); if (loc >= 0) { glBindAttribLocation(glprogram, gpu::Stream::POSITION, "position"); @@ -74,234 +74,235 @@ void makeBindings(GLBackend::GLShader* shader) { loc = glGetAttribLocation(glprogram, "clusterWeights"); if (loc >= 0) { glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "clusterWeights"); - } - - // Link again to take into account the assigned attrib location - glLinkProgram(glprogram); - - GLint linked = 0; - glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); - if (!linked) { - qDebug() << "GLShader::makeBindings - failed to link after assigning slotBindings?"; - } - - // now assign the ubo binding, then DON't relink! - - //Check for gpu specific uniform slotBindings - loc = glGetUniformBlockIndex(glprogram, "transformObjectBuffer"); - if (loc >= 0) { - glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT); - shader->_transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT; - } - - loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer"); - if (loc >= 0) { - glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT); - shader->_transformCameraSlot = gpu::TRANSFORM_OBJECT_SLOT; } + // Link again to take into account the assigned attrib location + glLinkProgram(glprogram); + + GLint linked = 0; + glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); + if (!linked) { + qDebug() << "GLShader::makeBindings - failed to link after assigning slotBindings?"; + } + + // now assign the ubo binding, then DON't relink! + + //Check for gpu specific uniform slotBindings +#if defined(Q_OS_WIN) + loc = glGetUniformBlockIndex(glprogram, "transformObjectBuffer"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT); + shader->_transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT; + } + + loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT); + shader->_transformCameraSlot = gpu::TRANSFORM_OBJECT_SLOT; + } +#endif } GLBackend::GLShader* compileShader(const Shader& shader) { - // Any GLSLprogram ? normally yes... - const std::string& shaderSource = shader.getSource().getCode(); - if (shaderSource.empty()) { - qDebug() << "GLShader::compileShader - no GLSL shader source code ? so failed to create"; - return nullptr; - } - - // Shader domain - const GLenum SHADER_DOMAINS[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER }; - GLenum shaderDomain = SHADER_DOMAINS[shader.getType()]; - - // Create the shader object - GLuint glshader = glCreateShader(shaderDomain); - if (!glshader) { - qDebug() << "GLShader::compileShader - failed to create the gl shader object"; - return nullptr; - } - - // Assign the source - const GLchar* srcstr = shaderSource.c_str(); - glShaderSource(glshader, 1, &srcstr, NULL); - - // Compile ! - glCompileShader(glshader); - - // check if shader compiled - GLint compiled = 0; - glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled); - - // if compilation fails - if (!compiled) { - // save the source code to a temp file so we can debug easily - /* std::ofstream filestream; - filestream.open("debugshader.glsl"); - if (filestream.is_open()) { - filestream << shaderSource->source; - filestream.close(); - } - */ - - GLint infoLength = 0; - glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength); - - char* temp = new char[infoLength] ; - glGetShaderInfoLog(glshader, infoLength, NULL, temp); - - qDebug() << "GLShader::compileShader - failed to compile the gl shader object:"; - qDebug() << temp; - - /* - filestream.open("debugshader.glsl.info.txt"); - if (filestream.is_open()) { - filestream << std::string(temp); - filestream.close(); - } - */ - delete[] temp; - - glDeleteShader(glshader); - return nullptr; - } - - GLuint glprogram = 0; -#ifdef SEPARATE_PROGRAM - // so far so good, program is almost done, need to link: - GLuint glprogram = glCreateProgram(); - if (!glprogram) { - qDebug() << "GLShader::compileShader - failed to create the gl shader & gl program object"; - return nullptr; - } - - glProgramParameteri(glprogram, GL_PROGRAM_SEPARABLE, GL_TRUE); - glAttachShader(glprogram, glshader); - glLinkProgram(glprogram); - - GLint linked = 0; - glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); - - if (!linked) { - /* - // save the source code to a temp file so we can debug easily - std::ofstream filestream; - filestream.open("debugshader.glsl"); - if (filestream.is_open()) { - filestream << shaderSource->source; - filestream.close(); - } - */ - - GLint infoLength = 0; - glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength); - - char* temp = new char[infoLength] ; - glGetProgramInfoLog(glprogram, infoLength, NULL, temp); - - qDebug() << "GLShader::compileShader - failed to LINK the gl program object :"; - qDebug() << temp; - - /* - filestream.open("debugshader.glsl.info.txt"); - if (filestream.is_open()) { - filestream << String(temp); - filestream.close(); - } - */ - delete[] temp; - - glDeleteShader(glshader); - glDeleteProgram(glprogram); - return nullptr; - } -#endif - - // So far so good, the shader is created successfully - GLBackend::GLShader* object = new GLBackend::GLShader(); - object->_shader = glshader; - object->_program = glprogram; - - makeBindings(object); - - return object; + // Any GLSLprogram ? normally yes... + const std::string& shaderSource = shader.getSource().getCode(); + if (shaderSource.empty()) { + qDebug() << "GLShader::compileShader - no GLSL shader source code ? so failed to create"; + return nullptr; + } + + // Shader domain + const GLenum SHADER_DOMAINS[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER }; + GLenum shaderDomain = SHADER_DOMAINS[shader.getType()]; + + // Create the shader object + GLuint glshader = glCreateShader(shaderDomain); + if (!glshader) { + qDebug() << "GLShader::compileShader - failed to create the gl shader object"; + return nullptr; + } + + // Assign the source + const GLchar* srcstr = shaderSource.c_str(); + glShaderSource(glshader, 1, &srcstr, NULL); + + // Compile ! + glCompileShader(glshader); + + // check if shader compiled + GLint compiled = 0; + glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled); + + // if compilation fails + if (!compiled) { + // save the source code to a temp file so we can debug easily + /* std::ofstream filestream; + filestream.open("debugshader.glsl"); + if (filestream.is_open()) { + filestream << shaderSource->source; + filestream.close(); + } + */ + + GLint infoLength = 0; + glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength); + + char* temp = new char[infoLength] ; + glGetShaderInfoLog(glshader, infoLength, NULL, temp); + + qDebug() << "GLShader::compileShader - failed to compile the gl shader object:"; + qDebug() << temp; + + /* + filestream.open("debugshader.glsl.info.txt"); + if (filestream.is_open()) { + filestream << std::string(temp); + filestream.close(); + } + */ + delete[] temp; + + glDeleteShader(glshader); + return nullptr; + } + + GLuint glprogram = 0; +#ifdef SEPARATE_PROGRAM + // so far so good, program is almost done, need to link: + GLuint glprogram = glCreateProgram(); + if (!glprogram) { + qDebug() << "GLShader::compileShader - failed to create the gl shader & gl program object"; + return nullptr; + } + + glProgramParameteri(glprogram, GL_PROGRAM_SEPARABLE, GL_TRUE); + glAttachShader(glprogram, glshader); + glLinkProgram(glprogram); + + GLint linked = 0; + glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); + + if (!linked) { + /* + // save the source code to a temp file so we can debug easily + std::ofstream filestream; + filestream.open("debugshader.glsl"); + if (filestream.is_open()) { + filestream << shaderSource->source; + filestream.close(); + } + */ + + GLint infoLength = 0; + glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength); + + char* temp = new char[infoLength] ; + glGetProgramInfoLog(glprogram, infoLength, NULL, temp); + + qDebug() << "GLShader::compileShader - failed to LINK the gl program object :"; + qDebug() << temp; + + /* + filestream.open("debugshader.glsl.info.txt"); + if (filestream.is_open()) { + filestream << String(temp); + filestream.close(); + } + */ + delete[] temp; + + glDeleteShader(glshader); + glDeleteProgram(glprogram); + return nullptr; + } +#endif + + // So far so good, the shader is created successfully + GLBackend::GLShader* object = new GLBackend::GLShader(); + object->_shader = glshader; + object->_program = glprogram; + + makeBindings(object); + + return object; } GLBackend::GLShader* compileProgram(const Shader& program) { - if(!program.isProgram()) { - return nullptr; - } - - // Let's go through every shaders and make sure they are ready to go - std::vector< GLuint > shaderObjects; - for (auto subShader : program.getShaders()) { - GLuint so = GLBackend::getShaderID(subShader); - if (!so) { - qDebug() << "GLShader::compileProgram - One of the shaders of the program is not compiled?"; - return nullptr; - } - shaderObjects.push_back(so); - } - - // so far so good, program is almost done, need to link: - GLuint glprogram = glCreateProgram(); - if (!glprogram) { - qDebug() << "GLShader::compileProgram - failed to create the gl program object"; - return nullptr; - } - - // glProgramParameteri(glprogram, GL_PROGRAM_, GL_TRUE); - // Create the program from the sub shaders - for (auto so : shaderObjects) { - glAttachShader(glprogram, so); - } - - // Link! - glLinkProgram(glprogram); - - GLint linked = 0; - glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); - - if (!linked) { - /* - // save the source code to a temp file so we can debug easily - std::ofstream filestream; - filestream.open("debugshader.glsl"); - if (filestream.is_open()) { - filestream << shaderSource->source; - filestream.close(); - } - */ - - GLint infoLength = 0; - glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength); - - char* temp = new char[infoLength] ; - glGetProgramInfoLog(glprogram, infoLength, NULL, temp); - - qDebug() << "GLShader::compileProgram - failed to LINK the gl program object :"; - qDebug() << temp; - - /* - filestream.open("debugshader.glsl.info.txt"); - if (filestream.is_open()) { - filestream << std::string(temp); - filestream.close(); - } - */ - delete[] temp; - - glDeleteProgram(glprogram); - return nullptr; - } - - // So far so good, the program is created successfully - GLBackend::GLShader* object = new GLBackend::GLShader(); - object->_shader = 0; - object->_program = glprogram; - - makeBindings(object); - - return object; + if(!program.isProgram()) { + return nullptr; + } + + // Let's go through every shaders and make sure they are ready to go + std::vector< GLuint > shaderObjects; + for (auto subShader : program.getShaders()) { + GLuint so = GLBackend::getShaderID(subShader); + if (!so) { + qDebug() << "GLShader::compileProgram - One of the shaders of the program is not compiled?"; + return nullptr; + } + shaderObjects.push_back(so); + } + + // so far so good, program is almost done, need to link: + GLuint glprogram = glCreateProgram(); + if (!glprogram) { + qDebug() << "GLShader::compileProgram - failed to create the gl program object"; + return nullptr; + } + + // glProgramParameteri(glprogram, GL_PROGRAM_, GL_TRUE); + // Create the program from the sub shaders + for (auto so : shaderObjects) { + glAttachShader(glprogram, so); + } + + // Link! + glLinkProgram(glprogram); + + GLint linked = 0; + glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); + + if (!linked) { + /* + // save the source code to a temp file so we can debug easily + std::ofstream filestream; + filestream.open("debugshader.glsl"); + if (filestream.is_open()) { + filestream << shaderSource->source; + filestream.close(); + } + */ + + GLint infoLength = 0; + glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength); + + char* temp = new char[infoLength] ; + glGetProgramInfoLog(glprogram, infoLength, NULL, temp); + + qDebug() << "GLShader::compileProgram - failed to LINK the gl program object :"; + qDebug() << temp; + + /* + filestream.open("debugshader.glsl.info.txt"); + if (filestream.is_open()) { + filestream << std::string(temp); + filestream.close(); + } + */ + delete[] temp; + + glDeleteProgram(glprogram); + return nullptr; + } + + // So far so good, the program is created successfully + GLBackend::GLShader* object = new GLBackend::GLShader(); + object->_shader = 0; + object->_program = glprogram; + + makeBindings(object); + + return object; } GLBackend::GLShader* GLBackend::syncGPUObject(const Shader& shader) { @@ -360,127 +361,135 @@ ElementResource getFormatFromGLUniform(GLenum gltype) { case GL_FLOAT_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER); case GL_FLOAT_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER); case GL_FLOAT_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER); - +/* case GL_DOUBLE: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER); case GL_DOUBLE_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER); case GL_DOUBLE_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER); case GL_DOUBLE_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER); - +*/ case GL_INT: return ElementResource(Element(SCALAR, gpu::INT32, UNIFORM), Resource::BUFFER); case GL_INT_VEC2: return ElementResource(Element(VEC2, gpu::INT32, UNIFORM), Resource::BUFFER); case GL_INT_VEC3: return ElementResource(Element(VEC3, gpu::INT32, UNIFORM), Resource::BUFFER); case GL_INT_VEC4: return ElementResource(Element(VEC4, gpu::INT32, UNIFORM), Resource::BUFFER); - + case GL_UNSIGNED_INT: return ElementResource(Element(SCALAR, gpu::UINT32, UNIFORM), Resource::BUFFER); +#if defined(Q_OS_WIN) case GL_UNSIGNED_INT_VEC2: return ElementResource(Element(VEC2, gpu::UINT32, UNIFORM), Resource::BUFFER); case GL_UNSIGNED_INT_VEC3: return ElementResource(Element(VEC3, gpu::UINT32, UNIFORM), Resource::BUFFER); case GL_UNSIGNED_INT_VEC4: return ElementResource(Element(VEC4, gpu::UINT32, UNIFORM), Resource::BUFFER); - +#endif + case GL_BOOL: return ElementResource(Element(SCALAR, gpu::BOOL, UNIFORM), Resource::BUFFER); case GL_BOOL_VEC2: return ElementResource(Element(VEC2, gpu::BOOL, UNIFORM), Resource::BUFFER); case GL_BOOL_VEC3: return ElementResource(Element(VEC3, gpu::BOOL, UNIFORM), Resource::BUFFER); case GL_BOOL_VEC4: return ElementResource(Element(VEC4, gpu::BOOL, UNIFORM), Resource::BUFFER); - - + + case GL_FLOAT_MAT2: return ElementResource(Element(gpu::MAT2, gpu::FLOAT, UNIFORM), Resource::BUFFER); case GL_FLOAT_MAT3: return ElementResource(Element(MAT3, gpu::FLOAT, UNIFORM), Resource::BUFFER); case GL_FLOAT_MAT4: return ElementResource(Element(MAT4, gpu::FLOAT, UNIFORM), Resource::BUFFER); - -/* {GL_FLOAT_MAT2x3 mat2x3}, - {GL_FLOAT_MAT2x4 mat2x4}, - {GL_FLOAT_MAT3x2 mat3x2}, - {GL_FLOAT_MAT3x4 mat3x4}, - {GL_FLOAT_MAT4x2 mat4x2}, - {GL_FLOAT_MAT4x3 mat4x3}, - {GL_DOUBLE_MAT2 dmat2}, - {GL_DOUBLE_MAT3 dmat3}, - {GL_DOUBLE_MAT4 dmat4}, - {GL_DOUBLE_MAT2x3 dmat2x3}, - {GL_DOUBLE_MAT2x4 dmat2x4}, - {GL_DOUBLE_MAT3x2 dmat3x2}, - {GL_DOUBLE_MAT3x4 dmat3x4}, - {GL_DOUBLE_MAT4x2 dmat4x2}, - {GL_DOUBLE_MAT4x3 dmat4x3}, - */ - + +/* {GL_FLOAT_MAT2x3 mat2x3}, + {GL_FLOAT_MAT2x4 mat2x4}, + {GL_FLOAT_MAT3x2 mat3x2}, + {GL_FLOAT_MAT3x4 mat3x4}, + {GL_FLOAT_MAT4x2 mat4x2}, + {GL_FLOAT_MAT4x3 mat4x3}, + {GL_DOUBLE_MAT2 dmat2}, + {GL_DOUBLE_MAT3 dmat3}, + {GL_DOUBLE_MAT4 dmat4}, + {GL_DOUBLE_MAT2x3 dmat2x3}, + {GL_DOUBLE_MAT2x4 dmat2x4}, + {GL_DOUBLE_MAT3x2 dmat3x2}, + {GL_DOUBLE_MAT3x4 dmat3x4}, + {GL_DOUBLE_MAT4x2 dmat4x2}, + {GL_DOUBLE_MAT4x3 dmat4x3}, + */ + case GL_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D); case GL_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D); - case GL_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); + case GL_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_3D); case GL_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_CUBE); - + +#if defined(Q_OS_WIN) + case GL_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); case GL_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D_ARRAY); case GL_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D_ARRAY); case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); - +#endif + case GL_SAMPLER_2D_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D); +#if defined(Q_OS_WIN) case GL_SAMPLER_CUBE_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_CUBE); case GL_SAMPLER_2D_ARRAY_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D_ARRAY); - -// {GL_SAMPLER_1D_SHADOW sampler1DShadow}, - // {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow}, - -// {GL_SAMPLER_BUFFER samplerBuffer}, -// {GL_SAMPLER_2D_RECT sampler2DRect}, - // {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow}, - +#endif + +// {GL_SAMPLER_1D_SHADOW sampler1DShadow}, + // {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow}, + +// {GL_SAMPLER_BUFFER samplerBuffer}, +// {GL_SAMPLER_2D_RECT sampler2DRect}, + // {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow}, + +#if defined(Q_OS_WIN) case GL_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D); case GL_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D); case GL_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); case GL_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_3D); case GL_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_CUBE); - + case GL_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D_ARRAY); case GL_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D_ARRAY); case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); - - // {GL_INT_SAMPLER_BUFFER isamplerBuffer}, - // {GL_INT_SAMPLER_2D_RECT isampler2DRect}, - + + // {GL_INT_SAMPLER_BUFFER isamplerBuffer}, + // {GL_INT_SAMPLER_2D_RECT isampler2DRect}, + case GL_UNSIGNED_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D); case GL_UNSIGNED_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D); case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); case GL_UNSIGNED_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_3D); case GL_UNSIGNED_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_CUBE); - + case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D_ARRAY); case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D_ARRAY); case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); - -// {GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer}, -// {GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect}, -/* - {GL_IMAGE_1D image1D}, - {GL_IMAGE_2D image2D}, - {GL_IMAGE_3D image3D}, - {GL_IMAGE_2D_RECT image2DRect}, - {GL_IMAGE_CUBE imageCube}, - {GL_IMAGE_BUFFER imageBuffer}, - {GL_IMAGE_1D_ARRAY image1DArray}, - {GL_IMAGE_2D_ARRAY image2DArray}, - {GL_IMAGE_2D_MULTISAMPLE image2DMS}, - {GL_IMAGE_2D_MULTISAMPLE_ARRAY image2DMSArray}, - {GL_INT_IMAGE_1D iimage1D}, - {GL_INT_IMAGE_2D iimage2D}, - {GL_INT_IMAGE_3D iimage3D}, - {GL_INT_IMAGE_2D_RECT iimage2DRect}, - {GL_INT_IMAGE_CUBE iimageCube}, - {GL_INT_IMAGE_BUFFER iimageBuffer}, - {GL_INT_IMAGE_1D_ARRAY iimage1DArray}, - {GL_INT_IMAGE_2D_ARRAY iimage2DArray}, - {GL_INT_IMAGE_2D_MULTISAMPLE iimage2DMS}, - {GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY iimage2DMSArray}, - {GL_UNSIGNED_INT_IMAGE_1D uimage1D}, - {GL_UNSIGNED_INT_IMAGE_2D uimage2D}, - {GL_UNSIGNED_INT_IMAGE_3D uimage3D}, - {GL_UNSIGNED_INT_IMAGE_2D_RECT uimage2DRect}, - {GL_UNSIGNED_INT_IMAGE_CUBE uimageCube},+ [0] {_name="fInnerRadius" _location=0 _element={_semantic=15 '\xf' _dimension=0 '\0' _type=0 '\0' } } gpu::Shader::Slot - - {GL_UNSIGNED_INT_IMAGE_BUFFER uimageBuffer}, - {GL_UNSIGNED_INT_IMAGE_1D_ARRAY uimage1DArray}, - {GL_UNSIGNED_INT_IMAGE_2D_ARRAY uimage2DArray}, - {GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS}, +#endif +// {GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer}, +// {GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect}, +/* + {GL_IMAGE_1D image1D}, + {GL_IMAGE_2D image2D}, + {GL_IMAGE_3D image3D}, + {GL_IMAGE_2D_RECT image2DRect}, + {GL_IMAGE_CUBE imageCube}, + {GL_IMAGE_BUFFER imageBuffer}, + {GL_IMAGE_1D_ARRAY image1DArray}, + {GL_IMAGE_2D_ARRAY image2DArray}, + {GL_IMAGE_2D_MULTISAMPLE image2DMS}, + {GL_IMAGE_2D_MULTISAMPLE_ARRAY image2DMSArray}, + {GL_INT_IMAGE_1D iimage1D}, + {GL_INT_IMAGE_2D iimage2D}, + {GL_INT_IMAGE_3D iimage3D}, + {GL_INT_IMAGE_2D_RECT iimage2DRect}, + {GL_INT_IMAGE_CUBE iimageCube}, + {GL_INT_IMAGE_BUFFER iimageBuffer}, + {GL_INT_IMAGE_1D_ARRAY iimage1DArray}, + {GL_INT_IMAGE_2D_ARRAY iimage2DArray}, + {GL_INT_IMAGE_2D_MULTISAMPLE iimage2DMS}, + {GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY iimage2DMSArray}, + {GL_UNSIGNED_INT_IMAGE_1D uimage1D}, + {GL_UNSIGNED_INT_IMAGE_2D uimage2D}, + {GL_UNSIGNED_INT_IMAGE_3D uimage3D}, + {GL_UNSIGNED_INT_IMAGE_2D_RECT uimage2DRect}, + {GL_UNSIGNED_INT_IMAGE_CUBE uimageCube},+ [0] {_name="fInnerRadius" _location=0 _element={_semantic=15 '\xf' _dimension=0 '\0' _type=0 '\0' } } gpu::Shader::Slot + + {GL_UNSIGNED_INT_IMAGE_BUFFER uimageBuffer}, + {GL_UNSIGNED_INT_IMAGE_1D_ARRAY uimage1DArray}, + {GL_UNSIGNED_INT_IMAGE_2D_ARRAY uimage2DArray}, + {GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS}, {GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY uimage2DMSArray}, {GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint} */ @@ -542,6 +551,7 @@ bool isUnusedSlot(GLint binding) { int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) { GLint buffersCount = 0; +#if defined(Q_OS_WIN) glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount); // fast exit @@ -595,7 +605,7 @@ int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindin Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER); buffers.insert(Shader::Slot(name, binding, element, Resource::BUFFER)); } - +#endif return buffersCount; } diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index e4786df792..473d3c7613 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -154,12 +154,9 @@ SunSkyStage::SunSkyStage() : // Begining of march setYearTime(60.0f); - auto skyShader = gpu::ShaderPointer( - gpu::Shader::createProgram( - gpu::ShaderPointer(gpu::Shader::createVertex(std::string(SkyFromAtmosphere_vert))), - gpu::ShaderPointer(gpu::Shader::createPixel(std::string(SkyFromAtmosphere_frag))) - ) - ); + auto skyFromAtmosphereVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(SkyFromAtmosphere_vert))); + auto skyFromAtmosphereFragment = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(SkyFromAtmosphere_frag))); + auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyFromAtmosphereVertex, skyFromAtmosphereFragment)); _skyPipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, gpu::States())); } From 2f22c0cd962b3193e92d59a75b341e7dad1f112f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 16:28:01 -0700 Subject: [PATCH 16/56] cleanup username API from GlobalServicesScriptingInterface --- .../oculus/virtualKeyboardTextEntityExample.js | 2 +- .../GlobalServicesScriptingInterface.cpp | 4 ---- .../scripting/GlobalServicesScriptingInterface.h | 16 +++++++++------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/examples/controllers/oculus/virtualKeyboardTextEntityExample.js b/examples/controllers/oculus/virtualKeyboardTextEntityExample.js index cf36fdbffb..15025831e7 100644 --- a/examples/controllers/oculus/virtualKeyboardTextEntityExample.js +++ b/examples/controllers/oculus/virtualKeyboardTextEntityExample.js @@ -86,7 +86,7 @@ keyboard.onKeyRelease = function(event) { var textLines = textText.split("\n"); var maxLineWidth = Overlays.textSize(textSizeMeasureOverlay, textText).width; - var usernameLine = "--" + GlobalServices.myUsername; + var usernameLine = "--" + GlobalServices.username; var usernameWidth = Overlays.textSize(textSizeMeasureOverlay, usernameLine).width; if (maxLineWidth < usernameWidth) { maxLineWidth = usernameWidth; diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.cpp b/interface/src/scripting/GlobalServicesScriptingInterface.cpp index 478b708e53..37367fe40c 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.cpp +++ b/interface/src/scripting/GlobalServicesScriptingInterface.cpp @@ -36,10 +36,6 @@ GlobalServicesScriptingInterface* GlobalServicesScriptingInterface::getInstance( return &sharedInstance; } -QString GlobalServicesScriptingInterface::getMyUsername() { - return AccountManager::getInstance().getAccountInfo().getUsername(); -} - void GlobalServicesScriptingInterface::loggedOut() { emit GlobalServicesScriptingInterface::disconnected(QString("logout")); } diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.h b/interface/src/scripting/GlobalServicesScriptingInterface.h index a71446a970..bf49df15ad 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.h +++ b/interface/src/scripting/GlobalServicesScriptingInterface.h @@ -31,20 +31,21 @@ Q_DECLARE_METATYPE(DownloadInfoResult) QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result); void DownloadInfoResultFromScriptValue(const QScriptValue& object, DownloadInfoResult& result); - class GlobalServicesScriptingInterface : public QObject { Q_OBJECT - Q_PROPERTY(QString myUsername READ getMyUsername) - GlobalServicesScriptingInterface(); - ~GlobalServicesScriptingInterface(); + + Q_PROPERTY(QString username READ getUsername) + public: static GlobalServicesScriptingInterface* getInstance(); - QString getMyUsername(); + const QString& getUsername() const { return AccountManager::getInstance().getAccountInfo().getUsername(); } public slots: DownloadInfoResult getDownloadInfo(); void updateDownloadInfo(); + + void setDiscoverability(const QString& discoverability); private slots: void loggedOut(); @@ -53,12 +54,13 @@ private slots: signals: void connected(); void disconnected(const QString& reason); - void incomingMessage(const QString& username, const QString& message); - void onlineUsersChanged(const QStringList& usernames); void myUsernameChanged(const QString& username); void downloadInfoChanged(DownloadInfoResult info); private: + GlobalServicesScriptingInterface(); + ~GlobalServicesScriptingInterface(); + bool _downloading; }; From f81ae309181f2d1b72fc86fe5b86891a4c967a66 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 16:32:09 -0700 Subject: [PATCH 17/56] fix getUsername for AccountManager include in implementation --- interface/src/scripting/GlobalServicesScriptingInterface.cpp | 4 ++++ interface/src/scripting/GlobalServicesScriptingInterface.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.cpp b/interface/src/scripting/GlobalServicesScriptingInterface.cpp index 37367fe40c..1b03fcd5e6 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.cpp +++ b/interface/src/scripting/GlobalServicesScriptingInterface.cpp @@ -36,6 +36,10 @@ GlobalServicesScriptingInterface* GlobalServicesScriptingInterface::getInstance( return &sharedInstance; } +const QString& GlobalServicesScriptingInterface::getUsername() const { + return AccountManager::getInstance().getAccountInfo().getUsername(); +} + void GlobalServicesScriptingInterface::loggedOut() { emit GlobalServicesScriptingInterface::disconnected(QString("logout")); } diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.h b/interface/src/scripting/GlobalServicesScriptingInterface.h index bf49df15ad..58d7259b6e 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.h +++ b/interface/src/scripting/GlobalServicesScriptingInterface.h @@ -39,7 +39,7 @@ class GlobalServicesScriptingInterface : public QObject { public: static GlobalServicesScriptingInterface* getInstance(); - const QString& getUsername() const { return AccountManager::getInstance().getAccountInfo().getUsername(); } + const QString& getUsername() const; public slots: DownloadInfoResult getDownloadInfo(); From 77a60a3d72eb8aaaf6c1540551ce647f0705ac72 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 16:34:00 -0700 Subject: [PATCH 18/56] remove discoverability setter until API ready --- interface/src/scripting/GlobalServicesScriptingInterface.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.h b/interface/src/scripting/GlobalServicesScriptingInterface.h index 58d7259b6e..ad19a9496c 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.h +++ b/interface/src/scripting/GlobalServicesScriptingInterface.h @@ -44,8 +44,6 @@ public: public slots: DownloadInfoResult getDownloadInfo(); void updateDownloadInfo(); - - void setDiscoverability(const QString& discoverability); private slots: void loggedOut(); From 0658b54263d5c9b4ebf4a2ac118b08832504f474 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 16:48:39 -0700 Subject: [PATCH 19/56] move location update to DiscoverabilityManager --- interface/src/Application.cpp | 45 ++-------------- interface/src/Application.h | 1 - interface/src/DiscoverabilityManager.cpp | 65 ++++++++++++++++++++++++ interface/src/DiscoverabilityManager.h | 26 ++++++++++ 4 files changed, 95 insertions(+), 42 deletions(-) create mode 100644 interface/src/DiscoverabilityManager.cpp create mode 100644 interface/src/DiscoverabilityManager.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7addc27b3b..f393587006 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -87,6 +87,7 @@ #include "Application.h" #include "AudioClient.h" +#include "DiscoverabilityManager.h" #include "InterfaceVersion.h" #include "LODManager.h" #include "Menu.h" @@ -367,11 +368,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(&domainHandler, &DomainHandler::hostnameChanged, DependencyManager::get().data(), &AddressManager::storeCurrentAddress); - // update our location every 5 seconds in the data-server, assuming that we are authenticated with one + // update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000; locationUpdateTimer = new QTimer(this); - connect(locationUpdateTimer, &QTimer::timeout, this, &Application::updateLocationInServer); + auto discoverabilityManager = DependencyManager::get(); + connect(locationUpdateTimer, &QTimer::timeout, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS); connect(nodeList.data(), &NodeList::nodeAdded, this, &Application::nodeAdded); @@ -3187,45 +3189,6 @@ void Application::updateWindowTitle(){ _window->setWindowTitle(title); } -void Application::updateLocationInServer() { - - AccountManager& accountManager = AccountManager::getInstance(); - auto addressManager = DependencyManager::get(); - DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); - - if (accountManager.isLoggedIn() && domainHandler.isConnected() - && (!addressManager->getRootPlaceID().isNull() || !domainHandler.getUUID().isNull())) { - - // construct a QJsonObject given the user's current address information - QJsonObject rootObject; - - QJsonObject locationObject; - - QString pathString = addressManager->currentPath(); - - const QString LOCATION_KEY_IN_ROOT = "location"; - - const QString PATH_KEY_IN_LOCATION = "path"; - locationObject.insert(PATH_KEY_IN_LOCATION, pathString); - - if (!addressManager->getRootPlaceID().isNull()) { - const QString PLACE_ID_KEY_IN_LOCATION = "place_id"; - locationObject.insert(PLACE_ID_KEY_IN_LOCATION, - uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID())); - - } else { - const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id"; - locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION, - uuidStringWithoutCurlyBraces(domainHandler.getUUID())); - } - - rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject); - - accountManager.authenticatedRequest("/api/v1/user/location", QNetworkAccessManager::PutOperation, - JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); - } -} - void Application::clearDomainOctreeDetails() { qDebug() << "Clearing domain octree details..."; // reset the environment so that we don't erroneously end up with multiple diff --git a/interface/src/Application.h b/interface/src/Application.h index ce4bae45b9..1da5f430b6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -318,7 +318,6 @@ signals: public slots: void domainChanged(const QString& domainHostname); void updateWindowTitle(); - void updateLocationInServer(); void nodeAdded(SharedNodePointer node); void nodeKilled(SharedNodePointer node); void packetSent(quint64 length); diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp new file mode 100644 index 0000000000..e2fa011ed8 --- /dev/null +++ b/interface/src/DiscoverabilityManager.cpp @@ -0,0 +1,65 @@ +// +// DiscoverabilityManager.cpp +// interface/src +// +// Created by Stephen Birarda on 2015-03-09. +// Copyright 2015 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 + +#include +#include +#include +#include +#include + +#include "DiscoverabilityManager.h" + +const QString API_USER_LOCATION_PATH = "/api/v1/user/location"; + +void DiscoverabilityManager::updateLocation() { + AccountManager& accountManager = AccountManager::getInstance(); + auto addressManager = DependencyManager::get(); + DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); + + if (accountManager.isLoggedIn() && domainHandler.isConnected() + && (!addressManager->getRootPlaceID().isNull() || !domainHandler.getUUID().isNull())) { + + // construct a QJsonObject given the user's current address information + QJsonObject rootObject; + + QJsonObject locationObject; + + QString pathString = addressManager->currentPath(); + + const QString LOCATION_KEY_IN_ROOT = "location"; + + const QString PATH_KEY_IN_LOCATION = "path"; + locationObject.insert(PATH_KEY_IN_LOCATION, pathString); + + if (!addressManager->getRootPlaceID().isNull()) { + const QString PLACE_ID_KEY_IN_LOCATION = "place_id"; + locationObject.insert(PLACE_ID_KEY_IN_LOCATION, + uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID())); + + } else { + const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id"; + locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION, + uuidStringWithoutCurlyBraces(domainHandler.getUUID())); + } + + rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject); + + accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::PutOperation, + JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); + } +} + +void DiscoverabilityManager::removeLocation() { + AccountManager& accountManager = AccountManager::getInstance(); + accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::DeleteOperation); +} \ No newline at end of file diff --git a/interface/src/DiscoverabilityManager.h b/interface/src/DiscoverabilityManager.h new file mode 100644 index 0000000000..a9533b5efe --- /dev/null +++ b/interface/src/DiscoverabilityManager.h @@ -0,0 +1,26 @@ +// +// DiscoverabilityManager.h +// interface/src +// +// Created by Stephen Birarda on 2015-03-09. +// Copyright 2015 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_DiscoverabilityManager_h +#define hifi_DiscoverabilityManager_h + +#include + +class DiscoverabilityManager : public QObject, public Dependency { + Q_OBJECT + SINGLETON_DEPENDENCY + +public slots: + void updateLocation(); + void removeLocation(); +}; + +#endif // hifi_DiscoverabilityManager_h \ No newline at end of file From 6d900d5a40d72c7a78b37f0b52957e8f02152844 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 17:05:57 -0700 Subject: [PATCH 20/56] handle discoverability change in DiscoverabilityManager --- interface/src/Application.cpp | 1 + interface/src/DiscoverabilityManager.cpp | 87 +++++++++++++++--------- interface/src/DiscoverabilityManager.h | 20 +++++- 3 files changed, 76 insertions(+), 32 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f393587006..b30be206df 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -247,6 +247,7 @@ bool setupEssentials(int& argc, char** argv) { #if defined(Q_OS_MAC) || defined(Q_OS_WIN) auto speechRecognizer = DependencyManager::set(); #endif + auto discoverabilityManager = DependencyManager::set(); return true; } diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index e2fa011ed8..3c27e90152 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -19,47 +19,72 @@ #include "DiscoverabilityManager.h" +const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::None; + +DiscoverabilityManager::DiscoverabilityManager() : + _mode("discoverabilityMode", DEFAULT_DISCOVERABILITY_MODE) +{ + +} + const QString API_USER_LOCATION_PATH = "/api/v1/user/location"; void DiscoverabilityManager::updateLocation() { - AccountManager& accountManager = AccountManager::getInstance(); - auto addressManager = DependencyManager::get(); - DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); - - if (accountManager.isLoggedIn() && domainHandler.isConnected() - && (!addressManager->getRootPlaceID().isNull() || !domainHandler.getUUID().isNull())) { + if (_mode.get() != Discoverability::None) { + AccountManager& accountManager = AccountManager::getInstance(); + auto addressManager = DependencyManager::get(); + DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); - // construct a QJsonObject given the user's current address information - QJsonObject rootObject; - - QJsonObject locationObject; - - QString pathString = addressManager->currentPath(); - - const QString LOCATION_KEY_IN_ROOT = "location"; - - const QString PATH_KEY_IN_LOCATION = "path"; - locationObject.insert(PATH_KEY_IN_LOCATION, pathString); - - if (!addressManager->getRootPlaceID().isNull()) { - const QString PLACE_ID_KEY_IN_LOCATION = "place_id"; - locationObject.insert(PLACE_ID_KEY_IN_LOCATION, - uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID())); + if (accountManager.isLoggedIn() && domainHandler.isConnected() + && (!addressManager->getRootPlaceID().isNull() || !domainHandler.getUUID().isNull())) { - } else { - const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id"; - locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION, - uuidStringWithoutCurlyBraces(domainHandler.getUUID())); + // construct a QJsonObject given the user's current address information + QJsonObject rootObject; + + QJsonObject locationObject; + + QString pathString = addressManager->currentPath(); + + const QString LOCATION_KEY_IN_ROOT = "location"; + + const QString PATH_KEY_IN_LOCATION = "path"; + locationObject.insert(PATH_KEY_IN_LOCATION, pathString); + + if (!addressManager->getRootPlaceID().isNull()) { + const QString PLACE_ID_KEY_IN_LOCATION = "place_id"; + locationObject.insert(PLACE_ID_KEY_IN_LOCATION, + uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID())); + + } else { + const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id"; + locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION, + uuidStringWithoutCurlyBraces(domainHandler.getUUID())); + } + + rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject); + + accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::PutOperation, + JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); } - - rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject); - - accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::PutOperation, - JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); + } else { + qDebug() << "not updating discoverability since it is currently set to none!"; } } void DiscoverabilityManager::removeLocation() { AccountManager& accountManager = AccountManager::getInstance(); accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::DeleteOperation); +} + +void DiscoverabilityManager::setDiscoverability(Discoverability::Mode discoverabilityMode) { + if (_mode.get() != discoverabilityMode) { + + // update the setting to the new value + _mode.set(discoverabilityMode); + + if (_mode.get() == Discoverability::None) { + // if we just got set to no discoverability, make sure that we delete our location in DB + removeLocation(); + } + } } \ No newline at end of file diff --git a/interface/src/DiscoverabilityManager.h b/interface/src/DiscoverabilityManager.h index a9533b5efe..cb7791e82f 100644 --- a/interface/src/DiscoverabilityManager.h +++ b/interface/src/DiscoverabilityManager.h @@ -13,6 +13,17 @@ #define hifi_DiscoverabilityManager_h #include +#include + +namespace Discoverability { + enum Mode { + None, + Friends, + All + }; +} + +Q_DECLARE_METATYPE(Discoverability::Mode); class DiscoverabilityManager : public QObject, public Dependency { Q_OBJECT @@ -20,7 +31,14 @@ class DiscoverabilityManager : public QObject, public Dependency { public slots: void updateLocation(); - void removeLocation(); + void removeLocation(); + + void setDiscoverability(Discoverability::Mode discoverabilityMode); + +private: + DiscoverabilityManager(); + + Setting::Handle _mode; }; #endif // hifi_DiscoverabilityManager_h \ No newline at end of file From cd382eeea5dc10aa8b06b8364c648aa2f08d043f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 17:20:09 -0700 Subject: [PATCH 21/56] expose discoverability changes to js --- interface/src/DiscoverabilityManager.cpp | 4 +-- interface/src/DiscoverabilityManager.h | 3 ++- .../GlobalServicesScriptingInterface.cpp | 27 +++++++++++++++++++ .../GlobalServicesScriptingInterface.h | 4 +++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 3c27e90152..7dca8c399a 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -66,8 +66,6 @@ void DiscoverabilityManager::updateLocation() { accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::PutOperation, JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); } - } else { - qDebug() << "not updating discoverability since it is currently set to none!"; } } @@ -76,7 +74,7 @@ void DiscoverabilityManager::removeLocation() { accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::DeleteOperation); } -void DiscoverabilityManager::setDiscoverability(Discoverability::Mode discoverabilityMode) { +void DiscoverabilityManager::setDiscoverabilityMode(Discoverability::Mode discoverabilityMode) { if (_mode.get() != discoverabilityMode) { // update the setting to the new value diff --git a/interface/src/DiscoverabilityManager.h b/interface/src/DiscoverabilityManager.h index cb7791e82f..6d9f912928 100644 --- a/interface/src/DiscoverabilityManager.h +++ b/interface/src/DiscoverabilityManager.h @@ -33,7 +33,8 @@ public slots: void updateLocation(); void removeLocation(); - void setDiscoverability(Discoverability::Mode discoverabilityMode); + Discoverability::Mode getDiscoverabilityMode() { return _mode.get(); } + void setDiscoverabilityMode(Discoverability::Mode discoverabilityMode); private: DiscoverabilityManager(); diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.cpp b/interface/src/scripting/GlobalServicesScriptingInterface.cpp index 1b03fcd5e6..d39da47e78 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.cpp +++ b/interface/src/scripting/GlobalServicesScriptingInterface.cpp @@ -11,6 +11,7 @@ #include "AccountManager.h" #include "Application.h" +#include "DiscoverabilityManager.h" #include "ResourceCache.h" #include "GlobalServicesScriptingInterface.h" @@ -44,6 +45,32 @@ void GlobalServicesScriptingInterface::loggedOut() { emit GlobalServicesScriptingInterface::disconnected(QString("logout")); } +QString GlobalServicesScriptingInterface::getFindableBy() const { + auto discoverabilityManager = DependencyManager::get(); + + if (discoverabilityManager->getDiscoverabilityMode() == Discoverability::None) { + return "none"; + } else if (discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends) { + return "friends"; + } else { + return "all"; + } +} + +void GlobalServicesScriptingInterface::setFindableBy(const QString& discoverabilityMode) { + auto discoverabilityManager = DependencyManager::get(); + + if (discoverabilityMode.toLower() == "none") { + discoverabilityManager->setDiscoverabilityMode(Discoverability::None); + } else if (discoverabilityMode.toLower() == "friends") { + discoverabilityManager->setDiscoverabilityMode(Discoverability::Friends); + } else if (discoverabilityMode.toLower() == "all") { + discoverabilityManager->setDiscoverabilityMode(Discoverability::All); + } else { + qDebug() << "GlobalServices setFindableBy called with an unrecognized value. Did not change discoverability."; + } +} + DownloadInfoResult::DownloadInfoResult() : downloading(QList()), pending(0.0f) diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.h b/interface/src/scripting/GlobalServicesScriptingInterface.h index ad19a9496c..a39219ba40 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.h +++ b/interface/src/scripting/GlobalServicesScriptingInterface.h @@ -35,6 +35,7 @@ class GlobalServicesScriptingInterface : public QObject { Q_OBJECT Q_PROPERTY(QString username READ getUsername) + Q_PROPERTY(QString findableBy READ getFindableBy WRITE setFindableBy) public: static GlobalServicesScriptingInterface* getInstance(); @@ -48,6 +49,9 @@ public slots: private slots: void loggedOut(); void checkDownloadInfo(); + + QString getFindableBy() const; + void setFindableBy(const QString& discoverabilityMode); signals: void connected(); From c6afa131d9a219d39e8e03c935fde19641095c0e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 17:26:56 -0700 Subject: [PATCH 22/56] store discoverability mode as an int --- interface/src/DiscoverabilityManager.cpp | 6 +++--- interface/src/DiscoverabilityManager.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 7dca8c399a..0d0139e1db 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -75,12 +75,12 @@ void DiscoverabilityManager::removeLocation() { } void DiscoverabilityManager::setDiscoverabilityMode(Discoverability::Mode discoverabilityMode) { - if (_mode.get() != discoverabilityMode) { + if (static_cast(_mode.get()) != discoverabilityMode) { // update the setting to the new value - _mode.set(discoverabilityMode); + _mode.set(static_cast(discoverabilityMode)); - if (_mode.get() == Discoverability::None) { + if (static_cast(_mode.get()) == Discoverability::None) { // if we just got set to no discoverability, make sure that we delete our location in DB removeLocation(); } diff --git a/interface/src/DiscoverabilityManager.h b/interface/src/DiscoverabilityManager.h index 6d9f912928..1dac7d63eb 100644 --- a/interface/src/DiscoverabilityManager.h +++ b/interface/src/DiscoverabilityManager.h @@ -33,13 +33,13 @@ public slots: void updateLocation(); void removeLocation(); - Discoverability::Mode getDiscoverabilityMode() { return _mode.get(); } + Discoverability::Mode getDiscoverabilityMode() { return static_cast(_mode.get()); } void setDiscoverabilityMode(Discoverability::Mode discoverabilityMode); private: DiscoverabilityManager(); - Setting::Handle _mode; + Setting::Handle _mode; }; #endif // hifi_DiscoverabilityManager_h \ No newline at end of file From de38221cf6a38e71eee63504bde83ed43175d23a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 17:28:44 -0700 Subject: [PATCH 23/56] default to All discoverability until UI is present --- interface/src/DiscoverabilityManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 0d0139e1db..49850e4ef6 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -19,7 +19,7 @@ #include "DiscoverabilityManager.h" -const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::None; +const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::All; DiscoverabilityManager::DiscoverabilityManager() : _mode("discoverabilityMode", DEFAULT_DISCOVERABILITY_MODE) From d9c071a2a9a6ed4c471a0efa498330b942724baf Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 10 Mar 2015 00:47:27 -0700 Subject: [PATCH 24/56] trying to put the atmospheric effect in a shader header and use it on the directional lighting pass --- libraries/gpu/src/gpu/Pipeline.h | 2 +- libraries/model/src/model/Atmosphere.slh | 244 ++++++++++++++++++ libraries/model/src/model/Stage.cpp | 50 ++++ libraries/model/src/model/Stage.h | 56 ++++ .../render-utils/src/DeferredGlobalLight.slh | 10 + .../src/DeferredLightingEffect.cpp | 31 +++ .../render-utils/src/DeferredLightingEffect.h | 4 + tools/scribe/src/main.cpp | 12 +- 8 files changed, 406 insertions(+), 3 deletions(-) create mode 100755 libraries/model/src/model/Atmosphere.slh diff --git a/libraries/gpu/src/gpu/Pipeline.h b/libraries/gpu/src/gpu/Pipeline.h index c2fc944bb7..faa671c30f 100755 --- a/libraries/gpu/src/gpu/Pipeline.h +++ b/libraries/gpu/src/gpu/Pipeline.h @@ -44,7 +44,7 @@ protected: friend class Backend; }; -typedef QSharedPointer< Pipeline > PipelinePointer; +typedef std::shared_ptr< Pipeline > PipelinePointer; typedef std::vector< PipelinePointer > Pipelines; }; diff --git a/libraries/model/src/model/Atmosphere.slh b/libraries/model/src/model/Atmosphere.slh new file mode 100755 index 0000000000..11b64dde70 --- /dev/null +++ b/libraries/model/src/model/Atmosphere.slh @@ -0,0 +1,244 @@ + +<@if not MODEL_ATMOSPHERE_SLH@> +<@def MODEL_ATMOSPHERE_SLH@> + + + +struct Atmosphere { + vec4 _invWaveLength; + vec4 _radiuses; + vec4 _scales; + vec4 _scatterings; + vec4 _control; +}; + +const int numSamples = 2; + +vec3 getAtmosphereInvWaveLength(Atmosphere a) { return a._invWaveLength.xyz; } // 1 / pow(wavelength, 4) for the red, green, and blue channels + +float getAtmosphereInnerRadius(Atmosphere a) { return a._radiuses.x; } // The inner (planetary) radius +float getAtmosphereOuterRadius(Atmosphere a) { return a._radiuses.y; } // The outer (atmosphere) radius + +float getAtmosphereScale(Atmosphere a) { return a._scales.x; } // 1 / (outerRadius - innerRadius) +float getAtmosphereScaleDepth(Atmosphere a) { return a._scales.y; } // The scale depth (i.e. the altitude at which the atmosphere's average density is found) +float getAtmosphereScaleOverScaleDepth(Atmosphere a) { return a._scales.z; } // scale / scaleDepth + +vec4 getAtmosphereScattering(Atmosphere a) { return a._scatterings; } // The full Mie and Rayleigh scattering coefficients +float getAtmosphereKrESun(Atmosphere a) { return a._scatterings.x; } // Kr * ESun +float getAtmosphereKmESun(Atmosphere a) { return a._scatterings.y; } // Km * ESun +float getAtmosphereKr4PI(Atmosphere a) { return a._scatterings.z; } // Kr * 4 * PI +float getAtmosphereKm4PI(Atmosphere a) { return a._scatterings.w; } // Km * 4 * PI + +float getAtmosphereNumSamples(Atmosphere a) { return a._control.x; } // numSamples +vec2 getAtmosphereGAndG2(Atmosphere a) { return a._control.yz; } // g and g2 + +float atmosphereScale(float scaleDepth, float fCos) +{ + float x = 1.0 - fCos; + return scaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); +} + +vec4 evalAtmosphereContribution(Atmosphere atmospheric, vec3 position, vec3 cameraPos, vec3 lightPos) { + float fInnerRadius = getAtmosphereInnerRadius(atmospheric); + float fSamples = getAtmosphereNumSamples(atmospheric); + + vec3 v3InvWavelength = getAtmosphereInvWaveLength(atmospheric); + vec4 scatteringCoefs = getAtmosphereScattering(atmospheric); + float fKrESun = scatteringCoefs.x; + float fKmESun = scatteringCoefs.y; + float fKr4PI = scatteringCoefs.z; + float fKm4PI = scatteringCoefs.w; + + vec2 gAndg2 = getAtmosphereGAndG2(atmospheric); + float g = gAndg2.x; + float g2 = gAndg2.y; + + float fScale = getAtmosphereScale(atmospheric); + float fScaleDepth = getAtmosphereScaleDepth(atmospheric); + float fScaleOverScaleDepth = getAtmosphereScaleOverScaleDepth(atmospheric); + + // Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere) + vec3 v3Pos = position; + vec3 v3Ray = v3Pos - cameraPos; + float fFar = length(v3Ray); + v3Ray /= fFar; + + // Calculate the ray's starting position, then calculate its scattering offset + vec3 v3Start = cameraPos; + float fHeight = length(v3Start); + float fDepthStart = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight)); + float fStartAngle = dot(v3Ray, v3Start) / fHeight; + float fStartOffset = fDepthStart * atmosphereScale(fScaleDepth, fStartAngle); + + // Initialize the scattering loop variables + //gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0); + float fSampleLength = fFar / fSamples; + float fScaledLength = fSampleLength * fScale; + vec3 v3SampleRay = v3Ray * fSampleLength; + vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; + + // Now loop through the sample rays + vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); + int nSamples = numSamples; + // int nSamples = int(fSamples); + for(int i=0; i +uniform atmosphereBuffer { + Atmosphere _atmosphere; +}; +Atmosphere getAtmosphere() { + return _atmosphere; +} +<@else@> +uniform vec4 atmosphereBuffer[9]; +Atmosphere getAtmosphere() { + Atmosphere atmosphere; + atmosphere._invWaveLength = atmosphereBuffer[0]; + atmosphere._radiuses = atmosphereBuffer[1]; + atmosphere._scales = atmosphereBuffer[2]; + atmosphere._scatterings = atmosphereBuffer[3]; + atmosphere._control = atmosphereBuffer[4]; + + return atmosphere; +} +<@endif@> + + + +<@endif@> diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 473d3c7613..970539a908 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -134,6 +134,56 @@ void EarthSunModel::setSunLongitude(float lon) { _sunLongitude = validateLongitude(lon); invalidate(); } + +Atmosphere::Atmosphere() { + // only if created from nothing shall we create the Buffer to store the properties + Data data; + _dataBuffer = gpu::BufferView(new gpu::Buffer(sizeof(Data), (const gpu::Buffer::Byte*) &data)); + + setScatteringWavelength(_scatteringWavelength); + setRayleighScattering(_rayleighScattering); + setInnerOuterRadiuses(getInnerRadius(), getOuterRadius()); +} + +void Atmosphere::setScatteringWavelength(Vec3 wavelength) { + _scatteringWavelength = wavelength; + Data& data = editData(); + data._invWaveLength = Vec4(1.0f / powf(wavelength.x, 4.0f), 1.0f / powf(wavelength.y, 4.0f), 1.0f / powf(wavelength.z, 4.0f), 0.0f); +} + +void Atmosphere::setRayleighScattering(float scattering) { + _rayleighScattering = scattering; + updateScattering(); +} + +void Atmosphere::setMieScattering(float scattering) { + _mieScattering = scattering; + updateScattering(); +} + +void Atmosphere::setSunBrightness(float brightness) { + _sunBrightness = brightness; + updateScattering(); +} + +void Atmosphere::updateScattering() { + Data& data = editData(); + + data._scatterings.x = getRayleighScattering() * getSunBrightness(); + data._scatterings.y = getMieScattering() * getSunBrightness(); + + data._scatterings.z = getRayleighScattering() * 4.0f * glm::pi(); + data._scatterings.w = getMieScattering() * 4.0f * glm::pi(); +} + +void Atmosphere::setInnerOuterRadiuses(float inner, float outer) { + Data& data = editData(); + data._radiuses.x = inner; + data._radiuses.y = outer; + data._scales.x = 1.0f / (outer - inner); + data._scales.z = data._scales.x / data._scales.y; +} + const int NUM_DAYS_PER_YEAR = 365; const float NUM_HOURS_PER_DAY = 24.0f; diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index 61914b5a6b..3cc8b4a6e9 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -106,6 +106,60 @@ protected: static Mat4d evalWorldToGeoLocationMat(double longitude, double latitude, double altitude, double scale); }; + +class Atmosphere { +public: + + Atmosphere(); + Atmosphere(const Atmosphere& atmosphere); + Atmosphere& operator= (const Atmosphere& atmosphere); + virtual ~Atmosphere() {}; + + + void setScatteringWavelength(Vec3 wavelength); + const Vec3& getScatteringWavelength() const { return _scatteringWavelength; } + + void setRayleighScattering(float scattering); + float getRayleighScattering() const { return _rayleighScattering; } + + void setMieScattering(float scattering); + float getMieScattering() const { return _mieScattering; } + + void setSunBrightness(float brightness); + float getSunBrightness() const { return _sunBrightness; } + + void setInnerOuterRadiuses(float inner, float outer); + float getInnerRadius() const { return getData()._radiuses.x; } + float getOuterRadius() const { return getData()._radiuses.y; } + + // Data to access the attribute values of the atmosphere + class Data { + public: + Vec4 _invWaveLength = Vec4(0.0f); + Vec4 _radiuses = Vec4(6000.0f, 6025.0f, 0.0f, 0.0f); + Vec4 _scales = Vec4(0.0f, 0.25f, 0.0f, 0.0f); + Vec4 _scatterings = Vec4(0.0f); + Vec4 _control = Vec4(2.0f, -0.990f, -0.990f*-0.990f, 0.f); + + Data() {} + }; + + const UniformBufferView& getDataBuffer() const { return _dataBuffer; } + +protected: + UniformBufferView _dataBuffer; + Vec3 _scatteringWavelength = Vec3(0.650f, 0.570f, 0.475f); + float _rayleighScattering = 0.0025f; + float _mieScattering = 0.0010f; + float _sunBrightness = 20.0f; + + const Data& getData() const { return _dataBuffer.get(); } + Data& editData() { return _dataBuffer.edit(); } + + void updateScattering(); +}; +typedef QSharedPointer< Atmosphere > AtmospherePointer; + // Sun sky stage generates the rendering primitives to display a scene realistically // at the specified location and time around earth class SunSkyStage { @@ -141,9 +195,11 @@ public: float getSunIntensity() const { return getSunLight()->getIntensity(); } LightPointer getSunLight() const { valid(); return _sunLight; } + AtmospherePointer getAtmosphere() const { valid(); return _atmosphere; } protected: LightPointer _sunLight; + AtmospherePointer _atmosphere; gpu::PipelinePointer _skyPipeline; diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 3039c92d67..b48b61fd9f 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -13,6 +13,7 @@ <@include DeferredLighting.slh@> + struct SphericalHarmonics { vec4 L00; vec4 L1m1; @@ -50,6 +51,7 @@ uniform SphericalHarmonics ambientSphere; // Everything about light <@include model/Light.slh@> +<@include model/Atmosphere.slh@> // The view Matrix uniform mat4 invViewMat; @@ -89,6 +91,14 @@ vec3 evalAmbienSphereGlobalColor(float shadowAttenuation, vec3 position, vec3 no color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + + vec3 fragPos = vec3(invViewMat * vec4(position, 1.0)); + vec3 cameraPos = invViewMat[3].xyz; + vec3 lightPos = 10000.0 * getLightDirection(light); + + Atmosphere atmo = getAtmosphere(); + vec4 atmoColor = evalAtmosphereContribution(atmo, fragPos, cameraPos, lightPos); + return color; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index c8ad3711d3..96ab790cd6 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -270,6 +270,12 @@ void DeferredLightingEffect::render() { batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer()); gpu::GLBackend::renderBatch(batch); } + + if (_atmosphere && (locations->atmosphereBufferUnit >= 0)) { + gpu::Batch batch; + batch.setUniformBuffer(locations->atmosphereBufferUnit, _atmosphere->getDataBuffer()); + gpu::GLBackend::renderBatch(batch); + } glUniformMatrix4fv(locations->invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); } @@ -511,6 +517,31 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit locations.lightBufferUnit = -1; } #endif + +#if defined(Q_OS_MAC) + loc = program.uniformLocation("atmosphereBufferUnit"); + if (loc >= 0) { + locations.atmosphereBufferUnit = loc; + } else { + locations.atmosphereBufferUnit = -1; + } +#elif defined(Q_OS_WIN) + loc = glGetUniformBlockIndex(program.programId(), "atmosphereBufferUnit"); + if (loc >= 0) { + glUniformBlockBinding(program.programId(), loc, 1); + locations.atmosphereBufferUnit = 1; + } else { + locations.atmosphereBufferUnit = -1; + } +#else + loc = program.uniformLocation("atmosphereBufferUnit"); + if (loc >= 0) { + locations.atmosphereBufferUnit = loc; + } else { + locations.atmosphereBufferUnit = -1; + } +#endif + program.release(); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 951c36f038..900c5243cb 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -20,6 +20,7 @@ #include "ProgramObject.h" #include "model/Light.h" +#include "model/Stage.h" class AbstractViewStateInterface; class PostLightingRenderable; @@ -73,6 +74,7 @@ public: // update global lighting void setAmbientLightMode(int preset); void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity); + void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; } private: DeferredLightingEffect() {} @@ -89,6 +91,7 @@ private: int radius; int ambientSphere; int lightBufferUnit; + int atmosphereBufferUnit; int invViewMat; }; @@ -146,6 +149,7 @@ private: AbstractViewStateInterface* _viewState; int _ambientLightMode = 0; + model::AtmospherePointer _atmosphere; }; /// Simple interface for objects that require something to be rendered after deferred lighting. diff --git a/tools/scribe/src/main.cpp b/tools/scribe/src/main.cpp index f68272c0ab..10f0a026ca 100755 --- a/tools/scribe/src/main.cpp +++ b/tools/scribe/src/main.cpp @@ -192,9 +192,17 @@ int main (int argc, char** argv) { targetStringStream << "#ifndef scribe_" << targetName << "_h" << std::endl; targetStringStream << "#define scribe_" << targetName << "_h" << std::endl << std::endl; - targetStringStream << "const char " << targetName << "[] = R\"XXXX(" << destStringStream.str() << ")XXXX\";"; + // targetStringStream << "const char " << targetName << "[] = R\"XXXX(" << destStringStream.str() << ")XXXX\";"; + std::istringstream destStringStreamAgain(destStringStream.str()); + targetStringStream << "const char " << targetName << "[] = \n"; + while (!destStringStreamAgain.eof()) { + std::string lineToken; + std::getline(destStringStreamAgain, lineToken); + // targetStringStream << "\"" << lineToken << "\"\n"; + targetStringStream << "R\"X(" << lineToken << ")X\"\"\\n\"\n"; + } - targetStringStream << std::endl << std::endl; + targetStringStream << ";\n" << std::endl << std::endl; targetStringStream << "#endif" << std::endl; } else { targetStringStream << destStringStream.str(); From 89f3a091f11db26a475b81aca391fccf93b0c691 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 10 Mar 2015 09:02:35 -0700 Subject: [PATCH 25/56] remove debugging --- interface/src/ModelUploader.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp index 4093b3e610..aca02cb904 100644 --- a/interface/src/ModelUploader.cpp +++ b/interface/src/ModelUploader.cpp @@ -338,9 +338,6 @@ void ModelUploader::populateBasicMapping(QVariantHash& mapping, QString filename geometry.blendshapeChannelNames.contains("Blink_Right") && geometry.blendshapeChannelNames.contains("Squint_Right")); -qDebug() << "likelyMixamoFile:" << likelyMixamoFile; -qDebug() << "geometry.blendshapeChannelNames:" << geometry.blendshapeChannelNames; - if (!mapping.contains(BLENDSHAPE_FIELD) && likelyMixamoFile) { QVariantHash blendshapes; blendshapes.insertMulti("BrowsD_L", QVariantList() << "BrowsDown_Left" << 1.0); From da16baf0ca2d9e409600d481f8f15351c1dd7c2f Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 10 Mar 2015 10:24:16 -0700 Subject: [PATCH 26/56] removing the atmosphere effect from the directional lighting --- libraries/render-utils/src/DeferredGlobalLight.slh | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index b48b61fd9f..556e7421af 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -51,7 +51,6 @@ uniform SphericalHarmonics ambientSphere; // Everything about light <@include model/Light.slh@> -<@include model/Atmosphere.slh@> // The view Matrix uniform mat4 invViewMat; @@ -91,14 +90,6 @@ vec3 evalAmbienSphereGlobalColor(float shadowAttenuation, vec3 position, vec3 no color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light); - - vec3 fragPos = vec3(invViewMat * vec4(position, 1.0)); - vec3 cameraPos = invViewMat[3].xyz; - vec3 lightPos = 10000.0 * getLightDirection(light); - - Atmosphere atmo = getAtmosphere(); - vec4 atmoColor = evalAtmosphereContribution(atmo, fragPos, cameraPos, lightPos); - return color; } From c8298ca617e4e59cdf8b5a425e146553f6288c5c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 10 Mar 2015 10:49:53 -0700 Subject: [PATCH 27/56] migrate SVO reading to use QDataStream in step toward reading from HTTP url --- libraries/octree/src/Octree.cpp | 239 +++++++++++++++++--------------- libraries/octree/src/Octree.h | 1 + 2 files changed, 129 insertions(+), 111 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 6b8f8c31e8..6c36b28c7a 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -18,7 +18,10 @@ #include #include // to load voxels from file +#include #include +#include +#include #include #include @@ -1836,141 +1839,155 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, bool Octree::readFromSVOFile(const char* fileName) { bool fileOk = false; - PacketVersion gotVersion = 0; - std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate); + QFile file(fileName); + QFileInfo fileInfo(fileName); + bool isOpen = file.open(QIODevice::ReadOnly); + QDataStream fileInputStream(&file); // read the data serialized from the file - if(file.is_open()) { + // get file length.... + unsigned long fileLength = fileInfo.size(); + + if(isOpen) { emit importSize(1.0f, 1.0f, 1.0f); emit importProgress(0); qDebug("Loading file %s...", fileName); + + fileOk = readFromStream(fileLength, fileInputStream); - // get file length.... - unsigned long fileLength = file.tellg(); - file.seekg( 0, std::ios::beg ); + emit importProgress(100); + file.close(); + } + + return fileOk; +} + +bool Octree::readFromStream(unsigned long streamLength, QDataStream& inputStream) { + bool fileOk = false; + + PacketVersion gotVersion = 0; + + unsigned long headerLength = 0; // bytes in the header + + bool wantImportProgress = true; + + PacketType expectedType = expectedDataPacketType(); + PacketVersion expectedVersion = versionForPacketType(expectedType); + bool hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion); + + // before reading the file, check to see if this version of the Octree supports file versions + if (getWantSVOfileVersions()) { + + // read just enough of the file to parse the header... + const unsigned long HEADER_LENGTH = sizeof(PacketType) + sizeof(PacketVersion); + unsigned char fileHeader[HEADER_LENGTH]; + //file.read((char*)&fileHeader, HEADER_LENGTH); + int bytesRead = inputStream.readRawData((char*)&fileHeader, HEADER_LENGTH); + qDebug() << "HEADER_LENGTH... bytesRead:" << bytesRead; - unsigned long headerLength = 0; // bytes in the header + headerLength = HEADER_LENGTH; // we need this later to skip to the data + + unsigned char* dataAt = (unsigned char*)&fileHeader; + unsigned long dataLength = HEADER_LENGTH; + + // if so, read the first byte of the file and see if it matches the expected version code + PacketType gotType; + memcpy(&gotType, dataAt, sizeof(gotType)); + + dataAt += sizeof(expectedType); + dataLength -= sizeof(expectedType); + gotVersion = *dataAt; - bool wantImportProgress = true; + if (gotType == expectedType) { + if (canProcessVersion(gotVersion)) { + dataAt += sizeof(gotVersion); + dataLength -= sizeof(gotVersion); + fileOk = true; + qDebug("SVO file version match. Expected: %d Got: %d", + versionForPacketType(expectedDataPacketType()), gotVersion); - PacketType expectedType = expectedDataPacketType(); - PacketVersion expectedVersion = versionForPacketType(expectedType); - bool hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion); - - // before reading the file, check to see if this version of the Octree supports file versions - if (getWantSVOfileVersions()) { - - // read just enough of the file to parse the header... - const unsigned long HEADER_LENGTH = sizeof(PacketType) + sizeof(PacketVersion); - unsigned char fileHeader[HEADER_LENGTH]; - file.read((char*)&fileHeader, HEADER_LENGTH); - - headerLength = HEADER_LENGTH; // we need this later to skip to the data - - unsigned char* dataAt = (unsigned char*)&fileHeader; - unsigned long dataLength = HEADER_LENGTH; - - // if so, read the first byte of the file and see if it matches the expected version code - PacketType gotType; - memcpy(&gotType, dataAt, sizeof(gotType)); - - dataAt += sizeof(expectedType); - dataLength -= sizeof(expectedType); - gotVersion = *dataAt; - - if (gotType == expectedType) { - if (canProcessVersion(gotVersion)) { - dataAt += sizeof(gotVersion); - dataLength -= sizeof(gotVersion); - fileOk = true; - qDebug("SVO file version match. Expected: %d Got: %d", - versionForPacketType(expectedDataPacketType()), gotVersion); - - hasBufferBreaks = versionHasSVOfileBreaks(gotVersion); - } else { - qDebug("SVO file version mismatch. Expected: %d Got: %d", - versionForPacketType(expectedDataPacketType()), gotVersion); - } + hasBufferBreaks = versionHasSVOfileBreaks(gotVersion); } else { - qDebug() << "SVO file type mismatch. Expected: " << nameForPacketType(expectedType) - << " Got: " << nameForPacketType(gotType); + qDebug("SVO file version mismatch. Expected: %d Got: %d", + versionForPacketType(expectedDataPacketType()), gotVersion); } - } else { - qDebug() << " NOTE: this file type does not include type and version information."; - fileOk = true; // assume the file is ok - } - - if (hasBufferBreaks) { - qDebug() << " this version includes buffer breaks"; - } else { - qDebug() << " this version does not include buffer breaks"; + qDebug() << "SVO file type mismatch. Expected: " << nameForPacketType(expectedType) + << " Got: " << nameForPacketType(gotType); } - if (fileOk) { + } else { + qDebug() << " NOTE: this file type does not include type and version information."; + fileOk = true; // assume the file is ok + } + + if (hasBufferBreaks) { + qDebug() << " this version includes buffer breaks"; + } else { + qDebug() << " this version does not include buffer breaks"; + } + + if (fileOk) { + + // if this version of the file does not include buffer breaks, then we need to load the entire file at once + if (!hasBufferBreaks) { - // if this version of the file does not include buffer breaks, then we need to load the entire file at once - if (!hasBufferBreaks) { + // read the entire file into a buffer, WHAT!? Why not. + unsigned long dataLength = streamLength - headerLength; + unsigned char* entireFileDataSection = new unsigned char[dataLength]; + inputStream.readRawData((char*)entireFileDataSection, dataLength); + + unsigned char* dataAt = entireFileDataSection; + + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, + SharedNodePointer(), wantImportProgress, gotVersion); + + readBitstreamToTree(dataAt, dataLength, args); + delete[] entireFileDataSection; + + } else { + - // read the entire file into a buffer, WHAT!? Why not. - unsigned long dataLength = fileLength - headerLength; - unsigned char* entireFileDataSection = new unsigned char[dataLength]; - file.read((char*)entireFileDataSection, dataLength); - unsigned char* dataAt = entireFileDataSection; + unsigned long dataLength = streamLength - headerLength; + unsigned long remainingLength = dataLength; + const unsigned long MAX_CHUNK_LENGTH = MAX_OCTREE_PACKET_SIZE * 2; + unsigned char* fileChunk = new unsigned char[MAX_CHUNK_LENGTH]; + while (remainingLength > 0) { + quint16 chunkLength = 0; + + inputStream.readRawData((char*)&chunkLength, sizeof(chunkLength)); + remainingLength -= sizeof(chunkLength); + + if (chunkLength > remainingLength) { + qDebug() << "UNEXPECTED chunk size of:" << chunkLength + << "greater than remaining length:" << remainingLength; + break; + } + + if (chunkLength > MAX_CHUNK_LENGTH) { + qDebug() << "UNEXPECTED chunk size of:" << chunkLength + << "greater than MAX_CHUNK_LENGTH:" << MAX_CHUNK_LENGTH; + break; + } + + inputStream.readRawData((char*)fileChunk, chunkLength); + + remainingLength -= chunkLength; + + unsigned char* dataAt = fileChunk; + unsigned long dataLength = chunkLength; + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress, gotVersion); readBitstreamToTree(dataAt, dataLength, args); - delete[] entireFileDataSection; - - } else { - - - unsigned long dataLength = fileLength - headerLength; - unsigned long remainingLength = dataLength; - const unsigned long MAX_CHUNK_LENGTH = MAX_OCTREE_PACKET_SIZE * 2; - unsigned char* fileChunk = new unsigned char[MAX_CHUNK_LENGTH]; - - while (remainingLength > 0) { - quint16 chunkLength = 0; - - file.read((char*)&chunkLength, sizeof(chunkLength)); // read the chunk size from the file - remainingLength -= sizeof(chunkLength); - - if (chunkLength > remainingLength) { - qDebug() << "UNEXPECTED chunk size of:" << chunkLength - << "greater than remaining length:" << remainingLength; - break; - } - - if (chunkLength > MAX_CHUNK_LENGTH) { - qDebug() << "UNEXPECTED chunk size of:" << chunkLength - << "greater than MAX_CHUNK_LENGTH:" << MAX_CHUNK_LENGTH; - break; - } - - file.read((char*)fileChunk, chunkLength); // read in a section of the file larger than the chunk; - - remainingLength -= chunkLength; - - unsigned char* dataAt = fileChunk; - unsigned long dataLength = chunkLength; - - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, - SharedNodePointer(), wantImportProgress, gotVersion); - - readBitstreamToTree(dataAt, dataLength, args); - } - - delete[] fileChunk; } + + delete[] fileChunk; } - - emit importProgress(100); - - file.close(); } + return fileOk; } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index a2265e38ed..c4e4e2205b 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -327,6 +327,7 @@ public: // these will read/write files that match the wireformat, excluding the 'V' leading void writeToSVOFile(const char* filename, OctreeElement* element = NULL); bool readFromSVOFile(const char* filename); + bool readFromStream(unsigned long streamLength, QDataStream& inputStream); unsigned long getOctreeElementsCount(); From 292354e180a0d37926fcf68419ac5ce80b0f906d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 10 Mar 2015 11:33:49 -0700 Subject: [PATCH 28/56] manually call delete on GLCanvas in Application dtor --- interface/src/Application.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6945e88949..aa5d0bfb88 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -602,7 +602,9 @@ Application::~Application() { _myAvatar = NULL; - ModelEntityItem::cleanupLoadedAnimations() ; + ModelEntityItem::cleanupLoadedAnimations(); + + delete _glWidget; DependencyManager::destroy(); DependencyManager::destroy(); @@ -614,7 +616,7 @@ Application::~Application() { } void Application::initializeGL() { - qDebug( "Created Display Window."); + qDebug() << "Created Display Window."; // initialize glut for shape drawing; Qt apparently initializes it on OS X #ifndef __APPLE__ @@ -629,7 +631,7 @@ void Application::initializeGL() { #ifdef WIN32 GLenum err = glewInit(); if (GLEW_OK != err) { - /* Problem: glewInit failed, something is seriously wrong. */ + /* Problem: glewInit fa iled, something is seriously wrong. */ qDebug("Error: %s\n", glewGetErrorString(err)); } qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); From a8046b8316bf477073fa37910fdf942f43146fcb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 10 Mar 2015 11:47:35 -0700 Subject: [PATCH 29/56] fix a typo in comment, NULL glWidget pointer --- interface/src/Application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index aa5d0bfb88..0182e6e195 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -605,6 +605,7 @@ Application::~Application() { ModelEntityItem::cleanupLoadedAnimations(); delete _glWidget; + _glWidget = NULL; DependencyManager::destroy(); DependencyManager::destroy(); @@ -631,7 +632,7 @@ void Application::initializeGL() { #ifdef WIN32 GLenum err = glewInit(); if (GLEW_OK != err) { - /* Problem: glewInit fa iled, something is seriously wrong. */ + /* Problem: glewInit failed, something is seriously wrong. */ qDebug("Error: %s\n", glewGetErrorString(err)); } qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); From 5facb39aa7b6cc0d5b0baa27a3643a72ff713ad3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 10 Mar 2015 12:21:37 -0700 Subject: [PATCH 30/56] support for import entities from network URL --- examples/editEntities.js | 24 +++++++++++++++++- interface/src/Application.cpp | 2 +- libraries/octree/src/Octree.cpp | 43 ++++++++++++++++++++++++++++++--- libraries/octree/src/Octree.h | 2 ++ 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/examples/editEntities.js b/examples/editEntities.js index 689f73eed4..a2ecd7ff02 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -699,7 +699,7 @@ function setupModelMenus() { Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Export Entities", shortcutKey: "CTRL+META+E", afterItem: "Models" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities", shortcutKey: "CTRL+META+I", afterItem: "Export Entities" }); - + Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities from URL", shortcutKey: "CTRL+META+U", afterItem: "Import Entities" }); Menu.addMenuItem({ menuName: "View", menuItemName: MENU_AUTO_FOCUS_ON_SELECT, afterItem: MENU_INSPECT_TOOL_ENABLED, isCheckable: true, isChecked: Settings.getValue(SETTING_AUTO_FOCUS_ON_SELECT) == "true" }); @@ -800,6 +800,28 @@ function handeMenuEvent(menuItem) { if (filename) { var success = Clipboard.importEntities(filename); + if (success) { + var distance = cameraManager.enabled ? cameraManager.zoomDistance : DEFAULT_ENTITY_DRAG_DROP_DISTANCE; + var direction = Quat.getFront(Camera.orientation); + var offset = Vec3.multiply(distance, direction); + var position = Vec3.sum(Camera.position, offset); + + position.x = Math.max(0, position.x); + position.y = Math.max(0, position.y); + position.z = Math.max(0, position.z); + + var pastedEntityIDs = Clipboard.pasteEntities(position); + + selectionManager.setSelections(pastedEntityIDs); + } else { + Window.alert("There was an error importing the entity file."); + } + } + } else if (menuItem == "Import Entities from URL") { + var url = Window.prompt("URL of SVO to import", ""); + if (url) { + var success = Clipboard.importEntities(url); + if (success) { var distance = cameraManager.enabled ? cameraManager.zoomDistance : DEFAULT_ENTITY_DRAG_DROP_DISTANCE; var direction = Quat.getFront(Camera.orientation); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6945e88949..4662f92427 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1723,7 +1723,7 @@ void Application::saveSettings() { bool Application::importEntities(const QString& filename) { _entityClipboard.eraseAllOctreeElements(); - bool success = _entityClipboard.readFromSVOFile(filename.toLocal8Bit().constData()); + bool success = _entityClipboard.readFromSVOURL(filename); if (success) { _entityClipboard.reaverageOctreeElements(); } diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 6c36b28c7a..fddbe0bef5 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -20,13 +20,18 @@ #include #include +#include #include #include +#include +#include +#include #include #include -#include #include +#include +#include #include #include #include @@ -1862,6 +1867,38 @@ bool Octree::readFromSVOFile(const char* fileName) { return fileOk; } +bool Octree::readFromSVOURL(const QString& urlString) { + bool readOk = false; + + // determine if this is a local file or a network resource + QUrl url(urlString); + + if (url.isLocalFile()) { + readOk = readFromSVOFile(qPrintable(url.toLocalFile())); + } else { + QNetworkRequest request; + request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + request.setUrl(url); + + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkReply* reply = networkAccessManager.get(request); + + qDebug() << "Downloading svo at" << qPrintable(urlString); + + QEventLoop loop; + QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + + if (reply->error() == QNetworkReply::NoError) { + int resourceSize = reply->bytesAvailable(); + QDataStream inputStream(reply); + readOk = readFromStream(resourceSize, inputStream); + } + } + return readOk; +} + + bool Octree::readFromStream(unsigned long streamLength, QDataStream& inputStream) { bool fileOk = false; @@ -1881,9 +1918,7 @@ bool Octree::readFromStream(unsigned long streamLength, QDataStream& inputStream // read just enough of the file to parse the header... const unsigned long HEADER_LENGTH = sizeof(PacketType) + sizeof(PacketVersion); unsigned char fileHeader[HEADER_LENGTH]; - //file.read((char*)&fileHeader, HEADER_LENGTH); - int bytesRead = inputStream.readRawData((char*)&fileHeader, HEADER_LENGTH); - qDebug() << "HEADER_LENGTH... bytesRead:" << bytesRead; + inputStream.readRawData((char*)&fileHeader, HEADER_LENGTH); headerLength = HEADER_LENGTH; // we need this later to skip to the data diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index c4e4e2205b..672a3b63d5 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -326,7 +326,9 @@ public: // these will read/write files that match the wireformat, excluding the 'V' leading void writeToSVOFile(const char* filename, OctreeElement* element = NULL); + bool readFromSVOFile(const char* filename); + bool readFromSVOURL(const QString& url); // will support file urls as well... bool readFromStream(unsigned long streamLength, QDataStream& inputStream); From feddea821ad4d144e5754dcd807114a090b3cc08 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 10 Mar 2015 12:35:12 -0700 Subject: [PATCH 31/56] cleanup import from file vs url --- examples/editEntities.js | 37 ++++++++++++----------------------- interface/src/Application.cpp | 12 ++++++++++-- interface/src/Application.h | 2 +- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/examples/editEntities.js b/examples/editEntities.js index a2ecd7ff02..e97fee583a 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -726,6 +726,7 @@ function cleanupModelMenus() { Menu.removeSeparator("File", "Models"); Menu.removeMenuItem("File", "Export Entities"); Menu.removeMenuItem("File", "Import Entities"); + Menu.removeMenuItem("File", "Import Entities from URL"); Menu.removeMenuItem("View", MENU_INSPECT_TOOL_ENABLED); Menu.removeMenuItem("View", MENU_AUTO_FOCUS_ON_SELECT); @@ -795,32 +796,18 @@ function handeMenuEvent(menuItem) { } } } - } else if (menuItem == "Import Entities") { - var filename = Window.browse("Select models to import", "", "*.svo") - if (filename) { - var success = Clipboard.importEntities(filename); - - if (success) { - var distance = cameraManager.enabled ? cameraManager.zoomDistance : DEFAULT_ENTITY_DRAG_DROP_DISTANCE; - var direction = Quat.getFront(Camera.orientation); - var offset = Vec3.multiply(distance, direction); - var position = Vec3.sum(Camera.position, offset); - - position.x = Math.max(0, position.x); - position.y = Math.max(0, position.y); - position.z = Math.max(0, position.z); - - var pastedEntityIDs = Clipboard.pasteEntities(position); - - selectionManager.setSelections(pastedEntityIDs); - } else { - Window.alert("There was an error importing the entity file."); - } + } else if (menuItem == "Import Entities" || menuItem == "Import Entities from URL") { + + var importURL; + if (menuItem == "Import Entities") { + importURL = Window.browse("Select models to import", "", "*.svo"); + //importURL = "file://" + filename; + } else { + importURL = Window.prompt("URL of SVO to import", ""); } - } else if (menuItem == "Import Entities from URL") { - var url = Window.prompt("URL of SVO to import", ""); - if (url) { - var success = Clipboard.importEntities(url); + + if (importURL) { + var success = Clipboard.importEntities(importURL); if (success) { var distance = cameraManager.enabled ? cameraManager.zoomDistance : DEFAULT_ENTITY_DRAG_DROP_DISTANCE; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4662f92427..fa511097cb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1721,9 +1721,17 @@ void Application::saveSettings() { _myAvatar->saveData(); } -bool Application::importEntities(const QString& filename) { +bool Application::importEntities(const QString& urlOrFilename) { _entityClipboard.eraseAllOctreeElements(); - bool success = _entityClipboard.readFromSVOURL(filename); + + QUrl url(urlOrFilename); + + // if the URL appears to be invalid or relative, then it is probably a local file + if (!url.isValid() || url.isRelative()) { + url = QUrl::fromLocalFile(urlOrFilename); + } + + bool success = _entityClipboard.readFromSVOURL(url.toString()); if (success) { _entityClipboard.reaverageOctreeElements(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 1da5f430b6..d409f6c6d1 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -325,7 +325,7 @@ public slots: QVector pasteEntities(float x, float y, float z); bool exportEntities(const QString& filename, const QVector& entityIDs); bool exportEntities(const QString& filename, float x, float y, float z, float scale); - bool importEntities(const QString& filename); + bool importEntities(const QString& url); void setLowVelocityFilter(bool lowVelocityFilter); void loadDialog(); From e16961c958244368a7dfe06a5f06565f2129bd83 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 10 Mar 2015 12:36:31 -0700 Subject: [PATCH 32/56] removed dead code --- examples/editEntities.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/editEntities.js b/examples/editEntities.js index e97fee583a..9568f4207f 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -801,7 +801,6 @@ function handeMenuEvent(menuItem) { var importURL; if (menuItem == "Import Entities") { importURL = Window.browse("Select models to import", "", "*.svo"); - //importURL = "file://" + filename; } else { importURL = Window.prompt("URL of SVO to import", ""); } From c9982e765ebcb29ab4513dc397cb2b214af8bd57 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 16:28:01 -0700 Subject: [PATCH 33/56] cleanup username API from GlobalServicesScriptingInterface --- .../oculus/virtualKeyboardTextEntityExample.js | 2 +- .../GlobalServicesScriptingInterface.cpp | 4 ---- .../scripting/GlobalServicesScriptingInterface.h | 16 +++++++++------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/examples/controllers/oculus/virtualKeyboardTextEntityExample.js b/examples/controllers/oculus/virtualKeyboardTextEntityExample.js index cf36fdbffb..15025831e7 100644 --- a/examples/controllers/oculus/virtualKeyboardTextEntityExample.js +++ b/examples/controllers/oculus/virtualKeyboardTextEntityExample.js @@ -86,7 +86,7 @@ keyboard.onKeyRelease = function(event) { var textLines = textText.split("\n"); var maxLineWidth = Overlays.textSize(textSizeMeasureOverlay, textText).width; - var usernameLine = "--" + GlobalServices.myUsername; + var usernameLine = "--" + GlobalServices.username; var usernameWidth = Overlays.textSize(textSizeMeasureOverlay, usernameLine).width; if (maxLineWidth < usernameWidth) { maxLineWidth = usernameWidth; diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.cpp b/interface/src/scripting/GlobalServicesScriptingInterface.cpp index 478b708e53..37367fe40c 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.cpp +++ b/interface/src/scripting/GlobalServicesScriptingInterface.cpp @@ -36,10 +36,6 @@ GlobalServicesScriptingInterface* GlobalServicesScriptingInterface::getInstance( return &sharedInstance; } -QString GlobalServicesScriptingInterface::getMyUsername() { - return AccountManager::getInstance().getAccountInfo().getUsername(); -} - void GlobalServicesScriptingInterface::loggedOut() { emit GlobalServicesScriptingInterface::disconnected(QString("logout")); } diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.h b/interface/src/scripting/GlobalServicesScriptingInterface.h index a71446a970..bf49df15ad 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.h +++ b/interface/src/scripting/GlobalServicesScriptingInterface.h @@ -31,20 +31,21 @@ Q_DECLARE_METATYPE(DownloadInfoResult) QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result); void DownloadInfoResultFromScriptValue(const QScriptValue& object, DownloadInfoResult& result); - class GlobalServicesScriptingInterface : public QObject { Q_OBJECT - Q_PROPERTY(QString myUsername READ getMyUsername) - GlobalServicesScriptingInterface(); - ~GlobalServicesScriptingInterface(); + + Q_PROPERTY(QString username READ getUsername) + public: static GlobalServicesScriptingInterface* getInstance(); - QString getMyUsername(); + const QString& getUsername() const { return AccountManager::getInstance().getAccountInfo().getUsername(); } public slots: DownloadInfoResult getDownloadInfo(); void updateDownloadInfo(); + + void setDiscoverability(const QString& discoverability); private slots: void loggedOut(); @@ -53,12 +54,13 @@ private slots: signals: void connected(); void disconnected(const QString& reason); - void incomingMessage(const QString& username, const QString& message); - void onlineUsersChanged(const QStringList& usernames); void myUsernameChanged(const QString& username); void downloadInfoChanged(DownloadInfoResult info); private: + GlobalServicesScriptingInterface(); + ~GlobalServicesScriptingInterface(); + bool _downloading; }; From dde84ac2b84800de2fb534610a1eddfd71e2182b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 16:32:09 -0700 Subject: [PATCH 34/56] fix getUsername for AccountManager include in implementation --- interface/src/scripting/GlobalServicesScriptingInterface.cpp | 4 ++++ interface/src/scripting/GlobalServicesScriptingInterface.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.cpp b/interface/src/scripting/GlobalServicesScriptingInterface.cpp index 37367fe40c..1b03fcd5e6 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.cpp +++ b/interface/src/scripting/GlobalServicesScriptingInterface.cpp @@ -36,6 +36,10 @@ GlobalServicesScriptingInterface* GlobalServicesScriptingInterface::getInstance( return &sharedInstance; } +const QString& GlobalServicesScriptingInterface::getUsername() const { + return AccountManager::getInstance().getAccountInfo().getUsername(); +} + void GlobalServicesScriptingInterface::loggedOut() { emit GlobalServicesScriptingInterface::disconnected(QString("logout")); } diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.h b/interface/src/scripting/GlobalServicesScriptingInterface.h index bf49df15ad..58d7259b6e 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.h +++ b/interface/src/scripting/GlobalServicesScriptingInterface.h @@ -39,7 +39,7 @@ class GlobalServicesScriptingInterface : public QObject { public: static GlobalServicesScriptingInterface* getInstance(); - const QString& getUsername() const { return AccountManager::getInstance().getAccountInfo().getUsername(); } + const QString& getUsername() const; public slots: DownloadInfoResult getDownloadInfo(); From 6e84e94b869b5edd6f0c84f62b49c4f7181a51e5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 16:34:00 -0700 Subject: [PATCH 35/56] remove discoverability setter until API ready --- interface/src/scripting/GlobalServicesScriptingInterface.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.h b/interface/src/scripting/GlobalServicesScriptingInterface.h index 58d7259b6e..ad19a9496c 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.h +++ b/interface/src/scripting/GlobalServicesScriptingInterface.h @@ -44,8 +44,6 @@ public: public slots: DownloadInfoResult getDownloadInfo(); void updateDownloadInfo(); - - void setDiscoverability(const QString& discoverability); private slots: void loggedOut(); From 91b473f0359d436f1c17a95f39a5dc6c65bef987 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 16:48:39 -0700 Subject: [PATCH 36/56] move location update to DiscoverabilityManager --- interface/src/Application.cpp | 45 ++-------------- interface/src/Application.h | 1 - interface/src/DiscoverabilityManager.cpp | 65 ++++++++++++++++++++++++ interface/src/DiscoverabilityManager.h | 26 ++++++++++ 4 files changed, 95 insertions(+), 42 deletions(-) create mode 100644 interface/src/DiscoverabilityManager.cpp create mode 100644 interface/src/DiscoverabilityManager.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 172f0c94a5..d85d84c7fb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -87,6 +87,7 @@ #include "Application.h" #include "AudioClient.h" +#include "DiscoverabilityManager.h" #include "InterfaceVersion.h" #include "LODManager.h" #include "Menu.h" @@ -367,11 +368,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(&domainHandler, &DomainHandler::hostnameChanged, DependencyManager::get().data(), &AddressManager::storeCurrentAddress); - // update our location every 5 seconds in the data-server, assuming that we are authenticated with one + // update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000; locationUpdateTimer = new QTimer(this); - connect(locationUpdateTimer, &QTimer::timeout, this, &Application::updateLocationInServer); + auto discoverabilityManager = DependencyManager::get(); + connect(locationUpdateTimer, &QTimer::timeout, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS); connect(nodeList.data(), &NodeList::nodeAdded, this, &Application::nodeAdded); @@ -3191,45 +3193,6 @@ void Application::updateWindowTitle(){ _window->setWindowTitle(title); } -void Application::updateLocationInServer() { - - AccountManager& accountManager = AccountManager::getInstance(); - auto addressManager = DependencyManager::get(); - DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); - - if (accountManager.isLoggedIn() && domainHandler.isConnected() - && (!addressManager->getRootPlaceID().isNull() || !domainHandler.getUUID().isNull())) { - - // construct a QJsonObject given the user's current address information - QJsonObject rootObject; - - QJsonObject locationObject; - - QString pathString = addressManager->currentPath(); - - const QString LOCATION_KEY_IN_ROOT = "location"; - - const QString PATH_KEY_IN_LOCATION = "path"; - locationObject.insert(PATH_KEY_IN_LOCATION, pathString); - - if (!addressManager->getRootPlaceID().isNull()) { - const QString PLACE_ID_KEY_IN_LOCATION = "place_id"; - locationObject.insert(PLACE_ID_KEY_IN_LOCATION, - uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID())); - - } else { - const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id"; - locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION, - uuidStringWithoutCurlyBraces(domainHandler.getUUID())); - } - - rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject); - - accountManager.authenticatedRequest("/api/v1/user/location", QNetworkAccessManager::PutOperation, - JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); - } -} - void Application::clearDomainOctreeDetails() { qDebug() << "Clearing domain octree details..."; // reset the environment so that we don't erroneously end up with multiple diff --git a/interface/src/Application.h b/interface/src/Application.h index ce4bae45b9..1da5f430b6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -318,7 +318,6 @@ signals: public slots: void domainChanged(const QString& domainHostname); void updateWindowTitle(); - void updateLocationInServer(); void nodeAdded(SharedNodePointer node); void nodeKilled(SharedNodePointer node); void packetSent(quint64 length); diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp new file mode 100644 index 0000000000..e2fa011ed8 --- /dev/null +++ b/interface/src/DiscoverabilityManager.cpp @@ -0,0 +1,65 @@ +// +// DiscoverabilityManager.cpp +// interface/src +// +// Created by Stephen Birarda on 2015-03-09. +// Copyright 2015 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 + +#include +#include +#include +#include +#include + +#include "DiscoverabilityManager.h" + +const QString API_USER_LOCATION_PATH = "/api/v1/user/location"; + +void DiscoverabilityManager::updateLocation() { + AccountManager& accountManager = AccountManager::getInstance(); + auto addressManager = DependencyManager::get(); + DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); + + if (accountManager.isLoggedIn() && domainHandler.isConnected() + && (!addressManager->getRootPlaceID().isNull() || !domainHandler.getUUID().isNull())) { + + // construct a QJsonObject given the user's current address information + QJsonObject rootObject; + + QJsonObject locationObject; + + QString pathString = addressManager->currentPath(); + + const QString LOCATION_KEY_IN_ROOT = "location"; + + const QString PATH_KEY_IN_LOCATION = "path"; + locationObject.insert(PATH_KEY_IN_LOCATION, pathString); + + if (!addressManager->getRootPlaceID().isNull()) { + const QString PLACE_ID_KEY_IN_LOCATION = "place_id"; + locationObject.insert(PLACE_ID_KEY_IN_LOCATION, + uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID())); + + } else { + const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id"; + locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION, + uuidStringWithoutCurlyBraces(domainHandler.getUUID())); + } + + rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject); + + accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::PutOperation, + JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); + } +} + +void DiscoverabilityManager::removeLocation() { + AccountManager& accountManager = AccountManager::getInstance(); + accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::DeleteOperation); +} \ No newline at end of file diff --git a/interface/src/DiscoverabilityManager.h b/interface/src/DiscoverabilityManager.h new file mode 100644 index 0000000000..a9533b5efe --- /dev/null +++ b/interface/src/DiscoverabilityManager.h @@ -0,0 +1,26 @@ +// +// DiscoverabilityManager.h +// interface/src +// +// Created by Stephen Birarda on 2015-03-09. +// Copyright 2015 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_DiscoverabilityManager_h +#define hifi_DiscoverabilityManager_h + +#include + +class DiscoverabilityManager : public QObject, public Dependency { + Q_OBJECT + SINGLETON_DEPENDENCY + +public slots: + void updateLocation(); + void removeLocation(); +}; + +#endif // hifi_DiscoverabilityManager_h \ No newline at end of file From d96691f2d008510e25997e0efeffa6a701bd32cf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 17:05:57 -0700 Subject: [PATCH 37/56] handle discoverability change in DiscoverabilityManager --- interface/src/Application.cpp | 1 + interface/src/DiscoverabilityManager.cpp | 87 +++++++++++++++--------- interface/src/DiscoverabilityManager.h | 20 +++++- 3 files changed, 76 insertions(+), 32 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d85d84c7fb..6945e88949 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -247,6 +247,7 @@ bool setupEssentials(int& argc, char** argv) { #if defined(Q_OS_MAC) || defined(Q_OS_WIN) auto speechRecognizer = DependencyManager::set(); #endif + auto discoverabilityManager = DependencyManager::set(); return true; } diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index e2fa011ed8..3c27e90152 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -19,47 +19,72 @@ #include "DiscoverabilityManager.h" +const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::None; + +DiscoverabilityManager::DiscoverabilityManager() : + _mode("discoverabilityMode", DEFAULT_DISCOVERABILITY_MODE) +{ + +} + const QString API_USER_LOCATION_PATH = "/api/v1/user/location"; void DiscoverabilityManager::updateLocation() { - AccountManager& accountManager = AccountManager::getInstance(); - auto addressManager = DependencyManager::get(); - DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); - - if (accountManager.isLoggedIn() && domainHandler.isConnected() - && (!addressManager->getRootPlaceID().isNull() || !domainHandler.getUUID().isNull())) { + if (_mode.get() != Discoverability::None) { + AccountManager& accountManager = AccountManager::getInstance(); + auto addressManager = DependencyManager::get(); + DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); - // construct a QJsonObject given the user's current address information - QJsonObject rootObject; - - QJsonObject locationObject; - - QString pathString = addressManager->currentPath(); - - const QString LOCATION_KEY_IN_ROOT = "location"; - - const QString PATH_KEY_IN_LOCATION = "path"; - locationObject.insert(PATH_KEY_IN_LOCATION, pathString); - - if (!addressManager->getRootPlaceID().isNull()) { - const QString PLACE_ID_KEY_IN_LOCATION = "place_id"; - locationObject.insert(PLACE_ID_KEY_IN_LOCATION, - uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID())); + if (accountManager.isLoggedIn() && domainHandler.isConnected() + && (!addressManager->getRootPlaceID().isNull() || !domainHandler.getUUID().isNull())) { - } else { - const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id"; - locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION, - uuidStringWithoutCurlyBraces(domainHandler.getUUID())); + // construct a QJsonObject given the user's current address information + QJsonObject rootObject; + + QJsonObject locationObject; + + QString pathString = addressManager->currentPath(); + + const QString LOCATION_KEY_IN_ROOT = "location"; + + const QString PATH_KEY_IN_LOCATION = "path"; + locationObject.insert(PATH_KEY_IN_LOCATION, pathString); + + if (!addressManager->getRootPlaceID().isNull()) { + const QString PLACE_ID_KEY_IN_LOCATION = "place_id"; + locationObject.insert(PLACE_ID_KEY_IN_LOCATION, + uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID())); + + } else { + const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id"; + locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION, + uuidStringWithoutCurlyBraces(domainHandler.getUUID())); + } + + rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject); + + accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::PutOperation, + JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); } - - rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject); - - accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::PutOperation, - JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); + } else { + qDebug() << "not updating discoverability since it is currently set to none!"; } } void DiscoverabilityManager::removeLocation() { AccountManager& accountManager = AccountManager::getInstance(); accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::DeleteOperation); +} + +void DiscoverabilityManager::setDiscoverability(Discoverability::Mode discoverabilityMode) { + if (_mode.get() != discoverabilityMode) { + + // update the setting to the new value + _mode.set(discoverabilityMode); + + if (_mode.get() == Discoverability::None) { + // if we just got set to no discoverability, make sure that we delete our location in DB + removeLocation(); + } + } } \ No newline at end of file diff --git a/interface/src/DiscoverabilityManager.h b/interface/src/DiscoverabilityManager.h index a9533b5efe..cb7791e82f 100644 --- a/interface/src/DiscoverabilityManager.h +++ b/interface/src/DiscoverabilityManager.h @@ -13,6 +13,17 @@ #define hifi_DiscoverabilityManager_h #include +#include + +namespace Discoverability { + enum Mode { + None, + Friends, + All + }; +} + +Q_DECLARE_METATYPE(Discoverability::Mode); class DiscoverabilityManager : public QObject, public Dependency { Q_OBJECT @@ -20,7 +31,14 @@ class DiscoverabilityManager : public QObject, public Dependency { public slots: void updateLocation(); - void removeLocation(); + void removeLocation(); + + void setDiscoverability(Discoverability::Mode discoverabilityMode); + +private: + DiscoverabilityManager(); + + Setting::Handle _mode; }; #endif // hifi_DiscoverabilityManager_h \ No newline at end of file From 5feb6be2219361951315b447e8790046e93696e8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 17:20:09 -0700 Subject: [PATCH 38/56] expose discoverability changes to js --- interface/src/DiscoverabilityManager.cpp | 4 +-- interface/src/DiscoverabilityManager.h | 3 ++- .../GlobalServicesScriptingInterface.cpp | 27 +++++++++++++++++++ .../GlobalServicesScriptingInterface.h | 4 +++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 3c27e90152..7dca8c399a 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -66,8 +66,6 @@ void DiscoverabilityManager::updateLocation() { accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::PutOperation, JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); } - } else { - qDebug() << "not updating discoverability since it is currently set to none!"; } } @@ -76,7 +74,7 @@ void DiscoverabilityManager::removeLocation() { accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::DeleteOperation); } -void DiscoverabilityManager::setDiscoverability(Discoverability::Mode discoverabilityMode) { +void DiscoverabilityManager::setDiscoverabilityMode(Discoverability::Mode discoverabilityMode) { if (_mode.get() != discoverabilityMode) { // update the setting to the new value diff --git a/interface/src/DiscoverabilityManager.h b/interface/src/DiscoverabilityManager.h index cb7791e82f..6d9f912928 100644 --- a/interface/src/DiscoverabilityManager.h +++ b/interface/src/DiscoverabilityManager.h @@ -33,7 +33,8 @@ public slots: void updateLocation(); void removeLocation(); - void setDiscoverability(Discoverability::Mode discoverabilityMode); + Discoverability::Mode getDiscoverabilityMode() { return _mode.get(); } + void setDiscoverabilityMode(Discoverability::Mode discoverabilityMode); private: DiscoverabilityManager(); diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.cpp b/interface/src/scripting/GlobalServicesScriptingInterface.cpp index 1b03fcd5e6..d39da47e78 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.cpp +++ b/interface/src/scripting/GlobalServicesScriptingInterface.cpp @@ -11,6 +11,7 @@ #include "AccountManager.h" #include "Application.h" +#include "DiscoverabilityManager.h" #include "ResourceCache.h" #include "GlobalServicesScriptingInterface.h" @@ -44,6 +45,32 @@ void GlobalServicesScriptingInterface::loggedOut() { emit GlobalServicesScriptingInterface::disconnected(QString("logout")); } +QString GlobalServicesScriptingInterface::getFindableBy() const { + auto discoverabilityManager = DependencyManager::get(); + + if (discoverabilityManager->getDiscoverabilityMode() == Discoverability::None) { + return "none"; + } else if (discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends) { + return "friends"; + } else { + return "all"; + } +} + +void GlobalServicesScriptingInterface::setFindableBy(const QString& discoverabilityMode) { + auto discoverabilityManager = DependencyManager::get(); + + if (discoverabilityMode.toLower() == "none") { + discoverabilityManager->setDiscoverabilityMode(Discoverability::None); + } else if (discoverabilityMode.toLower() == "friends") { + discoverabilityManager->setDiscoverabilityMode(Discoverability::Friends); + } else if (discoverabilityMode.toLower() == "all") { + discoverabilityManager->setDiscoverabilityMode(Discoverability::All); + } else { + qDebug() << "GlobalServices setFindableBy called with an unrecognized value. Did not change discoverability."; + } +} + DownloadInfoResult::DownloadInfoResult() : downloading(QList()), pending(0.0f) diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.h b/interface/src/scripting/GlobalServicesScriptingInterface.h index ad19a9496c..a39219ba40 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.h +++ b/interface/src/scripting/GlobalServicesScriptingInterface.h @@ -35,6 +35,7 @@ class GlobalServicesScriptingInterface : public QObject { Q_OBJECT Q_PROPERTY(QString username READ getUsername) + Q_PROPERTY(QString findableBy READ getFindableBy WRITE setFindableBy) public: static GlobalServicesScriptingInterface* getInstance(); @@ -48,6 +49,9 @@ public slots: private slots: void loggedOut(); void checkDownloadInfo(); + + QString getFindableBy() const; + void setFindableBy(const QString& discoverabilityMode); signals: void connected(); From f8fe8393ddfce102de12e9fa07916bb7924b8b31 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 17:26:56 -0700 Subject: [PATCH 39/56] store discoverability mode as an int --- interface/src/DiscoverabilityManager.cpp | 6 +++--- interface/src/DiscoverabilityManager.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 7dca8c399a..0d0139e1db 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -75,12 +75,12 @@ void DiscoverabilityManager::removeLocation() { } void DiscoverabilityManager::setDiscoverabilityMode(Discoverability::Mode discoverabilityMode) { - if (_mode.get() != discoverabilityMode) { + if (static_cast(_mode.get()) != discoverabilityMode) { // update the setting to the new value - _mode.set(discoverabilityMode); + _mode.set(static_cast(discoverabilityMode)); - if (_mode.get() == Discoverability::None) { + if (static_cast(_mode.get()) == Discoverability::None) { // if we just got set to no discoverability, make sure that we delete our location in DB removeLocation(); } diff --git a/interface/src/DiscoverabilityManager.h b/interface/src/DiscoverabilityManager.h index 6d9f912928..1dac7d63eb 100644 --- a/interface/src/DiscoverabilityManager.h +++ b/interface/src/DiscoverabilityManager.h @@ -33,13 +33,13 @@ public slots: void updateLocation(); void removeLocation(); - Discoverability::Mode getDiscoverabilityMode() { return _mode.get(); } + Discoverability::Mode getDiscoverabilityMode() { return static_cast(_mode.get()); } void setDiscoverabilityMode(Discoverability::Mode discoverabilityMode); private: DiscoverabilityManager(); - Setting::Handle _mode; + Setting::Handle _mode; }; #endif // hifi_DiscoverabilityManager_h \ No newline at end of file From 6ec5c387e2584040f8975f30063098acb8ffb3fd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 17:28:44 -0700 Subject: [PATCH 40/56] default to All discoverability until UI is present --- interface/src/DiscoverabilityManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 0d0139e1db..49850e4ef6 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -19,7 +19,7 @@ #include "DiscoverabilityManager.h" -const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::None; +const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::All; DiscoverabilityManager::DiscoverabilityManager() : _mode("discoverabilityMode", DEFAULT_DISCOVERABILITY_MODE) From 7ecde7be301bad4d86a565e461a2aa3dbf13f1dc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 10 Mar 2015 12:49:43 -0700 Subject: [PATCH 41/56] add fix for out of bounds Sound resampling --- libraries/audio/src/Sound.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index cc41a849e7..a7c8c887bb 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -94,22 +94,32 @@ void Sound::downloadFinished(QNetworkReply* reply) { void Sound::downSample(const QByteArray& rawAudioByteArray) { // assume that this was a RAW file and is now an array of samples that are - // signed, 16-bit, 48Khz, mono + // signed, 16-bit, 48Khz // we want to convert it to the format that the audio-mixer wants - // which is signed, 16-bit, 24Khz, mono + // which is signed, 16-bit, 24Khz + + int numDestinationBytes = rawAudioByteArray.size() / 2; + if (_isStereo && numDestinationBytes % 4 != 0) { + numDestinationBytes += 1; + } - _byteArray.resize(rawAudioByteArray.size() / 2); + _byteArray.resize(numDestinationBytes); int numSourceSamples = rawAudioByteArray.size() / sizeof(int16_t); int16_t* sourceSamples = (int16_t*) rawAudioByteArray.data(); int16_t* destinationSamples = (int16_t*) _byteArray.data(); - if (_isStereo) { for (int i = 0; i < numSourceSamples; i += 4) { - destinationSamples[i / 2] = (sourceSamples[i] / 2) + (sourceSamples[i + 2] / 2); - destinationSamples[(i / 2) + 1] = (sourceSamples[i + 1] / 2) + (sourceSamples[i + 3] / 2); + if (i + 2 >= numSourceSamples) { + destinationSamples[i / 2] = sourceSamples[i]; + destinationSamples[(i / 2) + 1] = sourceSamples[i + 1]; + } else { + destinationSamples[i / 2] = (sourceSamples[i] / 2) + (sourceSamples[i + 2] / 2); + destinationSamples[(i / 2) + 1] = (sourceSamples[i + 1] / 2) + (sourceSamples[i + 3] / 2); + } + } } else { for (int i = 1; i < numSourceSamples; i += 2) { From dc0ad0995307ac0b073ed71e607d144bbac96922 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 10 Mar 2015 12:58:58 -0700 Subject: [PATCH 42/56] fix for check of num source samples --- libraries/audio/src/Sound.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index a7c8c887bb..41ecfc5c96 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -99,14 +99,16 @@ void Sound::downSample(const QByteArray& rawAudioByteArray) { // we want to convert it to the format that the audio-mixer wants // which is signed, 16-bit, 24Khz + int numSourceSamples = rawAudioByteArray.size() / sizeof(int16_t); + int numDestinationBytes = rawAudioByteArray.size() / 2; - if (_isStereo && numDestinationBytes % 4 != 0) { + if (_isStereo && numSourceSamples % 4 != 0) { numDestinationBytes += 1; } - + _byteArray.resize(numDestinationBytes); - int numSourceSamples = rawAudioByteArray.size() / sizeof(int16_t); + int16_t* sourceSamples = (int16_t*) rawAudioByteArray.data(); int16_t* destinationSamples = (int16_t*) _byteArray.data(); From 271a4e2cae84a95639685def8491b8af6a80df49 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 10 Mar 2015 13:02:10 -0700 Subject: [PATCH 43/56] cleanup some divides for manual sound resampling --- libraries/audio/src/Sound.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 41ecfc5c96..6f149bb203 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -118,18 +118,17 @@ void Sound::downSample(const QByteArray& rawAudioByteArray) { destinationSamples[i / 2] = sourceSamples[i]; destinationSamples[(i / 2) + 1] = sourceSamples[i + 1]; } else { - destinationSamples[i / 2] = (sourceSamples[i] / 2) + (sourceSamples[i + 2] / 2); - destinationSamples[(i / 2) + 1] = (sourceSamples[i + 1] / 2) + (sourceSamples[i + 3] / 2); + destinationSamples[i / 2] = (sourceSamples[i] + sourceSamples[i + 2]) / 2; + destinationSamples[(i / 2) + 1] = (sourceSamples[i + 1] + sourceSamples[i + 3]) / 2; } } } else { for (int i = 1; i < numSourceSamples; i += 2) { if (i + 1 >= numSourceSamples) { - destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] / 2) + (sourceSamples[i] / 2); + destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] + sourceSamples[i]) / 2; } else { - destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] / 4) + (sourceSamples[i] / 2) - + (sourceSamples[i + 1] / 4); + destinationSamples[(i - 1) / 2] = ((sourceSamples[i - 1] + sourceSamples[i + 1]) / 4) + (sourceSamples[i] / 2); } } } From 6afdb260426fbc0a9edfa3c92b57a36ec3535f64 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 10 Mar 2015 13:19:32 -0700 Subject: [PATCH 44/56] let QMainWindow delete GLCanvas, just stop the QTimer instead --- interface/src/Application.cpp | 4 ++-- interface/src/GLCanvas.cpp | 4 ++++ interface/src/GLCanvas.h | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0182e6e195..c53f387518 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -604,8 +604,8 @@ Application::~Application() { ModelEntityItem::cleanupLoadedAnimations(); - delete _glWidget; - _glWidget = NULL; + // stop the glWidget frame timer so it doesn't call paintGL + _glWidget->stopFrameTimer(); DependencyManager::destroy(); DependencyManager::destroy(); diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 10090de51a..b72c00c779 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -31,6 +31,10 @@ GLCanvas::GLCanvas() : QGLWidget(QGL::NoDepthBuffer | QGL::NoStencilBuffer), #endif } +void GLCanvas::stopFrameTimer() { + _frameTimer.stop(); +} + bool GLCanvas::isThrottleRendering() const { return _throttleRendering || Application::getInstance()->getWindow()->isMinimized(); } diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index e2bbf3b841..7b86f983e9 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -22,6 +22,8 @@ class GLCanvas : public QGLWidget { public: GLCanvas(); + + void stopFrameTimer(); bool isThrottleRendering() const; From 2d6c51ac773e0a2c850d5111d34e6e508697dd5a Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 10 Mar 2015 13:32:56 -0700 Subject: [PATCH 45/56] Detect moving objects before catching them --- examples/controllers/hydra/toyball.js | 49 ++++++++++++++------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/examples/controllers/hydra/toyball.js b/examples/controllers/hydra/toyball.js index 89085fad19..57ad7d8fb0 100644 --- a/examples/controllers/hydra/toyball.js +++ b/examples/controllers/hydra/toyball.js @@ -48,10 +48,10 @@ var rightHandEntity = false; var newSound = SoundCache.getSound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw"); var catchSound = SoundCache.getSound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw"); var throwSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Switches%20and%20sliders/slider%20-%20whoosh1.raw"); -var targetRadius = 1.0; +var targetRadius = 0.25; -var wantDebugging = false; +var wantDebugging = true; function debugPrint(message) { if (wantDebugging) { print(message); @@ -120,30 +120,33 @@ function checkControllerSide(whichSide) { var closestEntity = Entities.findClosestEntity(palmPosition, targetRadius); if (closestEntity.isKnownID) { + var foundProperties = Entities.getEntityProperties(closestEntity); + if (Vec3.length(foundProperties.velocity) > 0.0) { - debugPrint(handMessage + " HAND- CAUGHT SOMETHING!!"); + debugPrint(handMessage + " - Catching a moving object!"); - if (whichSide == LEFT_PALM) { - leftBallAlreadyInHand = true; - leftHandEntity = closestEntity; - } else { - rightBallAlreadyInHand = true; - rightHandEntity = closestEntity; + if (whichSide == LEFT_PALM) { + leftBallAlreadyInHand = true; + leftHandEntity = closestEntity; + } else { + rightBallAlreadyInHand = true; + rightHandEntity = closestEntity; + } + var ballPosition = getBallHoldPosition(whichSide); + var properties = { position: { x: ballPosition.x, + y: ballPosition.y, + z: ballPosition.z }, + rotation: palmRotation, + color: HELD_COLOR, + velocity : { x: 0, y: 0, z: 0}, + gravity: { x: 0, y: 0, z: 0} + }; + Entities.editEntity(closestEntity, properties); + + Audio.playSound(catchSound, { position: ballPosition }); + + return; // exit early } - var ballPosition = getBallHoldPosition(whichSide); - var properties = { position: { x: ballPosition.x, - y: ballPosition.y, - z: ballPosition.z }, - rotation: palmRotation, - color: HELD_COLOR, - velocity : { x: 0, y: 0, z: 0}, - gravity: { x: 0, y: 0, z: 0} - }; - Entities.editEntity(closestEntity, properties); - - Audio.playSound(catchSound, { position: ballPosition }); - - return; // exit early } } From 182a1a726dfde2b759ecb9ada3a1f9ff2857a2f8 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 10 Mar 2015 13:34:16 -0700 Subject: [PATCH 46/56] remove debug --- examples/controllers/hydra/toyball.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/controllers/hydra/toyball.js b/examples/controllers/hydra/toyball.js index 57ad7d8fb0..83dcf2937d 100644 --- a/examples/controllers/hydra/toyball.js +++ b/examples/controllers/hydra/toyball.js @@ -51,7 +51,7 @@ var throwSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Switches%20and var targetRadius = 0.25; -var wantDebugging = true; +var wantDebugging = false; function debugPrint(message) { if (wantDebugging) { print(message); From 3bd3f5a6d22ca68d508c90a541015ab6c122c581 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 10 Mar 2015 14:23:23 -0700 Subject: [PATCH 47/56] make sure UserActivityLogger::close() waits for the pending log message to complete --- libraries/networking/src/AccountManager.cpp | 12 ++++++++++++ libraries/networking/src/AccountManager.h | 4 ++++ libraries/networking/src/UserActivityLogger.cpp | 4 +++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 2a809f2a7c..e71c80efc8 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -299,6 +300,8 @@ void AccountManager::processReply() { passErrorToCallback(requestReply); } delete requestReply; + + emit replyFinished(); } void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) { @@ -339,6 +342,15 @@ void AccountManager::passErrorToCallback(QNetworkReply* requestReply) { } } +void AccountManager::waitForAllPendingReplies() { + while (_pendingCallbackMap.size() > 0) { + QEventLoop loop; + QObject::connect(this, &AccountManager::replyFinished, &loop, &QEventLoop::quit); + loop.exec(); + } +} + + void AccountManager::persistAccountToSettings() { if (_shouldPersistToSettingsFile) { // store this access token into the local settings diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 2c9a441db1..22d070fbe6 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -72,6 +72,8 @@ public: void requestProfile(); DataServerAccountInfo& getAccountInfo() { return _accountInfo; } + + void waitForAllPendingReplies(); public slots: void requestAccessToken(const QString& login, const QString& password); @@ -93,6 +95,8 @@ signals: void loginFailed(); void logoutComplete(); void balanceChanged(qint64 newBalance); + void replyFinished(); + private slots: void processReply(); void handleKeypairGenerationError(); diff --git a/libraries/networking/src/UserActivityLogger.cpp b/libraries/networking/src/UserActivityLogger.cpp index f2646369c1..f74ea99c1e 100644 --- a/libraries/networking/src/UserActivityLogger.cpp +++ b/libraries/networking/src/UserActivityLogger.cpp @@ -61,7 +61,7 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall params.errorCallbackReceiver = this; params.errorCallbackMethod = "requestError"; } - + accountManager.authenticatedRequest(USER_ACTIVITY_URL, QNetworkAccessManager::PostOperation, params, @@ -89,6 +89,8 @@ void UserActivityLogger::launch(QString applicationVersion) { void UserActivityLogger::close() { const QString ACTION_NAME = "close"; logAction(ACTION_NAME, QJsonObject()); + + AccountManager::getInstance().waitForAllPendingReplies(); } void UserActivityLogger::changedDisplayName(QString displayName) { From 3d531e8304b99aa9923088268b8e67e10b427b1e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 10 Mar 2015 14:24:49 -0700 Subject: [PATCH 48/56] add f at end of float literal --- libraries/physics/src/PhysicsEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 66f8afb226..634c3707a8 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -616,7 +616,7 @@ void PhysicsEngine::setAvatarData(AvatarData *avatarData) { glmToBullet(_avatarData->getPosition()))); // XXX these values should be computed from the character model. - btScalar characterRadius = 0.3; + btScalar characterRadius = 0.3f; btScalar characterHeight = 1.75 - 2.0f * characterRadius; btScalar stepHeight = btScalar(0.35); From 503afc8c7324c971e45db608fa1ef3f5b1e25be0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 10 Mar 2015 14:26:19 -0700 Subject: [PATCH 49/56] erase deleted entities from pending sort list --- libraries/entities/src/EntitySimulation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 758cd6771a..b093dbe4f4 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -99,10 +99,11 @@ void EntitySimulation::sortEntitiesThatMoved() { _mortalEntities.remove(entity); _updateableEntities.remove(entity); removeEntityInternal(entity); + itemItr = _entitiesToBeSorted.erase(itemItr); } else { moveOperator.addEntityToMoveList(entity, newCube); + ++itemItr; } - ++itemItr; } if (moveOperator.hasMovingEntities()) { PerformanceTimer perfTimer("recurseTreeWithOperator"); From a0e7125e119ce7afa6b01d6ef808bf063fe54494 Mon Sep 17 00:00:00 2001 From: Virendra Singh Date: Wed, 11 Mar 2015 03:11:17 +0530 Subject: [PATCH 50/56] code revamp and correction in parallel axis theorem --- libraries/physics/src/MeshInfo.cpp | 85 ++++++++++++--------------- libraries/physics/src/MeshInfo.h | 1 - tests/physics/src/MeshInfoTests.cpp | 89 ++++++++++++++++++++--------- tests/physics/src/MeshInfoTests.h | 1 + 4 files changed, 99 insertions(+), 77 deletions(-) diff --git a/libraries/physics/src/MeshInfo.cpp b/libraries/physics/src/MeshInfo.cpp index 0d9149cb44..8df5ff914d 100644 --- a/libraries/physics/src/MeshInfo.cpp +++ b/libraries/physics/src/MeshInfo.cpp @@ -10,7 +10,7 @@ // #include "MeshInfo.h" -#include df +#include using namespace meshinfo; //class to compute volume, mass, center of mass, and inertia tensor of a mesh. @@ -29,14 +29,6 @@ MeshInfo::~MeshInfo(){ } -inline Vertex MeshInfo::getCentroid(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const{ - Vertex com; - com.x = (p1.x + p2.x + p3.x + p4.x) / 4.0f; - com.y = (p1.y + p2.y + p3.y + p4.y) / 4.0f; - com.z = (p1.z + p2.z + p3.z + p4.z) / 4.0f; - return com; -} - inline float MeshInfo::getVolume(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const{ glm::mat4 tet = { glm::vec4(p1.x, p2.x, p3.x, p4.x), glm::vec4(p1.y, p2.y, p3.y, p4.y), glm::vec4(p1.z, p2.z, p3.z, p4.z), glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) }; @@ -50,37 +42,19 @@ Vertex MeshInfo::getMeshCentroid() const{ vector MeshInfo::computeMassProperties(){ vector volumeAndInertia = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; Vertex origin(0.0, 0.0, 0.0); + glm::mat3 identity; float meshVolume = 0.0f; - glm::mat3 globalMomentOfInertia(0.0); - glm::mat3 globalProductOfInertia(0.0); + glm::mat3 globalInertiaTensors(0.0); - //First we need need the center of mass of the mesh in order to translate the tetrahedron inertia to center of mass of the mesh. for (unsigned int i = 0; i < _triangles->size(); i += 3){ Vertex p1 = _vertices->at(_triangles->at(i)); Vertex p2 = _vertices->at(_triangles->at(i + 1)); Vertex p3 = _vertices->at(_triangles->at(i + 2)); - float volume = getVolume(p1, p2, p3, origin); - Vertex com = getCentroid(origin, p1, p2, p3); - //Translate accumulated center of mass from each tetrahedron to mesh's center of mass using parallel axis theorem + float volume = getVolume(p1, p2, p3, origin); + Vertex com = 0.25f * (p1 + p2 + p3); meshVolume += volume; _centerOfMass += com * volume; - } - if (meshVolume == 0){ - return volumeAndInertia; - } - _centerOfMass = (_centerOfMass / (float)meshVolume); - //Translate the moment of inertia from each tetrahedron to mesh's center of mass using parallel axis theorem - for (unsigned int i = 0; i < _triangles->size(); i += 3){ - Vertex p1 = _vertices->at(_triangles->at(i)); - Vertex p2 = _vertices->at(_triangles->at(i + 1)); - Vertex p3 = _vertices->at(_triangles->at(i + 2)); - float volume = getVolume(p1, p2, p3, origin); - Vertex com = getCentroid(origin, p1, p2, p3); - glm::mat3 identity; - Vertex diff = _centerOfMass - com; - float diffDot = glm::dot(diff, diff); - glm::mat3 outerDiff = glm::outerProduct(diff, diff); //centroid is used for calculating inertia tensor relative to center of mass. // translate the tetrahedron to its center of mass using P = P - centroid Vertex p0 = origin - com; @@ -92,7 +66,7 @@ vector MeshInfo::computeMassProperties(){ //http://docsdrive.com/pdfs/sciencepublications/jmssp/2005/8-11.pdf //Explicit exact formulas for the 3-D tetrahedron inertia tensor in terms of its vertex coordinates - F.Tonon - float inertia_a = (volume * 6.0f / 60.0f) * ( + float i11 = (volume * 0.1f) * ( p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y + p1.y*p1.y + p1.y*p2.y + p1.y*p3.y + p2.y*p2.y + p2.y*p3.y + @@ -102,7 +76,7 @@ vector MeshInfo::computeMassProperties(){ p2.z*p2.z + p2.z*p3.z + p3.z*p3.z); - float inertia_b = (volume * 6.0f / 60.0f) * ( + float i22 = (volume * 0.1f) * ( p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + p2.x*p2.x + p2.x*p3.x + @@ -112,7 +86,7 @@ vector MeshInfo::computeMassProperties(){ p2.z*p2.z + p2.z*p3.z + p3.z*p3.z); - float inertia_c = (volume * 6.0f / 60.0f) * ( + float i33 = (volume * 0.1f) * ( p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x + p1.x*p1.x + p1.x*p2.x + p1.x*p3.x + p2.x*p2.x + p2.x*p3.x + @@ -122,40 +96,53 @@ vector MeshInfo::computeMassProperties(){ p2.y*p2.y + p2.y*p3.y + p3.y*p3.y); - float inertia_aa = (volume * 6.0f / 120.0f) * (2.0f * (p0.y*p0.z + p1.y*p1.z + p2.y*p2.z + p3.y*p3.z) + + float i23 = -(volume * 0.05f) * (2.0f * (p0.y*p0.z + p1.y*p1.z + p2.y*p2.z + p3.y*p3.z) + p0.y*p1.z + p0.y*p2.z + p0.y*p3.z + p1.y*p0.z + p1.y*p2.z + p1.y*p3.z + p2.y*p0.z + p2.y*p1.z + p2.y*p3.z + p3.y*p0.z + p3.y*p1.z + p3.y*p2.z); - float inertia_bb = (volume * 6.0f / 120.0f) * (2.0f * (p0.x*p0.z + p1.x*p1.z + p2.x*p2.z + p3.x*p3.z) + + float i21 = -(volume * 0.05f) * (2.0f * (p0.x*p0.z + p1.x*p1.z + p2.x*p2.z + p3.x*p3.z) + p0.x*p1.z + p0.x*p2.z + p0.x*p3.z + p1.x*p0.z + p1.x*p2.z + p1.x*p3.z + p2.x*p0.z + p2.x*p1.z + p2.x*p3.z + p3.x*p0.z + p3.x*p1.z + p3.x*p2.z); - float inertia_cc = (volume * 6.0f / 120.0f) * (2.0f * (p0.x*p0.y + p1.x*p1.y + p2.x*p2.y + p3.x*p3.y) + + float i31 = -(volume * 0.05f) * (2.0f * (p0.x*p0.y + p1.x*p1.y + p2.x*p2.y + p3.x*p3.y) + p0.x*p1.y + p0.x*p2.y + p0.x*p3.y + p1.x*p0.y + p1.x*p2.y + p1.x*p3.y + p2.x*p0.y + p2.x*p1.y + p2.x*p3.y + p3.x*p0.y + p3.x*p1.y + p3.x*p2.y); //3x3 of local inertia tensors of each tetrahedron. Inertia tensors are the diagonal elements - glm::mat3 localMomentInertia = { Vertex(inertia_a, 0.0f, 0.0f), Vertex(0.0f, inertia_b, 0.0f), - Vertex(0.0f, 0.0f, inertia_c) }; - glm::mat3 localProductInertia = { Vertex(inertia_aa, 0.0f, 0.0f), Vertex(0.0f, inertia_bb, 0.0f), - Vertex(0.0f, 0.0f, inertia_cc) }; + // | I11 -I12 -I13 | + // I = | -I21 I22 -I23 | + // | -I31 -I32 I33 | + glm::mat3 localInertiaTensors = { Vertex(i11, i21, i31), Vertex(i21, i22, i23), + Vertex(i31, i23, i33) }; + //Translate the inertia tensors from center of mass to origin //Parallel axis theorem J = I * m[(R.R)*Identity - RxR] where x is outer cross product - globalMomentOfInertia += localMomentInertia + volume * ((diffDot*identity) - outerDiff); - globalProductOfInertia += localProductInertia + volume * ((diffDot * identity) - outerDiff); + globalInertiaTensors += localInertiaTensors + volume * ((glm::dot(com, com) * identity) - + glm::outerProduct(com, com)); } + + //Translate accumulated center of mass from each tetrahedron to mesh's center of mass using parallel axis theorem + if (meshVolume == 0){ + return volumeAndInertia; + } + _centerOfMass = (_centerOfMass / meshVolume); + + //Translate the inertia tensors from origin to mesh's center of mass. + globalInertiaTensors = globalInertiaTensors - meshVolume * ((glm::dot(_centerOfMass, _centerOfMass) * + identity) - glm::outerProduct(_centerOfMass, _centerOfMass)); + volumeAndInertia[0] = meshVolume; - volumeAndInertia[1] = globalMomentOfInertia[0][0]; - volumeAndInertia[2] = globalMomentOfInertia[1][1]; - volumeAndInertia[3] = globalMomentOfInertia[2][2]; - volumeAndInertia[4] = globalProductOfInertia[0][0]; - volumeAndInertia[5] = globalProductOfInertia[1][1]; - volumeAndInertia[6] = globalProductOfInertia[2][2]; + volumeAndInertia[1] = globalInertiaTensors[0][0]; //i11 + volumeAndInertia[2] = globalInertiaTensors[1][1]; //i22 + volumeAndInertia[3] = globalInertiaTensors[2][2]; //i33 + volumeAndInertia[4] = -globalInertiaTensors[2][1]; //i23 or i32 + volumeAndInertia[5] = -globalInertiaTensors[1][0]; //i21 or i12 + volumeAndInertia[6] = -globalInertiaTensors[2][0]; //i13 or i31 return volumeAndInertia; } \ No newline at end of file diff --git a/libraries/physics/src/MeshInfo.h b/libraries/physics/src/MeshInfo.h index d267c75ae6..67dbc8b0d6 100644 --- a/libraries/physics/src/MeshInfo.h +++ b/libraries/physics/src/MeshInfo.h @@ -26,7 +26,6 @@ namespace meshinfo{ vector *_triangles; MeshInfo(vector *vertices, vector *triangles); ~MeshInfo(); - inline Vertex getCentroid(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const; Vertex getMeshCentroid() const; vector computeMassProperties(); }; diff --git a/tests/physics/src/MeshInfoTests.cpp b/tests/physics/src/MeshInfoTests.cpp index 73364b207e..58c38017a6 100644 --- a/tests/physics/src/MeshInfoTests.cpp +++ b/tests/physics/src/MeshInfoTests.cpp @@ -14,7 +14,7 @@ #include #include "MeshInfoTests.h" -const float epsilon = 0.01f; +const float epsilon = 0.015f; void MeshInfoTests::testWithTetrahedron(){ glm::vec3 p0(8.33220, -11.86875, 0.93355); glm::vec3 p1(0.75523, 5.00000, 16.37072); @@ -40,9 +40,12 @@ void MeshInfoTests::testWithTetrahedron(){ float inertia_cc = 11996.20119f; meshinfo::MeshInfo meshinfo(&vertices,&triangles); - glm::vec3 tetCenterOfMass = meshinfo.getCentroid(p0, p1, p2, p3); - glm::vec3 diff = centroid - tetCenterOfMass; vector voumeAndInertia = meshinfo.computeMassProperties(); + glm::vec3 tetCenterOfMass = meshinfo.getMeshCentroid(); + + //get original center of mass + tetCenterOfMass = tetCenterOfMass + p0; + glm::vec3 diff = centroid - tetCenterOfMass; std::cout << std::setprecision(12); //test if centroid is correct if (diff.x > epsilon || diff.y > epsilon || diff.z > epsilon){ @@ -95,6 +98,37 @@ void MeshInfoTests::testWithTetrahedron(){ } +void MeshInfoTests::testWithTetrahedronAsMesh(){ + glm::vec3 p0(8.33220, -11.86875, 0.93355); + glm::vec3 p1(0.75523, 5.00000, 16.37072); + glm::vec3 p2(52.61236, 5.00000, -5.38580); + glm::vec3 p3(2.00000, 5.00000, 3.00000); + glm::vec3 centroid(15.92492, 0.782813, 3.72962); + float volume = 1873.233236f; + float inertia_a = 43520.33257f; + //actual should be 194711.28938f. But for some reason it becomes 194711.296875 during + //runtime due to how floating points are stored. + float inertia_b = 194711.289f; + float inertia_c = 191168.76173f; + float inertia_aa = 4417.66150f; + float inertia_bb = -46343.16662f; + float inertia_cc = 11996.20119f; + std::cout << std::setprecision(12); + vector vertices = { p0, p1, p2, p3 }; + vector triangles = { 0, 1, 2, 0, 3, 1, 1, 3, 2, 0, 2, 3 }; //clockwise direction + meshinfo::MeshInfo massProp(&vertices, &triangles); + vector volumeAndInertia = massProp.computeMassProperties(); + std::cout << volumeAndInertia[0] << " " << volumeAndInertia[1] << " " << volumeAndInertia[2] + << " " << volumeAndInertia[3] + << " " << volumeAndInertia[4] + << " " << volumeAndInertia[5] << " " << volumeAndInertia[6] << std::endl; + + //translate the tetrahedron so that the model is placed at origin i.e. com is at origin + p0 -= centroid; + p1 -= centroid; + p2 -= centroid; + p3 -= centroid; +} void MeshInfoTests::testWithCube(){ glm::vec3 p0(1.0, -1.0, -1.0); glm::vec3 p1(1.0, -1.0, 1.0); @@ -122,25 +156,25 @@ void MeshInfoTests::testWithCube(){ double inertia = (volume * side * side) / 6.0; //inertia of a unit cube is (mass * side * side) /6 //test with origin as reference point - meshinfo::MeshInfo massProp1(&vertices, &triangles); - vector volumeAndInertia1 = massProp1.computeMassProperties(); - if (abs(centerOfMass.x - massProp1.getMeshCentroid().x) > epsilon || abs(centerOfMass.y - massProp1.getMeshCentroid().y) > epsilon || - abs(centerOfMass.z - massProp1.getMeshCentroid().z) > epsilon){ + meshinfo::MeshInfo massProp(&vertices, &triangles); + vector volumeAndInertia = massProp.computeMassProperties(); + if (abs(centerOfMass.x - massProp.getMeshCentroid().x) > epsilon || abs(centerOfMass.y - massProp.getMeshCentroid().y) > epsilon || + abs(centerOfMass.z - massProp.getMeshCentroid().z) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << " " << - centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getMeshCentroid().x << " " << - massProp1.getMeshCentroid().y << " " << massProp1.getMeshCentroid().z << std::endl; + centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp.getMeshCentroid().x << " " << + massProp.getMeshCentroid().y << " " << massProp.getMeshCentroid().z << std::endl; } - if (abs(volume - volumeAndInertia1.at(0)) > epsilon){ + if (abs(volume - volumeAndInertia.at(0)) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << - ", actual = " << volumeAndInertia1.at(0) << std::endl; + ", actual = " << volumeAndInertia.at(0) << std::endl; } - if (abs(inertia - (volumeAndInertia1.at(1))) > epsilon || abs(inertia - (volumeAndInertia1.at(2))) > epsilon || - abs(inertia - (volumeAndInertia1.at(3))) > epsilon){ + if (abs(inertia - (volumeAndInertia.at(1))) > epsilon || abs(inertia - (volumeAndInertia.at(2))) > epsilon || + abs(inertia - (volumeAndInertia.at(3))) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia is incorrect : Expected = " << inertia << " " << - inertia << " " << inertia << ", actual = " << (volumeAndInertia1.at(1)) << " " << (volumeAndInertia1.at(2)) << - " " << (volumeAndInertia1.at(3)) << std::endl; + inertia << " " << inertia << ", actual = " << (volumeAndInertia.at(1)) << " " << (volumeAndInertia.at(2)) << + " " << (volumeAndInertia.at(3)) << std::endl; } } @@ -172,29 +206,30 @@ void MeshInfoTests::testWithUnitCube() std::cout << std::setprecision(10); //test with origin as reference point - meshinfo::MeshInfo massProp1(&vertices, &triangles); - vector volumeAndInertia1 = massProp1.computeMassProperties(); - if (abs(centerOfMass.x - massProp1.getMeshCentroid().x) > epsilon || abs(centerOfMass.y - massProp1.getMeshCentroid().y) > - epsilon || abs(centerOfMass.z - massProp1.getMeshCentroid().z) > epsilon){ + meshinfo::MeshInfo massProp(&vertices, &triangles); + vector volumeAndInertia = massProp.computeMassProperties(); + if (abs(centerOfMass.x - massProp.getMeshCentroid().x) > epsilon || abs(centerOfMass.y - massProp.getMeshCentroid().y) > + epsilon || abs(centerOfMass.z - massProp.getMeshCentroid().z) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << - " " << centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp1.getMeshCentroid().x << " " << - massProp1.getMeshCentroid().y << " " << massProp1.getMeshCentroid().z << std::endl; + " " << centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp.getMeshCentroid().x << " " << + massProp.getMeshCentroid().y << " " << massProp.getMeshCentroid().z << std::endl; } - if (abs(volume - volumeAndInertia1.at(0)) > epsilon){ + if (abs(volume - volumeAndInertia.at(0)) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << - ", actual = " << volumeAndInertia1.at(0) << std::endl; + ", actual = " << volumeAndInertia.at(0) << std::endl; } - if (abs(inertia - (volumeAndInertia1.at(1))) > epsilon || abs(inertia - (volumeAndInertia1.at(2))) > epsilon || - abs(inertia - (volumeAndInertia1.at(3))) > epsilon){ + if (abs(inertia - (volumeAndInertia.at(1))) > epsilon || abs(inertia - (volumeAndInertia.at(2))) > epsilon || + abs(inertia - (volumeAndInertia.at(3))) > epsilon){ std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia is incorrect : Expected = " << inertia << " " << - inertia << " " << inertia << ", actual = " << (volumeAndInertia1.at(1)) << " " << (volumeAndInertia1.at(2)) << - " " << (volumeAndInertia1.at(3)) << std::endl; + inertia << " " << inertia << ", actual = " << (volumeAndInertia.at(1)) << " " << (volumeAndInertia.at(2)) << + " " << (volumeAndInertia.at(3)) << std::endl; } } void MeshInfoTests::runAllTests(){ testWithTetrahedron(); + testWithTetrahedronAsMesh(); testWithUnitCube(); testWithCube(); } \ No newline at end of file diff --git a/tests/physics/src/MeshInfoTests.h b/tests/physics/src/MeshInfoTests.h index d4c954b802..0ddd8d0944 100644 --- a/tests/physics/src/MeshInfoTests.h +++ b/tests/physics/src/MeshInfoTests.h @@ -16,5 +16,6 @@ namespace MeshInfoTests{ void testWithUnitCube(); void testWithCube(); void runAllTests(); + void testWithTetrahedronAsMesh(); } #endif // hifi_MeshInfoTests_h \ No newline at end of file From 7954dd4d67b4a73825bbd61ffacc0c32cccc0c5d Mon Sep 17 00:00:00 2001 From: Virendra Singh Date: Wed, 11 Mar 2015 03:27:26 +0530 Subject: [PATCH 51/56] anticlockwise triangle order --- tests/physics/src/MeshInfoTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/physics/src/MeshInfoTests.cpp b/tests/physics/src/MeshInfoTests.cpp index 58c38017a6..fa841f3930 100644 --- a/tests/physics/src/MeshInfoTests.cpp +++ b/tests/physics/src/MeshInfoTests.cpp @@ -115,7 +115,7 @@ void MeshInfoTests::testWithTetrahedronAsMesh(){ float inertia_cc = 11996.20119f; std::cout << std::setprecision(12); vector vertices = { p0, p1, p2, p3 }; - vector triangles = { 0, 1, 2, 0, 3, 1, 1, 3, 2, 0, 2, 3 }; //clockwise direction + vector triangles = { 0, 2, 1, 0, 3, 2, 0, 1, 3, 1, 2, 3 }; meshinfo::MeshInfo massProp(&vertices, &triangles); vector volumeAndInertia = massProp.computeMassProperties(); std::cout << volumeAndInertia[0] << " " << volumeAndInertia[1] << " " << volumeAndInertia[2] From b9671f3f9b2afc8597f6e98f9f08c67bdff24559 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 10 Mar 2015 15:27:44 -0700 Subject: [PATCH 52/56] CR feedback --- libraries/octree/src/Octree.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index fddbe0bef5..2b29529f4e 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1845,14 +1845,13 @@ bool Octree::readFromSVOFile(const char* fileName) { bool fileOk = false; QFile file(fileName); - QFileInfo fileInfo(fileName); - bool isOpen = file.open(QIODevice::ReadOnly); - QDataStream fileInputStream(&file); // read the data serialized from the file + fileOk = file.open(QIODevice::ReadOnly); - // get file length.... - unsigned long fileLength = fileInfo.size(); + if(fileOk) { + QDataStream fileInputStream(&file); + QFileInfo fileInfo(fileName); + unsigned long fileLength = fileInfo.size(); - if(isOpen) { emit importSize(1.0f, 1.0f, 1.0f); emit importProgress(0); From 8ede9fb39be383fc1e0ad7f129f0f3c9feabcad4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 10 Mar 2015 15:50:30 -0700 Subject: [PATCH 53/56] fix stereo to stereo resampling --- .../utilities/diagnostics/orbitingSound.js | 12 +++++----- libraries/audio-client/src/AudioClient.cpp | 24 +++++++++++++------ libraries/audio/src/AudioInjector.h | 6 ++++- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/examples/utilities/diagnostics/orbitingSound.js b/examples/utilities/diagnostics/orbitingSound.js index 1af6fab827..370ed38595 100644 --- a/examples/utilities/diagnostics/orbitingSound.js +++ b/examples/utilities/diagnostics/orbitingSound.js @@ -20,11 +20,11 @@ var trailingLoudness = 0.0; var soundClip = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Tabla+Loops/Tabla1.wav"); var properties = { - type: "Box", - position: orbitCenter, - dimensions: { x: 0.25, y: 0.25, z: 0.25 }, - color: { red: 100, green: 0, blue : 0 } - }; + type: "Box", + position: orbitCenter, + dimensions: { x: 0.25, y: 0.25, z: 0.25 }, + color: { red: 100, green: 0, blue : 0 } +}; var objectId = Entities.addEntity(properties); var sound = Audio.playSound(soundClip, { position: orbitCenter, loop: true, volume: 0.5 }); @@ -34,7 +34,7 @@ function update(deltaTime) { currentPosition = { x: orbitCenter.x + Math.cos(time * SPEED) * RADIUS, y: orbitCenter.y, z: orbitCenter.z + Math.sin(time * SPEED) * RADIUS }; trailingLoudness = 0.9 * trailingLoudness + 0.1 * sound.loudness; Entities.editEntity( objectId, { position: currentPosition, color: { red: Math.min(trailingLoudness * 2000, 255), green: 0, blue: 0 } } ); - sound.setOptions({ position: currentPosition }); + sound.options = { position: currentPosition }; } Script.scriptEnding.connect(function() { diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 6e068e0635..c083fbc085 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -320,6 +320,7 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, #ifdef Q_OS_ANDROID adjustedAudioFormat.setSampleRate(FORTY_FOUR); #else + const int HALF_FORTY_FOUR = FORTY_FOUR / 2; if (audioDevice.supportedSampleRates().contains(AudioConstants::SAMPLE_RATE * 2)) { @@ -397,18 +398,24 @@ soxr_error_t possibleResampling(soxr_t resampler, numSourceSamples, sourceAudioFormat, destinationAudioFormat); - qDebug() << "resample from" << sourceAudioFormat << "to" << destinationAudioFormat - << "from" << numChannelCoversionSamples << "to" << numDestinationSamples; - resampleError = soxr_process(resampler, channelConversionSamples, numChannelCoversionSamples, NULL, destinationSamples, numDestinationSamples, NULL); delete[] channelConversionSamples; } else { + + unsigned int numAdjustedSourceSamples = numSourceSamples; + unsigned int numAdjustedDestinationSamples = numDestinationSamples; + + if (sourceAudioFormat.channelCount() == 2 && destinationAudioFormat.channelCount() == 2) { + numAdjustedSourceSamples /= 2; + numAdjustedDestinationSamples /= 2; + } + resampleError = soxr_process(resampler, - sourceSamples, numSourceSamples, NULL, - destinationSamples, numDestinationSamples, NULL); + sourceSamples, numAdjustedSourceSamples, NULL, + destinationSamples, numAdjustedDestinationSamples, NULL); } return resampleError; @@ -429,9 +436,12 @@ soxr_t soxrResamplerFromInputFormatToOutputFormat(const QAudioFormat& sourceAudi // setup soxr_quality_spec_t for quality options soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0); + int channelCount = (sourceAudioFormat.channelCount() == 2 && destinationAudioFormat.channelCount() == 2) + ? 2 : 1; + soxr_t newResampler = soxr_create(sourceAudioFormat.sampleRate(), destinationAudioFormat.sampleRate(), - 1, + channelCount, &soxrError, &inputToNetworkSpec, &qualitySpec, 0); if (soxrError) { @@ -1136,7 +1146,7 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice if (!outputDeviceInfo.isNull()) { qDebug() << "The audio output device " << outputDeviceInfo.deviceName() << "is available."; _outputAudioDeviceName = outputDeviceInfo.deviceName().trimmed(); - + if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) { qDebug() << "The format to be used for audio output is" << _outputFormat; diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 25d0c1699d..ca39dcbdc4 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -30,6 +30,8 @@ class AbstractAudioInterface; class AudioInjector : public QObject { Q_OBJECT + + Q_PROPERTY(AudioInjectorOptions options WRITE setOptions READ getOptions) public: AudioInjector(QObject* parent); AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions); @@ -51,7 +53,9 @@ public slots: void triggerDeleteAfterFinish() { _shouldDeleteAfterFinish = true; } void stopAndDeleteLater(); - void setOptions(AudioInjectorOptions& options) { _options = options; } + const AudioInjectorOptions& getOptions() const { return _options; } + void setOptions(const AudioInjectorOptions& options) { _options = options; } + void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; } float getLoudness() const { return _loudness; } bool isPlaying() const { return !_isFinished; } From 3579bb46ab5a91e52bcc0eae87f9adda5fd98c4d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 10 Mar 2015 17:04:30 -0700 Subject: [PATCH 54/56] handle touch update without a touch begin event --- examples/lookWithTouch.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/lookWithTouch.js b/examples/lookWithTouch.js index 68b29c305b..e9e7b0735a 100644 --- a/examples/lookWithTouch.js +++ b/examples/lookWithTouch.js @@ -38,6 +38,13 @@ function touchUpdateEvent(event) { if (wantDebugging) { print("touchUpdateEvent event.x,y=" + event.x + ", " + event.y); } + + if (!startedTouching) { + // handle Qt 5.4.x bug where we get touch update without a touch begin event + startedTouching = true; + lastX = event.x; + lastY = event.y; + } var MOUSE_YAW_SCALE = -0.25; var MOUSE_PITCH_SCALE = -12.5; From 76f3378223772e10c95927ac60caed77784b4cbd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 10 Mar 2015 18:05:10 -0700 Subject: [PATCH 55/56] don't pass no-libraries option to windeployqt --- cmake/macros/CopyDllsBesideWindowsExecutable.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/macros/CopyDllsBesideWindowsExecutable.cmake b/cmake/macros/CopyDllsBesideWindowsExecutable.cmake index 24996fde03..e8d499bab8 100644 --- a/cmake/macros/CopyDllsBesideWindowsExecutable.cmake +++ b/cmake/macros/CopyDllsBesideWindowsExecutable.cmake @@ -37,7 +37,7 @@ macro(COPY_DLLS_BESIDE_WINDOWS_EXECUTABLE) add_custom_command( TARGET ${TARGET_NAME} POST_BUILD - COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} --no-libraries $" + COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} $" ) endif () endmacro() \ No newline at end of file From 931a234ba74e0fed0d14d721acb18e3b824216f9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 10 Mar 2015 18:08:19 -0700 Subject: [PATCH 56/56] fix reset for close button SVG in LoginDialog --- interface/src/ui/LoginDialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 4817727909..004f863901 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -58,6 +58,7 @@ void LoginDialog::reset() { _ui->emailLineEdit->setFocus(); _ui->logoLabel->setPixmap(QPixmap(PathUtils::resourcesPath() + "images/hifi-logo.svg")); _ui->loginButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/login.svg")); + _ui->closeButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/close.svg")); _ui->infoLabel->setVisible(false); _ui->errorLabel->setVisible(false);