From 660d9237e6e77fbefa8d4845132fc01e3b65eba8 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sat, 28 Feb 2015 13:07:16 -0800 Subject: [PATCH 01/99] 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/99] 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/99] 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/99] 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/99] 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 5d4ef8d5b8054fcf33a7dddc768f6518d33e499a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Mar 2015 14:30:26 -0800 Subject: [PATCH 06/99] initial flailing --- interface/src/avatar/Avatar.h | 2 +- interface/src/avatar/MyAvatar.cpp | 42 +++++++++++++++++++++-- interface/src/avatar/MyAvatar.h | 16 +++++++++ libraries/physics/src/PhysicsSimulation.h | 2 ++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 72b7ecf93a..9b166e866f 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -188,7 +188,7 @@ protected: // These position histories and derivatives are in the world-frame. // The derivatives are the MEASURED results of all external and internal forces - // and are therefor READ-ONLY --> motion control of the Avatar is NOT obtained + // and are therefore READ-ONLY --> motion control of the Avatar is NOT obtained // by setting these values. // Floating point error prevents us from accurately measuring velocity using a naive approach // (e.g. vel = (pos - lastPos)/dt) so instead we use _positionDeltaAccumulator. diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8c4ea73775..3ec53ca396 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -92,8 +92,7 @@ MyAvatar::MyAvatar() : _physicsSimulation(), _feetTouchFloor(true), _isLookingAtLeftEye(true), - _realWorldFieldOfView("realWorldFieldOfView", - DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES) + _realWorldFieldOfView("realWorldFieldOfView", DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES) { ShapeCollider::initDispatchTable(); for (int i = 0; i < MAX_DRIVE_KEYS; i++) { @@ -107,6 +106,8 @@ MyAvatar::MyAvatar() : // connect to AddressManager signal for location jumps connect(DependencyManager::get().data(), &AddressManager::locationChangeRequired, this, &MyAvatar::goToLocation); + + setupAvatarCollision(); } MyAvatar::~MyAvatar() { @@ -1979,3 +1980,40 @@ void MyAvatar::clearDriveKeys() { _driveKeys[i] = 0.0f; } } + + +void MyAvatar::setupAvatarCollision() { + btTransform startTransform = btTransform (glmToBullet(getOrientation()), glmToBullet(getPosition())); + + class btPairCachingGhostObject* m_ghostObject = new btPairCachingGhostObject(); + m_ghostObject->setWorldTransform(startTransform); + + btScalar characterHeight = 1.75; + btScalar characterWidth = 1.75; + btScalar stepHeight = btScalar(0.35); + + btConvexShape* capsule = new btCapsuleShape(characterWidth, characterHeight); + m_ghostObject->setCollisionShape(capsule); + m_ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); + + _characterController = new btKinematicCharacterController(m_ghostObject, capsule, stepHeight); + + // PhysicsSimulation _physicsSimulation + // PhysicsEngine --> ThreadSafeDynamicsWorld* _dynamicsWorld = NULL; + + _dynamicsWorld->addCollisionObject(m_ghostObject, btBroadphaseProxy::CharacterFilter, + btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); + _dynamicsWorld->addAction(_characterController); +} + + +void MyAvatar::setAvatarMotion() { + /* + float dt = getDeltaTimeMicroseconds() * 0.000001f; + btVector3 walkDirection = btVector3(0.0, 0.0, 0.0); + btScalar walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s + btScalar walkSpeed = walkVelocity * dt; + + _characterController->setWalkDirection(walkDirection*walkSpeed); + */ +} diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index ae392268f0..9e425e2ec8 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -15,10 +15,21 @@ #include #include + +#include +#include +#include +#include +#include + + + #include "Avatar.h" class ModelItemID; + + class MyAvatar : public Avatar { Q_OBJECT Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally) @@ -241,6 +252,11 @@ private: void updateChatCircle(float deltaTime); void maybeUpdateBillboard(); void setGravity(const glm::vec3& gravity); + + /// character collisions + btCharacterControllerInterface* _characterController; + void setupAvatarCollision(); + void setAvatarMotion(); }; #endif // hifi_MyAvatar_h diff --git a/libraries/physics/src/PhysicsSimulation.h b/libraries/physics/src/PhysicsSimulation.h index 90d6e38187..404731e589 100644 --- a/libraries/physics/src/PhysicsSimulation.h +++ b/libraries/physics/src/PhysicsSimulation.h @@ -61,6 +61,8 @@ public: bool getShapeCollisions(const Shape* shape, CollisionList& collisions) const; + void setupAvatarCollision(); + protected: void integrate(float deltaTime); From 7e4b597ca32d8dee914139118818ca6b8e4a2423 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Mar 2015 15:45:10 -0800 Subject: [PATCH 07/99] keep physics specific code in PhysicsEngine --- interface/src/Application.cpp | 2 ++ interface/src/avatar/MyAvatar.cpp | 39 ---------------------- interface/src/avatar/MyAvatar.h | 14 -------- libraries/physics/src/PhysicsEngine.cpp | 43 +++++++++++++++++++++++++ libraries/physics/src/PhysicsEngine.h | 11 +++++++ 5 files changed, 56 insertions(+), 53 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fe41621dc1..811af7403d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1766,6 +1766,8 @@ void Application::init() { tree->setSimulation(&_physicsEngine); _physicsEngine.init(&_entityEditSender); + _physicsEngine.setAvatarData(_myAvatar); + connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity, ScriptEngine::getEntityScriptingInterface(), &EntityScriptingInterface::entityCollisionWithEntity); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3ec53ca396..b5cd2c0bfe 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -106,8 +106,6 @@ MyAvatar::MyAvatar() : // connect to AddressManager signal for location jumps connect(DependencyManager::get().data(), &AddressManager::locationChangeRequired, this, &MyAvatar::goToLocation); - - setupAvatarCollision(); } MyAvatar::~MyAvatar() { @@ -1980,40 +1978,3 @@ void MyAvatar::clearDriveKeys() { _driveKeys[i] = 0.0f; } } - - -void MyAvatar::setupAvatarCollision() { - btTransform startTransform = btTransform (glmToBullet(getOrientation()), glmToBullet(getPosition())); - - class btPairCachingGhostObject* m_ghostObject = new btPairCachingGhostObject(); - m_ghostObject->setWorldTransform(startTransform); - - btScalar characterHeight = 1.75; - btScalar characterWidth = 1.75; - btScalar stepHeight = btScalar(0.35); - - btConvexShape* capsule = new btCapsuleShape(characterWidth, characterHeight); - m_ghostObject->setCollisionShape(capsule); - m_ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); - - _characterController = new btKinematicCharacterController(m_ghostObject, capsule, stepHeight); - - // PhysicsSimulation _physicsSimulation - // PhysicsEngine --> ThreadSafeDynamicsWorld* _dynamicsWorld = NULL; - - _dynamicsWorld->addCollisionObject(m_ghostObject, btBroadphaseProxy::CharacterFilter, - btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); - _dynamicsWorld->addAction(_characterController); -} - - -void MyAvatar::setAvatarMotion() { - /* - float dt = getDeltaTimeMicroseconds() * 0.000001f; - btVector3 walkDirection = btVector3(0.0, 0.0, 0.0); - btScalar walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s - btScalar walkSpeed = walkVelocity * dt; - - _characterController->setWalkDirection(walkDirection*walkSpeed); - */ -} diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 9e425e2ec8..f0102b2824 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -15,15 +15,6 @@ #include #include - -#include -#include -#include -#include -#include - - - #include "Avatar.h" class ModelItemID; @@ -252,11 +243,6 @@ private: void updateChatCircle(float deltaTime); void maybeUpdateBillboard(); void setGravity(const glm::vec3& gravity); - - /// character collisions - btCharacterControllerInterface* _characterController; - void setupAvatarCollision(); - void setAvatarMotion(); }; #endif // hifi_MyAvatar_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 10c7f42546..99dcedf9a7 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -13,6 +13,7 @@ #include "ShapeInfoUtil.h" #include "PhysicsHelpers.h" #include "ThreadSafeDynamicsWorld.h" +#include "AvatarData.h" static uint32_t _numSubsteps; @@ -582,3 +583,45 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio body->activate(); return true; } + + + +void PhysicsEngine::setAvatarData(AvatarData *avatarData) { + btTransform startTransform = btTransform (glmToBullet(avatarData->getOrientation()), + glmToBullet(avatarData->getPosition())); + + class btPairCachingGhostObject* m_ghostObject = new btPairCachingGhostObject(); + m_ghostObject->setWorldTransform(startTransform); + + btScalar characterHeight = 1.75; + btScalar characterWidth = 1.75; + btScalar stepHeight = btScalar(0.35); + + btConvexShape* capsule = new btCapsuleShape(characterWidth, characterHeight); + m_ghostObject->setCollisionShape(capsule); + m_ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); + + _characterController = new btKinematicCharacterController(m_ghostObject, capsule, stepHeight); + + // PhysicsSimulation _physicsSimulation + // PhysicsEngine --> ThreadSafeDynamicsWorld* _dynamicsWorld = NULL; + // PhysicsEngine Application::_physicsEngine + + // ThreadSafeDynamicsWorld* dynamicsWorld; + // dynamicsWorld = Application::getInstance()->_physicsEngine; + _dynamicsWorld->addCollisionObject(m_ghostObject, btBroadphaseProxy::CharacterFilter, + btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); + _dynamicsWorld->addAction(_characterController); +} + + +// void PhysicsEngine::setAvatarMotion(AvatarData *avatarData) { + /* + float dt = getDeltaTimeMicroseconds() * 0.000001f; + btVector3 walkDirection = btVector3(0.0, 0.0, 0.0); + btScalar walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s + btScalar walkSpeed = walkVelocity * dt; + + _characterController->setWalkDirection(walkDirection*walkSpeed); + */ +// } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 2a7baa3ec6..1725b36314 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -16,6 +16,11 @@ #include #include +#include +#include +#include +#include +#include #include #include @@ -25,6 +30,7 @@ #include "EntityMotionState.h" #include "ShapeManager.h" #include "ThreadSafeDynamicsWorld.h" +#include "AvatarData.h" const float HALF_SIMULATION_EXTENT = 512.0f; // meters @@ -82,6 +88,8 @@ public: /// process queue of changed from external sources void relayIncomingChangesToSimulation(); + void setAvatarData(AvatarData *avatarData); + private: /// \param motionState pointer to Object's MotionState void removeObjectFromBullet(ObjectMotionState* motionState); @@ -113,6 +121,9 @@ private: ContactMap _contactMap; uint32_t _numContactFrames = 0; uint32_t _lastNumSubstepsAtUpdateInternal = 0; + + /// character collisions + btCharacterControllerInterface* _characterController; }; #endif // hifi_PhysicsEngine_h From 1facbbb844c8941883fb1ce26e9f7980dccbfad4 Mon Sep 17 00:00:00 2001 From: Virendra Singh Date: Wed, 4 Mar 2015 08:21:39 +0530 Subject: [PATCH 08/99] 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 09/99] 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 b4998e9c53bfebccbbfd0e6edd8a05332399bfd5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 Mar 2015 08:48:48 -0800 Subject: [PATCH 10/99] falling onto an object works --- interface/src/avatar/MyAvatar.cpp | 26 ++++++++++++++++++++++++- interface/src/avatar/MyAvatar.h | 1 + libraries/physics/src/PhysicsEngine.cpp | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f212402294..3068bd2046 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -181,7 +181,11 @@ void MyAvatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("transform"); updateOrientation(deltaTime); - updatePosition(deltaTime); + if (_enablePhysics) { + updatePhysicsPosition(deltaTime); + } else { + updatePosition(deltaTime); + } } { @@ -1391,6 +1395,26 @@ void MyAvatar::updatePosition(float deltaTime) { measureMotionDerivatives(deltaTime); } + +void MyAvatar::updatePhysicsPosition(float deltaTime) { + glm::vec3 velocity = _velocity; + + bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f; + + glm::quat rotation = getHead()->getCameraOrientation(); + glm::vec3 localVelocity = glm::inverse(rotation) * velocity; + + bool hasFloor = false; + glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor); + newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); + + // rotate back into world-frame + velocity = rotation * newLocalVelocity; + +} + + + void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) { glm::vec3 up = getBodyUpDirection(); const float ENVIRONMENT_SURFACE_ELASTICITY = 0.0f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f2f965032d..d74b7fc5ac 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -235,6 +235,7 @@ private: glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor); glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity); void updatePosition(float deltaTime); + void updatePhysicsPosition(float deltaTime); void updateCollisionWithAvatars(float deltaTime); void updateCollisionWithEnvironment(float deltaTime, float radius); void updateCollisionWithVoxels(float deltaTime, float radius); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 2cfa50b44d..63e6901ec4 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -370,7 +370,7 @@ void PhysicsEngine::computeCollisionEvents() { btBroadphasePairArray& pairArray = _avatarGhostObject->getOverlappingPairCache()->getOverlappingPairArray(); int numPairs = pairArray.size(); - for (int i=0;i Date: Wed, 4 Mar 2015 15:26:02 -0800 Subject: [PATCH 11/99] move _velocity into base class. walking on a cube works --- interface/src/avatar/Avatar.cpp | 1 - interface/src/avatar/Avatar.h | 3 --- interface/src/avatar/MyAvatar.cpp | 22 +++++++++++++--------- interface/src/avatar/MyAvatar.h | 4 +--- libraries/avatars/src/AvatarData.cpp | 3 ++- libraries/avatars/src/AvatarData.h | 4 ++++ libraries/physics/src/PhysicsEngine.cpp | 17 +++-------------- 7 files changed, 23 insertions(+), 31 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index cac071a677..3333c0ab92 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -63,7 +63,6 @@ Avatar::Avatar() : _skeletonModel(this), _skeletonOffset(0.0f), _bodyYawDelta(0.0f), - _velocity(0.0f), _positionDeltaAccumulator(0.0f), _lastVelocity(0.0f), _acceleration(0.0f), diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 77c9459999..2951208d95 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -155,7 +155,6 @@ public: Q_INVOKABLE glm::vec3 getNeckPosition() const; - Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; } Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; } Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; } Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; } @@ -184,8 +183,6 @@ protected: QVector _attachmentModels; float _bodyYawDelta; - glm::vec3 _velocity; - // These position histories and derivatives are in the world-frame. // The derivatives are the MEASURED results of all external and internal forces // and are therefore READ-ONLY --> motion control of the Avatar is NOT obtained diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3068bd2046..e6f84330bc 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -181,8 +181,8 @@ void MyAvatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("transform"); updateOrientation(deltaTime); - if (_enablePhysics) { - updatePhysicsPosition(deltaTime); + if (isPhysicsEnabled()) { + updatePositionWithPhysics(deltaTime); } else { updatePosition(deltaTime); } @@ -1396,21 +1396,25 @@ void MyAvatar::updatePosition(float deltaTime) { } -void MyAvatar::updatePhysicsPosition(float deltaTime) { - glm::vec3 velocity = _velocity; - - bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f; +void MyAvatar::updatePositionWithPhysics(float deltaTime) { + // bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f; + // rotate velocity into camera frame glm::quat rotation = getHead()->getCameraOrientation(); - glm::vec3 localVelocity = glm::inverse(rotation) * velocity; + glm::vec3 localVelocity = glm::inverse(rotation) * _velocity; bool hasFloor = false; glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor); newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); - // rotate back into world-frame - velocity = rotation * newLocalVelocity; + // cap avatar speed + float speed = glm::length(_velocity); + if (speed > MAX_AVATAR_SPEED) { + _velocity *= MAX_AVATAR_SPEED / speed; + } + // rotate back into world-frame + _velocity = rotation * newLocalVelocity; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index d74b7fc5ac..6c55125b5c 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -166,8 +166,6 @@ public slots: glm::vec3 getThrust() { return _thrust; }; void setThrust(glm::vec3 newThrust) { _thrust = newThrust; } - void setVelocity(const glm::vec3 velocity) { _velocity = velocity; } - void updateMotionBehavior(); void onToggleRagdoll(); @@ -235,7 +233,7 @@ private: glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor); glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity); void updatePosition(float deltaTime); - void updatePhysicsPosition(float deltaTime); + void updatePositionWithPhysics(float deltaTime); void updateCollisionWithAvatars(float deltaTime); void updateCollisionWithEnvironment(float deltaTime, float radius); void updateCollisionWithVoxels(float deltaTime, float radius); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a3d330f84b..5b391b33f8 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -55,7 +55,8 @@ AvatarData::AvatarData() : _billboard(), _errorLogExpiry(0), _owningAvatarMixer(), - _lastUpdateTimer() + _lastUpdateTimer(), + _velocity(0.0f) { } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 857489eaa7..bc0305338c 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -311,6 +311,8 @@ public: bool tryLockForWrite() { return _lock.tryLockForWrite(); } void unlock() { _lock.unlock(); } + void setVelocity(const glm::vec3 velocity) { _velocity = velocity; } + Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; } public slots: void sendAvatarDataPacket(); @@ -401,6 +403,8 @@ protected: virtual void updateJointMappings(); void changeReferential(Referential* ref); + glm::vec3 _velocity; + private: // privatize the copy constructor and assignment operator so they cannot be called AvatarData(const AvatarData&); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 63e6901ec4..d7df649713 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -284,6 +284,7 @@ void PhysicsEngine::stepSimulation() { if (_avatarData->isPhysicsEnabled()) { _avatarGhostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), glmToBullet(_avatarData->getPosition()))); + _characterController->setWalkDirection(glmToBullet(_avatarData->getVelocity())); } const int MAX_NUM_SUBSTEPS = 4; @@ -364,7 +365,7 @@ void PhysicsEngine::computeCollisionEvents() { } - +#if 0 // avatar collisions btManifoldArray manifoldArray; btBroadphasePairArray& pairArray = _avatarGhostObject->getOverlappingPairCache()->getOverlappingPairArray(); @@ -399,7 +400,7 @@ void PhysicsEngine::computeCollisionEvents() { } } } - +#endif @@ -667,15 +668,3 @@ void PhysicsEngine::setAvatarData(AvatarData *avatarData) { btGhostPairCallback* ghostPairCallback = new btGhostPairCallback(); _dynamicsWorld->getPairCache()->setInternalGhostPairCallback(ghostPairCallback); } - - -// void PhysicsEngine::setAvatarMotion() { - /* - float dt = getDeltaTimeMicroseconds() * 0.000001f; - btVector3 walkDirection = btVector3(0.0, 0.0, 0.0); - btScalar walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s - btScalar walkSpeed = walkVelocity * dt; - - _characterController->setWalkDirection(walkDirection*walkSpeed); - */ -// } From ac0c4e8512cc6f4ae752310c0c6816188b00e285 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 Mar 2015 19:57:06 -0800 Subject: [PATCH 12/99] cap max speed at MAX_WALKING_SPEED --- interface/src/avatar/MyAvatar.cpp | 8 +++----- libraries/physics/src/PhysicsEngine.cpp | 13 +++++++------ 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e6f84330bc..f30a22d78c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1397,8 +1397,6 @@ void MyAvatar::updatePosition(float deltaTime) { void MyAvatar::updatePositionWithPhysics(float deltaTime) { - // bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f; - // rotate velocity into camera frame glm::quat rotation = getHead()->getCameraOrientation(); glm::vec3 localVelocity = glm::inverse(rotation) * _velocity; @@ -1408,9 +1406,9 @@ void MyAvatar::updatePositionWithPhysics(float deltaTime) { newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); // cap avatar speed - float speed = glm::length(_velocity); - if (speed > MAX_AVATAR_SPEED) { - _velocity *= MAX_AVATAR_SPEED / speed; + float speed = glm::length(newLocalVelocity); + if (speed > MAX_WALKING_SPEED) { + newLocalVelocity *= MAX_WALKING_SPEED / speed; } // rotate back into world-frame diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index d7df649713..625afca683 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -281,18 +281,19 @@ void PhysicsEngine::stepSimulation() { // This is step (1). relayIncomingChangesToSimulation(); - if (_avatarData->isPhysicsEnabled()) { - _avatarGhostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), - glmToBullet(_avatarData->getPosition()))); - _characterController->setWalkDirection(glmToBullet(_avatarData->getVelocity())); - } - const int MAX_NUM_SUBSTEPS = 4; const float MAX_TIMESTEP = (float)MAX_NUM_SUBSTEPS * PHYSICS_ENGINE_FIXED_SUBSTEP; float dt = 1.0e-6f * (float)(_clock.getTimeMicroseconds()); _clock.reset(); float timeStep = btMin(dt, MAX_TIMESTEP); + if (_avatarData->isPhysicsEnabled()) { + _avatarGhostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), + glmToBullet(_avatarData->getPosition()))); + // _characterController->setWalkDirection(glmToBullet(_avatarData->getVelocity())); + _characterController->setVelocityForTimeInterval(glmToBullet(_avatarData->getVelocity()), timeStep); + } + // This is step (2). int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); _numSubsteps += (uint32_t)numSubsteps; From af4957ff141609835f0890d1b668c7c134b15f26 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 5 Mar 2015 06:38:42 -0800 Subject: [PATCH 13/99] start to write out obj from vhacd --- tools/vhacd/src/VHACDUtil.cpp | 2 +- tools/vhacd/src/main.cpp | 47 +++++++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/tools/vhacd/src/VHACDUtil.cpp b/tools/vhacd/src/VHACDUtil.cpp index 63b3bba459..0f72032af1 100644 --- a/tools/vhacd/src/VHACDUtil.cpp +++ b/tools/vhacd/src/VHACDUtil.cpp @@ -14,7 +14,7 @@ //Read all the meshes from provided FBX file -bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results){ +bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results) { // open the fbx file QFile fbx(filename); diff --git a/tools/vhacd/src/main.cpp b/tools/vhacd/src/main.cpp index e43f712fa0..530f4ad648 100644 --- a/tools/vhacd/src/main.cpp +++ b/tools/vhacd/src/main.cpp @@ -19,6 +19,22 @@ using namespace std; using namespace VHACD; + +bool writeOBJ(QString outFileName, QVector>& convexHullList) { + QFile file(outFileName); + if (!file.open(QIODevice::WriteOnly)) { + qDebug() << "Unable to write to " << outFileName; + return false; + } + + QTextStream out(&file); + + out << "testing\n"; + + return true; +} + + int main(int argc, char * argv[]){ vector triangles; // array of indexes vector points; // array of coordinates @@ -27,17 +43,23 @@ int main(int argc, char * argv[]){ vhacd::ComputeResults results; // results after computing vhacd VHACD::IVHACD::Parameters params; vhacd::ProgressCallback pCallBack; - if (argc < 2){ - cout << "please provide a FBX file as argument\n "; + if (argc < 3) { + cout << argv[0] << " input-file.fbx output-file.obj\n"; return 1; } - string filename(argv[1]); - if (filename.empty()){ - cout << "please provide a FBX file as argument\n "; + string inputFilename(argv[1]); + if (inputFilename.empty()) { + cout << "please provide a FBX file as first argument\n"; + return 1; + } + string outputFilename(argv[2]); + if (outputFilename.empty()) { + cout << "please provide a OBJ file as second argument\n"; return 1; } - QString fname = QString::fromStdString(filename); + QString inFileName = QString::fromStdString(inputFilename); + QString outFileName = QString::fromStdString(outputFilename); //set parameters for V-HACD params.m_callback = &pCallBack; //progress callback @@ -53,7 +75,7 @@ int main(int argc, char * argv[]){ // load the mesh auto begin = std::chrono::high_resolution_clock::now(); - if (!vUtil.loadFBX(fname, &fbx)){ + if (!vUtil.loadFBX(inFileName, &fbx)){ cout << "Error in opening FBX file...."; return 1; } @@ -85,7 +107,7 @@ int main(int argc, char * argv[]){ totalHulls += hullCounts.at(i); } cout << endl << "Summary of V-HACD Computation..................." << endl; - cout << "File Path : " << fname.toStdString() << endl; + cout << "File Path : " << inFileName.toStdString() << endl; cout << "Number Of Meshes : " << fbx.meshCount << endl; cout << "Processed Meshes : " << results.meshCount << endl; cout << "Total vertices : " << totalVertices << endl; @@ -94,7 +116,7 @@ int main(int argc, char * argv[]){ cout << "Total FBX load time: " << (double)loadDuration / 1000000000.00 << " seconds" << endl; cout << "V-HACD Compute time: " << (double)computeDuration / 1000000000.00 << " seconds" << endl; cout << endl << "Summary per convex hull ........................" << endl < chList = results.convexHullList.at(i); cout << "\t" << "Number Of Hulls : " << chList.count() << endl; @@ -106,6 +128,9 @@ int main(int argc, char * argv[]){ } } - getchar(); + + writeOBJ(outFileName, results.convexHullList); + + return 0; -} \ No newline at end of file +} From 0d093b4921b5ae7e8dfcc6afc0924093eb8ac2f5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 5 Mar 2015 15:38:55 -0800 Subject: [PATCH 14/99] rename binary from vhacd to vhacd-util. vhacd-util outpus obj files --- tools/vhacd/CMakeLists.txt | 4 +- tools/vhacd/src/VHACDUtil.cpp | 22 +++ tools/vhacd/src/VHACDUtil.h | 16 +- tools/vhacd/src/VHACDUtilApp.cpp | 250 +++++++++++++++++++++++++++++++ tools/vhacd/src/VHACDUtilApp.h | 28 ++++ tools/vhacd/src/main.cpp | 119 +-------------- 6 files changed, 315 insertions(+), 124 deletions(-) create mode 100644 tools/vhacd/src/VHACDUtilApp.cpp create mode 100644 tools/vhacd/src/VHACDUtilApp.h diff --git a/tools/vhacd/CMakeLists.txt b/tools/vhacd/CMakeLists.txt index 31a7f7c8e2..f003b685e0 100644 --- a/tools/vhacd/CMakeLists.txt +++ b/tools/vhacd/CMakeLists.txt @@ -1,5 +1,5 @@ -set(TARGET_NAME vhacd) -setup_hifi_project() +set(TARGET_NAME vhacd-util) +setup_hifi_project(Core Widgets) link_hifi_libraries(shared model fbx gpu networking octree) #find_package(VHACD REQUIRED) done in CMakeList.txt in parent directory diff --git a/tools/vhacd/src/VHACDUtil.cpp b/tools/vhacd/src/VHACDUtil.cpp index 0f72032af1..caa213572b 100644 --- a/tools/vhacd/src/VHACDUtil.cpp +++ b/tools/vhacd/src/VHACDUtil.cpp @@ -13,6 +13,11 @@ #include "VHACDUtil.h" + + + + + //Read all the meshes from provided FBX file bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results) { @@ -82,6 +87,23 @@ bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD for (unsigned int j = 0; j < nConvexHulls; j++){ VHACD::IVHACD::ConvexHull hull; interfaceVHACD->GetConvexHull(j, hull); + + double *m_points_copy = new double[hull.m_nPoints * 3]; + // std::copy(std::begin(hull.m_points), std::end(hull.m_points), std::begin(m_points_copy)); + for (unsigned int i=0; iconvexHullList.append(convexHulls); diff --git a/tools/vhacd/src/VHACDUtil.h b/tools/vhacd/src/VHACDUtil.h index b87ba07ff0..ce1c157025 100644 --- a/tools/vhacd/src/VHACDUtil.h +++ b/tools/vhacd/src/VHACDUtil.h @@ -21,28 +21,28 @@ #include #include -namespace vhacd{ +namespace vhacd { - typedef struct{ + typedef struct { int meshCount; QVector convexHullsCountList; QVector> convexHullList; - }ComputeResults; + } ComputeResults; - typedef struct{ + typedef struct { int meshCount; QVector> perMeshVertices; QVector> perMeshTriangleIndices; - }LoadFBXResults; + } LoadFBXResults; - class VHACDUtil{ + class VHACDUtil { public: bool loadFBX(const QString filename, vhacd::LoadFBXResults *results); bool computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD::Parameters params, vhacd::ComputeResults *results)const; ~VHACDUtil(); }; - class ProgressCallback : public VHACD::IVHACD::IUserCallback{ + class ProgressCallback : public VHACD::IVHACD::IUserCallback { public: ProgressCallback(void); ~ProgressCallback(); @@ -52,4 +52,4 @@ namespace vhacd{ const char * const stage, const char * const operation); }; } -#endif //hifi_VHACDUtil_h \ No newline at end of file +#endif //hifi_VHACDUtil_h diff --git a/tools/vhacd/src/VHACDUtilApp.cpp b/tools/vhacd/src/VHACDUtilApp.cpp new file mode 100644 index 0000000000..d4b0f48766 --- /dev/null +++ b/tools/vhacd/src/VHACDUtilApp.cpp @@ -0,0 +1,250 @@ +// +// VHACDUtil.h +// tools/vhacd/src +// +// Created by Seth Alves on 3/5/15. +// 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 "VHACDUtilApp.h" +#include "VHACDUtil.h" + +using namespace std; +using namespace VHACD; + + + +QString formatFloat(double n) { + // limit precision to 6, but don't output trailing zeros. + QString s = QString::number(n, 'f', 6); + while (s.endsWith("0")) { + s.remove(s.size() - 1, 1); + } + if (s.endsWith(".")) { + s.remove(s.size() - 1, 1); + } + return s; +} + + +bool writeOBJ(QString outFileName, QVector>& convexHullList, bool outputOneMesh) { + QFile file(outFileName); + if (!file.open(QIODevice::WriteOnly)) { + qDebug() << "Unable to write to " << outFileName; + return false; + } + + QTextStream out(&file); + + + if (convexHullList.size() != 1) { + qDebug() << "unexpected number of meshes --" << convexHullList.size(); + exit(1); + } + + QVector hulls = convexHullList[0]; + + + if (outputOneMesh) { + foreach (VHACD::IVHACD::ConvexHull hull, hulls) { + for (unsigned int i = 0; i < hull.m_nPoints; i++) { + out << "v "; + out << formatFloat(hull.m_points[i*3]) << " "; + out << formatFloat(hull.m_points[i*3+1]) << " "; + out << formatFloat(hull.m_points[i*3+2]) << " 1\n"; + } + } + + unsigned int pointStartOffset = 0; + foreach (VHACD::IVHACD::ConvexHull hull, hulls) { + for (unsigned int i = 0; i < hull.m_nTriangles; i++) { + out << "f "; + out << hull.m_triangles[i*3] + 1 + pointStartOffset << " "; + out << hull.m_triangles[i*3+1] + 1 + pointStartOffset << " "; + out << hull.m_triangles[i*3+2] + 1 + pointStartOffset << "\n"; + } + pointStartOffset += hull.m_nPoints; + } + } else { + unsigned int nth = 0; + foreach (VHACD::IVHACD::ConvexHull hull, hulls) { + out << "o hull-" << nth++ << "\n"; + for (unsigned int i = 0; i < hull.m_nPoints; i++) { + out << "v "; + out << formatFloat(hull.m_points[i*3]) << " "; + out << formatFloat(hull.m_points[i*3+1]) << " "; + out << formatFloat(hull.m_points[i*3+2]) << " 1\n"; + } + for (unsigned int i = 0; i < hull.m_nTriangles; i++) { + out << "f "; + out << hull.m_triangles[i*3] + 1 << " "; + out << hull.m_triangles[i*3+1] + 1 << " "; + out << hull.m_triangles[i*3+2] + 1 << "\n"; + } + out << "\n"; + } + } + + return true; +} + + + + +VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) : + QCoreApplication(argc, argv) +{ + vector triangles; // array of indexes + vector points; // array of coordinates + vhacd::VHACDUtil vUtil; + vhacd::LoadFBXResults fbx; //mesh data from loaded fbx file + vhacd::ComputeResults results; // results after computing vhacd + VHACD::IVHACD::Parameters params; + vhacd::ProgressCallback pCallBack; + + + // parse command-line + QCommandLineParser parser; + parser.setApplicationDescription("High Fidelity Object Decomposer"); + parser.addHelpOption(); + + const QCommandLineOption helpOption = parser.addHelpOption(); + + const QCommandLineOption outputOneMeshOption("1", "output hulls as single mesh"); + parser.addOption(outputOneMeshOption); + + const QCommandLineOption inputFilenameOption("i", "input file", "filename.fbx"); + parser.addOption(inputFilenameOption); + + const QCommandLineOption outputFilenameOption("o", "output file", "filename.obj"); + parser.addOption(outputFilenameOption); + + + if (!parser.parse(QCoreApplication::arguments())) { + qCritical() << parser.errorText() << endl; + parser.showHelp(); + Q_UNREACHABLE(); + } + + if (parser.isSet(helpOption)) { + parser.showHelp(); + Q_UNREACHABLE(); + } + + + bool outputOneMesh = parser.isSet(outputOneMeshOption); + + QString inputFilename; + // check for an assignment pool passed on the command line or in the config + if (parser.isSet(inputFilenameOption)) { + inputFilename = parser.value(inputFilenameOption); + } + + QString outputFilename; + // check for an assignment pool passed on the command line or in the config + if (parser.isSet(outputFilenameOption)) { + outputFilename = parser.value(outputFilenameOption); + } + + + if (inputFilename == "") { + cerr << "input filename is required."; + parser.showHelp(); + Q_UNREACHABLE(); + } + + if (outputFilename == "") { + cerr << "output filename is required."; + parser.showHelp(); + Q_UNREACHABLE(); + } + + + //set parameters for V-HACD + params.m_callback = &pCallBack; //progress callback + params.m_resolution = 100000; // 100000 + params.m_depth = 20; // 20 + params.m_concavity = 0.001; // 0.001 + params.m_delta = 0.01; // 0.05 + params.m_planeDownsampling = 4; // 4 + params.m_convexhullDownsampling = 4; // 4 + params.m_alpha = 0.05; // 0.05 // controls the bias toward clipping along symmetry planes + params.m_beta = 0.05; // 0.05 + params.m_gamma = 0.0005; // 0.0005 + params.m_pca = 0; // 0 enable/disable normalizing the mesh before applying the convex decomposition + params.m_mode = 0; // 0: voxel-based (recommended), 1: tetrahedron-based + params.m_maxNumVerticesPerCH = 64; // 64 + params.m_minVolumePerCH = 0.00001; // 0.0001 + params.m_callback = 0; // 0 + params.m_logger = 0; // 0 + params.m_convexhullApproximation = true; // true + params.m_oclAcceleration = true; // true + + + + // load the mesh + + auto begin = std::chrono::high_resolution_clock::now(); + if (!vUtil.loadFBX(inputFilename, &fbx)){ + cout << "Error in opening FBX file...."; + } + auto end = std::chrono::high_resolution_clock::now(); + auto loadDuration = std::chrono::duration_cast(end - begin).count(); + + //perform vhacd computation + begin = std::chrono::high_resolution_clock::now(); + + + if (!vUtil.computeVHACD(&fbx, params, &results)){ + cout << "Compute Failed..."; + } + end = std::chrono::high_resolution_clock::now(); + auto computeDuration = std::chrono::duration_cast(end - begin).count(); + + int totalVertices = 0; + for (int i = 0; i < fbx.meshCount; i++){ + totalVertices += fbx.perMeshVertices.at(i).count(); + } + + int totalTriangles = 0; + for (int i = 0; i < fbx.meshCount; i++){ + totalTriangles += fbx.perMeshTriangleIndices.at(i).count(); + } + + int totalHulls = 0; + QVector hullCounts = results.convexHullsCountList; + for (int i = 0; i < results.meshCount; i++){ + totalHulls += hullCounts.at(i); + } + cout << endl << "Summary of V-HACD Computation..................." << endl; + cout << "File Path : " << inputFilename.toStdString() << endl; + cout << "Number Of Meshes : " << fbx.meshCount << endl; + cout << "Processed Meshes : " << results.meshCount << endl; + cout << "Total vertices : " << totalVertices << endl; + cout << "Total Triangles : " << totalTriangles << endl; + cout << "Total Convex Hulls : " << totalHulls << endl; + cout << "Total FBX load time: " << (double)loadDuration / 1000000000.00 << " seconds" << endl; + cout << "V-HACD Compute time: " << (double)computeDuration / 1000000000.00 << " seconds" << endl; + cout << endl << "Summary per convex hull ........................" << endl < chList = results.convexHullList.at(i); + cout << "\t" << "Number Of Hulls : " << chList.count() << endl; + + for (int j = 0; j < results.convexHullList.at(i).count(); j++){ + cout << "\tHUll : " << j + 1 << endl; + cout << "\t\tNumber Of Points : " << chList.at(j).m_nPoints << endl; + cout << "\t\tNumber Of Triangles : " << chList.at(j).m_nTriangles << endl; + } + } + + writeOBJ(outputFilename, results.convexHullList, outputOneMesh); +} + +VHACDUtilApp::~VHACDUtilApp() { +} diff --git a/tools/vhacd/src/VHACDUtilApp.h b/tools/vhacd/src/VHACDUtilApp.h new file mode 100644 index 0000000000..016b7b7b2f --- /dev/null +++ b/tools/vhacd/src/VHACDUtilApp.h @@ -0,0 +1,28 @@ +// +// VHACDUtil.h +// tools/vhacd/src +// +// Created by Seth Alves on 3/5/15. +// 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_VHACDUtilApp_h +#define hifi_VHACDUtilApp_h + +#include + + +class VHACDUtilApp : public QCoreApplication { + Q_OBJECT + public: + VHACDUtilApp(int argc, char* argv[]); + ~VHACDUtilApp(); +}; + + + +#endif //hifi_VHACDUtilApp_h diff --git a/tools/vhacd/src/main.cpp b/tools/vhacd/src/main.cpp index 530f4ad648..0e8d72abd3 100644 --- a/tools/vhacd/src/main.cpp +++ b/tools/vhacd/src/main.cpp @@ -8,129 +8,20 @@ // 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 -#include "VHACDUtil.h" + +#include "VHACDUtilApp.h" using namespace std; using namespace VHACD; -bool writeOBJ(QString outFileName, QVector>& convexHullList) { - QFile file(outFileName); - if (!file.open(QIODevice::WriteOnly)) { - qDebug() << "Unable to write to " << outFileName; - return false; - } - - QTextStream out(&file); - - out << "testing\n"; - - return true; -} - - -int main(int argc, char * argv[]){ - vector triangles; // array of indexes - vector points; // array of coordinates - vhacd::VHACDUtil vUtil; - vhacd::LoadFBXResults fbx; //mesh data from loaded fbx file - vhacd::ComputeResults results; // results after computing vhacd - VHACD::IVHACD::Parameters params; - vhacd::ProgressCallback pCallBack; - if (argc < 3) { - cout << argv[0] << " input-file.fbx output-file.obj\n"; - return 1; - } - string inputFilename(argv[1]); - if (inputFilename.empty()) { - cout << "please provide a FBX file as first argument\n"; - return 1; - } - string outputFilename(argv[2]); - if (outputFilename.empty()) { - cout << "please provide a OBJ file as second argument\n"; - return 1; - } - - QString inFileName = QString::fromStdString(inputFilename); - QString outFileName = QString::fromStdString(outputFilename); - - //set parameters for V-HACD - params.m_callback = &pCallBack; //progress callback - params.m_resolution = 50000; - params.m_depth = 10; - params.m_concavity = 0.003; - params.m_alpha = 0.05; // controls the bias toward clipping along symmetry planes - params.m_pca = 1; // enable/disable normalizing the mesh before applying the convex decomposition - params.m_mode = 1; // 0: voxel - based approximate convex decomposition, 1 : tetrahedron - based approximate convex decomposition - params.m_maxNumVerticesPerCH = 128; - params.m_minVolumePerCH = 0.0001; // controls the adaptive sampling of the generated convex - hulls - - // load the mesh - - auto begin = std::chrono::high_resolution_clock::now(); - if (!vUtil.loadFBX(inFileName, &fbx)){ - cout << "Error in opening FBX file...."; - return 1; - } - auto end = std::chrono::high_resolution_clock::now(); - auto loadDuration = std::chrono::duration_cast(end - begin).count(); - - //perform vhacd computation - begin = std::chrono::high_resolution_clock::now(); - if (!vUtil.computeVHACD(&fbx, params, &results)){ - cout << "Compute Failed..."; - return 1; - } - end = std::chrono::high_resolution_clock::now(); - auto computeDuration = std::chrono::duration_cast(end - begin).count(); - - int totalVertices = 0; - for (int i = 0; i < fbx.meshCount; i++){ - totalVertices += fbx.perMeshVertices.at(i).count(); - } - - int totalTriangles = 0; - for (int i = 0; i < fbx.meshCount; i++){ - totalTriangles += fbx.perMeshTriangleIndices.at(i).count(); - } - - int totalHulls = 0; - QVector hullCounts = results.convexHullsCountList; - for (int i = 0; i < results.meshCount; i++){ - totalHulls += hullCounts.at(i); - } - cout << endl << "Summary of V-HACD Computation..................." << endl; - cout << "File Path : " << inFileName.toStdString() << endl; - cout << "Number Of Meshes : " << fbx.meshCount << endl; - cout << "Processed Meshes : " << results.meshCount << endl; - cout << "Total vertices : " << totalVertices << endl; - cout << "Total Triangles : " << totalTriangles << endl; - cout << "Total Convex Hulls : " << totalHulls << endl; - cout << "Total FBX load time: " << (double)loadDuration / 1000000000.00 << " seconds" << endl; - cout << "V-HACD Compute time: " << (double)computeDuration / 1000000000.00 << " seconds" << endl; - cout << endl << "Summary per convex hull ........................" << endl < chList = results.convexHullList.at(i); - cout << "\t" << "Number Of Hulls : " << chList.count() << endl; - - for (int j = 0; j < results.convexHullList.at(i).count(); j++){ - cout << "\tHUll : " << j + 1 << endl; - cout << "\t\tNumber Of Points : " << chList.at(j).m_nPoints << endl; - cout << "\t\tNumber Of Triangles : " << chList.at(j).m_nTriangles << endl; - } - } - - - writeOBJ(outFileName, results.convexHullList); - - +int main(int argc, char * argv[]) { + VHACDUtilApp app(argc, argv); return 0; } From 42867bf98d089cdeb6e5c4a4f663a8c5fd5d7159 Mon Sep 17 00:00:00 2001 From: Virendra Singh Date: Fri, 6 Mar 2015 11:10:38 +0530 Subject: [PATCH 15/99] 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 16/99] 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 17/99] 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 858d15d0ba8191efd304589b09ff8860f47c6fc3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 6 Mar 2015 13:15:53 -0800 Subject: [PATCH 18/99] obj reader sort-of works --- libraries/fbx/src/OBJReader.cpp | 190 +++++++++++++++++++ libraries/fbx/src/OBJReader.h | 6 + libraries/render-utils/src/GeometryCache.cpp | 2 + libraries/render-utils/src/GeometryCache.h | 1 + tools/vhacd/src/VHACDUtil.cpp | 32 +++- tools/vhacd/src/VHACDUtil.h | 1 + tools/vhacd/src/VHACDUtilApp.cpp | 42 ++-- 7 files changed, 233 insertions(+), 41 deletions(-) create mode 100644 libraries/fbx/src/OBJReader.cpp create mode 100644 libraries/fbx/src/OBJReader.h diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp new file mode 100644 index 0000000000..1ff4f7a2ae --- /dev/null +++ b/libraries/fbx/src/OBJReader.cpp @@ -0,0 +1,190 @@ + + +#include +#include + + +#include "FBXReader.h" +#include "OBJReader.h" + + + +class OBJTokenizer { +public: + OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) { } + enum SpecialToken { DATUM_TOKEN = 0x100 }; + int nextToken(); + const QByteArray& getDatum() const { return _datum; } + void skipLine() { _device->readLine(); } + void pushBackToken(int token) { _pushedBackToken = token; } + void ungetChar(char ch) { _device->ungetChar(ch); } + +private: + QIODevice* _device; + QByteArray _datum; + int _pushedBackToken; +}; + +int OBJTokenizer::nextToken() { + if (_pushedBackToken != -1) { + int token = _pushedBackToken; + _pushedBackToken = -1; + return token; + } + + char ch; + while (_device->getChar(&ch)) { + if (QChar(ch).isSpace()) { + continue; // skip whitespace + } + switch (ch) { + case '#': + _device->readLine(); // skip the comment + break; + + case '\"': + _datum = ""; + while (_device->getChar(&ch)) { + if (ch == '\"') { // end on closing quote + break; + } + if (ch == '\\') { // handle escaped quotes + if (_device->getChar(&ch) && ch != '\"') { + _datum.append('\\'); + } + } + _datum.append(ch); + } + return DATUM_TOKEN; + + default: + _datum = ""; + _datum.append(ch); + while (_device->getChar(&ch)) { + if (QChar(ch).isSpace() || ch == '\"') { + ungetChar(ch); // read until we encounter a special character, then replace it + break; + } + _datum.append(ch); + } + + return DATUM_TOKEN; + } + } + return -1; +} + + + +bool parseOBJMesh(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeometry &geometry, int& indexStart) { + FBXMesh mesh; + FBXMeshPart meshPart; + bool sawG = false; + bool meshHasData = true; + bool result = true; + + try { // XXX move this out/up + while (true) { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + result = false; + break; + } + QByteArray token = tokenizer.getDatum(); + if (token == "g") { + if (sawG) { + // we've encountered the beginning of the next group. + tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); + break; + } + sawG = true; + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + QByteArray groupName = tokenizer.getDatum(); + meshPart.materialID = groupName; + meshHasData = true; + } else if (token == "v") { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float x = std::stof(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float y = std::stof(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float z = std::stof(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + + // float w = 1.0; + try{ + // w = + std::stof(tokenizer.getDatum().data()); + } + catch(const std::exception& e){ + // next token wasn't a number (the w field is optional), push it back + tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); + } + + mesh.vertices.append(glm::vec3(x, y, z)); + meshHasData = true; + } else if (token == "f") { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + int p0 = std::stoi(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + int p1 = std::stoi(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + int p2 = std::stoi(tokenizer.getDatum().data()); + + // obj indexes is 1 based and index over the entire file. mesh indexes are 0 based + // and index within the mesh. + meshPart.triangleIndices.append(p0 - 1 - indexStart); // obj index is 1 based + meshPart.triangleIndices.append(p1 - 1 - indexStart); + meshPart.triangleIndices.append(p2 - 1 - indexStart); + meshHasData = true; + } else { + // something we don't (yet) care about + qDebug() << "skipping line with" << token; + tokenizer.skipLine(); + } + } + } + catch(const std::exception& e) { + // something went wrong, stop here. + qDebug() << "something went wrong"; + return false; + } + + if (meshHasData) { + mesh.parts.append(meshPart); + geometry.meshes.append(mesh); + } + + indexStart += mesh.vertices.count(); + + return result; +} + + + +FBXGeometry extractOBJGeometry(const FBXNode& node, const QVariantHash& mapping) { + FBXGeometry geometry; + return geometry; +} + + + +FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping) { + QBuffer buffer(const_cast(&model)); + buffer.open(QIODevice::ReadOnly); + return readOBJ(&buffer, mapping); +} + + +FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { + FBXGeometry geometry; + OBJTokenizer tokenizer(device); + int indexStart = 0; + + while (true) { + if (!parseOBJMesh(tokenizer, mapping, geometry, indexStart)) { + break; + } + } + + return geometry; +} diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h new file mode 100644 index 0000000000..2ff55a9a61 --- /dev/null +++ b/libraries/fbx/src/OBJReader.h @@ -0,0 +1,6 @@ + + +#include "FBXReader.h" + +FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping); +FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 9ecdfa43e1..1b773f2bf9 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -2101,6 +2101,8 @@ void GeometryReader::run() { lightmapLevel = 3.5f; } fbxgeo = readFBX(_reply, _mapping, grabLightmaps, lightmapLevel); + } else if (_url.path().toLower().endsWith(".obj")) { + fbxgeo = readOBJ(_reply, _mapping); } QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo)); } else { diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 92b6d44b6c..ba7c16bc10 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -22,6 +22,7 @@ #include #include +#include #include diff --git a/tools/vhacd/src/VHACDUtil.cpp b/tools/vhacd/src/VHACDUtil.cpp index caa213572b..4c8a9eb62d 100644 --- a/tools/vhacd/src/VHACDUtil.cpp +++ b/tools/vhacd/src/VHACDUtil.cpp @@ -13,11 +13,6 @@ #include "VHACDUtil.h" - - - - - //Read all the meshes from provided FBX file bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results) { @@ -29,14 +24,31 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re std::cout << "Reading FBX.....\n"; QByteArray fbxContents = fbx.readAll(); - FBXGeometry geometry = readFBX(fbxContents, QVariantHash()); + + + FBXGeometry geometry; + + if (filename.toLower().endsWith(".obj")) { + geometry = readOBJ(fbxContents, QVariantHash()); + } else if (filename.toLower().endsWith(".fbx")) { + geometry = readFBX(fbxContents, QVariantHash()); + } else { + qDebug() << "unknown file extension"; + return false; + } + + //results->meshCount = geometry.meshes.count(); + qDebug() << "read in" << geometry.meshes.count() << "meshes"; + int count = 0; - foreach(FBXMesh mesh, geometry.meshes){ + foreach(FBXMesh mesh, geometry.meshes) { //get vertices for each mesh QVector vertices = mesh.vertices; + qDebug() << "vertex count is" << vertices.count(); + //get the triangle indices for each mesh QVector triangles; foreach(FBXMeshPart part, mesh.parts){ @@ -45,9 +57,9 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re } //only read meshes with triangles - if (triangles.count() <= 0){ - continue; - } + if (triangles.count() <= 0){ + continue; + } results->perMeshVertices.append(vertices); results->perMeshTriangleIndices.append(triangles); count++; diff --git a/tools/vhacd/src/VHACDUtil.h b/tools/vhacd/src/VHACDUtil.h index ce1c157025..b0b9da9720 100644 --- a/tools/vhacd/src/VHACDUtil.h +++ b/tools/vhacd/src/VHACDUtil.h @@ -19,6 +19,7 @@ #include //c++11 feature #include #include +#include #include namespace vhacd { diff --git a/tools/vhacd/src/VHACDUtilApp.cpp b/tools/vhacd/src/VHACDUtilApp.cpp index d4b0f48766..6d4bf5adcb 100644 --- a/tools/vhacd/src/VHACDUtilApp.cpp +++ b/tools/vhacd/src/VHACDUtilApp.cpp @@ -32,7 +32,7 @@ QString formatFloat(double n) { } -bool writeOBJ(QString outFileName, QVector>& convexHullList, bool outputOneMesh) { +bool writeOBJ(QString outFileName, QVector>& meshList, bool outputOneMesh) { QFile file(outFileName); if (!file.open(QIODevice::WriteOnly)) { qDebug() << "Unable to write to " << outFileName; @@ -41,52 +41,32 @@ bool writeOBJ(QString outFileName, QVector>& QTextStream out(&file); + // if (meshList.size() != 1) { + // qDebug() << "unexpected number of meshes --" << meshList.size(); + // exit(1); + // } + // QVector hulls = meshList[0]; - if (convexHullList.size() != 1) { - qDebug() << "unexpected number of meshes --" << convexHullList.size(); - exit(1); - } + unsigned int pointStartOffset = 0; - QVector hulls = convexHullList[0]; - - - if (outputOneMesh) { + foreach (QVector hulls, meshList) { + unsigned int nth = 0; foreach (VHACD::IVHACD::ConvexHull hull, hulls) { + out << "g hull-" << nth++ << "\n"; for (unsigned int i = 0; i < hull.m_nPoints; i++) { out << "v "; out << formatFloat(hull.m_points[i*3]) << " "; out << formatFloat(hull.m_points[i*3+1]) << " "; out << formatFloat(hull.m_points[i*3+2]) << " 1\n"; } - } - - unsigned int pointStartOffset = 0; - foreach (VHACD::IVHACD::ConvexHull hull, hulls) { for (unsigned int i = 0; i < hull.m_nTriangles; i++) { out << "f "; out << hull.m_triangles[i*3] + 1 + pointStartOffset << " "; out << hull.m_triangles[i*3+1] + 1 + pointStartOffset << " "; out << hull.m_triangles[i*3+2] + 1 + pointStartOffset << "\n"; } - pointStartOffset += hull.m_nPoints; - } - } else { - unsigned int nth = 0; - foreach (VHACD::IVHACD::ConvexHull hull, hulls) { - out << "o hull-" << nth++ << "\n"; - for (unsigned int i = 0; i < hull.m_nPoints; i++) { - out << "v "; - out << formatFloat(hull.m_points[i*3]) << " "; - out << formatFloat(hull.m_points[i*3+1]) << " "; - out << formatFloat(hull.m_points[i*3+2]) << " 1\n"; - } - for (unsigned int i = 0; i < hull.m_nTriangles; i++) { - out << "f "; - out << hull.m_triangles[i*3] + 1 << " "; - out << hull.m_triangles[i*3+1] + 1 << " "; - out << hull.m_triangles[i*3+2] + 1 << "\n"; - } out << "\n"; + pointStartOffset += hull.m_nPoints; } } From 22d9ff278815c88afbbbff56a7b721468ea5501b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 6 Mar 2015 14:36:08 -0800 Subject: [PATCH 19/99] 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 20/99] 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 591edc052738ddaf30d83b0d213d78b18af73943 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:51:47 -0800 Subject: [PATCH 21/99] _mesh instance variable doesn't appear to be in use. --- libraries/fbx/src/FBXReader.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 6912dd730f..ecce607575 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -152,8 +152,6 @@ public: bool hasSpecularTexture() const; bool hasEmissiveTexture() const; - - model::Mesh _mesh; }; /// A single animation frame extracted from an FBX document. From 8a4339e57f2ac2688225d1aeb0ae4edae0d0336e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:52:20 -0800 Subject: [PATCH 22/99] stray control-Ms --- libraries/model/src/model/Material.h | 36 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 57e0f68a9c..2718b1dfa8 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -76,26 +76,26 @@ public: void setOpacity(float opacity); // Schema to access the attribute values of the material - class Schema { - public: - - Color _diffuse; - float _opacity; - Color _specular; - float _shininess; - Color _emissive; - float _spare0; - - Schema() : - _diffuse(0.5f), - _opacity(1.0f), - _specular(0.03f), - _shininess(0.1f), - _emissive(0.0f) - {} + class Schema { + public: + + Color _diffuse; + float _opacity; + Color _specular; + float _shininess; + Color _emissive; + float _spare0; + + Schema() : + _diffuse(0.5f), + _opacity(1.0f), + _specular(0.03f), + _shininess(0.1f), + _emissive(0.0f) + {} }; - const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; } + const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; } void setTextureView(MapChannel channel, const TextureView& texture); const TextureMap& getTextureMap() const { return _textureMap; } From 6772847d0bfb916558767805fad9ab7c61f39d23 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:52:39 -0800 Subject: [PATCH 23/99] make it so I don't have to count --- libraries/networking/src/Assignment.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/Assignment.h b/libraries/networking/src/Assignment.h index a3b810c4ac..26b38914ba 100644 --- a/libraries/networking/src/Assignment.h +++ b/libraries/networking/src/Assignment.h @@ -26,14 +26,14 @@ class Assignment : public NodeData { public: enum Type { - AudioMixerType, - AvatarMixerType, - AgentType, - UNUSED_0, - UNUSED_1, - UNUSED_2, - EntityServerType, - AllTypes + AudioMixerType = 0, + AvatarMixerType = 1, + AgentType = 2, + UNUSED_0 = 3, + UNUSED_1 = 4, + UNUSED_2 = 5, + EntityServerType = 6, + AllTypes = 7 }; enum Command { From d7c8f2224665174c4f34e51297534eab8e1c44cf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:53:04 -0800 Subject: [PATCH 24/99] stray control-Ms --- libraries/shared/src/AABox.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index d862957642..9beb0a85f2 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -72,9 +72,9 @@ public: AABox clamp(const glm::vec3& min, const glm::vec3& max) const; AABox clamp(float min, float max) const; - AABox& operator += (const glm::vec3& point); - AABox& operator += (const AABox& box); - + AABox& operator += (const glm::vec3& point); + AABox& operator += (const AABox& box); + bool isInvalid() const { return _corner == glm::vec3(std::numeric_limits::infinity()); } private: From 4a7dd2b3e6c935efa014a1818f4137a4f8232bb5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:53:25 -0800 Subject: [PATCH 25/99] allow downloading of obj files --- libraries/render-utils/src/GeometryCache.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 1b773f2bf9..b80cc04b3f 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -2084,6 +2084,7 @@ void GeometryReader::run() { urlValid &= !urlname.isEmpty(); urlValid &= !_url.path().isEmpty(); urlValid &= _url.path().toLower().endsWith(".fbx") + || _url.path().toLower().endsWith(".obj") || _url.path().toLower().endsWith(".svo"); if (urlValid) { From adfacf1e9830611c78f6c8375752b5653946420f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:53:45 -0800 Subject: [PATCH 26/99] adjust debugging prints --- tools/vhacd/src/VHACDUtil.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tools/vhacd/src/VHACDUtil.cpp b/tools/vhacd/src/VHACDUtil.cpp index 4c8a9eb62d..bc9ad09bde 100644 --- a/tools/vhacd/src/VHACDUtil.cpp +++ b/tools/vhacd/src/VHACDUtil.cpp @@ -39,16 +39,13 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re //results->meshCount = geometry.meshes.count(); - - qDebug() << "read in" << geometry.meshes.count() << "meshes"; + // qDebug() << "read in" << geometry.meshes.count() << "meshes"; int count = 0; foreach(FBXMesh mesh, geometry.meshes) { //get vertices for each mesh QVector vertices = mesh.vertices; - qDebug() << "vertex count is" << vertices.count(); - //get the triangle indices for each mesh QVector triangles; foreach(FBXMeshPart part, mesh.parts){ From d642b52de3fdbd49b3f5d5c3d6bbc1b8c3d9e40c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:54:19 -0800 Subject: [PATCH 27/99] swap y and z coords because normal obj format has 3rd value as up --- tools/vhacd/src/VHACDUtilApp.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/vhacd/src/VHACDUtilApp.cpp b/tools/vhacd/src/VHACDUtilApp.cpp index 6d4bf5adcb..66ee71840f 100644 --- a/tools/vhacd/src/VHACDUtilApp.cpp +++ b/tools/vhacd/src/VHACDUtilApp.cpp @@ -41,12 +41,6 @@ bool writeOBJ(QString outFileName, QVector>& QTextStream out(&file); - // if (meshList.size() != 1) { - // qDebug() << "unexpected number of meshes --" << meshList.size(); - // exit(1); - // } - // QVector hulls = meshList[0]; - unsigned int pointStartOffset = 0; foreach (QVector hulls, meshList) { @@ -56,8 +50,9 @@ bool writeOBJ(QString outFileName, QVector>& for (unsigned int i = 0; i < hull.m_nPoints; i++) { out << "v "; out << formatFloat(hull.m_points[i*3]) << " "; + // swap y and z because up is 3rd value in OBJ + out << formatFloat(hull.m_points[i*3+2]) << "\n"; out << formatFloat(hull.m_points[i*3+1]) << " "; - out << formatFloat(hull.m_points[i*3+2]) << " 1\n"; } for (unsigned int i = 0; i < hull.m_nTriangles; i++) { out << "f "; From f807384dfe26ef729e78ed0b480844b094f6bef4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:55:04 -0800 Subject: [PATCH 28/99] build a joint and caclulate extents. obj models now show up, though not correctly. --- libraries/fbx/src/OBJReader.cpp | 158 ++++++++++++++++++++++++++------ 1 file changed, 130 insertions(+), 28 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 1ff4f7a2ae..55fcdca89e 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -1,12 +1,15 @@ + +// http://en.wikipedia.org/wiki/Wavefront_.obj_file + + #include #include - #include "FBXReader.h" #include "OBJReader.h" - +#include "Shape.h" class OBJTokenizer { @@ -83,6 +86,22 @@ bool parseOBJMesh(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeome bool meshHasData = true; bool result = true; + + // QString materialID; + // model::MaterialPointer _material; + + meshPart.materialID = "dontknow"; + // meshPart._material = { glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(), 96.0f, 1.0f }; + meshPart._material = model::MaterialPointer(new model::Material()); + meshPart.opacity = 1.0; + + // material._material->setEmissive(material.emissive); + // material._material->setDiffuse(material.diffuse); + // material._material->setSpecular(material.specular); + // material._material->setShininess(material.shininess); + // material._material->setOpacity(material.opacity); + + try { // XXX move this out/up while (true) { if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { @@ -104,40 +123,55 @@ bool parseOBJMesh(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeome } else if (token == "v") { if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } float x = std::stof(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - float y = std::stof(tokenizer.getDatum().data()); + // notice the order of z and y -- in OBJ files, up is the 3rd value if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } float z = std::stof(tokenizer.getDatum().data()); if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float y = std::stof(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - // float w = 1.0; - try{ - // w = - std::stof(tokenizer.getDatum().data()); - } - catch(const std::exception& e){ - // next token wasn't a number (the w field is optional), push it back - tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); - } + // the spec gets vague here. might be w, might be a color... chop it off. + tokenizer.skipLine(); mesh.vertices.append(glm::vec3(x, y, z)); + mesh.colors.append(glm::vec3(1, 1, 1)); meshHasData = true; } else if (token == "f") { - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - int p0 = std::stoi(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - int p1 = std::stoi(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - int p2 = std::stoi(tokenizer.getDatum().data()); + // a face can have 3 or more vertices + QVector indices; + while (true) { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { goto done; } + try { + int vertexIndex = std::stoi(tokenizer.getDatum().data()); + // negative indexes count backward from the current end of the vertex list + vertexIndex = (vertexIndex >= 0 ? vertexIndex : mesh.vertices.count() + vertexIndex + 1); + // obj index is 1 based + vertexIndex = vertexIndex - 1 - indexStart; + assert(vertexIndex >= 0); + indices.append(vertexIndex); + } + catch(const std::exception& e) { + // wasn't a number, but it back. + tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); + break; + } + } - // obj indexes is 1 based and index over the entire file. mesh indexes are 0 based - // and index within the mesh. - meshPart.triangleIndices.append(p0 - 1 - indexStart); // obj index is 1 based - meshPart.triangleIndices.append(p1 - 1 - indexStart); - meshPart.triangleIndices.append(p2 - 1 - indexStart); + if (indices.count() == 3) { + meshPart.triangleIndices << indices; + } else if (indices.count() == 4) { + meshPart.quadIndices << indices; + } else { + qDebug() << "no support for more than 4 vertices on a face in OBJ files"; + } meshHasData = true; } else { // something we don't (yet) care about + // vp + // mtllib + // usemtl + // s 1, s off + qDebug() << "skipping line with" << token; tokenizer.skipLine(); } @@ -145,14 +179,78 @@ bool parseOBJMesh(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeome } catch(const std::exception& e) { // something went wrong, stop here. - qDebug() << "something went wrong"; + qDebug() << "something went wrong in obj reader"; return false; } - if (meshHasData) { - mesh.parts.append(meshPart); - geometry.meshes.append(mesh); + done: + +#if 0 + // add bogus normal data for this mesh + // mesh.normals.resize(mesh.vertices.count()); + mesh.normals.fill(glm::vec3(0,0,0), mesh.vertices.count()); + mesh.tangents.fill(glm::vec3(0,0,0), mesh.vertices.count()); + int triCount = meshPart.triangleIndices.count() / 3; + for (int i = 0; i < triCount; i++) { + int p0Index = meshPart.triangleIndices[ i*3 ]; + int p1Index = meshPart.triangleIndices[ i*3+1 ]; + int p2Index = meshPart.triangleIndices[ i*3+2 ]; + + glm::vec3 p0 = mesh.vertices[ p0Index ]; + glm::vec3 p1 = mesh.vertices[ p1Index ]; + glm::vec3 p2 = mesh.vertices[ p2Index ]; + + glm::vec3 n = glm::cross(p2 - p0, p1 - p0); + glm::vec3 t = glm::cross(p2 - p0, n); + + mesh.normals[ p0Index ] = n; + mesh.normals[ p1Index ] = n; + mesh.normals[ p2Index ] = n; + + mesh.tangents[ p0Index ] = t; + mesh.tangents[ p1Index ] = t; + mesh.tangents[ p2Index ] = t; } +#endif + + + if (! meshHasData) + return result; + + + mesh.meshExtents.reset(); + foreach (const glm::vec3& vertex, mesh.vertices) { + mesh.meshExtents.addPoint(vertex); + geometry.meshExtents.addPoint(vertex); + } + + mesh.parts.append(meshPart); + geometry.meshes.append(mesh); + + + geometry.joints.resize(1); + geometry.joints[ 0 ].isFree = false; + // geometry.joints[ 0 ].freeLineage; + geometry.joints[ 0 ].parentIndex = -1; + geometry.joints[ 0 ].distanceToParent = 0; + geometry.joints[ 0 ].boneRadius = 0; + geometry.joints[ 0 ].translation = glm::vec3(0, 0, 0); + // geometry.joints[ 0 ].preTransform = ; + geometry.joints[ 0 ].preRotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].rotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].postRotation = glm::quat(0, 0, 0, 1); + // geometry.joints[ 0 ].postTransform = ; + // geometry.joints[ 0 ].transform = ; + geometry.joints[ 0 ].rotationMin = glm::vec3(0, 0, 0); + geometry.joints[ 0 ].rotationMax = glm::vec3(0, 0, 0); + geometry.joints[ 0 ].inverseDefaultRotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].inverseBindRotation = glm::quat(0, 0, 0, 1); + // geometry.joints[ 0 ].bindTransform = ; + geometry.joints[ 0 ].name = "OBJ"; + geometry.joints[ 0 ].shapePosition = glm::vec3(0, 0, 0); + geometry.joints[ 0 ].shapeRotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].shapeType = SPHERE_SHAPE; + geometry.joints[ 0 ].isSkeletonJoint = false; indexStart += mesh.vertices.count(); @@ -180,10 +278,14 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { OBJTokenizer tokenizer(device); int indexStart = 0; + geometry.meshExtents.reset(); + while (true) { if (!parseOBJMesh(tokenizer, mapping, geometry, indexStart)) { break; } + + qDebug() << "indexStart is" << indexStart; } return geometry; From b96e455b72fc81db69405d77ebcf669c84e1f4a5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 11:27:27 -0800 Subject: [PATCH 29/99] uninitialized variable --- libraries/entities/src/EntitySimulation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index e7f2219c19..1eb4fdc951 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -35,7 +35,7 @@ const int DIRTY_SIMULATION_FLAGS = class EntitySimulation : public QObject { Q_OBJECT public: - EntitySimulation() : _mutex(QMutex::Recursive), _entityTree(NULL) { } + EntitySimulation() : _mutex(QMutex::Recursive), _entityTree(NULL), _nextExpiry(quint64(-1)) { } virtual ~EntitySimulation() { setEntityTree(NULL); } void lock() { _mutex.lock(); } From bb0f6b4d28cd4a5d0a2520a24e60e4c15c7405f8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 11:27:52 -0800 Subject: [PATCH 30/99] uninitialized variable --- libraries/networking/src/LimitedNodeList.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index cf5b2eef27..279d958082 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -48,7 +48,8 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short _localSockAddr(), _publicSockAddr(), _stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT), - _packetStatTimer() + _packetStatTimer(), + _thisNodeCanAdjustLocks(false) { static bool firstCall = true; if (firstCall) { From 3642e93b3f121240972c22cbdec9cd595abb17f3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 11:28:09 -0800 Subject: [PATCH 31/99] keep triangles facing outward --- tools/vhacd/src/VHACDUtilApp.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/vhacd/src/VHACDUtilApp.cpp b/tools/vhacd/src/VHACDUtilApp.cpp index 66ee71840f..bea1b48206 100644 --- a/tools/vhacd/src/VHACDUtilApp.cpp +++ b/tools/vhacd/src/VHACDUtilApp.cpp @@ -51,13 +51,14 @@ bool writeOBJ(QString outFileName, QVector>& out << "v "; out << formatFloat(hull.m_points[i*3]) << " "; // swap y and z because up is 3rd value in OBJ - out << formatFloat(hull.m_points[i*3+2]) << "\n"; - out << formatFloat(hull.m_points[i*3+1]) << " "; + out << formatFloat(hull.m_points[i*3+2]) << " "; + out << formatFloat(hull.m_points[i*3+1]) << "\n"; } for (unsigned int i = 0; i < hull.m_nTriangles; i++) { out << "f "; - out << hull.m_triangles[i*3] + 1 + pointStartOffset << " "; + // change order to flip normal (due to swapping y and z, above) out << hull.m_triangles[i*3+1] + 1 + pointStartOffset << " "; + out << hull.m_triangles[i*3] + 1 + pointStartOffset << " "; out << hull.m_triangles[i*3+2] + 1 + pointStartOffset << "\n"; } out << "\n"; From 05e0fe353677b0c9cbc474aad72196020782ed59 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 11:28:30 -0800 Subject: [PATCH 32/99] object display correctly now? --- libraries/fbx/src/OBJReader.cpp | 304 ++++++++++++++------------------ 1 file changed, 136 insertions(+), 168 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 55fcdca89e..c09cd3091b 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -2,6 +2,8 @@ // http://en.wikipedia.org/wiki/Wavefront_.obj_file +// http://www.scratchapixel.com/old/lessons/3d-advanced-lessons/obj-file-format/obj-file-format/ +// http://paulbourke.net/dataformats/obj/ #include @@ -28,6 +30,7 @@ private: int _pushedBackToken; }; + int OBJTokenizer::nextToken() { if (_pushedBackToken != -1) { int token = _pushedBackToken; @@ -78,194 +81,99 @@ int OBJTokenizer::nextToken() { } - -bool parseOBJMesh(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeometry &geometry, int& indexStart) { - FBXMesh mesh; - FBXMeshPart meshPart; +bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeometry &geometry) { + FBXMesh &mesh = geometry.meshes[0]; + mesh.parts.append(FBXMeshPart()); + FBXMeshPart &meshPart = mesh.parts.last(); bool sawG = false; - bool meshHasData = true; bool result = true; - - // QString materialID; - // model::MaterialPointer _material; - - meshPart.materialID = "dontknow"; - // meshPart._material = { glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(), 96.0f, 1.0f }; - meshPart._material = model::MaterialPointer(new model::Material()); + meshPart.materialID = QString("dontknow") + QString::number(mesh.parts.count()); meshPart.opacity = 1.0; + meshPart._material = model::MaterialPointer(new model::Material()); + meshPart._material->setDiffuse(glm::vec3(1.0, 1.0, 1.0)); + meshPart._material->setOpacity(1.0); + meshPart._material->setSpecular(glm::vec3(1.0, 1.0, 1.0)); + meshPart._material->setShininess(96.0); + meshPart._material->setEmissive(glm::vec3(0.0, 0.0, 0.0)); - // material._material->setEmissive(material.emissive); - // material._material->setDiffuse(material.diffuse); - // material._material->setSpecular(material.specular); - // material._material->setShininess(material.shininess); - // material._material->setOpacity(material.opacity); - - - try { // XXX move this out/up - while (true) { - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { - result = false; + while (true) { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + result = false; + break; + } + QByteArray token = tokenizer.getDatum(); + if (token == "g") { + if (sawG) { + // we've encountered the beginning of the next group. + tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); break; } - QByteArray token = tokenizer.getDatum(); - if (token == "g") { - if (sawG) { - // we've encountered the beginning of the next group. + sawG = true; + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + QByteArray groupName = tokenizer.getDatum(); + meshPart.materialID = groupName; + } else if (token == "v") { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float x = std::stof(tokenizer.getDatum().data()); + // notice the order of z and y -- in OBJ files, up is the 3rd value + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float z = std::stof(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float y = std::stof(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + // the spec gets vague here. might be w, might be a color... chop it off. + tokenizer.skipLine(); + mesh.vertices.append(glm::vec3(x, y, z)); + mesh.colors.append(glm::vec3(1, 1, 1)); + } else if (token == "f") { + // a face can have 3 or more vertices + QVector indices; + while (true) { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { goto done; } + try { + int vertexIndex = std::stoi(tokenizer.getDatum().data()); + // negative indexes count backward from the current end of the vertex list + vertexIndex = (vertexIndex >= 0 ? vertexIndex : mesh.vertices.count() + vertexIndex + 1); + // obj index is 1 based + assert(vertexIndex >= 1); + indices.append(vertexIndex - 1); + } + catch(const std::exception& e) { + // wasn't a number, but it back. tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); break; } - sawG = true; - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - QByteArray groupName = tokenizer.getDatum(); - meshPart.materialID = groupName; - meshHasData = true; - } else if (token == "v") { - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - float x = std::stof(tokenizer.getDatum().data()); - // notice the order of z and y -- in OBJ files, up is the 3rd value - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - float z = std::stof(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - float y = std::stof(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - - // the spec gets vague here. might be w, might be a color... chop it off. - tokenizer.skipLine(); - - mesh.vertices.append(glm::vec3(x, y, z)); - mesh.colors.append(glm::vec3(1, 1, 1)); - meshHasData = true; - } else if (token == "f") { - // a face can have 3 or more vertices - QVector indices; - while (true) { - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { goto done; } - try { - int vertexIndex = std::stoi(tokenizer.getDatum().data()); - // negative indexes count backward from the current end of the vertex list - vertexIndex = (vertexIndex >= 0 ? vertexIndex : mesh.vertices.count() + vertexIndex + 1); - // obj index is 1 based - vertexIndex = vertexIndex - 1 - indexStart; - assert(vertexIndex >= 0); - indices.append(vertexIndex); - } - catch(const std::exception& e) { - // wasn't a number, but it back. - tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); - break; - } - } - - if (indices.count() == 3) { - meshPart.triangleIndices << indices; - } else if (indices.count() == 4) { - meshPart.quadIndices << indices; - } else { - qDebug() << "no support for more than 4 vertices on a face in OBJ files"; - } - meshHasData = true; - } else { - // something we don't (yet) care about - // vp - // mtllib - // usemtl - // s 1, s off - - qDebug() << "skipping line with" << token; - tokenizer.skipLine(); } + + if (indices.count() == 3) { + // flip these around (because of the y/z swap above) so our triangles face outward + meshPart.triangleIndices.append(indices[0]); + meshPart.triangleIndices.append(indices[2]); + meshPart.triangleIndices.append(indices[1]); + } else if (indices.count() == 4) { + meshPart.quadIndices << indices; + } else { + qDebug() << "no support for more than 4 vertices on a face in OBJ files"; + } + } else { + // something we don't (yet) care about + qDebug() << "OBJ parser is skipping a line with" << token; + tokenizer.skipLine(); } } - catch(const std::exception& e) { - // something went wrong, stop here. - qDebug() << "something went wrong in obj reader"; - return false; - } done: - -#if 0 - // add bogus normal data for this mesh - // mesh.normals.resize(mesh.vertices.count()); - mesh.normals.fill(glm::vec3(0,0,0), mesh.vertices.count()); - mesh.tangents.fill(glm::vec3(0,0,0), mesh.vertices.count()); - int triCount = meshPart.triangleIndices.count() / 3; - for (int i = 0; i < triCount; i++) { - int p0Index = meshPart.triangleIndices[ i*3 ]; - int p1Index = meshPart.triangleIndices[ i*3+1 ]; - int p2Index = meshPart.triangleIndices[ i*3+2 ]; - - glm::vec3 p0 = mesh.vertices[ p0Index ]; - glm::vec3 p1 = mesh.vertices[ p1Index ]; - glm::vec3 p2 = mesh.vertices[ p2Index ]; - - glm::vec3 n = glm::cross(p2 - p0, p1 - p0); - glm::vec3 t = glm::cross(p2 - p0, n); - - mesh.normals[ p0Index ] = n; - mesh.normals[ p1Index ] = n; - mesh.normals[ p2Index ] = n; - - mesh.tangents[ p0Index ] = t; - mesh.tangents[ p1Index ] = t; - mesh.tangents[ p2Index ] = t; - } -#endif - - - if (! meshHasData) - return result; - - - mesh.meshExtents.reset(); - foreach (const glm::vec3& vertex, mesh.vertices) { - mesh.meshExtents.addPoint(vertex); - geometry.meshExtents.addPoint(vertex); - } - - mesh.parts.append(meshPart); - geometry.meshes.append(mesh); - - - geometry.joints.resize(1); - geometry.joints[ 0 ].isFree = false; - // geometry.joints[ 0 ].freeLineage; - geometry.joints[ 0 ].parentIndex = -1; - geometry.joints[ 0 ].distanceToParent = 0; - geometry.joints[ 0 ].boneRadius = 0; - geometry.joints[ 0 ].translation = glm::vec3(0, 0, 0); - // geometry.joints[ 0 ].preTransform = ; - geometry.joints[ 0 ].preRotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].rotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].postRotation = glm::quat(0, 0, 0, 1); - // geometry.joints[ 0 ].postTransform = ; - // geometry.joints[ 0 ].transform = ; - geometry.joints[ 0 ].rotationMin = glm::vec3(0, 0, 0); - geometry.joints[ 0 ].rotationMax = glm::vec3(0, 0, 0); - geometry.joints[ 0 ].inverseDefaultRotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].inverseBindRotation = glm::quat(0, 0, 0, 1); - // geometry.joints[ 0 ].bindTransform = ; - geometry.joints[ 0 ].name = "OBJ"; - geometry.joints[ 0 ].shapePosition = glm::vec3(0, 0, 0); - geometry.joints[ 0 ].shapeRotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].shapeType = SPHERE_SHAPE; - geometry.joints[ 0 ].isSkeletonJoint = false; - - indexStart += mesh.vertices.count(); - return result; } - FBXGeometry extractOBJGeometry(const FBXNode& node, const QVariantHash& mapping) { FBXGeometry geometry; return geometry; } - FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping) { QBuffer buffer(const_cast(&model)); buffer.open(QIODevice::ReadOnly); @@ -276,16 +184,76 @@ FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping) { FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { FBXGeometry geometry; OBJTokenizer tokenizer(device); - int indexStart = 0; geometry.meshExtents.reset(); + geometry.meshes.append(FBXMesh()); - while (true) { - if (!parseOBJMesh(tokenizer, mapping, geometry, indexStart)) { - break; + try { + while (parseOBJGroup(tokenizer, mapping, geometry)) { } - qDebug() << "indexStart is" << indexStart; + FBXMesh &mesh = geometry.meshes[0]; + + mesh.meshExtents.reset(); + foreach (const glm::vec3& vertex, mesh.vertices) { + mesh.meshExtents.addPoint(vertex); + geometry.meshExtents.addPoint(vertex); + } + + geometry.joints.resize(1); + geometry.joints[ 0 ].isFree = false; + // geometry.joints[ 0 ].freeLineage; + geometry.joints[ 0 ].parentIndex = -1; + geometry.joints[ 0 ].distanceToParent = 0; + geometry.joints[ 0 ].boneRadius = 0; + geometry.joints[ 0 ].translation = glm::vec3(0, 0, 0); + // geometry.joints[ 0 ].preTransform = ; + geometry.joints[ 0 ].preRotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].rotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].postRotation = glm::quat(0, 0, 0, 1); + // geometry.joints[ 0 ].postTransform = ; + // geometry.joints[ 0 ].transform = ; + geometry.joints[ 0 ].rotationMin = glm::vec3(0, 0, 0); + geometry.joints[ 0 ].rotationMax = glm::vec3(0, 0, 0); + geometry.joints[ 0 ].inverseDefaultRotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].inverseBindRotation = glm::quat(0, 0, 0, 1); + // geometry.joints[ 0 ].bindTransform = ; + geometry.joints[ 0 ].name = "OBJ"; + geometry.joints[ 0 ].shapePosition = glm::vec3(0, 0, 0); + geometry.joints[ 0 ].shapeRotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].shapeType = SPHERE_SHAPE; + geometry.joints[ 0 ].isSkeletonJoint = false; + + // add bogus normal data for this mesh + mesh.normals.fill(glm::vec3(0,0,0), mesh.vertices.count()); + mesh.tangents.fill(glm::vec3(0,0,0), mesh.vertices.count()); + + foreach (FBXMeshPart meshPart, mesh.parts) { + int triCount = meshPart.triangleIndices.count() / 3; + for (int i = 0; i < triCount; i++) { + int p0Index = meshPart.triangleIndices[ i*3 ]; + int p1Index = meshPart.triangleIndices[ i*3+1 ]; + int p2Index = meshPart.triangleIndices[ i*3+2 ]; + + glm::vec3 p0 = mesh.vertices[ p0Index ]; + glm::vec3 p1 = mesh.vertices[ p1Index ]; + glm::vec3 p2 = mesh.vertices[ p2Index ]; + + glm::vec3 n = glm::cross(p1 - p0, p2 - p0); + glm::vec3 t = glm::cross(p2 - p0, n); + + mesh.normals[ p0Index ] = n; + mesh.normals[ p1Index ] = n; + mesh.normals[ p2Index ] = n; + + mesh.tangents[ p0Index ] = t; + mesh.tangents[ p1Index ] = t; + mesh.tangents[ p2Index ] = t; + } + } + } + catch(const std::exception& e) { + qDebug() << "something went wrong in OBJ reader"; } return geometry; From 72ebae72c0f3a351ae772693a7617cf96bd76697 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:22:32 -0800 Subject: [PATCH 33/99] allow adding entities with model urls that end in .obj --- examples/editEntities.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/editEntities.js b/examples/editEntities.js index e6d4534b86..689f73eed4 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -385,7 +385,7 @@ var toolBar = (function () { } else if (browseModelsButtonDown) { var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); if (browseModelsButton === toolBar.clicked(clickedOverlay)) { - url = Window.s3Browse(".*(fbx|FBX)"); + url = Window.s3Browse(".*(fbx|FBX|obj|OBJ)"); if (url !== null && url !== "") { addModel(url); } From f6948193f1967405a10ca7ec11005e58aedc7d82 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:24:11 -0800 Subject: [PATCH 34/99] add fields for collision model url --- examples/html/entityProperties.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index fd1a4e3821..f2c7d80cfd 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -138,6 +138,7 @@ var elModelSections = document.querySelectorAll(".model-section"); var elModelURL = document.getElementById("property-model-url"); + var elCollisionModelURL = document.getElementById("property-collision-model-url"); var elModelAnimationURL = document.getElementById("property-model-animation-url"); var elModelAnimationPlaying = document.getElementById("property-model-animation-playing"); var elModelAnimationFPS = document.getElementById("property-model-animation-fps"); @@ -267,6 +268,7 @@ } elModelURL.value = properties.modelURL; + elCollisionModelURL.value = properties.collisionModelURL; elModelAnimationURL.value = properties.animationURL; elModelAnimationPlaying.checked = properties.animationIsPlaying; elModelAnimationFPS.value = properties.animationFPS; @@ -391,6 +393,7 @@ elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff')); elModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('modelURL')); + elCollisionModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionModelURL')); elModelAnimationURL.addEventListener('change', createEmitTextPropertyUpdateFunction('animationURL')); elModelAnimationPlaying.addEventListener('change', createEmitCheckedPropertyUpdateFunction('animationIsPlaying')); elModelAnimationFPS.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFPS')); @@ -622,6 +625,12 @@ +
+
Collision Model URL
+
+ +
+
Animation URL
From 1bf8054cecef9bc325390067669ac5cfa0e4410e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:24:50 -0800 Subject: [PATCH 35/99] Collision Model --- examples/libraries/ToolTip.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/libraries/ToolTip.js b/examples/libraries/ToolTip.js index f12525af57..680f617436 100644 --- a/examples/libraries/ToolTip.js +++ b/examples/libraries/ToolTip.js @@ -53,6 +53,7 @@ function Tooltip() { text += "ID: " + properties.id + "\n" if (properties.type == "Model") { text += "Model URL: " + properties.modelURL + "\n" + text += "Collision Model URL: " + properties.collisionModelURL + "\n" text += "Animation URL: " + properties.animationURL + "\n" text += "Animation is playing: " + properties.animationIsPlaying + "\n" if (properties.sittingPoints && properties.sittingPoints.length > 0) { From cdeda67942224b1f386f10cf704e61f4506549a6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:25:18 -0800 Subject: [PATCH 36/99] Collision Model url --- examples/libraries/entityPropertyDialogBox.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index 0cb76276d8..8fb7c10e5b 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -49,6 +49,8 @@ EntityPropertyDialogBox = (function () { if (properties.type == "Model") { array.push({ label: "Model URL:", value: properties.modelURL }); index++; + array.push({ label: "Collision Model URL:", value: properties.collisionModelURL }); + index++; array.push({ label: "Animation URL:", value: properties.animationURL }); index++; array.push({ label: "Animation is playing:", type: "checkbox", value: properties.animationIsPlaying }); @@ -271,6 +273,7 @@ EntityPropertyDialogBox = (function () { properties.locked = array[index++].value; if (properties.type == "Model") { properties.modelURL = array[index++].value; + properties.collisionModelURL = array[index++].value; properties.animationURL = array[index++].value; var newAnimationIsPlaying = array[index++].value; From 9ec72e4902c51cb0a42ca084eb3566632ab6c6eb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:25:46 -0800 Subject: [PATCH 37/99] quiet warning on linux --- interface/src/Application.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f3d9c09a67..53d2ccd0b2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3916,8 +3916,8 @@ void Application::takeSnapshot() { } void Application::setVSyncEnabled() { - bool vsyncOn = Menu::getInstance()->isOptionChecked(MenuOption::RenderTargetFramerateVSyncOn); #if defined(Q_OS_WIN) + bool vsyncOn = Menu::getInstance()->isOptionChecked(MenuOption::RenderTargetFramerateVSyncOn); if (wglewGetExtension("WGL_EXT_swap_control")) { wglSwapIntervalEXT(vsyncOn); int swapInterval = wglGetSwapIntervalEXT(); @@ -3940,7 +3940,6 @@ void Application::setVSyncEnabled() { #else qDebug("V-Sync is FORCED ON on this system\n"); #endif - vsyncOn = true; // Turns off unused variable warning } bool Application::isVSyncOn() const { From 630b5dd03bc9c9e940360d3c9a78044b71196903 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:27:02 -0800 Subject: [PATCH 38/99] collisionModelURL property --- libraries/entities/src/EntityItemProperties.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index e53a6ede3d..51b6f2de21 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -39,6 +39,7 @@ EntityItemProperties::EntityItemProperties() : CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT), CONSTRUCT_PROPERTY(color, ), CONSTRUCT_PROPERTY(modelURL, ""), + CONSTRUCT_PROPERTY(collisionModelURL, ""), CONSTRUCT_PROPERTY(animationURL, ""), CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS), CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX), @@ -150,6 +151,7 @@ void EntityItemProperties::debugDump() const { qDebug() << " _position=" << _position.x << "," << _position.y << "," << _position.z; qDebug() << " _dimensions=" << getDimensions(); qDebug() << " _modelURL=" << _modelURL; + qDebug() << " _collisionModelURL=" << _collisionModelURL; qDebug() << " changed properties..."; EntityPropertyFlags props = getChangedProperties(); props.debugDumpBits(); @@ -205,6 +207,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script); CHECK_PROPERTY_CHANGE(PROP_COLOR, color); CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); + CHECK_PROPERTY_CHANGE(PROP_COLLISION_MODEL_URL, collisionModelURL); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, animationIsPlaying); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex); @@ -261,6 +264,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(visible); COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(color); COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(collisionModelURL); COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL); COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying); COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS); @@ -334,6 +338,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(visible, setVisible); COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(color, setColor); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(modelURL, setModelURL); + COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(collisionModelURL, setCollisionModelURL); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(animationURL, setAnimationURL); COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(animationIsPlaying, setAnimationIsPlaying); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS); @@ -512,6 +517,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem if (properties.getType() == EntityTypes::Model) { APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, properties.getModelURL()); + APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, properties.getCollisionModelURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, properties.getAnimationURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, properties.getAnimationFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, properties.getAnimationFrameIndex()); @@ -730,6 +736,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int if (properties.getType() == EntityTypes::Model) { READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MODEL_URL, setModelURL); + READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COLLISION_MODEL_URL, setCollisionModelURL); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_URL, setAnimationURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex); @@ -796,6 +803,7 @@ void EntityItemProperties::markAllChanged() { _visibleChanged = true; _colorChanged = true; _modelURLChanged = true; + _collisionModelURLChanged = true; _animationURLChanged = true; _animationIsPlayingChanged = true; _animationFrameIndexChanged = true; From bcfd1d8a89e0c23e108f626ed7d4cbe1e3756b01 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:27:20 -0800 Subject: [PATCH 39/99] collisionModelURL property --- libraries/entities/src/EntityItemProperties.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 9bf3c93c2b..49c7cf1d08 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -93,6 +93,7 @@ enum EntityPropertyList { PROP_TEXT = PROP_MODEL_URL, PROP_LINE_HEIGHT = PROP_ANIMATION_URL, PROP_BACKGROUND_COLOR = PROP_ANIMATION_FPS, + PROP_COLLISION_MODEL_URL, }; typedef PropertyFlags EntityPropertyFlags; @@ -155,6 +156,7 @@ public: DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString); DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor); DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString); + DEFINE_PROPERTY_REF(PROP_COLLISION_MODEL_URL, CollisionModelURL, collisionModelURL, QString); DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString); DEFINE_PROPERTY(PROP_ANIMATION_FPS, AnimationFPS, animationFPS, float); DEFINE_PROPERTY(PROP_ANIMATION_FRAME_INDEX, AnimationFrameIndex, animationFrameIndex, float); @@ -275,6 +277,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, Script, script, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionModelURL, collisionModelURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFPS, animationFPS, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFrameIndex, animationFrameIndex, ""); From 58bd8a5c6502e1b3914e08bbf1e58089e7f5834b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:30:29 -0800 Subject: [PATCH 40/99] collision model url --- libraries/entities/src/ModelEntityItem.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index ed76b8c99f..026dc8af96 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -19,6 +19,7 @@ #include "ModelEntityItem.h" const QString ModelEntityItem::DEFAULT_MODEL_URL = QString(""); +const QString ModelEntityItem::DEFAULT_COLLISION_MODEL_URL = QString(""); const QString ModelEntityItem::DEFAULT_ANIMATION_URL = QString(""); const float ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f; const bool ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false; @@ -44,6 +45,7 @@ EntityItemProperties ModelEntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionModelURL, getCollisionModelURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationURL, getAnimationURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex); @@ -61,6 +63,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionModelURL, setCollisionModelURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationURL, setAnimationURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex); @@ -92,6 +95,11 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color); READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL); + if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) { + setCollisionModelURL(""); + } else { + READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL, setCollisionModelURL); + } READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL); // Because we're using AnimationLoop which will reset the frame index if you change it's running state @@ -128,6 +136,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_MODEL_URL; + requestedProperties += PROP_COLLISION_MODEL_URL; requestedProperties += PROP_ANIMATION_URL; requestedProperties += PROP_ANIMATION_FPS; requestedProperties += PROP_ANIMATION_FRAME_INDEX; @@ -151,6 +160,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, getModelURL()); + APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, getCollisionModelURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, getAnimationURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, getAnimationFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex()); @@ -258,6 +268,7 @@ void ModelEntityItem::debugDump() const { qDebug() << " position:" << getPosition() * (float)TREE_SCALE; qDebug() << " dimensions:" << getDimensions() * (float)TREE_SCALE; qDebug() << " model URL:" << getModelURL(); + qDebug() << " collision model URL:" << getCollisionModelURL(); } void ModelEntityItem::updateShapeType(ShapeType type) { From 96d94e1b0973ef5e587cd01ae0333892814990e4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:31:04 -0800 Subject: [PATCH 41/99] collision model url --- libraries/entities/src/ModelEntityItem.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 94d262fc9f..081cb429ed 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -57,10 +57,14 @@ public: const rgbColor& getColor() const { return _color; } xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } bool hasModel() const { return !_modelURL.isEmpty(); } + bool hasCollisionModel() const { return !_collisionModelURL.isEmpty(); } static const QString DEFAULT_MODEL_URL; const QString& getModelURL() const { return _modelURL; } + static const QString DEFAULT_COLLISION_MODEL_URL; + const QString& getCollisionModelURL() const { return _collisionModelURL; } + bool hasAnimation() const { return !_animationURL.isEmpty(); } static const QString DEFAULT_ANIMATION_URL; const QString& getAnimationURL() const { return _animationURL; } @@ -74,6 +78,7 @@ public: // model related properties void setModelURL(const QString& url) { _modelURL = url; } + void setCollisionModelURL(const QString& url) { _collisionModelURL = url; } void setAnimationURL(const QString& url); static const float DEFAULT_ANIMATION_FRAME_INDEX; void setAnimationFrameIndex(float value); @@ -121,6 +126,7 @@ protected: rgbColor _color; QString _modelURL; + QString _collisionModelURL; quint64 _lastAnimated; QString _animationURL; From 804d4a096336895e4c505284cc0c0bcefadd9587 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:31:37 -0800 Subject: [PATCH 42/99] coding standard --- libraries/fbx/src/OBJReader.cpp | 81 ++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index c09cd3091b..6020bc861b 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -1,6 +1,13 @@ - - - +// +// EntityItemProperties.h +// libraries/entities/src +// +// Created by Seth Alves on 3/7/15. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// // http://en.wikipedia.org/wiki/Wavefront_.obj_file // http://www.scratchapixel.com/old/lessons/3d-advanced-lessons/obj-file-format/obj-file-format/ // http://paulbourke.net/dataformats/obj/ @@ -201,28 +208,28 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { } geometry.joints.resize(1); - geometry.joints[ 0 ].isFree = false; - // geometry.joints[ 0 ].freeLineage; - geometry.joints[ 0 ].parentIndex = -1; - geometry.joints[ 0 ].distanceToParent = 0; - geometry.joints[ 0 ].boneRadius = 0; - geometry.joints[ 0 ].translation = glm::vec3(0, 0, 0); - // geometry.joints[ 0 ].preTransform = ; - geometry.joints[ 0 ].preRotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].rotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].postRotation = glm::quat(0, 0, 0, 1); - // geometry.joints[ 0 ].postTransform = ; - // geometry.joints[ 0 ].transform = ; - geometry.joints[ 0 ].rotationMin = glm::vec3(0, 0, 0); - geometry.joints[ 0 ].rotationMax = glm::vec3(0, 0, 0); - geometry.joints[ 0 ].inverseDefaultRotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].inverseBindRotation = glm::quat(0, 0, 0, 1); - // geometry.joints[ 0 ].bindTransform = ; - geometry.joints[ 0 ].name = "OBJ"; - geometry.joints[ 0 ].shapePosition = glm::vec3(0, 0, 0); - geometry.joints[ 0 ].shapeRotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].shapeType = SPHERE_SHAPE; - geometry.joints[ 0 ].isSkeletonJoint = false; + geometry.joints[0].isFree = false; + // geometry.joints[0].freeLineage; + geometry.joints[0].parentIndex = -1; + geometry.joints[0].distanceToParent = 0; + geometry.joints[0].boneRadius = 0; + geometry.joints[0].translation = glm::vec3(0, 0, 0); + // geometry.joints[0].preTransform = ; + geometry.joints[0].preRotation = glm::quat(0, 0, 0, 1); + geometry.joints[0].rotation = glm::quat(0, 0, 0, 1); + geometry.joints[0].postRotation = glm::quat(0, 0, 0, 1); + // geometry.joints[0].postTransform = ; + // geometry.joints[0].transform = ; + geometry.joints[0].rotationMin = glm::vec3(0, 0, 0); + geometry.joints[0].rotationMax = glm::vec3(0, 0, 0); + geometry.joints[0].inverseDefaultRotation = glm::quat(0, 0, 0, 1); + geometry.joints[0].inverseBindRotation = glm::quat(0, 0, 0, 1); + // geometry.joints[0].bindTransform = ; + geometry.joints[0].name = "OBJ"; + geometry.joints[0].shapePosition = glm::vec3(0, 0, 0); + geometry.joints[0].shapeRotation = glm::quat(0, 0, 0, 1); + geometry.joints[0].shapeType = SPHERE_SHAPE; + geometry.joints[0].isSkeletonJoint = false; // add bogus normal data for this mesh mesh.normals.fill(glm::vec3(0,0,0), mesh.vertices.count()); @@ -231,24 +238,24 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { foreach (FBXMeshPart meshPart, mesh.parts) { int triCount = meshPart.triangleIndices.count() / 3; for (int i = 0; i < triCount; i++) { - int p0Index = meshPart.triangleIndices[ i*3 ]; - int p1Index = meshPart.triangleIndices[ i*3+1 ]; - int p2Index = meshPart.triangleIndices[ i*3+2 ]; + int p0Index = meshPart.triangleIndices[i*3]; + int p1Index = meshPart.triangleIndices[i*3+1]; + int p2Index = meshPart.triangleIndices[i*3+2]; - glm::vec3 p0 = mesh.vertices[ p0Index ]; - glm::vec3 p1 = mesh.vertices[ p1Index ]; - glm::vec3 p2 = mesh.vertices[ p2Index ]; + glm::vec3 p0 = mesh.vertices[p0Index]; + glm::vec3 p1 = mesh.vertices[p1Index]; + glm::vec3 p2 = mesh.vertices[p2Index]; glm::vec3 n = glm::cross(p1 - p0, p2 - p0); glm::vec3 t = glm::cross(p2 - p0, n); - mesh.normals[ p0Index ] = n; - mesh.normals[ p1Index ] = n; - mesh.normals[ p2Index ] = n; + mesh.normals[p0Index] = n; + mesh.normals[p1Index] = n; + mesh.normals[p2Index] = n; - mesh.tangents[ p0Index ] = t; - mesh.tangents[ p1Index ] = t; - mesh.tangents[ p2Index ] = t; + mesh.tangents[p0Index] = t; + mesh.tangents[p1Index] = t; + mesh.tangents[p2Index] = t; } } } From b8cdf1a31836f025d015a46c59c8dbd74be32bc2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:31:53 -0800 Subject: [PATCH 43/99] quiet warning --- libraries/networking/src/LimitedNodeList.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 85db739cda..afbdf23fba 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -216,7 +216,6 @@ protected: void handleNodeKill(const SharedNodePointer& node); QUuid _sessionUUID; - bool _thisNodeCanAdjustLocks; NodeHash _nodeHash; QReadWriteLock _nodeMutex; QUdpSocket _nodeSocket; @@ -230,6 +229,7 @@ protected: int _numCollectedBytes; QElapsedTimer _packetStatTimer; + bool _thisNodeCanAdjustLocks; template void eachNodeHashIterator(IteratorLambda functor) { From d713d5596ffcadffb6dfd64687362ed5be2df08d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:32:28 -0800 Subject: [PATCH 44/99] bump entity-data message version number --- libraries/networking/src/PacketHeaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index c9add10e5f..a14191bf09 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -74,7 +74,7 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES; + return VERSION_ENTITIES_HAS_COLLISION_MODEL; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: From 1a1863679d22dee0ab94f8f1bf31b5b4ca9b7188 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:32:41 -0800 Subject: [PATCH 45/99] bump entity-data message version number --- libraries/networking/src/PacketHeaders.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index c89127058f..0b969182b0 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -130,5 +130,6 @@ const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7; const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE = 8; const PacketVersion VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES = 9; const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; +const PacketVersion VERSION_ENTITIES_HAS_COLLISION_MODEL = 10; #endif // hifi_PacketHeaders_h From e4baaa38b4f82af0f8e8ff5a5506345ef8b41001 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:33:00 -0800 Subject: [PATCH 46/99] collision model url --- tests/octree/src/OctreeTests.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp index 4fc543d5d3..705a50aa10 100644 --- a/tests/octree/src/OctreeTests.cpp +++ b/tests/octree/src/OctreeTests.cpp @@ -32,6 +32,7 @@ enum ExamplePropertyList { EXAMPLE_PROP_POSITION, EXAMPLE_PROP_RADIUS, EXAMPLE_PROP_MODEL_URL, + EXAMPLE_PROP_COLLISION_MODEL_URL, EXAMPLE_PROP_ROTATION, EXAMPLE_PROP_COLOR, EXAMPLE_PROP_SCRIPT, @@ -73,6 +74,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) { props.setHasProperty(PROP_POSITION); props.setHasProperty(PROP_RADIUS); props.setHasProperty(PROP_MODEL_URL); + props.setHasProperty(PROP_COLLISION_MODEL_URL); props.setHasProperty(PROP_ROTATION); QByteArray encoded = props.encode(); From b2cfed8bcad7678e3028e0cd356d28e2913fcabf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 8 Mar 2015 09:04:00 -0700 Subject: [PATCH 47/99] removed unused blob of code --- libraries/physics/src/PhysicsEngine.cpp | 42 ------------------------- 1 file changed, 42 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 625afca683..501b39428a 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -364,48 +364,6 @@ void PhysicsEngine::computeCollisionEvents() { } } } - - -#if 0 - // avatar collisions - btManifoldArray manifoldArray; - btBroadphasePairArray& pairArray = _avatarGhostObject->getOverlappingPairCache()->getOverlappingPairArray(); - int numPairs = pairArray.size(); - - for (int i = 0; i < numPairs; i++) { - manifoldArray.clear(); - const btBroadphasePair& pair = pairArray[i]; - // unless we manually perform collision detection on this pair, the contacts are in the dynamics world paircache: - btBroadphasePair* collisionPair = _dynamicsWorld->getPairCache()->findPair(pair.m_pProxy0, pair.m_pProxy1); - if (!collisionPair) { - continue; - } - if (collisionPair->m_algorithm) { - collisionPair->m_algorithm->getAllContactManifolds(manifoldArray); - } - - for (int j=0;jgetBody0() == _avatarGhostObject ? btScalar(-1.0) : btScalar(1.0); - for (int p=0; pgetNumContacts(); p++) { - const btManifoldPoint& pt = manifold->getContactPoint(p); - if (pt.getDistance() < 0.f) { - - - const btVector3& ptA = pt.getPositionWorldOnA(); - const btVector3& ptB = pt.getPositionWorldOnB(); - const btVector3& normalOnB = pt.m_normalWorldOnB; - /// work here - qDebug() << "HERE"; - } - } - } - } -#endif - - - - // We harvest collision callbacks every few frames, which contributes the following effects: // From 23a6326aa175e696e1b8f611dcd99e9e66a11499 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sun, 8 Mar 2015 10:53:29 -0700 Subject: [PATCH 48/99] 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 a180eadc91667aaa926e7ea4fd3fef60a3150b02 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 8 Mar 2015 18:07:07 -0700 Subject: [PATCH 49/99] remove stray control-Ms --- libraries/render-utils/src/Model.cpp | 228 +++++++++++++-------------- 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index bbb4dfe8cf..83d98fa9b1 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -198,51 +198,51 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, boo locations.emissiveTextureUnit = -1; } - // bindable uniform version -#if defined(Q_OS_MAC) - loc = program.uniformLocation("materialBuffer"); - if (loc >= 0) { - locations.materialBufferUnit = loc; - } else { - locations.materialBufferUnit = -1; - } -#elif defined(Q_OS_WIN) - loc = glGetUniformBlockIndex(program.programId(), "materialBuffer"); - if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, 1); - locations.materialBufferUnit = 1; - } else { - locations.materialBufferUnit = -1; - } -#else - loc = program.uniformLocation("materialBuffer"); - if (loc >= 0) { - locations.materialBufferUnit = loc; - } else { - locations.materialBufferUnit = -1; - } -#endif - -#if defined(Q_OS_WIN) - loc = glGetUniformBlockIndex(program.programId(), "transformObjectBuffer"); - if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_OBJECT_SLOT); - // locations.materialBufferUnit = 1; - } -#endif - -#if defined(Q_OS_WIN) - loc = glGetUniformBlockIndex(program.programId(), "transformCameraBuffer"); - if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_CAMERA_SLOT); - // locations.materialBufferUnit = 1; - } -#endif - + // bindable uniform version +#if defined(Q_OS_MAC) + loc = program.uniformLocation("materialBuffer"); + if (loc >= 0) { + locations.materialBufferUnit = loc; + } else { + locations.materialBufferUnit = -1; + } +#elif defined(Q_OS_WIN) + loc = glGetUniformBlockIndex(program.programId(), "materialBuffer"); + if (loc >= 0) { + glUniformBlockBinding(program.programId(), loc, 1); + locations.materialBufferUnit = 1; + } else { + locations.materialBufferUnit = -1; + } +#else + loc = program.uniformLocation("materialBuffer"); + if (loc >= 0) { + locations.materialBufferUnit = loc; + } else { + locations.materialBufferUnit = -1; + } +#endif + +#if defined(Q_OS_WIN) + loc = glGetUniformBlockIndex(program.programId(), "transformObjectBuffer"); + if (loc >= 0) { + glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_OBJECT_SLOT); + // locations.materialBufferUnit = 1; + } +#endif + +#if defined(Q_OS_WIN) + loc = glGetUniformBlockIndex(program.programId(), "transformCameraBuffer"); + if (loc >= 0) { + glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_CAMERA_SLOT); + // locations.materialBufferUnit = 1; + } +#endif + //program.link(); - if (!program.isLinked()) { - program.release(); - } + if (!program.isLinked()) { + program.release(); + } program.release(); } @@ -303,70 +303,70 @@ void Model::init() { _program.addShaderFromSourceCode(QGLShader::Fragment, model_frag); initProgram(_program, _locations); - _normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); - _normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); - initProgram(_normalMapProgram, _normalMapLocations); - - _specularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _specularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); - initProgram(_specularMapProgram, _specularMapLocations); - - _normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); - _normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); - initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations); - - _translucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _translucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); - initProgram(_translucentProgram, _translucentLocations); - - // Lightmap - _lightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); - _lightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag); - initProgram(_lightmapProgram, _lightmapLocations); - - _lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); - _lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag); - initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations); - - _lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); - _lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag); - initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations); - - _lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); - _lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag); - initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations); - // end lightmap - - - _shadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert); - _shadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); - // Shadow program uses the same locations as standard rendering path but we still need to set the bindings - Model::Locations tempLoc; - initProgram(_shadowProgram, tempLoc); - - _skinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); - _skinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag); - initSkinProgram(_skinProgram, _skinLocations); - - _skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); - _skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); - initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); - - _skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); - initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations); - - _skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); - _skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); - initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations); - - _skinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert); - _skinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); - initSkinProgram(_skinShadowProgram, _skinShadowLocations); - - - _skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); - _skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); + _normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); + _normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); + initProgram(_normalMapProgram, _normalMapLocations); + + _specularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); + _specularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); + initProgram(_specularMapProgram, _specularMapLocations); + + _normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); + _normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); + initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations); + + _translucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); + _translucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); + initProgram(_translucentProgram, _translucentLocations); + + // Lightmap + _lightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); + _lightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag); + initProgram(_lightmapProgram, _lightmapLocations); + + _lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); + _lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag); + initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations); + + _lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); + _lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag); + initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations); + + _lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); + _lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag); + initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations); + // end lightmap + + + _shadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert); + _shadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); + // Shadow program uses the same locations as standard rendering path but we still need to set the bindings + Model::Locations tempLoc; + initProgram(_shadowProgram, tempLoc); + + _skinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); + _skinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag); + initSkinProgram(_skinProgram, _skinLocations); + + _skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); + _skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); + initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); + + _skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); + _skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); + initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations); + + _skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); + _skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); + initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations); + + _skinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert); + _skinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); + initSkinProgram(_skinShadowProgram, _skinShadowLocations); + + + _skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); + _skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations); } } @@ -2470,16 +2470,16 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod qDebug() << "part INDEX:" << j; qDebug() << "NEW part.materialID:" << part.materialID; } - - if (locations->glowIntensity >= 0) { - GLBATCH(glUniform1f)(locations->glowIntensity, glowEffect->getIntensity()); + + if (locations->glowIntensity >= 0) { + GLBATCH(glUniform1f)(locations->glowIntensity, glowEffect->getIntensity()); } if (!(translucent && alphaThreshold == 0.0f)) { GLBATCH(glAlphaFunc)(GL_EQUAL, glowEffect->getIntensity()); } - - if (locations->materialBufferUnit >= 0) { - batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer()); + + if (locations->materialBufferUnit >= 0) { + batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer()); } Texture* diffuseMap = networkPart.diffuseTexture.data(); From 3604fd639afb87c729d09f2a4b06237efa12bdf8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 8 Mar 2015 20:03:10 -0700 Subject: [PATCH 50/99] formatting --- interface/src/Application.cpp | 1 - interface/src/avatar/MyAvatar.cpp | 6 ++---- interface/src/avatar/MyAvatar.h | 2 -- libraries/avatars/src/AvatarData.h | 2 +- libraries/fbx/src/OBJReader.cpp | 4 ++-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e4501eac0e..23654e7745 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1817,7 +1817,6 @@ void Application::init() { auto entityScriptingInterface = DependencyManager::get(); - connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity, entityScriptingInterface.data(), &EntityScriptingInterface::entityCollisionWithEntity); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5fb0b9dc5f..82aa4e8177 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -91,7 +91,8 @@ MyAvatar::MyAvatar() : _physicsSimulation(), _feetTouchFloor(true), _isLookingAtLeftEye(true), - _realWorldFieldOfView("realWorldFieldOfView", DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES) + _realWorldFieldOfView("realWorldFieldOfView", + DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES) { ShapeCollider::initDispatchTable(); for (int i = 0; i < MAX_DRIVE_KEYS; i++) { @@ -1400,7 +1401,6 @@ void MyAvatar::updatePosition(float deltaTime) { measureMotionDerivatives(deltaTime); } - void MyAvatar::updatePositionWithPhysics(float deltaTime) { // rotate velocity into camera frame glm::quat rotation = getHead()->getCameraOrientation(); @@ -1420,8 +1420,6 @@ void MyAvatar::updatePositionWithPhysics(float deltaTime) { _velocity = rotation * newLocalVelocity; } - - void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) { glm::vec3 up = getBodyUpDirection(); const float ENVIRONMENT_SURFACE_ELASTICITY = 0.0f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 6c55125b5c..7e7281f6a1 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -19,8 +19,6 @@ class ModelItemID; - - class MyAvatar : public Avatar { Q_OBJECT Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index bc0305338c..c131588fb0 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -411,7 +411,7 @@ private: AvatarData& operator= (const AvatarData&); QReadWriteLock _lock; - bool _enablePhysics = false; // XXX + bool _enablePhysics = false; }; Q_DECLARE_METATYPE(AvatarData*) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 6020bc861b..668e62bf3a 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -1,6 +1,6 @@ // -// EntityItemProperties.h -// libraries/entities/src +// OBJReader.cpp +// libraries/fbx/src/ // // Created by Seth Alves on 3/7/15. // Copyright 2013 High Fidelity, Inc. From 0833fc588b64f892f3f71cfb62cd9370e4080026 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 9 Mar 2015 06:56:35 -0700 Subject: [PATCH 51/99] coding standard --- libraries/fbx/src/FBXReader.cpp | 14 ++++++++----- libraries/fbx/src/OBJReader.cpp | 14 +++++++++---- tools/vhacd/src/VHACDUtilApp.cpp | 34 +++++++++++++++----------------- 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index cbbaae3d82..a2c217c97d 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -295,7 +295,11 @@ public: Tokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) { } - enum SpecialToken { DATUM_TOKEN = 0x100 }; + enum SpecialToken { + NO_TOKEN = -1, + NO_PUSHBACKED_TOKEN = -1, + DATUM_TOKEN = 0x100 + }; int nextToken(); const QByteArray& getDatum() const { return _datum; } @@ -311,9 +315,9 @@ private: }; int Tokenizer::nextToken() { - if (_pushedBackToken != -1) { + if (_pushedBackToken != NO_PUSHBACKED_TOKEN) { int token = _pushedBackToken; - _pushedBackToken = -1; + _pushedBackToken = NO_PUSHBACKED_TOKEN; return token; } @@ -361,7 +365,7 @@ int Tokenizer::nextToken() { return DATUM_TOKEN; } } - return -1; + return NO_TOKEN; } FBXNode parseTextFBXNode(Tokenizer& tokenizer) { @@ -378,7 +382,7 @@ FBXNode parseTextFBXNode(Tokenizer& tokenizer) { int token; bool expectingDatum = true; - while ((token = tokenizer.nextToken()) != -1) { + while ((token = tokenizer.nextToken()) != Tokenizer::NO_TOKEN) { if (token == '{') { for (FBXNode child = parseTextFBXNode(tokenizer); !child.name.isNull(); child = parseTextFBXNode(tokenizer)) { node.children.append(child); diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 668e62bf3a..194aaa4ac0 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -24,7 +24,11 @@ class OBJTokenizer { public: OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) { } - enum SpecialToken { DATUM_TOKEN = 0x100 }; + enum SpecialToken { + NO_TOKEN = -1, + NO_PUSHBACKED_TOKEN = -1, + DATUM_TOKEN = 0x100 + }; int nextToken(); const QByteArray& getDatum() const { return _datum; } void skipLine() { _device->readLine(); } @@ -39,9 +43,9 @@ private: int OBJTokenizer::nextToken() { - if (_pushedBackToken != -1) { + if (_pushedBackToken != NO_PUSHBACKED_TOKEN) { int token = _pushedBackToken; - _pushedBackToken = -1; + _pushedBackToken = NO_PUSHBACKED_TOKEN; return token; } @@ -84,7 +88,7 @@ int OBJTokenizer::nextToken() { return DATUM_TOKEN; } } - return -1; + return NO_TOKEN; } @@ -196,6 +200,8 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { geometry.meshes.append(FBXMesh()); try { + // call parseOBJGroup as long as it's returning true. Each successful call will + // add a new meshPart to the geometry's single mesh. while (parseOBJGroup(tokenizer, mapping, geometry)) { } diff --git a/tools/vhacd/src/VHACDUtilApp.cpp b/tools/vhacd/src/VHACDUtilApp.cpp index bea1b48206..958a91dbfe 100644 --- a/tools/vhacd/src/VHACDUtilApp.cpp +++ b/tools/vhacd/src/VHACDUtilApp.cpp @@ -143,25 +143,23 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) : //set parameters for V-HACD params.m_callback = &pCallBack; //progress callback - params.m_resolution = 100000; // 100000 - params.m_depth = 20; // 20 - params.m_concavity = 0.001; // 0.001 - params.m_delta = 0.01; // 0.05 - params.m_planeDownsampling = 4; // 4 - params.m_convexhullDownsampling = 4; // 4 - params.m_alpha = 0.05; // 0.05 // controls the bias toward clipping along symmetry planes - params.m_beta = 0.05; // 0.05 - params.m_gamma = 0.0005; // 0.0005 - params.m_pca = 0; // 0 enable/disable normalizing the mesh before applying the convex decomposition - params.m_mode = 0; // 0: voxel-based (recommended), 1: tetrahedron-based - params.m_maxNumVerticesPerCH = 64; // 64 - params.m_minVolumePerCH = 0.00001; // 0.0001 - params.m_callback = 0; // 0 - params.m_logger = 0; // 0 + params.m_resolution = 100000; // 100000 + params.m_depth = 20; // 20 + params.m_concavity = 0.001; // 0.001 + params.m_delta = 0.01; // 0.05 + params.m_planeDownsampling = 4; // 4 + params.m_convexhullDownsampling = 4; // 4 + params.m_alpha = 0.05; // 0.05 // controls the bias toward clipping along symmetry planes + params.m_beta = 0.05; // 0.05 + params.m_gamma = 0.0005; // 0.0005 + params.m_pca = 0; // 0 enable/disable normalizing the mesh before applying the convex decomposition + params.m_mode = 0; // 0: voxel-based (recommended), 1: tetrahedron-based + params.m_maxNumVerticesPerCH = 64; // 64 + params.m_minVolumePerCH = 0.00001; // 0.0001 + params.m_callback = 0; // 0 + params.m_logger = 0; // 0 params.m_convexhullApproximation = true; // true - params.m_oclAcceleration = true; // true - - + params.m_oclAcceleration = true; // true // load the mesh From cc85f468d6268cff98cd2741670bde7696b82f1e Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 9 Mar 2015 11:14:42 -0700 Subject: [PATCH 52/99] 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 ab8784f1b497b9eeb8521f1b422e85a94ef5b72f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 9 Mar 2015 13:51:08 -0700 Subject: [PATCH 53/99] add comment about character capsule being hard-coded --- libraries/fbx/src/OBJReader.cpp | 26 +++++++++++++++++++------ libraries/physics/src/PhysicsEngine.cpp | 1 + 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 194aaa4ac0..4f0f1246d2 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -121,18 +121,28 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeom break; } sawG = true; - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + break; + } QByteArray groupName = tokenizer.getDatum(); meshPart.materialID = groupName; } else if (token == "v") { - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + break; + } float x = std::stof(tokenizer.getDatum().data()); // notice the order of z and y -- in OBJ files, up is the 3rd value - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + break; + } float z = std::stof(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + break; + } float y = std::stof(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + break; + } // the spec gets vague here. might be w, might be a color... chop it off. tokenizer.skipLine(); mesh.vertices.append(glm::vec3(x, y, z)); @@ -199,10 +209,14 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { geometry.meshExtents.reset(); geometry.meshes.append(FBXMesh()); + + try { // call parseOBJGroup as long as it's returning true. Each successful call will // add a new meshPart to the geometry's single mesh. - while (parseOBJGroup(tokenizer, mapping, geometry)) { + bool success = true; + while (success) { + success = parseOBJGroup(tokenizer, mapping, geometry); } FBXMesh &mesh = geometry.meshes[0]; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 501b39428a..6c5ac4b275 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -608,6 +608,7 @@ void PhysicsEngine::setAvatarData(AvatarData *avatarData) { _avatarGhostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), glmToBullet(_avatarData->getPosition()))); + // XXX these values should be computed from the character model. btScalar characterHeight = 1.75; btScalar characterWidth = 1.75; btScalar stepHeight = btScalar(0.35); From c947f3b62c096e690da161ef72c00fc136e68e2e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 9 Mar 2015 14:06:59 -0700 Subject: [PATCH 54/99] use meters in wire-protocol for versions greater than VERSION_ENTITIES_USE_METERS_AND_RADIANS --- libraries/entities/src/EntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 093f8cf84c..4f74438a45 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -501,7 +501,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef EntityPropertyFlags propertyFlags = encodedPropertyFlags; dataAt += propertyFlags.getEncodedLength(); bytesRead += propertyFlags.getEncodedLength(); - bool useMeters = (args.bitstreamVersion == VERSION_ENTITIES_USE_METERS_AND_RADIANS); + bool useMeters = (args.bitstreamVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS); if (useMeters) { READ_ENTITY_PROPERTY_SETTER(PROP_POSITION, glm::vec3, updatePosition); } else { From ee5409b0a8c4a9e8e6d4d7b89872ed6a90ddec6a Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 9 Mar 2015 14:25:59 -0700 Subject: [PATCH 55/99] 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 2a5d25e01007e63833612eefbbb4a8f11e4edc20 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 9 Mar 2015 16:02:07 -0700 Subject: [PATCH 56/99] more hacking on mixamo pipeline files --- interface/src/ModelUploader.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp index f1c5def149..4093b3e610 100644 --- a/interface/src/ModelUploader.cpp +++ b/interface/src/ModelUploader.cpp @@ -332,8 +332,7 @@ void ModelUploader::populateBasicMapping(QVariantHash& mapping, QString filename // mixamo blendshapes - in the event that a mixamo file was edited by some other tool, it's likely the applicationName will // be rewritten, so we detect the existence of several different blendshapes which indicate we're likely a mixamo file bool likelyMixamoFile = geometry.applicationName == "mixamo.com" || - (geometry.blendshapeChannelNames.contains("Facial_Blends") && - geometry.blendshapeChannelNames.contains("BrowsDown_Right") && + (geometry.blendshapeChannelNames.contains("BrowsDown_Right") && geometry.blendshapeChannelNames.contains("MouthOpen") && geometry.blendshapeChannelNames.contains("Blink_Left") && geometry.blendshapeChannelNames.contains("Blink_Right") && From 2f22c0cd962b3193e92d59a75b341e7dad1f112f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Mar 2015 16:28:01 -0700 Subject: [PATCH 57/99] 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 58/99] 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 59/99] 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 60/99] 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 61/99] 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 62/99] 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 63/99] 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 64/99] 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 3c05d685d726dccb9e64580e8ca542fb2bcc5a25 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 9 Mar 2015 17:37:34 -0700 Subject: [PATCH 65/99] avoid assert for zero-length character velocity --- libraries/physics/src/PhysicsEngine.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 6c5ac4b275..bd477a1c3c 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -290,8 +290,15 @@ void PhysicsEngine::stepSimulation() { if (_avatarData->isPhysicsEnabled()) { _avatarGhostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), glmToBullet(_avatarData->getPosition()))); - // _characterController->setWalkDirection(glmToBullet(_avatarData->getVelocity())); - _characterController->setVelocityForTimeInterval(glmToBullet(_avatarData->getVelocity()), timeStep); + // WORKAROUND: there is a bug in the debug Bullet-2.82 libs where a zero length walk velocity will trigger + // an assert when the getNormalizedVector() helper function in btKinematicCharacterController.cpp tries to + // first normalize a vector before checking its length. Here we workaround the problem by checking the + // length first. NOTE: the character's velocity is reset to zero after each step, so when we DON'T set + // the velocity for this time interval it is the same thing as setting its velocity to zero. + btVector3 walkVelocity = glmToBullet(_avatarData->getVelocity()); + if (walkVelocity.length2() > FLT_EPSILON * FLT_EPSILON) { + _characterController->setVelocityForTimeInterval(walkVelocity, timeStep); + } } // This is step (2). From fd76eda383c45ea5590b125ee845c596b8be626e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 9 Mar 2015 17:59:45 -0700 Subject: [PATCH 66/99] slightly better hardcoded size for avatar capsule we'll be measuring avatar dimensions more correctly soon --- libraries/physics/src/PhysicsEngine.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index bd477a1c3c..66f8afb226 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -616,11 +616,11 @@ void PhysicsEngine::setAvatarData(AvatarData *avatarData) { glmToBullet(_avatarData->getPosition()))); // XXX these values should be computed from the character model. - btScalar characterHeight = 1.75; - btScalar characterWidth = 1.75; + btScalar characterRadius = 0.3; + btScalar characterHeight = 1.75 - 2.0f * characterRadius; btScalar stepHeight = btScalar(0.35); - btConvexShape* capsule = new btCapsuleShape(characterWidth, characterHeight); + btConvexShape* capsule = new btCapsuleShape(characterRadius, characterHeight); _avatarGhostObject->setCollisionShape(capsule); _avatarGhostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); From d9c071a2a9a6ed4c471a0efa498330b942724baf Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 10 Mar 2015 00:47:27 -0700 Subject: [PATCH 67/99] 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 68/99] 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 69/99] 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 70/99] 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 71/99] 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 72/99] 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 73/99] 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 74/99] 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 75/99] 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 76/99] 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 77/99] 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 78/99] 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 79/99] 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 80/99] 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 81/99] 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 82/99] 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 83/99] 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 84/99] 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 85/99] 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 86/99] 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 87/99] 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 88/99] 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 89/99] 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 90/99] 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 91/99] 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 92/99] 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 93/99] 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 94/99] 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 95/99] 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 96/99] 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 97/99] 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 98/99] 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 99/99] 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);