From ea23d8283ff5a0c80bdb2e499bf356dab36c29e4 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 25 Jan 2017 16:02:58 -0800 Subject: [PATCH 01/72] Introducing the TextureTable in the gpu shader system --- libraries/gpu/src/gpu/TextureTable.slh | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 libraries/gpu/src/gpu/TextureTable.slh diff --git a/libraries/gpu/src/gpu/TextureTable.slh b/libraries/gpu/src/gpu/TextureTable.slh new file mode 100644 index 0000000000..1aa727c99d --- /dev/null +++ b/libraries/gpu/src/gpu/TextureTable.slh @@ -0,0 +1,29 @@ + +<@if not GPU_TEXTURE_TABLE_SLH@> +<@def GPU_TEXTURE_TABLE_SLH@> + +#ifdef GPU_TEXTURE_TABLE_BINDLESS +#define GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES 8 + +struct TextureTable { + uvec4 _textures[GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES]; +}; + +#define TextureTable(index) layout (std140) uniform gpu_textureTableBuffer##index { TextureTable _table##index; }; + +#else + +#endif + + + + +<@endif@> From 536ada39735112199080376a9e729d1c2081003a Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 25 Jan 2017 18:38:05 -0800 Subject: [PATCH 02/72] Introducing the TextureTable in the gpu shader system --- .../gpu-gl/src/gpu/gl/GLBackendShader.cpp | 15 +++- libraries/gpu/src/gpu/TextureTable.slh | 8 ++- .../render-utils/src/MaterialTextures.slh | 72 +++++++++++++++++++ 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp index 93c9b0d2ff..557591ffb6 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp @@ -50,6 +50,12 @@ static const std::string stereoVersion { #endif }; +// TextureTable specific defines +static const std::string textureTableVersion { + "#extension GL_ARB_bindless_texture : require\n#define GPU_TEXTURE_TABLE_BINDLESS\n" +}; + + // Versions specific of the shader static const std::array VERSION_DEFINES { { "", @@ -64,10 +70,15 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::Co Shader::CompilationLogs compilationLogs(GLShader::NumVersions); shader.incrementCompilationAttempt(); + bool supportTextureTableBindless = true; + for (int version = 0; version < GLShader::NumVersions; version++) { auto& shaderObject = shaderObjects[version]; - std::string shaderDefines = getBackendShaderHeader() + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version]; + std::string shaderDefines = getBackendShaderHeader() + "\n" + + (supportTextureTableBindless ? textureTableVersion : "\n") + + DOMAIN_DEFINES[shader.getType()] + "\n" + + VERSION_DEFINES[version]; if (handler) { bool retest = true; std::string currentSrc = shaderSource; @@ -89,7 +100,7 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::Co compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, compilationLogs[version].message); } - if (!compilationLogs[version].compiled) { + if (!compilationLogs[version].compiled) { qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str(); shader.setCompilationLogs(compilationLogs); return nullptr; diff --git a/libraries/gpu/src/gpu/TextureTable.slh b/libraries/gpu/src/gpu/TextureTable.slh index 1aa727c99d..7859057bdb 100644 --- a/libraries/gpu/src/gpu/TextureTable.slh +++ b/libraries/gpu/src/gpu/TextureTable.slh @@ -13,11 +13,13 @@ #ifdef GPU_TEXTURE_TABLE_BINDLESS #define GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES 8 -struct TextureTable { - uvec4 _textures[GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES]; +struct GPUTextureTable { + uvec2 _textures[GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES]; }; -#define TextureTable(index) layout (std140) uniform gpu_textureTableBuffer##index { TextureTable _table##index; }; +#define TextureTable(index, name) layout (std140) uniform gpu_textureTableBuffer { GPUTextureTable name; } + +#define tableTex(name, slot) sampler2D(name._textures[slot]) #else diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index 40709b3668..ef77954fad 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -48,6 +48,76 @@ TexMapArray getTexMapArray() { <@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion, withScattering)@> + + +<@include gpu/TextureTable.slh@> + +TextureTable(0, matTex); + + +<@if withAlbedo@> +#define albedoMap 1 +vec4 fetchAlbedoMap(vec2 uv) { + return texture(tableTex(matTex, albedoMap), uv); +} +<@endif@> + +<@if withRoughness@> +#define roughnessMap 3 +float fetchRoughnessMap(vec2 uv) { + return (texture(tableTex(matTex, roughnessMap), uv).r); +} +<@endif@> + +<@if withNormal@> +#define normalMap 4 +vec3 fetchNormalMap(vec2 uv) { + return texture(tableTex(matTex, normalMap), uv).xyz; +} +<@endif@> + +<@if withMetallic@> +#define metallicMap 2 +float fetchMetallicMap(vec2 uv) { + return (texture(tableTex(matTex, metallicMap), uv).r); +} +<@endif@> + +<@if withEmissive@> +#define emissiveMap 0 +vec3 fetchEmissiveMap(vec2 uv) { + return texture(tableTex(matTex, emissiveMap), uv).rgb; +} +<@endif@> + +<@if withOcclusion@> +#define occlusionMap 5 +float fetchOcclusionMap(vec2 uv) { + return texture(tableTex(matTex, occlusionMap), uv).r; +} +<@endif@> + +<@if withScattering@> +#define scatteringMap 7 +float fetchScatteringMap(vec2 uv) { + float scattering = texture(tableTex(matTex, scatteringMap), uv).r; // boolean scattering for now + return max(((scattering - 0.1) / 0.9), 0.0); + return texture(tableTex(matTex, scatteringMap), uv).r; // boolean scattering for now +} +<@endif@> + + + <@if withAlbedo@> uniform sampler2D albedoMap; vec4 fetchAlbedoMap(vec2 uv) { @@ -101,6 +171,8 @@ float fetchScatteringMap(vec2 uv) { return texture(scatteringMap, uv).r; // boolean scattering for now } <@endif@> +<@endif@> +!> <@endfunc@> From 03aeb7addaa865a2448edd1a361a8e90d7b0b4a4 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 26 Jan 2017 11:04:46 -0800 Subject: [PATCH 03/72] Adding the ubo slot assignment for the resource texture table --- libraries/gpu-gl/src/gpu/gl/GLBackend.h | 6 + libraries/gpu-gl/src/gpu/gl/GLShader.cpp | 444 +++++++++++++++++- libraries/gpu-gl/src/gpu/gl/GLShader.h | 11 + libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 2 +- .../src/gpu/gl45/GL45BackendTexture.cpp | 82 ++++ libraries/gpu/src/gpu/Batch.h | 5 + libraries/gpu/src/gpu/TextureTable.slh | 6 +- .../render-utils/src/MeshPartPayload.cpp | 52 +- 8 files changed, 573 insertions(+), 35 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 18916ac18c..e13bfe8166 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -98,6 +98,12 @@ public: static const int MAX_NUM_RESOURCE_TEXTURES = 16; size_t getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; } + // Texture Tables offers 2 dedicated slot (taken from the ubo slots) + static const int MAX_NUM_RESOURCE_TABLE_TEXTURES = 2; + static const int RESOURCE_TABLE_TEXTURE_SLOT_OFFSET = TRANSFORM_CAMERA_SLOT + 1; + size_t getMaxNumResourceTextureTables() const { return MAX_NUM_RESOURCE_TABLE_TEXTURES; } + + // Draw Stage virtual void do_draw(const Batch& batch, size_t paramOffset) = 0; virtual void do_drawIndexed(const Batch& batch, size_t paramOffset) = 0; diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp index 010a7c479c..9c3de94957 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp @@ -10,6 +10,447 @@ #include "GLBackend.h" +namespace gpu { + namespace gl { + + 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 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 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}, + */ + + 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_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); +#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}, + + 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); +#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} + */ + default: + return ElementResource(Element(), Resource::BUFFER); + } + + }; + + int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, + Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& textureTables, 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); + GLint location = glGetUniformLocation(glprogram, name); + const GLint INVALID_UNIFORM_LOCATION = -1; + + // Try to make sense of the gltype + auto elementResource = getFormatFromGLUniform(type); + + // The uniform as a standard var type + if (location != INVALID_UNIFORM_LOCATION) { + // Let's make sure the name doesn't contains an array element + std::string sname(name); + auto foundBracket = sname.find_first_of('['); + if (foundBracket != std::string::npos) { + // std::string arrayname = sname.substr(0, foundBracket); + + if (sname[foundBracket + 1] == '0') { + sname = sname.substr(0, foundBracket); + } else { + // skip this uniform since it's not the first element of an array + continue; + } + } + + if (elementResource._resource == Resource::BUFFER) { + uniforms.insert(Shader::Slot(sname, 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(sname)); + if (requestedBinding != slotBindings.end()) { + if (binding != (*requestedBinding)._location) { + binding = (*requestedBinding)._location; + glProgramUniform1i(glprogram, location, binding); + } + } + + textures.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); + samplers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); + } + } + } + + return uniformsCount; + } + + 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); + + struct UniformBlockInfo { + using Vector = std::vector; + const GLuint index { 0 }; + const std::string name; + GLint binding { -1 }; + GLint size { 0 }; + + static std::string getName(GLuint glprogram, GLuint i) { + static const GLint NAME_LENGTH = 256; + GLint length = 0; + GLchar nameBuffer[NAME_LENGTH]; + glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length); + glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, nameBuffer); + return std::string(nameBuffer); + } + + UniformBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) { + glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_BINDING, &binding); + glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_DATA_SIZE, &size); + } + }; + + UniformBlockInfo::Vector uniformBlocks; + uniformBlocks.reserve(buffersCount); + for (int i = 0; i < buffersCount; i++) { + uniformBlocks.push_back(UniformBlockInfo(glprogram, i)); + } + + for (auto& info : uniformBlocks) { + auto requestedBinding = slotBindings.find(info.name); + if (requestedBinding != slotBindings.end()) { + info.binding = (*requestedBinding)._location; + glUniformBlockBinding(glprogram, info.index, info.binding); + uniformBufferSlotMap[info.binding] = info.index; + } + } + + for (auto& info : uniformBlocks) { + if (slotBindings.count(info.name)) { + continue; + } + + // If the binding is 0, or the binding maps to an already used binding + if (info.binding == 0 || uniformBufferSlotMap[info.binding] != UNUSED_SLOT) { + // 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()) { + info.binding = slotIt - uniformBufferSlotMap.begin(); + glUniformBlockBinding(glprogram, info.index, info.binding); + } else { + // This should neve happen, an active ubo cannot find an available slot among the max available?! + info.binding = -1; + } + } + + uniformBufferSlotMap[info.binding] = info.index; + } + + for (auto& info : uniformBlocks) { + static const Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER); + buffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size)); + } + return buffersCount; + } + + int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, 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); + + GLint binding = glGetAttribLocation(glprogram, name); + + auto elementResource = getFormatFromGLUniform(type); + inputs.insert(Shader::Slot(name, binding, elementResource._element, -1)); + } + + return inputsCount; + } + + int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, 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; + } + + void makeProgramBindings(ShaderObject& shaderObject) { + if (!shaderObject.glprogram) { + return; + } + GLuint glprogram = shaderObject.glprogram; + GLint loc = -1; + + //Check for gpu specific attribute slotBindings + loc = glGetAttribLocation(glprogram, "inPosition"); + if (loc >= 0 && loc != gpu::Stream::POSITION) { + glBindAttribLocation(glprogram, gpu::Stream::POSITION, "inPosition"); + } + + loc = glGetAttribLocation(glprogram, "inNormal"); + if (loc >= 0 && loc != gpu::Stream::NORMAL) { + glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "inNormal"); + } + + loc = glGetAttribLocation(glprogram, "inColor"); + if (loc >= 0 && loc != gpu::Stream::COLOR) { + glBindAttribLocation(glprogram, gpu::Stream::COLOR, "inColor"); + } + + loc = glGetAttribLocation(glprogram, "inTexCoord0"); + if (loc >= 0 && loc != gpu::Stream::TEXCOORD) { + glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "inTexCoord0"); + } + + loc = glGetAttribLocation(glprogram, "inTangent"); + if (loc >= 0 && loc != gpu::Stream::TANGENT) { + glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "inTangent"); + } + + loc = glGetAttribLocation(glprogram, "inTexCoord1"); + if (loc >= 0 && loc != gpu::Stream::TEXCOORD1) { + glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD1, "inTexCoord1"); + } + + loc = glGetAttribLocation(glprogram, "inSkinClusterIndex"); + if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_INDEX) { + glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "inSkinClusterIndex"); + } + + loc = glGetAttribLocation(glprogram, "inSkinClusterWeight"); + if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_WEIGHT) { + glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "inSkinClusterWeight"); + } + + loc = glGetAttribLocation(glprogram, "_drawCallInfo"); + if (loc >= 0 && loc != gpu::Stream::DRAW_CALL_INFO) { + glBindAttribLocation(glprogram, gpu::Stream::DRAW_CALL_INFO, "_drawCallInfo"); + } + + // Link again to take into account the assigned attrib location + glLinkProgram(glprogram); + + GLint linked = 0; + glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); + if (!linked) { + qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?"; + } + + // now assign the ubo binding, then DON't relink! + + //Check for gpu specific uniform slotBindings +#ifdef GPU_SSBO_DRAW_CALL_INFO + loc = glGetProgramResourceIndex(glprogram, GL_SHADER_STORAGE_BLOCK, "transformObjectBuffer"); + if (loc >= 0) { + glShaderStorageBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT); + shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT; + } +#else + loc = glGetUniformLocation(glprogram, "transformObjectBuffer"); + if (loc >= 0) { + glProgramUniform1i(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT); + shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT; + } +#endif + + loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT); + shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT; + } + + loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable0"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET); + shaderObject.resourceTextureTableSlot0 = GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET; + } + loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable1"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET + 1); + shaderObject.resourceTextureTableSlot1 = GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET + 1; + } + (void)CHECK_GL_ERROR(); + } + } +} + + using namespace gpu; using namespace gpu::gl; @@ -73,8 +514,9 @@ bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::Bin Shader::SlotSet uniforms; Shader::SlotSet textures; + Shader::SlotSet textureTables; Shader::SlotSet samplers; - backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers); + backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, textureTables, samplers); Shader::SlotSet resourceBuffers; backend.makeResourceBufferSlots(shaderObject.glprogram, slotBindings, resourceBuffers); diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.h b/libraries/gpu-gl/src/gpu/gl/GLShader.h index 3259982e93..a5a6a6e72c 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.h +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.h @@ -17,8 +17,19 @@ struct ShaderObject { GLuint glprogram { 0 }; GLint transformCameraSlot { -1 }; GLint transformObjectSlot { -1 }; + + GLint resourceTextureTableSlot0 { -1 }; + GLint resourceTextureTableSlot1 { -1 }; }; +int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, + Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& textureTables, Shader::SlotSet& samplers); +int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers); +int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs); +int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs); +void makeProgramBindings(ShaderObject& shaderObject); + + class GLShader : public GPUObject { public: static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr); diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 1a4b63d35f..098ac11763 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -103,7 +103,7 @@ public: friend class GL45Backend; using PromoteLambda = std::function; - + const uvec4& getHandle(); protected: GL45VariableAllocationTexture(const std::weak_ptr& backend, const Texture& texture); ~GL45VariableAllocationTexture(); diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 1d415c7ca3..45900a62b6 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -212,6 +212,7 @@ void GL45Texture::syncSampler() const { glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + (void)CHECK_GL_ERROR(); } using GL45FixedAllocationTexture = GL45Backend::GL45FixedAllocationTexture; @@ -275,6 +276,10 @@ GL45StrictResourceTexture::GL45StrictResourceTexture(const std::weak_ptr& backend, const TextureTable& textureTable, const HandlesArray& handles, bool handlesComplete) + : Parent(backend, textureTable, allocate()), _stamp(textureTable.getStamp()), _handles(handles), _complete(handlesComplete) { + Backend::setGPUObject(textureTable, this); + // FIXME include these in overall buffer storage reporting + glNamedBufferStorage(_id, sizeof(uvec4) * TextureTable::COUNT, &_handles[0], 0); +} + + +GL45TextureTable::~GL45TextureTable() { + if (_id) { + auto backend = _backend.lock(); + if (backend) { + // FIXME include these in overall buffer storage reporting + backend->releaseBuffer(_id, 0); + } + } +} + + +GL45TextureTable* GL45Backend::syncGPUObject(const TextureTablePointer& textureTablePointer) { + const auto& textureTable = *textureTablePointer; + + // Find the target handles + auto textures = textureTable.getTextures(); + bool handlesComplete = true; + GL45TextureTable::HandlesArray handles{}; + for (size_t i = 0; i < textures.size(); ++i) { + auto texture = textures[i]; + if (!texture) { + continue; + } + // FIXME what if we have a non-transferrable texture here? + auto gltexture = (GL45Texture*)syncGPUObject(texture, true); + if (!gltexture) { + handlesComplete = false; + continue; + } + auto handle = gltexture->getHandle(); + memcpy(&handles[i], &handle, sizeof(handle)); + } + + // If the object hasn't been created, or the object definition is out of date, drop and re-create + GL45TextureTable* object = Backend::getGPUObject(textureTable); + + if (!object || object->_stamp != textureTable.getStamp() || !object->_complete || handles != object->_handles) { + object = new GL45TextureTable(shared_from_this(), textureTable, handles, handlesComplete); + } + + return object; +} + +void GL45Backend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) { + auto textureTable = batch._textureTables.get(batch._params[paramOffset]._uint); + auto slot = batch._params[paramOffset + 1]._uint; + GL45TextureTable* glTextureTable = syncGPUObject(textureTable); + if (glTextureTable) { + glBindBufferBase(GL_UNIFORM_BUFFER, slot + GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET, glTextureTable->_id); + } +} diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 79f08ea5cc..a57ee94747 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -30,6 +30,11 @@ class QDebug; namespace gpu { enum ReservedSlot { +#ifdef GPU_SSBO_DRAW_CALL_INFO + TRANSFORM_OBJECT_SLOT = 14, +#else + TRANSFORM_OBJECT_SLOT = 31, +#endif TRANSFORM_CAMERA_SLOT = 15, }; diff --git a/libraries/gpu/src/gpu/TextureTable.slh b/libraries/gpu/src/gpu/TextureTable.slh index 7859057bdb..d45c8f819b 100644 --- a/libraries/gpu/src/gpu/TextureTable.slh +++ b/libraries/gpu/src/gpu/TextureTable.slh @@ -14,12 +14,12 @@ #define GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES 8 struct GPUTextureTable { - uvec2 _textures[GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES]; + uvec4 _textures[GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES]; }; -#define TextureTable(index, name) layout (std140) uniform gpu_textureTableBuffer { GPUTextureTable name; } +#define TextureTable(index, name) layout (std140) uniform gpu_resourceTextureTable##index { GPUTextureTable name; } -#define tableTex(name, slot) sampler2D(name._textures[slot]) +#define tableTex(name, slot) sampler2D(name._textures[slot].xy) #else diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 9655b60a78..2428ec95aa 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -145,6 +145,17 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat } auto textureCache = DependencyManager::get(); + if (!_drawMaterialTextures) { + _drawMaterialTextures = std::make_shared(); + _drawMaterialTextures->setTexture(model::MaterialKey::ALBEDO_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::ROUGHNESS_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::NORMAL_MAP, textureCache->getBlueTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::OCCLUSION_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::SCATTERING_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture()); + } batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, _drawMaterial->getSchemaBuffer()); batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::TEXMAPARRAY, _drawMaterial->getTexMapArrayBuffer()); @@ -172,9 +183,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isAlbedoMap()) { auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::ALBEDO_MAP, itr->second->getTextureView()); } } @@ -182,11 +191,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isRoughnessMap()) { auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::ROUGHNESS_MAP, itr->second->getTextureView()); } } @@ -194,11 +199,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isNormalMap()) { auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::NORMAL_MAP, itr->second->getTextureView()); } } @@ -206,11 +207,11 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isMetallicMap()) { auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, itr->second->getTextureView()); // texcoord are assumed to be the same has albedo } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, textureCache->getBlackTexture()); } } @@ -218,11 +219,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isOcclusionMap()) { auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::OCCLUSION_MAP, itr->second->getTextureView()); } } @@ -230,11 +227,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isScatteringMap()) { auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::SCATTERING_MAP, itr->second->getTextureView()); } } @@ -243,17 +236,16 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, itr->second->getTextureView()); } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture()); } } else if (materialKey.isEmissiveMap()) { auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, itr->second->getTextureView()); } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture()); } } } From ab5355dbdd91ad8e8e0c5e2c8a803fb79819e610 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Wed, 25 Jan 2017 17:47:33 -0800 Subject: [PATCH 04/72] First pass at bindless textures --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 1 + libraries/gpu-gl/src/gpu/gl/GLBackend.h | 1 + libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 3 ++ .../src/gpu/gl41/GL41BackendTexture.cpp | 3 ++ libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 21 ++++++++ .../src/gpu/gl45/GL45BackendTexture.cpp | 3 +- libraries/gpu/src/gpu/Batch.cpp | 8 +++ libraries/gpu/src/gpu/Batch.h | 4 ++ libraries/gpu/src/gpu/Forward.h | 2 + libraries/gpu/src/gpu/TextureTable.cpp | 48 ++++++++++++++++++ libraries/gpu/src/gpu/TextureTable.h | 42 ++++++++++++++++ .../render-utils/src/MeshPartPayload.cpp | 49 +++++++++---------- libraries/render-utils/src/MeshPartPayload.h | 1 + 13 files changed, 160 insertions(+), 26 deletions(-) create mode 100644 libraries/gpu/src/gpu/TextureTable.cpp create mode 100644 libraries/gpu/src/gpu/TextureTable.h diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 08bd20be66..3a4c7b4f47 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -99,6 +99,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::gl::GLBackend::do_setUniformBuffer), (&::gpu::gl::GLBackend::do_setResourceBuffer), (&::gpu::gl::GLBackend::do_setResourceTexture), + (&::gpu::gl::GLBackend::do_setResourceTextureTable), (&::gpu::gl::GLBackend::do_setFramebuffer), (&::gpu::gl::GLBackend::do_clearFramebuffer), diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index e13bfe8166..35aabef48f 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -132,6 +132,7 @@ public: // Resource Stage virtual void do_setResourceBuffer(const Batch& batch, size_t paramOffset) final; virtual void do_setResourceTexture(const Batch& batch, size_t paramOffset) final; + virtual void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) = 0; // Pipeline Stage virtual void do_setPipeline(const Batch& batch, size_t paramOffset) final; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 42926fdb1c..1b7882518d 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -157,6 +157,9 @@ protected: void resetInputStage() override; void updateInput() override; + // Resource stage + void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) override; + // Synchronize the state cache of this Backend with the actual real state of the GL Context void transferTransformState(const Batch& batch) const override; void initTransform() override; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index 925e83bb77..b70730fd98 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -611,3 +611,6 @@ GL41ResourceTexture::GL41ResourceTexture(const std::weak_ptr& backend GL41ResourceTexture::~GL41ResourceTexture() { } +void GL41Backend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) { + +} diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 098ac11763..4fb12fbdb1 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -15,6 +15,7 @@ #include "../gl/GLBackend.h" #include "../gl/GLTexture.h" #include +#include #define INCREMENTAL_TRANSFER 0 #define GPU_SSBO_TRANSFORM_OBJECT 1 @@ -48,6 +49,21 @@ public: static const std::string GL45_VERSION; const std::string& getVersion() const override { return GL45_VERSION; } + class GL45TextureTable : public GLObject { + static GLuint allocate(); + using Parent = GLObject; + public: + using HandlesArray = std::array; + GL45TextureTable(const std::weak_ptr& backend, const TextureTable& texture, const HandlesArray& newHandles, bool complete); + ~GL45TextureTable(); + + // FIXME instead of making a buffer for each table, there should be a global buffer of all materials + // and we should store an offset into that buffer + const uint32_t _stamp { 0 }; + const HandlesArray _handles; + const bool _complete { false }; + }; + class GL45Texture : public GLTexture { using Parent = GLTexture; friend class GL45Backend; @@ -181,6 +197,8 @@ protected: GLuint getQueryID(const QueryPointer& query) override; GLQuery* syncGPUObject(const Query& query) override; + GL45TextureTable* syncGPUObject(const TextureTablePointer& textureTable); + // Draw Stage void do_draw(const Batch& batch, size_t paramOffset) override; void do_drawIndexed(const Batch& batch, size_t paramOffset) override; @@ -193,6 +211,9 @@ protected: void resetInputStage() override; void updateInput() override; + // Resource stage + void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) override; + // Synchronize the state cache of this Backend with the actual real state of the GL Context void transferTransformState(const Batch& batch) const override; void initTransform() override; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 45900a62b6..e3c10928b4 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -20,15 +20,16 @@ #include #include +#include #include "../gl/GLTexelFormat.h" using namespace gpu; using namespace gpu::gl; using namespace gpu::gl45; -#define SPARSE_PAGE_SIZE_OVERHEAD_ESTIMATE 1.3f #define MAX_RESOURCE_TEXTURES_PER_FRAME 2 + GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { if (!texturePointer) { return nullptr; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index c432e19368..3764a94494 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -59,6 +59,7 @@ Batch::Batch(const Batch& batch_) { _buffers._items.swap(batch._buffers._items); _textures._items.swap(batch._textures._items); + _textureTables._items.swap(batch._textureTables._items); _streamFormats._items.swap(batch._streamFormats._items); _transforms._items.swap(batch._transforms._items); _pipelines._items.swap(batch._pipelines._items); @@ -96,6 +97,7 @@ void Batch::clear() { _data.clear(); _buffers.clear(); _textures.clear(); + _textureTables.clear(); _streamFormats.clear(); _transforms.clear(); _pipelines.clear(); @@ -306,6 +308,12 @@ void Batch::setResourceTexture(uint32 slot, const TexturePointer& texture) { _params.emplace_back(slot); } +void Batch::setResourceTextureTable(const TextureTablePointer& textureTable, uint32 slot) { + ADD_COMMAND(setResourceTextureTable); + _params.emplace_back(_textureTables.cache(textureTable)); + _params.emplace_back(slot); +} + void Batch::setResourceTexture(uint32 slot, const TextureView& view) { setResourceTexture(slot, view._texture); } diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index a57ee94747..8eb769a6fe 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -193,6 +193,7 @@ public: void setResourceTexture(uint32 slot, const TexturePointer& texture); void setResourceTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView + void setResourceTextureTable(const TextureTablePointer& table, uint32 slot = 0); // Ouput Stage void setFramebuffer(const FramebufferPointer& framebuffer); @@ -304,6 +305,7 @@ public: COMMAND_setUniformBuffer, COMMAND_setResourceBuffer, COMMAND_setResourceTexture, + COMMAND_setResourceTextureTable, COMMAND_setFramebuffer, COMMAND_clearFramebuffer, @@ -422,6 +424,7 @@ public: typedef Cache::Vector BufferCaches; typedef Cache::Vector TextureCaches; + typedef Cache::Vector TextureTableCaches; typedef Cache::Vector StreamFormatCaches; typedef Cache::Vector TransformCaches; typedef Cache::Vector PipelineCaches; @@ -476,6 +479,7 @@ public: BufferCaches _buffers; TextureCaches _textures; + TextureTableCaches _textureTables; StreamFormatCaches _streamFormats; TransformCaches _transforms; PipelineCaches _pipelines; diff --git a/libraries/gpu/src/gpu/Forward.h b/libraries/gpu/src/gpu/Forward.h index 8100efafaf..987788c29b 100644 --- a/libraries/gpu/src/gpu/Forward.h +++ b/libraries/gpu/src/gpu/Forward.h @@ -91,6 +91,8 @@ namespace gpu { using Textures = std::vector; class TextureView; using TextureViews = std::vector; + class TextureTable; + using TextureTablePointer = std::shared_ptr; struct StereoState { bool isStereo() const { diff --git a/libraries/gpu/src/gpu/TextureTable.cpp b/libraries/gpu/src/gpu/TextureTable.cpp new file mode 100644 index 0000000000..17a9e87f3e --- /dev/null +++ b/libraries/gpu/src/gpu/TextureTable.cpp @@ -0,0 +1,48 @@ +// +// Created by Bradley Austin Davis on 2017/01/25 +// Copyright 2013-2017 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 "TextureTable.h" +#include "Texture.h" + +using namespace gpu; + +TextureTable::TextureTable() { } + +TextureTable::TextureTable(const std::initializer_list& textures) { + auto max = std::min(COUNT, textures.size()); + auto itr = textures.begin(); + size_t index = 0; + while (itr != textures.end() && index < max) { + setTexture(index, *itr); + ++index; + } +} + +TextureTable::TextureTable(const std::array& textures) : _stamp(1), _textures(textures) { +} + +void TextureTable::setTexture(size_t index, const TexturePointer& texturePointer) { + if (index >= COUNT || _textures[index] == texturePointer) { + return; + } + { + Lock lock(_mutex); + ++_stamp; + _textures[index] = texturePointer; + } +} + +void TextureTable::setTexture(size_t index, const TextureView& textureView) { + setTexture(index, textureView._texture); +} + +TextureTable::Array TextureTable::getTextures() const { + Array result; + Lock lock(_mutex); + result = _textures; + return result; +} diff --git a/libraries/gpu/src/gpu/TextureTable.h b/libraries/gpu/src/gpu/TextureTable.h new file mode 100644 index 0000000000..7b278bf304 --- /dev/null +++ b/libraries/gpu/src/gpu/TextureTable.h @@ -0,0 +1,42 @@ +// +// Created by Bradley Austin Davis on 2017/01/25 +// Copyright 2013-2017 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_TextureTable_h +#define hifi_gpu_TextureTable_h + +#include "Forward.h" + +#include + +namespace gpu { + +class TextureTable { +public: + static const size_t COUNT = 8; + using Array = std::array; + using Array = std::array; + TextureTable(); + TextureTable(const std::initializer_list& textures); + TextureTable(const std::array& textures); + + // Only for gpu::Context + const GPUObjectPointer gpuObject{}; + + void setTexture(size_t index, const TexturePointer& texturePointer); + void setTexture(size_t index, const TextureView& texturePointer); + + Array getTextures() const; + Stamp getStamp() const { return _stamp; } +private: + mutable Mutex _mutex; + Array _textures; + Stamp _stamp{ 0 }; +}; + +} + +#endif diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 2428ec95aa..181eb19c8a 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include "DeferredLightingEffect.h" using namespace render; @@ -144,24 +146,25 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat return; } + + const auto& textureMaps = _drawMaterial->getTextureMaps(); + const auto& materialKey = _drawMaterial->getKey(); auto textureCache = DependencyManager::get(); if (!_drawMaterialTextures) { _drawMaterialTextures = std::make_shared(); - _drawMaterialTextures->setTexture(model::MaterialKey::ALBEDO_MAP, textureCache->getWhiteTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::ROUGHNESS_MAP, textureCache->getWhiteTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::NORMAL_MAP, textureCache->getBlueTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, textureCache->getBlackTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::OCCLUSION_MAP, textureCache->getWhiteTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::SCATTERING_MAP, textureCache->getWhiteTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::ALBEDO_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::ROUGHNESS_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::NORMAL_MAP, textureCache->getBlueTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::METALLIC_MAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::OCCLUSION_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::SCATTERING_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture()); } batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, _drawMaterial->getSchemaBuffer()); batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::TEXMAPARRAY, _drawMaterial->getTexMapArrayBuffer()); - - const auto& materialKey = _drawMaterial->getKey(); - const auto& textureMaps = _drawMaterial->getTextureMaps(); + batch.setResourceTextureTable(_drawMaterialTextures); int numUnlit = 0; if (materialKey.isUnlit()) { @@ -183,7 +186,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isAlbedoMap()) { auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::ALBEDO_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::ALBEDO_MAP, itr->second->getTextureView()); } } @@ -191,7 +194,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isRoughnessMap()) { auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::ROUGHNESS_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::ROUGHNESS_MAP, itr->second->getTextureView()); } } @@ -199,7 +202,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isNormalMap()) { auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::NORMAL_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::NORMAL_MAP, itr->second->getTextureView()); } } @@ -207,11 +210,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isMetallicMap()) { auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - _drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::METALLIC_MAP, itr->second->getTextureView()); } } @@ -219,7 +218,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isOcclusionMap()) { auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::OCCLUSION_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::OCCLUSION_MAP, itr->second->getTextureView()); } } @@ -227,7 +226,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isScatteringMap()) { auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::SCATTERING_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::SCATTERING_MAP, itr->second->getTextureView()); } } @@ -236,16 +235,16 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::LIGHTMAP_MAP, itr->second->getTextureView()); } else { - _drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture()); } } else if (materialKey.isEmissiveMap()) { auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::EMISSIVE_MAP, itr->second->getTextureView()); } else { - _drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture()); } } } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 21f9dc2e68..51bc7f39e0 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -67,6 +67,7 @@ public: std::shared_ptr _drawMaterial; graphics::Mesh::Part _drawPart; + mutable gpu::TextureTablePointer _drawMaterialTextures; size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } size_t getMaterialTextureSize() { return _drawMaterial ? _drawMaterial->getTextureSize() : 0; } From 5139f3f50328c0299801906ba435d5e1528c72f8 Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Mon, 5 Mar 2018 14:15:50 -0800 Subject: [PATCH 05/72] Update repo script with marketplace script --- scripts/tutorials/entity_scripts/sit.js | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/scripts/tutorials/entity_scripts/sit.js b/scripts/tutorials/entity_scripts/sit.js index 70456ea493..9de65d7037 100644 --- a/scripts/tutorials/entity_scripts/sit.js +++ b/scripts/tutorials/entity_scripts/sit.js @@ -12,9 +12,9 @@ Script.include("/~/system/libraries/utils.js"); if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position){ - position = position || 0; - return this.substr(position, searchString.length) === searchString; - }; + position = position || 0; + return this.substr(position, searchString.length) === searchString; + }; } var SETTING_KEY = "com.highfidelity.avatar.isSitting"; @@ -122,20 +122,10 @@ this.rolesToOverride = function() { return MyAvatar.getAnimationRoles().filter(function(role) { - return !(role.startsWith("right") || role.startsWith("left")); + return !(role.startsWith("right") || role.startsWith("left")); }); } - // Handler for user changing the avatar model while sitting. There's currently an issue with changing avatar models while override role animations are applied, - // so to avoid that problem, re-apply the role overrides once the model has finished changing. - this.modelURLChangeFinished = function () { - print("Sitter's model has FINISHED changing. Reapply anim role overrides."); - var roles = this.rolesToOverride(); - for (i in roles) { - MyAvatar.overrideRoleAnimation(roles[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME); - } - } - this.sitDown = function() { if (this.checkSeatForAvatar()) { print("Someone is already sitting in that chair."); @@ -174,14 +164,12 @@ return { headType: 0 }; }, ["headType"]); Script.update.connect(this, this.update); - MyAvatar.onLoadComplete.connect(this, this.modelURLChangeFinished); } this.standUp = function() { print("Standing up (" + this.entityID + ")"); MyAvatar.removeAnimationStateHandler(this.animStateHandlerID); Script.update.disconnect(this, this.update); - MyAvatar.onLoadComplete.disconnect(this, this.modelURLChangeFinished); if (MyAvatar.sessionUUID === this.getSeatUser()) { this.setSeatUser(null); @@ -343,7 +331,7 @@ } this.cleanupOverlay(); } - + this.clickDownOnEntity = function (id, event) { if (isInEditMode()) { return; @@ -352,4 +340,4 @@ this.sitDown(); } } -}); +}); \ No newline at end of file From b7d0260a17654dd79854e5b65058b2cd74c6115f Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Thu, 8 Feb 2018 14:05:21 -0800 Subject: [PATCH 06/72] Fix the uniform target for bindless --- libraries/gpu-gl/src/gpu/gl/GLShader.cpp | 444 +----------------- libraries/gpu-gl/src/gpu/gl/GLShader.h | 9 - .../src/gpu/gl41/GL41BackendTexture.cpp | 4 - libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 84 +++- .../gpu-gl/src/gpu/gl45/GL45BackendShader.cpp | 5 + .../src/gpu/gl45/GL45BackendTexture.cpp | 183 ++++++-- .../gpu/gl45/GL45BackendVariableTexture.cpp | 19 +- libraries/gpu/src/gpu/Texture.h | 34 +- libraries/gpu/src/gpu/TextureTable.h | 1 - libraries/gpu/src/gpu/TextureTable.slh | 3 - 10 files changed, 259 insertions(+), 527 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp index 9c3de94957..7a26642024 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp @@ -10,447 +10,6 @@ #include "GLBackend.h" -namespace gpu { - namespace gl { - - 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 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 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}, - */ - - 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_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); -#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}, - - 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); -#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} - */ - default: - return ElementResource(Element(), Resource::BUFFER); - } - - }; - - int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, - Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& textureTables, 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); - GLint location = glGetUniformLocation(glprogram, name); - const GLint INVALID_UNIFORM_LOCATION = -1; - - // Try to make sense of the gltype - auto elementResource = getFormatFromGLUniform(type); - - // The uniform as a standard var type - if (location != INVALID_UNIFORM_LOCATION) { - // Let's make sure the name doesn't contains an array element - std::string sname(name); - auto foundBracket = sname.find_first_of('['); - if (foundBracket != std::string::npos) { - // std::string arrayname = sname.substr(0, foundBracket); - - if (sname[foundBracket + 1] == '0') { - sname = sname.substr(0, foundBracket); - } else { - // skip this uniform since it's not the first element of an array - continue; - } - } - - if (elementResource._resource == Resource::BUFFER) { - uniforms.insert(Shader::Slot(sname, 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(sname)); - if (requestedBinding != slotBindings.end()) { - if (binding != (*requestedBinding)._location) { - binding = (*requestedBinding)._location; - glProgramUniform1i(glprogram, location, binding); - } - } - - textures.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); - samplers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); - } - } - } - - return uniformsCount; - } - - 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); - - struct UniformBlockInfo { - using Vector = std::vector; - const GLuint index { 0 }; - const std::string name; - GLint binding { -1 }; - GLint size { 0 }; - - static std::string getName(GLuint glprogram, GLuint i) { - static const GLint NAME_LENGTH = 256; - GLint length = 0; - GLchar nameBuffer[NAME_LENGTH]; - glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length); - glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, nameBuffer); - return std::string(nameBuffer); - } - - UniformBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) { - glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_BINDING, &binding); - glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_DATA_SIZE, &size); - } - }; - - UniformBlockInfo::Vector uniformBlocks; - uniformBlocks.reserve(buffersCount); - for (int i = 0; i < buffersCount; i++) { - uniformBlocks.push_back(UniformBlockInfo(glprogram, i)); - } - - for (auto& info : uniformBlocks) { - auto requestedBinding = slotBindings.find(info.name); - if (requestedBinding != slotBindings.end()) { - info.binding = (*requestedBinding)._location; - glUniformBlockBinding(glprogram, info.index, info.binding); - uniformBufferSlotMap[info.binding] = info.index; - } - } - - for (auto& info : uniformBlocks) { - if (slotBindings.count(info.name)) { - continue; - } - - // If the binding is 0, or the binding maps to an already used binding - if (info.binding == 0 || uniformBufferSlotMap[info.binding] != UNUSED_SLOT) { - // 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()) { - info.binding = slotIt - uniformBufferSlotMap.begin(); - glUniformBlockBinding(glprogram, info.index, info.binding); - } else { - // This should neve happen, an active ubo cannot find an available slot among the max available?! - info.binding = -1; - } - } - - uniformBufferSlotMap[info.binding] = info.index; - } - - for (auto& info : uniformBlocks) { - static const Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER); - buffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size)); - } - return buffersCount; - } - - int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, 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); - - GLint binding = glGetAttribLocation(glprogram, name); - - auto elementResource = getFormatFromGLUniform(type); - inputs.insert(Shader::Slot(name, binding, elementResource._element, -1)); - } - - return inputsCount; - } - - int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, 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; - } - - void makeProgramBindings(ShaderObject& shaderObject) { - if (!shaderObject.glprogram) { - return; - } - GLuint glprogram = shaderObject.glprogram; - GLint loc = -1; - - //Check for gpu specific attribute slotBindings - loc = glGetAttribLocation(glprogram, "inPosition"); - if (loc >= 0 && loc != gpu::Stream::POSITION) { - glBindAttribLocation(glprogram, gpu::Stream::POSITION, "inPosition"); - } - - loc = glGetAttribLocation(glprogram, "inNormal"); - if (loc >= 0 && loc != gpu::Stream::NORMAL) { - glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "inNormal"); - } - - loc = glGetAttribLocation(glprogram, "inColor"); - if (loc >= 0 && loc != gpu::Stream::COLOR) { - glBindAttribLocation(glprogram, gpu::Stream::COLOR, "inColor"); - } - - loc = glGetAttribLocation(glprogram, "inTexCoord0"); - if (loc >= 0 && loc != gpu::Stream::TEXCOORD) { - glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "inTexCoord0"); - } - - loc = glGetAttribLocation(glprogram, "inTangent"); - if (loc >= 0 && loc != gpu::Stream::TANGENT) { - glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "inTangent"); - } - - loc = glGetAttribLocation(glprogram, "inTexCoord1"); - if (loc >= 0 && loc != gpu::Stream::TEXCOORD1) { - glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD1, "inTexCoord1"); - } - - loc = glGetAttribLocation(glprogram, "inSkinClusterIndex"); - if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_INDEX) { - glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "inSkinClusterIndex"); - } - - loc = glGetAttribLocation(glprogram, "inSkinClusterWeight"); - if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_WEIGHT) { - glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "inSkinClusterWeight"); - } - - loc = glGetAttribLocation(glprogram, "_drawCallInfo"); - if (loc >= 0 && loc != gpu::Stream::DRAW_CALL_INFO) { - glBindAttribLocation(glprogram, gpu::Stream::DRAW_CALL_INFO, "_drawCallInfo"); - } - - // Link again to take into account the assigned attrib location - glLinkProgram(glprogram); - - GLint linked = 0; - glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); - if (!linked) { - qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?"; - } - - // now assign the ubo binding, then DON't relink! - - //Check for gpu specific uniform slotBindings -#ifdef GPU_SSBO_DRAW_CALL_INFO - loc = glGetProgramResourceIndex(glprogram, GL_SHADER_STORAGE_BLOCK, "transformObjectBuffer"); - if (loc >= 0) { - glShaderStorageBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT); - shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT; - } -#else - loc = glGetUniformLocation(glprogram, "transformObjectBuffer"); - if (loc >= 0) { - glProgramUniform1i(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT); - shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT; - } -#endif - - loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer"); - if (loc >= 0) { - glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT); - shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT; - } - - loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable0"); - if (loc >= 0) { - glUniformBlockBinding(glprogram, loc, GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET); - shaderObject.resourceTextureTableSlot0 = GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET; - } - loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable1"); - if (loc >= 0) { - glUniformBlockBinding(glprogram, loc, GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET + 1); - shaderObject.resourceTextureTableSlot1 = GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET + 1; - } - (void)CHECK_GL_ERROR(); - } - } -} - - using namespace gpu; using namespace gpu::gl; @@ -516,7 +75,8 @@ bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::Bin Shader::SlotSet textures; Shader::SlotSet textureTables; Shader::SlotSet samplers; - backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, textureTables, samplers); + //backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, textureTables, samplers); + backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers); Shader::SlotSet resourceBuffers; backend.makeResourceBufferSlots(shaderObject.glprogram, slotBindings, resourceBuffers); diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.h b/libraries/gpu-gl/src/gpu/gl/GLShader.h index a5a6a6e72c..b2a1f189a2 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.h +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.h @@ -17,19 +17,10 @@ struct ShaderObject { GLuint glprogram { 0 }; GLint transformCameraSlot { -1 }; GLint transformObjectSlot { -1 }; - GLint resourceTextureTableSlot0 { -1 }; GLint resourceTextureTableSlot1 { -1 }; }; -int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, - Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& textureTables, Shader::SlotSet& samplers); -int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers); -int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs); -int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs); -void makeProgramBindings(ShaderObject& shaderObject); - - class GLShader : public GPUObject { public: static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr); diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index b70730fd98..495f11e4a8 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -167,7 +167,6 @@ void GL41Texture::syncSampler() const { glTexParameteri(_target, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); - glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, (uint16)sampler.getMipOffset()); glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); @@ -206,9 +205,6 @@ void GL41FixedAllocationTexture::allocateStorage() const { void GL41FixedAllocationTexture::syncSampler() const { Parent::syncSampler(); const Sampler& sampler = _gpuObject.getSampler(); - auto baseMip = std::max(sampler.getMipOffset(), sampler.getMinMip()); - - glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, baseMip); glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.0f : sampler.getMaxMip())); } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 4fb12fbdb1..d733b38a2f 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -19,6 +19,7 @@ #define INCREMENTAL_TRANSFER 0 #define GPU_SSBO_TRANSFORM_OBJECT 1 +#define GPU_BINDLESS_TEXTURES 1 namespace gpu { namespace gl45 { @@ -49,21 +50,6 @@ public: static const std::string GL45_VERSION; const std::string& getVersion() const override { return GL45_VERSION; } - class GL45TextureTable : public GLObject { - static GLuint allocate(); - using Parent = GLObject; - public: - using HandlesArray = std::array; - GL45TextureTable(const std::weak_ptr& backend, const TextureTable& texture, const HandlesArray& newHandles, bool complete); - ~GL45TextureTable(); - - // FIXME instead of making a buffer for each table, there should be a global buffer of all materials - // and we should store an offset into that buffer - const uint32_t _stamp { 0 }; - const HandlesArray _handles; - const bool _complete { false }; - }; - class GL45Texture : public GLTexture { using Parent = GLTexture; friend class GL45Backend; @@ -73,8 +59,72 @@ public: void generateMips() const override; Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const override; void syncSampler() const override; + + bool isBindless() const { +#if GPU_BINDLESS_TEXTURES + return _bindless.operator bool(); +#else + return false; +#endif + } + +#if GPU_BINDLESS_TEXTURES + struct Bindless { + uint64_t handle{ 0 }; + uint32_t minMip{ 0 }; + uint32_t sampler{ 0 }; + + operator bool() const { + return handle != 0; + } + }; + + virtual const Bindless& getBindless() const; + void releaseBindless() const; + void recreateBindless() const; + virtual uint16 getMinMip() const = 0; + + + private: + class InvalidSampler : public Sampler { + public: + InvalidSampler() { + _desc._borderColor = vec4(-1.0f); + } + + operator const Sampler&() const { + return *this; + } + }; + + static const Sampler INVALID_SAMPLER; + // This stores the texture handle (64 bits) in xy, the min mip available in z, and the sampler ID in w + mutable Sampler _cachedSampler{ INVALID_SAMPLER }; + + mutable Bindless _bindless; + +#endif }; +#if GPU_BINDLESS_TEXTURES + class GL45TextureTable : public GLObject { + static GLuint allocate(); + using Parent = GLObject; + public: + using BindlessArray = std::array; + + GL45TextureTable(const std::weak_ptr& backend, const TextureTable& texture); + ~GL45TextureTable(); + + void update(const BindlessArray& newHandles); + + // FIXME instead of making a buffer for each table, there should be a global buffer of all materials + // and we should store an offset into that buffer + BindlessArray _handles; + }; +#endif + + // // Textures that have fixed allocation sizes and cannot be managed at runtime // @@ -89,6 +139,8 @@ public: protected: Size size() const override { return _size; } + uint16 getMinMip() const override { return 0; } + void allocateStorage() const; void syncSampler() const override; const Size _size { 0 }; @@ -125,6 +177,8 @@ public: ~GL45VariableAllocationTexture(); Size size() const override { return _size; } + uint16 getMinMip() const override { return _populatedMip; } + virtual const Bindless& getBindless() const override; Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const override; void copyTextureMipsInGPUMem(GLuint srcId, GLuint destId, uint16_t srcMipOffset, uint16_t destMipOffset, uint16_t populatedMips) override; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp index c2490524ae..9c973c9a6a 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp @@ -165,6 +165,11 @@ void GL45Backend::makeProgramBindings(ShaderObject& shaderObject) { shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT; } + loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable0"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, RESOURCE_TABLE_TEXTURE_SLOT_OFFSET); + } + (void)CHECK_GL_ERROR(); } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index e3c10928b4..d33afc0e67 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include "../gl/GLTexelFormat.h" @@ -29,6 +30,10 @@ using namespace gpu::gl45; #define MAX_RESOURCE_TEXTURES_PER_FRAME 2 +#pragma optimize("", off) + +#define FORCE_STRICT_TEXTURE 0 +#define ENABLE_SPARSE_TEXTURE 0 GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { if (!texturePointer) { @@ -52,14 +57,18 @@ GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { object = new GL45AttachmentTexture(shared_from_this(), texture); break; +#if FORCE_STRICT_TEXTURE + case TextureUsageType::RESOURCE: +#endif case TextureUsageType::STRICT_RESOURCE: qCDebug(gpugllogging) << "Strict texture " << texture.source().c_str(); object = new GL45StrictResourceTexture(shared_from_this(), texture); break; +#if !FORCE_STRICT_TEXTURE case TextureUsageType::RESOURCE: { if (GL45VariableAllocationTexture::_frameTexturesCreated < MAX_RESOURCE_TEXTURES_PER_FRAME) { -#if 0 +#if ENABLE_SPARSE_TEXTURE if (isTextureManagementSparseEnabled() && GL45Texture::isSparseEligible(texture)) { object = new GL45SparseResourceTexture(shared_from_this(), texture); } else { @@ -77,7 +86,7 @@ GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { } break; } - +#endif default: Q_UNREACHABLE(); } @@ -115,6 +124,50 @@ void GL45Backend::initTextureManagementStage() { using GL45Texture = GL45Backend::GL45Texture; + +class GLSamplerCache { +public: + GLuint getGLSampler(const Sampler& sampler) { + if (0 == _samplerCache.count(sampler)) { + GLuint result = 0; + glGenSamplers(1, &result); + const auto& fm = GLTexture::FILTER_MODES[sampler.getFilter()]; + glSamplerParameteri(result, GL_TEXTURE_MIN_FILTER, fm.minFilter); + glSamplerParameteri(result, GL_TEXTURE_MAG_FILTER, fm.magFilter); + if (sampler.doComparison()) { + glSamplerParameteri(result, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); + glSamplerParameteri(result, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); + } else { + glSamplerParameteri(result, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + + glSamplerParameteri(result, GL_TEXTURE_WRAP_S, GLTexture::WRAP_MODES[sampler.getWrapModeU()]); + glSamplerParameteri(result, GL_TEXTURE_WRAP_T, GLTexture::WRAP_MODES[sampler.getWrapModeV()]); + glSamplerParameteri(result, GL_TEXTURE_WRAP_R, GLTexture::WRAP_MODES[sampler.getWrapModeW()]); + + glSamplerParameterf(result, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); + glSamplerParameterfv(result, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); + + glSamplerParameterf(result, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); + glSamplerParameterf(result, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + _samplerCache[sampler] = result; + return result; + } + + return _samplerCache[sampler]; + } + + void releaseGLSampler(GLuint sampler) { + // NO OP + } + +private: + std::unordered_map _samplerCache; +}; + +static GLSamplerCache SAMPLER_CACHE; +const Sampler GL45Texture::INVALID_SAMPLER = GL45Texture::InvalidSampler(); + GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture) : GLTexture(backend, texture, allocate(texture)) { } @@ -122,10 +175,10 @@ GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& GLuint GL45Texture::allocate(const Texture& texture) { GLuint result; glCreateTextures(getGLTextureType(texture), 1, &result); -#ifdef DEBUG - auto source = texture.source(); - glObjectLabel(GL_TEXTURE, result, (GLsizei)source.length(), source.data()); -#endif + if (::gl::Context::enableDebugLogger()) { + auto source = texture.source(); + glObjectLabel(GL_TEXTURE, result, (GLsizei)source.length(), source.data()); + } return result; } @@ -190,32 +243,69 @@ Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const return amountCopied; } -void GL45Texture::syncSampler() const { - const Sampler& sampler = _gpuObject.getSampler(); - - const auto& fm = FILTER_MODES[sampler.getFilter()]; - glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); - glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); - - if (sampler.doComparison()) { - glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); - glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); - } else { - glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); +void GL45Texture::releaseBindless() const { + // Release the old handler + SAMPLER_CACHE.releaseGLSampler(_bindless.sampler); + glMakeTextureHandleNonResidentARB(_bindless.handle); + _bindless = Bindless(); +} + +void GL45Texture::recreateBindless() const { + if (isBindless()) { + releaseBindless(); } - glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]); - glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); - glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); + _bindless.sampler = SAMPLER_CACHE.getGLSampler(_cachedSampler); + _bindless.handle = glGetTextureSamplerHandleARB(_id, _bindless.sampler); + glMakeTextureHandleResidentARB(_bindless.handle); +} - glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); - glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); +const GL45Texture::Bindless& GL45Texture::getBindless() const { + if (!_bindless) { + recreateBindless(); + } + _bindless.minMip = getMinMip(); + return _bindless; +} - glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); - glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); +void GL45Texture::syncSampler() const { + const Sampler& sampler = _gpuObject.getSampler(); + bool samplerChanged = _cachedSampler != sampler; + if (samplerChanged) { + _cachedSampler = sampler; + } + + if (isBindless()) { + if (samplerChanged) { + recreateBindless(); + } + } else if (samplerChanged) { + const auto& fm = FILTER_MODES[sampler.getFilter()]; + glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); + glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); + + if (sampler.doComparison()) { + glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); + glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); + } else { + glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + + glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]); + glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); + glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); + + glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); + glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); + + glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); + glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + } (void)CHECK_GL_ERROR(); } +// Fixed allocation textures, used for strict resources & framebuffer attachments + using GL45FixedAllocationTexture = GL45Backend::GL45FixedAllocationTexture; GL45FixedAllocationTexture::GL45FixedAllocationTexture(const std::weak_ptr& backend, const Texture& texture) : GL45Texture(backend, texture), _size(texture.evalTotalSize()) { @@ -240,8 +330,6 @@ void GL45FixedAllocationTexture::allocateStorage() const { void GL45FixedAllocationTexture::syncSampler() const { Parent::syncSampler(); const Sampler& sampler = _gpuObject.getSampler(); - auto baseMip = std::max(sampler.getMipOffset(), sampler.getMinMip()); - glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, baseMip); glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); } @@ -280,7 +368,6 @@ GL45StrictResourceTexture::GL45StrictResourceTexture(const std::weak_ptr& backend, const TextureTable& textureTable, const HandlesArray& handles, bool handlesComplete) - : Parent(backend, textureTable, allocate()), _stamp(textureTable.getStamp()), _handles(handles), _complete(handlesComplete) { +GL45TextureTable::GL45TextureTable(const std::weak_ptr& backend, const TextureTable& textureTable) + : Parent(backend, textureTable, allocate()){ Backend::setGPUObject(textureTable, this); // FIXME include these in overall buffer storage reporting - glNamedBufferStorage(_id, sizeof(uvec4) * TextureTable::COUNT, &_handles[0], 0); + glNamedBufferStorage(_id, sizeof(uvec4) * TextureTable::COUNT, nullptr, GL_DYNAMIC_STORAGE_BIT); } +void GL45TextureTable::update(const BindlessArray& handles) { + if (_handles != handles) { + _handles = handles; + // FIXME include these in overall buffer storage reporting + // FIXME use a single shared buffer for bindless data + glNamedBufferSubData(_id, 0, sizeof(GL45Texture::Bindless) * TextureTable::COUNT, &_handles[0]); + } +} GL45TextureTable::~GL45TextureTable() { if (_id) { @@ -324,36 +410,33 @@ GL45TextureTable::~GL45TextureTable() { } } - GL45TextureTable* GL45Backend::syncGPUObject(const TextureTablePointer& textureTablePointer) { const auto& textureTable = *textureTablePointer; // Find the target handles auto textures = textureTable.getTextures(); - bool handlesComplete = true; - GL45TextureTable::HandlesArray handles{}; + GL45TextureTable::BindlessArray handles{}; for (size_t i = 0; i < textures.size(); ++i) { auto texture = textures[i]; if (!texture) { continue; } // FIXME what if we have a non-transferrable texture here? - auto gltexture = (GL45Texture*)syncGPUObject(texture, true); + auto gltexture = (GL45Texture*)syncGPUObject(texture); if (!gltexture) { - handlesComplete = false; continue; } - auto handle = gltexture->getHandle(); - memcpy(&handles[i], &handle, sizeof(handle)); + handles[i] = gltexture->getBindless(); } // If the object hasn't been created, or the object definition is out of date, drop and re-create GL45TextureTable* object = Backend::getGPUObject(textureTable); - if (!object || object->_stamp != textureTable.getStamp() || !object->_complete || handles != object->_handles) { - object = new GL45TextureTable(shared_from_this(), textureTable, handles, handlesComplete); + if (!object) { + object = new GL45TextureTable(shared_from_this(), textureTable); } + object->update(handles); return object; } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp index 0f1de0f868..ab5577940c 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp @@ -27,6 +27,7 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gl45; +using GL45Texture = GL45Backend::GL45Texture; using GL45VariableAllocationTexture = GL45Backend::GL45VariableAllocationTexture; GL45VariableAllocationTexture::GL45VariableAllocationTexture(const std::weak_ptr& backend, const Texture& texture) : GL45Texture(backend, texture) { @@ -40,6 +41,12 @@ GL45VariableAllocationTexture::~GL45VariableAllocationTexture() { Backend::textureResourcePopulatedGPUMemSize.update(_populatedSize, 0); } +const GL45Texture::Bindless& GL45VariableAllocationTexture::getBindless() const { + auto& result = Parent::getBindless(); + _bindless.minMip = _populatedMip - _allocatedMip; + return result; +} + Size GL45VariableAllocationTexture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const { Size amountCopied = 0; amountCopied = Parent::copyMipFaceLinesFromTexture(mip, face, size, yOffset, internalFormat, format, type, sourceSize, sourcePointer); @@ -127,7 +134,9 @@ Size GL45ResourceTexture::copyMipsFromTexture() { void GL45ResourceTexture::syncSampler() const { Parent::syncSampler(); - glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip); + if (!isBindless()) { + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip); + } } void GL45ResourceTexture::promote() { @@ -137,6 +146,10 @@ void GL45ResourceTexture::promote() { uint16_t targetAllocatedMip = _allocatedMip - std::min(_allocatedMip, 2); targetAllocatedMip = std::max(_minAllocatedMip, targetAllocatedMip); + if (isBindless()) { + releaseBindless(); + } + GLuint oldId = _id; auto oldSize = _size; uint16_t oldAllocatedMip = _allocatedMip; @@ -170,6 +183,10 @@ void GL45ResourceTexture::demote() { auto oldSize = _size; auto oldPopulatedMip = _populatedMip; + if (isBindless()) { + releaseBindless(); + } + // allocate new texture const_cast(_id) = allocate(_gpuObject); uint16_t oldAllocatedMip = _allocatedMip; diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index ad3dc5fada..096d6368f8 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -17,8 +17,10 @@ #include #include +#include #include #include +#include #include "Forward.h" #include "Resource.h" #include "Metric.h" @@ -126,12 +128,23 @@ public: uint8 _wrapModeV = WRAP_REPEAT; uint8 _wrapModeW = WRAP_REPEAT; - uint8 _mipOffset = 0; uint8 _minMip = 0; uint8 _maxMip = MAX_MIP_LEVEL; Desc() {} Desc(const Filter filter, const WrapMode wrap = WRAP_REPEAT) : _filter(filter), _wrapModeU(wrap), _wrapModeV(wrap), _wrapModeW(wrap) {} + + bool operator==(const Desc& other) const { + return _borderColor == other._borderColor && + _maxAnisotropy == other._maxAnisotropy && + _filter == other._filter && + _comparisonFunc == other._comparisonFunc && + _wrapModeU == other._wrapModeU && + _wrapModeV == other._wrapModeV && + _wrapModeW == other._wrapModeW && + _minMip == other._minMip && + _maxMip == other._maxMip; + } }; Sampler() {} @@ -151,11 +164,17 @@ public: ComparisonFunction getComparisonFunction() const { return ComparisonFunction(_desc._comparisonFunc); } bool doComparison() const { return getComparisonFunction() != ALWAYS; } - uint8 getMipOffset() const { return _desc._mipOffset; } uint8 getMinMip() const { return _desc._minMip; } uint8 getMaxMip() const { return _desc._maxMip; } const Desc& getDesc() const { return _desc; } + + bool operator==(const Sampler& other) const { + return _desc == other._desc; + } + bool operator!=(const Sampler& other) const { + return !(*this == other); + } protected: Desc _desc; }; @@ -667,6 +686,17 @@ typedef std::shared_ptr< TextureSource > TextureSourcePointer; }; +namespace std { + template<> struct hash { + size_t operator()(const gpu::Sampler& sampler) const noexcept { + size_t result = 0; + const auto& desc = sampler.getDesc(); + hash_combine(result, desc._comparisonFunc, desc._filter, desc._maxAnisotropy, desc._maxMip, desc._minMip, desc._wrapModeU, desc._wrapModeV, desc._wrapModeW); + return result; + } + }; +} + Q_DECLARE_METATYPE(gpu::TexturePointer) #endif diff --git a/libraries/gpu/src/gpu/TextureTable.h b/libraries/gpu/src/gpu/TextureTable.h index 7b278bf304..4307e60adb 100644 --- a/libraries/gpu/src/gpu/TextureTable.h +++ b/libraries/gpu/src/gpu/TextureTable.h @@ -18,7 +18,6 @@ class TextureTable { public: static const size_t COUNT = 8; using Array = std::array; - using Array = std::array; TextureTable(); TextureTable(const std::initializer_list& textures); TextureTable(const std::array& textures); diff --git a/libraries/gpu/src/gpu/TextureTable.slh b/libraries/gpu/src/gpu/TextureTable.slh index d45c8f819b..1b83f4d622 100644 --- a/libraries/gpu/src/gpu/TextureTable.slh +++ b/libraries/gpu/src/gpu/TextureTable.slh @@ -25,7 +25,4 @@ struct GPUTextureTable { #endif - - - <@endif@> From f9605cffb127cc1870c132ec17907dbcc1770c1d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 6 Mar 2018 11:20:54 -0800 Subject: [PATCH 07/72] Target available mip --- .../gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 18 ++++++++++-------- libraries/gpu/src/gpu/TextureTable.slh | 10 ++++++++++ libraries/gpu/src/gpu/Texture_ktx.cpp | 4 +++- .../render-utils/src/MaterialTextures.slh | 14 +++++++------- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index d33afc0e67..f02615c5c7 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -253,6 +253,9 @@ void GL45Texture::releaseBindless() const { void GL45Texture::recreateBindless() const { if (isBindless()) { releaseBindless(); + } else { + // Once a texture is about to become bindless, it's base mip level MUST be set to 0 + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); } _bindless.sampler = SAMPLER_CACHE.getGLSampler(_cachedSampler); @@ -270,16 +273,15 @@ const GL45Texture::Bindless& GL45Texture::getBindless() const { void GL45Texture::syncSampler() const { const Sampler& sampler = _gpuObject.getSampler(); - bool samplerChanged = _cachedSampler != sampler; - if (samplerChanged) { - _cachedSampler = sampler; - } + if (_cachedSampler == sampler) { + return; + } + + _cachedSampler = sampler; if (isBindless()) { - if (samplerChanged) { - recreateBindless(); - } - } else if (samplerChanged) { + recreateBindless(); + } else { const auto& fm = FILTER_MODES[sampler.getFilter()]; glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); diff --git a/libraries/gpu/src/gpu/TextureTable.slh b/libraries/gpu/src/gpu/TextureTable.slh index 1b83f4d622..f2d89e753b 100644 --- a/libraries/gpu/src/gpu/TextureTable.slh +++ b/libraries/gpu/src/gpu/TextureTable.slh @@ -20,7 +20,17 @@ struct GPUTextureTable { #define TextureTable(index, name) layout (std140) uniform gpu_resourceTextureTable##index { GPUTextureTable name; } #define tableTex(name, slot) sampler2D(name._textures[slot].xy) +#define tableTexMinLod(name, slot) float(name._textures[slot].z) +#define tableTexValue(name, slot, uv) \ + tableTexValueLod(tableTex(matTex, albedoMap), tableTexMinLod(matTex, albedoMap), uv) + +vec4 tableTexValueLod(sampler2D sampler, float minLod, vec2 uv) { + float queryLod = textureQueryLod(sampler, uv).x; + queryLod = max(minLod, queryLod); + return textureLod(sampler, uv, queryLod); +} + #else #endif diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 754bdca445..803acbd961 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -504,6 +504,8 @@ TexturePointer Texture::build(const ktx::KTXDescriptor& descriptor) { gpuktxKeyValue._usage = Texture::Usage::Builder().withColor().withAlpha().build(); } + auto samplerDesc = gpuktxKeyValue._samplerDesc; + samplerDesc._maxMip = gpu::Sampler::MAX_MIP_LEVEL; auto texture = create(gpuktxKeyValue._usageType, type, texelFormat, @@ -513,7 +515,7 @@ TexturePointer Texture::build(const ktx::KTXDescriptor& descriptor) { 1, // num Samples header.getNumberOfSlices(), header.getNumberOfLevels(), - gpuktxKeyValue._samplerDesc); + samplerDesc); texture->setUsage(gpuktxKeyValue._usage); // Assing the mips availables diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index ef77954fad..72db15aea9 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -67,42 +67,42 @@ SCATTERING_MAP, <@if withAlbedo@> #define albedoMap 1 vec4 fetchAlbedoMap(vec2 uv) { - return texture(tableTex(matTex, albedoMap), uv); + return tableTexValue(matTex, albedoMap, uv); } <@endif@> <@if withRoughness@> #define roughnessMap 3 float fetchRoughnessMap(vec2 uv) { - return (texture(tableTex(matTex, roughnessMap), uv).r); + return tableTexValue(matTex, roughnessMap, uv).r; } <@endif@> <@if withNormal@> #define normalMap 4 vec3 fetchNormalMap(vec2 uv) { - return texture(tableTex(matTex, normalMap), uv).xyz; + return tableTexValue(matTex, normalMap, uv).xyz; } <@endif@> <@if withMetallic@> #define metallicMap 2 float fetchMetallicMap(vec2 uv) { - return (texture(tableTex(matTex, metallicMap), uv).r); + return tableTexValue(matTex, metallicMap, uv).r; } <@endif@> <@if withEmissive@> #define emissiveMap 0 vec3 fetchEmissiveMap(vec2 uv) { - return texture(tableTex(matTex, emissiveMap), uv).rgb; + return tableTexValue(matTex, emissiveMap, uv).rgb; } <@endif@> <@if withOcclusion@> #define occlusionMap 5 float fetchOcclusionMap(vec2 uv) { - return texture(tableTex(matTex, occlusionMap), uv).r; + return tableTexValue(matTex, occlusionMap, uv).r; } <@endif@> @@ -111,7 +111,7 @@ float fetchOcclusionMap(vec2 uv) { float fetchScatteringMap(vec2 uv) { float scattering = texture(tableTex(matTex, scatteringMap), uv).r; // boolean scattering for now return max(((scattering - 0.1) / 0.9), 0.0); - return texture(tableTex(matTex, scatteringMap), uv).r; // boolean scattering for now + return tableTexValue(matTex, scatteringMap, uv).r; // boolean scattering for now } <@endif@> From bf1e5f1dbc816e9868094d5d94b2bc62737cde79 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 7 Mar 2018 16:00:14 -0800 Subject: [PATCH 08/72] Fix varaible allocated bindless textures --- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 10 +++++++++- .../gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 3 ++- .../src/gpu/gl45/GL45BackendVariableTexture.cpp | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index d733b38a2f..e4a96349a9 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -74,6 +74,14 @@ public: uint32_t minMip{ 0 }; uint32_t sampler{ 0 }; + bool operator==(const Bindless& other) const { + return handle == other.handle && minMip == other.minMip && sampler == other.sampler; + } + + bool operator!=(const Bindless& other) const { + return !(*this == other); + } + operator bool() const { return handle != 0; } @@ -177,7 +185,7 @@ public: ~GL45VariableAllocationTexture(); Size size() const override { return _size; } - uint16 getMinMip() const override { return _populatedMip; } + uint16 getMinMip() const override { return _populatedMip - _allocatedMip; } virtual const Bindless& getBindless() const override; Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const override; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index f02615c5c7..a87999781a 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -249,7 +249,7 @@ void GL45Texture::releaseBindless() const { glMakeTextureHandleNonResidentARB(_bindless.handle); _bindless = Bindless(); } - + void GL45Texture::recreateBindless() const { if (isBindless()) { releaseBindless(); @@ -439,6 +439,7 @@ GL45TextureTable* GL45Backend::syncGPUObject(const TextureTablePointer& textureT } object->update(handles); + return object; } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp index ab5577940c..293b34fb39 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp @@ -146,7 +146,8 @@ void GL45ResourceTexture::promote() { uint16_t targetAllocatedMip = _allocatedMip - std::min(_allocatedMip, 2); targetAllocatedMip = std::max(_minAllocatedMip, targetAllocatedMip); - if (isBindless()) { + bool bindless = isBindless(); + if (bindless) { releaseBindless(); } @@ -163,6 +164,10 @@ void GL45ResourceTexture::promote() { // copy pre-existing mips copyTextureMipsInGPUMem(oldId, _id, oldAllocatedMip, _allocatedMip, _populatedMip); + if (bindless) { + getBindless(); + } + // destroy the old texture glDeleteTextures(1, &oldId); @@ -183,7 +188,8 @@ void GL45ResourceTexture::demote() { auto oldSize = _size; auto oldPopulatedMip = _populatedMip; - if (isBindless()) { + bool bindless = isBindless(); + if (bindless) { releaseBindless(); } @@ -196,6 +202,10 @@ void GL45ResourceTexture::demote() { // copy pre-existing mips copyTextureMipsInGPUMem(oldId, _id, oldAllocatedMip, _allocatedMip, _populatedMip); + if (bindless) { + getBindless(); + } + // destroy the old texture glDeleteTextures(1, &oldId); From d858d3452336a2fbba9612a6b8cd7cb594be0c3d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 7 Mar 2018 17:27:47 -0800 Subject: [PATCH 09/72] Update material binding --- libraries/graphics/src/graphics/Material.h | 11 +++ .../render-utils/src/MaterialTextures.slh | 25 +++-- .../render-utils/src/RenderPipelines.cpp | 96 +++++++++++++++++++ 3 files changed, 119 insertions(+), 13 deletions(-) diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 632cf99391..d31a0cbd31 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -20,9 +20,12 @@ #include #include +#include class Transform; +#define USE_BINDLESS_TEXTURES 1 + namespace graphics { class TextureMap; @@ -360,6 +363,11 @@ public: void setModel(const std::string& model) { _model = model; } +#if USE_BINDLESS_TEXTURES + const gpu::TextureTablePointer& getTextureTable() const { return _textureTable; } + void setTextureTable(const gpu::TextureTablePointer& textureTable) { _textureTable = textureTable; } +#endif + protected: std::string _name { "" }; @@ -367,6 +375,9 @@ private: mutable MaterialKey _key; mutable UniformBufferView _schemaBuffer; mutable UniformBufferView _texMapArrayBuffer; +#if USE_BINDLESS_TEXTURES + mutable gpu::TextureTablePointer _textureTable; +#endif TextureMaps _textureMaps; diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index 594fb5c380..6c335353fd 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -54,32 +54,31 @@ TexMapArray getTexMapArray() { TextureTable(0, matTex); <@if withAlbedo@> -#define albedoMap 1 +#define albedoMap 0 vec4 fetchAlbedoMap(vec2 uv) { return tableTexValue(matTex, albedoMap, uv); } <@endif@> <@if withRoughness@> -#define roughnessMap 3 +#define roughnessMap 4 float fetchRoughnessMap(vec2 uv) { return tableTexValue(matTex, roughnessMap, uv).r; } <@endif@> <@if withNormal@> -#define normalMap 4 +#define normalMap 1 vec3 fetchNormalMap(vec2 uv) { return tableTexValue(matTex, normalMap, uv).xyz; } @@ -93,7 +92,7 @@ float fetchMetallicMap(vec2 uv) { <@endif@> <@if withEmissive@> -#define emissiveMap 0 +#define emissiveMap 3 vec3 fetchEmissiveMap(vec2 uv) { return tableTexValue(matTex, emissiveMap, uv).rgb; } @@ -107,7 +106,7 @@ float fetchOcclusionMap(vec2 uv) { <@endif@> <@if withScattering@> -#define scatteringMap 7 +#define scatteringMap 6 float fetchScatteringMap(vec2 uv) { float scattering = texture(tableTex(matTex, scatteringMap), uv).r; // boolean scattering for now return max(((scattering - 0.1) / 0.9), 0.0); diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index aca8439547..8165e09754 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -612,6 +612,21 @@ void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state) { #include "RenderPipelines.h" #include +#if USE_BINDLESS_TEXTURES +gpu::TextureTablePointer makeTextureTable() { + auto textureCache = DependencyManager::get(); + auto textureTable = std::make_shared(); + textureTable->setTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); + textureTable->setTexture(ShapePipeline::Slot::ROUGHNESS, textureCache->getWhiteTexture()); + textureTable->setTexture(ShapePipeline::Slot::NORMAL, textureCache->getBlueTexture()); + textureTable->setTexture(ShapePipeline::Slot::METALLIC, textureCache->getBlackTexture()); + textureTable->setTexture(ShapePipeline::Slot::OCCLUSION, textureCache->getWhiteTexture()); + textureTable->setTexture(ShapePipeline::Slot::SCATTERING, textureCache->getWhiteTexture()); + textureTable->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); + return textureTable; +} +#endif + void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures) { if (!material) { return; @@ -630,6 +645,86 @@ void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batc numUnlit++; } +#if USE_BINDLESS_TEXTURES + if (!material->getTextureTable()) { + material->setTextureTable(makeTextureTable()); + } + + batch.setResourceTextureTable(material->getTextureTable()); + if (!enableTextures) { + return; + } + + const auto& drawMaterialTextures = material->getTextureTable(); + + // Albedo + if (materialKey.isAlbedoMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView()); + } + } + + // Roughness map + if (materialKey.isRoughnessMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::ROUGHNESS, itr->second->getTextureView()); + } + } + + // Normal map + if (materialKey.isNormalMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::NORMAL, itr->second->getTextureView()); + } + } + + // Metallic map + if (materialKey.isMetallicMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::METALLIC, itr->second->getTextureView()); + } + } + + // Occlusion map + if (materialKey.isOcclusionMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::OCCLUSION, itr->second->getTextureView()); + } + } + + // Scattering map + if (materialKey.isScatteringMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::SCATTERING, itr->second->getTextureView()); + } + } + + // Emissive / Lightmap + if (materialKey.isLightmapMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); + + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture()); + } + } else if (materialKey.isEmissiveMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); + } + } + + +#else if (!enableTextures) { batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); @@ -729,4 +824,5 @@ void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batc batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); } } +#endif } From 09996e0b65c14829283380492e8900bc894aaa6b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 8 Mar 2018 15:54:50 -0800 Subject: [PATCH 10/72] Bindless texture work cleanup --- libraries/gpu-gl/src/gpu/gl/GLBackend.h | 13 +- .../gpu-gl/src/gpu/gl/GLBackendPipeline.cpp | 27 ++- .../gpu-gl/src/gpu/gl/GLBackendShader.cpp | 9 +- libraries/gpu-gl/src/gpu/gl/GLShader.cpp | 2 - libraries/gpu-gl/src/gpu/gl/GLShader.h | 2 - libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 3 - .../src/gpu/gl41/GL41BackendTexture.cpp | 4 - libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 36 ++-- .../src/gpu/gl45/GL45BackendTexture.cpp | 65 ++++--- .../gpu/gl45/GL45BackendVariableTexture.cpp | 21 ++- libraries/gpu/src/gpu/Batch.cpp | 8 +- libraries/gpu/src/gpu/Batch.h | 10 +- libraries/gpu/src/gpu/TextureTable.cpp | 7 +- libraries/gpu/src/gpu/TextureTable.h | 1 + libraries/graphics/src/graphics/Material.h | 9 +- .../render-utils/src/MaterialTextures.slh | 11 +- .../render-utils/src/MeshPartPayload.cpp | 2 - .../render-utils/src/RenderPipelines.cpp | 159 +++--------------- libraries/render-utils/src/RenderPipelines.h | 2 +- 19 files changed, 152 insertions(+), 239 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 35aabef48f..f0f7093845 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -36,7 +36,6 @@ //#define GPU_STEREO_TECHNIQUE_DOUBLED_SMARTER #define GPU_STEREO_TECHNIQUE_INSTANCED - // Let these be configured by the one define picked above #ifdef GPU_STEREO_TECHNIQUE_DOUBLED_SIMPLE #define GPU_STEREO_DRAWCALL_DOUBLED @@ -52,6 +51,8 @@ #define GPU_STEREO_CAMERA_BUFFER #endif +#define GPU_BINDLESS_TEXTURES 0 + namespace gpu { namespace gl { class GLBackend : public Backend, public std::enable_shared_from_this { @@ -132,7 +133,7 @@ public: // Resource Stage virtual void do_setResourceBuffer(const Batch& batch, size_t paramOffset) final; virtual void do_setResourceTexture(const Batch& batch, size_t paramOffset) final; - virtual void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) = 0; + virtual void do_setResourceTextureTable(const Batch& batch, size_t paramOffset); // Pipeline Stage virtual void do_setPipeline(const Batch& batch, size_t paramOffset) final; @@ -229,6 +230,10 @@ protected: void recycle() const override; + // FIXME instead of a single flag, create a features struct similar to + // https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkPhysicalDeviceFeatures.html + virtual bool supportsBindless() const { return false; } + static const size_t INVALID_OFFSET = (size_t)-1; bool _inRenderTransferPass { false }; int32_t _uboAlignment { 0 }; @@ -383,6 +388,10 @@ protected: virtual bool bindResourceBuffer(uint32_t slot, BufferPointer& buffer) = 0; virtual void releaseResourceBuffer(uint32_t slot) = 0; + // Helper function that provides common code used by do_setResourceTexture and + // do_setResourceTextureTable (in non-bindless mode) + void bindResourceTexture(uint32_t slot, const TexturePointer& texture); + // update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s void releaseResourceTexture(uint32_t slot); diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp index 7ef64343ea..03b53bc5cb 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp @@ -1,4 +1,4 @@ -// +// // GLBackendPipeline.cpp // libraries/gpu/src/gpu // @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "GLBackend.h" +#include + #include "GLShared.h" #include "GLPipeline.h" #include "GLShader.h" @@ -247,8 +249,11 @@ void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) { return; } - TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); + const auto& resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); + bindResourceTexture(slot, resourceTexture); +} +void GLBackend::bindResourceTexture(uint32_t slot, const TexturePointer& resourceTexture) { if (!resourceTexture) { releaseResourceTexture(slot); return; @@ -269,11 +274,11 @@ void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) { glActiveTexture(GL_TEXTURE0 + slot); glBindTexture(target, to); - (void) CHECK_GL_ERROR(); + (void)CHECK_GL_ERROR(); _resource._textures[slot] = resourceTexture; - _stats._RSAmountTextureMemoryBounded += (int) object->size(); + _stats._RSAmountTextureMemoryBounded += (int)object->size(); } else { releaseResourceTexture(slot); @@ -281,6 +286,19 @@ void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) { } } +void GLBackend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) { + const auto& textureTablePointer = batch._textureTables.get(batch._params[paramOffset]._uint); + if (!textureTablePointer) { + return; + } + + const auto& textureTable = *textureTablePointer; + const auto& textures = textureTable.getTextures(); + for (GLuint slot = 0; slot < textures.size(); ++slot) { + bindResourceTexture(slot, textures[slot]); + } +} + int GLBackend::ResourceStageState::findEmptyTextureSlot() const { // start from the end of the slots, try to find an empty one that can be used for (auto i = MAX_NUM_RESOURCE_TEXTURES - 1; i > 0; i--) { @@ -290,4 +308,3 @@ int GLBackend::ResourceStageState::findEmptyTextureSlot() const { } return -1; } - diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp index 557591ffb6..e7a64c797e 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp @@ -55,7 +55,6 @@ static const std::string textureTableVersion { "#extension GL_ARB_bindless_texture : require\n#define GPU_TEXTURE_TABLE_BINDLESS\n" }; - // Versions specific of the shader static const std::array VERSION_DEFINES { { "", @@ -70,15 +69,13 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::Co Shader::CompilationLogs compilationLogs(GLShader::NumVersions); shader.incrementCompilationAttempt(); - bool supportTextureTableBindless = true; - for (int version = 0; version < GLShader::NumVersions; version++) { auto& shaderObject = shaderObjects[version]; std::string shaderDefines = getBackendShaderHeader() + "\n" - + (supportTextureTableBindless ? textureTableVersion : "\n") - + DOMAIN_DEFINES[shader.getType()] + "\n" - + VERSION_DEFINES[version]; + + (supportsBindless() ? textureTableVersion : "\n") + + DOMAIN_DEFINES[shader.getType()] + "\n" + + VERSION_DEFINES[version]; if (handler) { bool retest = true; std::string currentSrc = shaderSource; diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp index 7a26642024..010a7c479c 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp @@ -73,9 +73,7 @@ bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::Bin Shader::SlotSet uniforms; Shader::SlotSet textures; - Shader::SlotSet textureTables; Shader::SlotSet samplers; - //backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, textureTables, samplers); backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers); Shader::SlotSet resourceBuffers; diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.h b/libraries/gpu-gl/src/gpu/gl/GLShader.h index b2a1f189a2..3259982e93 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.h +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.h @@ -17,8 +17,6 @@ struct ShaderObject { GLuint glprogram { 0 }; GLint transformCameraSlot { -1 }; GLint transformObjectSlot { -1 }; - GLint resourceTextureTableSlot0 { -1 }; - GLint resourceTextureTableSlot1 { -1 }; }; class GLShader : public GPUObject { diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 1b7882518d..42926fdb1c 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -157,9 +157,6 @@ protected: void resetInputStage() override; void updateInput() override; - // Resource stage - void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) override; - // Synchronize the state cache of this Backend with the actual real state of the GL Context void transferTransformState(const Batch& batch) const override; void initTransform() override; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index 28e474b729..381faf14fc 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -606,7 +606,3 @@ GL41ResourceTexture::GL41ResourceTexture(const std::weak_ptr& backend GL41ResourceTexture::~GL41ResourceTexture() { } - -void GL41Backend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) { - -} diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index e4a96349a9..2271dc6e01 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -19,7 +19,6 @@ #define INCREMENTAL_TRANSFER 0 #define GPU_SSBO_TRANSFORM_OBJECT 1 -#define GPU_BINDLESS_TEXTURES 1 namespace gpu { namespace gl45 { @@ -32,6 +31,9 @@ class GL45Backend : public GLBackend { friend class Context; public: +#if GPU_BINDLESS_TEXTURES + virtual bool supportsBindless() const override { return true; } +#endif #ifdef GPU_SSBO_TRANSFORM_OBJECT static const GLint TRANSFORM_OBJECT_SLOT { 14 }; // SSBO binding slot @@ -60,15 +62,11 @@ public: Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const override; void syncSampler() const override; - bool isBindless() const { #if GPU_BINDLESS_TEXTURES + bool isBindless() const { return _bindless.operator bool(); -#else - return false; -#endif } -#if GPU_BINDLESS_TEXTURES struct Bindless { uint64_t handle{ 0 }; uint32_t minMip{ 0 }; @@ -90,10 +88,9 @@ public: virtual const Bindless& getBindless() const; void releaseBindless() const; void recreateBindless() const; - virtual uint16 getMinMip() const = 0; - - private: + mutable Bindless _bindless; +#endif class InvalidSampler : public Sampler { public: InvalidSampler() { @@ -108,10 +105,6 @@ public: static const Sampler INVALID_SAMPLER; // This stores the texture handle (64 bits) in xy, the min mip available in z, and the sampler ID in w mutable Sampler _cachedSampler{ INVALID_SAMPLER }; - - mutable Bindless _bindless; - -#endif }; #if GPU_BINDLESS_TEXTURES @@ -147,7 +140,6 @@ public: protected: Size size() const override { return _size; } - uint16 getMinMip() const override { return 0; } void allocateStorage() const; void syncSampler() const override; @@ -179,18 +171,18 @@ public: friend class GL45Backend; using PromoteLambda = std::function; - const uvec4& getHandle(); protected: GL45VariableAllocationTexture(const std::weak_ptr& backend, const Texture& texture); ~GL45VariableAllocationTexture(); Size size() const override { return _size; } - uint16 getMinMip() const override { return _populatedMip - _allocatedMip; } - virtual const Bindless& getBindless() const override; Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const override; void copyTextureMipsInGPUMem(GLuint srcId, GLuint destId, uint16_t srcMipOffset, uint16_t destMipOffset, uint16_t populatedMips) override; +#if GPU_BINDLESS_TEXTURES + virtual const Bindless& getBindless() const override; +#endif }; class GL45ResourceTexture : public GL45VariableAllocationTexture { @@ -259,7 +251,6 @@ protected: GLuint getQueryID(const QueryPointer& query) override; GLQuery* syncGPUObject(const Query& query) override; - GL45TextureTable* syncGPUObject(const TextureTablePointer& textureTable); // Draw Stage void do_draw(const Batch& batch, size_t paramOffset) override; @@ -273,9 +264,6 @@ protected: void resetInputStage() override; void updateInput() override; - // Resource stage - void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) override; - // Synchronize the state cache of this Backend with the actual real state of the GL Context void transferTransformState(const Batch& batch) const override; void initTransform() override; @@ -295,6 +283,12 @@ protected: // Texture Management Stage void initTextureManagementStage() override; + +#if GPU_BINDLESS_TEXTURES + GL45TextureTable* syncGPUObject(const TextureTablePointer& textureTable); + // Resource stage + void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) override; +#endif }; } } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index a87999781a..2a35415cc3 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -29,9 +29,6 @@ using namespace gpu::gl; using namespace gpu::gl45; #define MAX_RESOURCE_TEXTURES_PER_FRAME 2 - -#pragma optimize("", off) - #define FORCE_STRICT_TEXTURE 0 #define ENABLE_SPARSE_TEXTURE 0 @@ -243,6 +240,7 @@ Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const return amountCopied; } +#if GPU_BINDLESS_TEXTURES void GL45Texture::releaseBindless() const { // Release the old handler SAMPLER_CACHE.releaseGLSampler(_bindless.sampler); @@ -267,9 +265,10 @@ const GL45Texture::Bindless& GL45Texture::getBindless() const { if (!_bindless) { recreateBindless(); } - _bindless.minMip = getMinMip(); return _bindless; } +#endif + void GL45Texture::syncSampler() const { const Sampler& sampler = _gpuObject.getSampler(); @@ -279,31 +278,33 @@ void GL45Texture::syncSampler() const { _cachedSampler = sampler; +#if GPU_BINDLESS_TEXTURES if (isBindless()) { recreateBindless(); + return; + } +#endif + + const auto& fm = FILTER_MODES[sampler.getFilter()]; + glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); + glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); + + if (sampler.doComparison()) { + glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); + glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); } else { - const auto& fm = FILTER_MODES[sampler.getFilter()]; - glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); - glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); - - if (sampler.doComparison()) { - glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); - glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); - } else { - glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); - } - - glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]); - glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); - glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); - - glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); - glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); - - glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); - glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); } - (void)CHECK_GL_ERROR(); + + glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]); + glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); + glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); + + glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); + glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); + + glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); + glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); } // Fixed allocation textures, used for strict resources & framebuffer attachments @@ -378,6 +379,7 @@ GL45StrictResourceTexture::~GL45StrictResourceTexture() { } // Encapsulate bindless textures +#if GPU_BINDLESS_TEXTURES using GL45TextureTable = GL45Backend::GL45TextureTable; GLuint GL45TextureTable::allocate() { @@ -416,10 +418,14 @@ GL45TextureTable* GL45Backend::syncGPUObject(const TextureTablePointer& textureT const auto& textureTable = *textureTablePointer; // Find the target handles + auto defaultTextures = gpu::TextureTable::getDefault()->getTextures(); auto textures = textureTable.getTextures(); GL45TextureTable::BindlessArray handles{}; for (size_t i = 0; i < textures.size(); ++i) { auto texture = textures[i]; + if (!texture) { + texture = defaultTextures[i]; + } if (!texture) { continue; } @@ -444,10 +450,15 @@ GL45TextureTable* GL45Backend::syncGPUObject(const TextureTablePointer& textureT } void GL45Backend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) { - auto textureTable = batch._textureTables.get(batch._params[paramOffset]._uint); + auto textureTablePointer = batch._textureTables.get(batch._params[paramOffset]._uint); + if (!textureTablePointer) { + return; + } + auto slot = batch._params[paramOffset + 1]._uint; - GL45TextureTable* glTextureTable = syncGPUObject(textureTable); + GL45TextureTable* glTextureTable = syncGPUObject(textureTablePointer); if (glTextureTable) { glBindBufferBase(GL_UNIFORM_BUFFER, slot + GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET, glTextureTable->_id); } } +#endif diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp index 293b34fb39..aaeb786c51 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp @@ -41,11 +41,16 @@ GL45VariableAllocationTexture::~GL45VariableAllocationTexture() { Backend::textureResourcePopulatedGPUMemSize.update(_populatedSize, 0); } +#if GPU_BINDLESS_TEXTURES const GL45Texture::Bindless& GL45VariableAllocationTexture::getBindless() const { - auto& result = Parent::getBindless(); + // The parent call may re-initialize the _bindless member, so we need to call it first + const auto& result = Parent::getBindless(); + // Make sure the referenced structure has the correct minimum available mip value _bindless.minMip = _populatedMip - _allocatedMip; + // Now return the result return result; } +#endif Size GL45VariableAllocationTexture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const { Size amountCopied = 0; @@ -134,9 +139,13 @@ Size GL45ResourceTexture::copyMipsFromTexture() { void GL45ResourceTexture::syncSampler() const { Parent::syncSampler(); +#if GPU_BINDLESS_TEXTURES if (!isBindless()) { glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip); } +#else + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip); +#endif } void GL45ResourceTexture::promote() { @@ -146,10 +155,12 @@ void GL45ResourceTexture::promote() { uint16_t targetAllocatedMip = _allocatedMip - std::min(_allocatedMip, 2); targetAllocatedMip = std::max(_minAllocatedMip, targetAllocatedMip); +#if GPU_BINDLESS_TEXTURES bool bindless = isBindless(); if (bindless) { releaseBindless(); } +#endif GLuint oldId = _id; auto oldSize = _size; @@ -164,14 +175,17 @@ void GL45ResourceTexture::promote() { // copy pre-existing mips copyTextureMipsInGPUMem(oldId, _id, oldAllocatedMip, _allocatedMip, _populatedMip); +#if GPU_BINDLESS_TEXTURES if (bindless) { getBindless(); } +#endif // destroy the old texture glDeleteTextures(1, &oldId); // Update sampler + _cachedSampler = InvalidSampler(); syncSampler(); // update the memory usage @@ -188,10 +202,12 @@ void GL45ResourceTexture::demote() { auto oldSize = _size; auto oldPopulatedMip = _populatedMip; +#if GPU_BINDLESS_TEXTURES bool bindless = isBindless(); if (bindless) { releaseBindless(); } +#endif // allocate new texture const_cast(_id) = allocate(_gpuObject); @@ -202,14 +218,17 @@ void GL45ResourceTexture::demote() { // copy pre-existing mips copyTextureMipsInGPUMem(oldId, _id, oldAllocatedMip, _allocatedMip, _populatedMip); +#if GPU_BINDLESS_TEXTURES if (bindless) { getBindless(); } +#endif // destroy the old texture glDeleteTextures(1, &oldId); // Update sampler + _cachedSampler = InvalidSampler(); syncSampler(); // update the memory usage diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 45d86757df..550175ef75 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -325,16 +325,16 @@ void Batch::setResourceTexture(uint32 slot, const TexturePointer& texture) { _params.emplace_back(slot); } +void Batch::setResourceTexture(uint32 slot, const TextureView& view) { + setResourceTexture(slot, view._texture); +} + void Batch::setResourceTextureTable(const TextureTablePointer& textureTable, uint32 slot) { ADD_COMMAND(setResourceTextureTable); _params.emplace_back(_textureTables.cache(textureTable)); _params.emplace_back(slot); } -void Batch::setResourceTexture(uint32 slot, const TextureView& view) { - setResourceTexture(slot, view._texture); -} - void Batch::setFramebuffer(const FramebufferPointer& framebuffer) { ADD_COMMAND(setFramebuffer); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 8eb769a6fe..2db1b9b420 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -30,11 +30,6 @@ class QDebug; namespace gpu { enum ReservedSlot { -#ifdef GPU_SSBO_DRAW_CALL_INFO - TRANSFORM_OBJECT_SLOT = 14, -#else - TRANSFORM_OBJECT_SLOT = 31, -#endif TRANSFORM_CAMERA_SLOT = 15, }; @@ -409,9 +404,10 @@ public: return offset; } - Data get(uint32 offset) const { + const Data& get(uint32 offset) const { if (offset >= _items.size()) { - return Data(); + static const Data EMPTY; + return EMPTY; } return (_items.data() + offset)->_data; } diff --git a/libraries/gpu/src/gpu/TextureTable.cpp b/libraries/gpu/src/gpu/TextureTable.cpp index 17a9e87f3e..40f3decc83 100644 --- a/libraries/gpu/src/gpu/TextureTable.cpp +++ b/libraries/gpu/src/gpu/TextureTable.cpp @@ -8,6 +8,7 @@ #include "TextureTable.h" #include "Texture.h" +#include using namespace gpu; TextureTable::TextureTable() { } @@ -42,7 +43,9 @@ void TextureTable::setTexture(size_t index, const TextureView& textureView) { TextureTable::Array TextureTable::getTextures() const { Array result; - Lock lock(_mutex); - result = _textures; + { + Lock lock(_mutex); + result = _textures; + } return result; } diff --git a/libraries/gpu/src/gpu/TextureTable.h b/libraries/gpu/src/gpu/TextureTable.h index 4307e60adb..02b777bbd6 100644 --- a/libraries/gpu/src/gpu/TextureTable.h +++ b/libraries/gpu/src/gpu/TextureTable.h @@ -30,6 +30,7 @@ public: Array getTextures() const; Stamp getStamp() const { return _stamp; } + private: mutable Mutex _mutex; Array _textures; diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index d31a0cbd31..4ebf0eb1db 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -24,8 +24,6 @@ class Transform; -#define USE_BINDLESS_TEXTURES 1 - namespace graphics { class TextureMap; @@ -363,10 +361,7 @@ public: void setModel(const std::string& model) { _model = model; } -#if USE_BINDLESS_TEXTURES const gpu::TextureTablePointer& getTextureTable() const { return _textureTable; } - void setTextureTable(const gpu::TextureTablePointer& textureTable) { _textureTable = textureTable; } -#endif protected: std::string _name { "" }; @@ -375,9 +370,7 @@ private: mutable MaterialKey _key; mutable UniformBufferView _schemaBuffer; mutable UniformBufferView _texMapArrayBuffer; -#if USE_BINDLESS_TEXTURES - mutable gpu::TextureTablePointer _textureTable; -#endif + mutable gpu::TextureTablePointer _textureTable{ std::make_shared() }; TextureMaps _textureMaps; diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index 6c335353fd..d9d2cb2e47 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -48,10 +48,10 @@ TexMapArray getTexMapArray() { <@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion, withScattering)@> - - <@include gpu/TextureTable.slh@> +#ifdef GPU_TEXTURE_TABLE_BINDLESS + TextureTable(0, matTex); - +#else <@if withAlbedo@> uniform sampler2D albedoMap; @@ -170,8 +169,8 @@ float fetchScatteringMap(vec2 uv) { return texture(scatteringMap, uv).r; // boolean scattering for now } <@endif@> -<@endif@> -!> + +#endif <@endfunc@> diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index e4d71b98ee..6dfc099284 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -14,8 +14,6 @@ #include #include -#include - #include "DeferredLightingEffect.h" #include "RenderPipelines.h" diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 8165e09754..ef4b0a5683 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -612,22 +612,8 @@ void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state) { #include "RenderPipelines.h" #include -#if USE_BINDLESS_TEXTURES -gpu::TextureTablePointer makeTextureTable() { - auto textureCache = DependencyManager::get(); - auto textureTable = std::make_shared(); - textureTable->setTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); - textureTable->setTexture(ShapePipeline::Slot::ROUGHNESS, textureCache->getWhiteTexture()); - textureTable->setTexture(ShapePipeline::Slot::NORMAL, textureCache->getBlueTexture()); - textureTable->setTexture(ShapePipeline::Slot::METALLIC, textureCache->getBlackTexture()); - textureTable->setTexture(ShapePipeline::Slot::OCCLUSION, textureCache->getWhiteTexture()); - textureTable->setTexture(ShapePipeline::Slot::SCATTERING, textureCache->getWhiteTexture()); - textureTable->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); - return textureTable; -} -#endif - -void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures) { +// FIXME find a better way to setup the default textures +void RenderPipelines::bindMaterial(const graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures) { if (!material) { return; } @@ -645,63 +631,65 @@ void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batc numUnlit++; } -#if USE_BINDLESS_TEXTURES - if (!material->getTextureTable()) { - material->setTextureTable(makeTextureTable()); - } - - batch.setResourceTextureTable(material->getTextureTable()); - if (!enableTextures) { - return; - } - const auto& drawMaterialTextures = material->getTextureTable(); // Albedo if (materialKey.isAlbedoMap()) { auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); } } // Roughness map if (materialKey.isRoughnessMap()) { auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::ROUGHNESS, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::ROUGHNESS, textureCache->getWhiteTexture()); } } // Normal map if (materialKey.isNormalMap()) { auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::NORMAL, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::NORMAL, textureCache->getBlueTexture()); } } // Metallic map if (materialKey.isMetallicMap()) { auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::METALLIC, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::METALLIC, textureCache->getBlackTexture()); } } // Occlusion map if (materialKey.isOcclusionMap()) { auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::OCCLUSION, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::OCCLUSION, textureCache->getWhiteTexture()); } } // Scattering map if (materialKey.isScatteringMap()) { auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::SCATTERING, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::SCATTERING, textureCache->getWhiteTexture()); } } @@ -709,120 +697,19 @@ void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batc if (materialKey.isLightmapMap()) { auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); } else { drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture()); } } else if (materialKey.isEmissiveMap()) { auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); } else { drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); } } - -#else - if (!enableTextures) { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); - return; - } - - // Albedo - if (materialKey.isAlbedoMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture()); - } - } - - // Roughness map - if (materialKey.isRoughnessMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); - } - } - - // Normal map - if (materialKey.isNormalMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); - } - } - - // Metallic map - if (materialKey.isMetallicMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); - } - } - - // Occlusion map - if (materialKey.isOcclusionMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); - } - } - - // Scattering map - if (materialKey.isScatteringMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); - } - } - - // Emissive / Lightmap - if (materialKey.isLightmapMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); - - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture()); - } - } else if (materialKey.isEmissiveMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); - - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); - } - } -#endif + batch.setResourceTextureTable(material->getTextureTable()); } diff --git a/libraries/render-utils/src/RenderPipelines.h b/libraries/render-utils/src/RenderPipelines.h index 9b9ad2c001..b7d22bc72d 100644 --- a/libraries/render-utils/src/RenderPipelines.h +++ b/libraries/render-utils/src/RenderPipelines.h @@ -15,7 +15,7 @@ class RenderPipelines { public: - static void bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures); + static void bindMaterial(const graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures); }; From 2598be16f81734e86e00f2789bc2111bcdf448b8 Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Sat, 10 Mar 2018 21:46:20 -0800 Subject: [PATCH 11/72] Updating default mouse pitch/yaw input to be more stabilized --- interface/src/avatar/MyAvatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b6fa3fde96..5b49fcd11c 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -67,8 +67,8 @@ using namespace std; const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.0f; -const float YAW_SPEED_DEFAULT = 100.0f; // degrees/sec -const float PITCH_SPEED_DEFAULT = 75.0f; // degrees/sec +const float YAW_SPEED_DEFAULT = 75.0f; // degrees/sec +const float PITCH_SPEED_DEFAULT = 50.0f; // degrees/sec const float MAX_BOOST_SPEED = 0.5f * DEFAULT_AVATAR_MAX_WALKING_SPEED; // action motor gets additive boost below this speed const float MIN_AVATAR_SPEED = 0.05f; From 748507f1e357b7a03177f847c63362297de9663e Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Sat, 10 Mar 2018 22:20:00 -0800 Subject: [PATCH 12/72] Increasing speed on mousescroll - zooming in/out of avatar --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5b49fcd11c..8bbbef041a 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2229,7 +2229,7 @@ void MyAvatar::updateActionMotor(float deltaTime) { } float boomChange = getDriveKey(ZOOM); - _boomLength += 2.0f * _boomLength * boomChange + boomChange * boomChange; + _boomLength += 4.0f * _boomLength * boomChange + boomChange * boomChange; _boomLength = glm::clamp(_boomLength, ZOOM_MIN, ZOOM_MAX); } From c793a8d2c0bf7304a06e4e2b315e7fe03101f3a0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 12 Mar 2018 12:28:12 -0700 Subject: [PATCH 13/72] Move bindless compile time flag to GL45 backend, fix warnings and compile errors --- libraries/gpu-gl-common/src/gpu/gl/GLBackend.h | 2 -- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 14 +++----------- .../gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 13 ++++++++++++- .../src/gpu/gl45/GL45BackendVariableTexture.cpp | 4 ++-- libraries/gpu/src/gpu/TextureTable.cpp | 5 ++++- libraries/gpu/src/gpu/TextureTable.h | 10 ++++++---- 6 files changed, 27 insertions(+), 21 deletions(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 0d85ca6789..feff3e2710 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -55,8 +55,6 @@ #define GPU_STEREO_CAMERA_BUFFER #endif -#define GPU_BINDLESS_TEXTURES 0 - namespace gpu { namespace gl { class GLBackend : public Backend, public std::enable_shared_from_this { diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 22b5ad87e0..c23a83eaf9 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -20,6 +20,7 @@ #define INCREMENTAL_TRANSFER 0 #define GPU_SSBO_TRANSFORM_OBJECT 1 +#define GPU_BINDLESS_TEXTURES 0 namespace gpu { namespace gl45 { @@ -92,20 +93,11 @@ public: private: mutable Bindless _bindless; #endif - class InvalidSampler : public Sampler { - public: - InvalidSampler() { - _desc._borderColor = vec4(-1.0f); - } - operator const Sampler&() const { - return *this; - } - }; + static Sampler getInvalidSampler(); - static const Sampler INVALID_SAMPLER; // This stores the texture handle (64 bits) in xy, the min mip available in z, and the sampler ID in w - mutable Sampler _cachedSampler{ INVALID_SAMPLER }; + mutable Sampler _cachedSampler{ getInvalidSampler() }; }; #if GPU_BINDLESS_TEXTURES diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 3791a9802b..5a5d701150 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -163,7 +163,18 @@ private: }; static GLSamplerCache SAMPLER_CACHE; -const Sampler GL45Texture::INVALID_SAMPLER = GL45Texture::InvalidSampler(); + + +Sampler GL45Texture::getInvalidSampler() { + static Sampler INVALID_SAMPLER; + static std::once_flag once; + std::call_once(once, [] { + Sampler::Desc invalidDesc; + invalidDesc._borderColor = vec4(-1.0f); + INVALID_SAMPLER = Sampler(invalidDesc); + }); + return INVALID_SAMPLER; +} GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture) : GLTexture(backend, texture, allocate(texture)) { diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp index 150ea7a488..08d077605d 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp @@ -185,7 +185,7 @@ void GL45ResourceTexture::promote() { glDeleteTextures(1, &oldId); // Update sampler - _cachedSampler = InvalidSampler(); + _cachedSampler = getInvalidSampler(); syncSampler(); // update the memory usage @@ -228,7 +228,7 @@ void GL45ResourceTexture::demote() { glDeleteTextures(1, &oldId); // Update sampler - _cachedSampler = InvalidSampler(); + _cachedSampler = getInvalidSampler(); syncSampler(); // update the memory usage diff --git a/libraries/gpu/src/gpu/TextureTable.cpp b/libraries/gpu/src/gpu/TextureTable.cpp index 40f3decc83..0c3a43808b 100644 --- a/libraries/gpu/src/gpu/TextureTable.cpp +++ b/libraries/gpu/src/gpu/TextureTable.cpp @@ -11,6 +11,9 @@ #include using namespace gpu; + +const size_t TextureTable::COUNT{ TEXTURE_TABLE_COUNT }; + TextureTable::TextureTable() { } TextureTable::TextureTable(const std::initializer_list& textures) { @@ -23,7 +26,7 @@ TextureTable::TextureTable(const std::initializer_list& textures } } -TextureTable::TextureTable(const std::array& textures) : _stamp(1), _textures(textures) { +TextureTable::TextureTable(const Array& textures) : _textures(textures) { } void TextureTable::setTexture(size_t index, const TexturePointer& texturePointer) { diff --git a/libraries/gpu/src/gpu/TextureTable.h b/libraries/gpu/src/gpu/TextureTable.h index 02b777bbd6..794b8535d0 100644 --- a/libraries/gpu/src/gpu/TextureTable.h +++ b/libraries/gpu/src/gpu/TextureTable.h @@ -12,15 +12,17 @@ #include +#define TEXTURE_TABLE_COUNT 8 + namespace gpu { class TextureTable { public: - static const size_t COUNT = 8; - using Array = std::array; + static const size_t COUNT; + using Array = std::array; TextureTable(); TextureTable(const std::initializer_list& textures); - TextureTable(const std::array& textures); + TextureTable(const Array& textures); // Only for gpu::Context const GPUObjectPointer gpuObject{}; @@ -34,7 +36,7 @@ public: private: mutable Mutex _mutex; Array _textures; - Stamp _stamp{ 0 }; + Stamp _stamp{ 1 }; }; } From c385bf26e937adf235dbaee02031a4ade481b438 Mon Sep 17 00:00:00 2001 From: vladest Date: Thu, 15 Mar 2018 19:43:00 +0100 Subject: [PATCH 14/72] Do not use timer for switching bubble button active state --- scripts/system/bubble.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/scripts/system/bubble.js b/scripts/system/bubble.js index 994bde49eb..f1a403a49c 100644 --- a/scripts/system/bubble.js +++ b/scripts/system/bubble.js @@ -89,14 +89,8 @@ bubbleOverlayTimestamp = nowTimestamp; Script.update.connect(update); updateConnected = true; - - // Flash button - if (!bubbleFlashTimer) { - bubbleFlashTimer = Script.setInterval(function () { - writeButtonProperties(bubbleButtonFlashState); - bubbleButtonFlashState = !bubbleButtonFlashState; - }, 500); - } + writeButtonProperties(bubbleButtonFlashState); + bubbleButtonFlashState = !bubbleButtonFlashState; } // Called from the C++ scripting interface to show the bubble overlay From 0d6e8f349096b2b4265a9806413a2791f0f23388 Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Fri, 16 Mar 2018 11:39:02 -0700 Subject: [PATCH 15/72] Revert "Update repo script with marketplace script" This reverts commit 5139f3f50328c0299801906ba435d5e1528c72f8. --- scripts/tutorials/entity_scripts/sit.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/scripts/tutorials/entity_scripts/sit.js b/scripts/tutorials/entity_scripts/sit.js index 9de65d7037..70456ea493 100644 --- a/scripts/tutorials/entity_scripts/sit.js +++ b/scripts/tutorials/entity_scripts/sit.js @@ -12,9 +12,9 @@ Script.include("/~/system/libraries/utils.js"); if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position){ - position = position || 0; - return this.substr(position, searchString.length) === searchString; - }; + position = position || 0; + return this.substr(position, searchString.length) === searchString; + }; } var SETTING_KEY = "com.highfidelity.avatar.isSitting"; @@ -122,10 +122,20 @@ this.rolesToOverride = function() { return MyAvatar.getAnimationRoles().filter(function(role) { - return !(role.startsWith("right") || role.startsWith("left")); + return !(role.startsWith("right") || role.startsWith("left")); }); } + // Handler for user changing the avatar model while sitting. There's currently an issue with changing avatar models while override role animations are applied, + // so to avoid that problem, re-apply the role overrides once the model has finished changing. + this.modelURLChangeFinished = function () { + print("Sitter's model has FINISHED changing. Reapply anim role overrides."); + var roles = this.rolesToOverride(); + for (i in roles) { + MyAvatar.overrideRoleAnimation(roles[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME); + } + } + this.sitDown = function() { if (this.checkSeatForAvatar()) { print("Someone is already sitting in that chair."); @@ -164,12 +174,14 @@ return { headType: 0 }; }, ["headType"]); Script.update.connect(this, this.update); + MyAvatar.onLoadComplete.connect(this, this.modelURLChangeFinished); } this.standUp = function() { print("Standing up (" + this.entityID + ")"); MyAvatar.removeAnimationStateHandler(this.animStateHandlerID); Script.update.disconnect(this, this.update); + MyAvatar.onLoadComplete.disconnect(this, this.modelURLChangeFinished); if (MyAvatar.sessionUUID === this.getSeatUser()) { this.setSeatUser(null); @@ -331,7 +343,7 @@ } this.cleanupOverlay(); } - + this.clickDownOnEntity = function (id, event) { if (isInEditMode()) { return; @@ -340,4 +352,4 @@ this.sitDown(); } } -}); \ No newline at end of file +}); From 69f462baeb79dc6d1c3dc36dfad84c68ff1adfdc Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 19 Mar 2018 18:53:00 -0700 Subject: [PATCH 16/72] Disable elbow pole vectors, solve from joint limit centers. --- libraries/animation/src/Rig.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 848f384687..7996c3372c 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1246,6 +1246,7 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab const FBXJointShapeInfo& hipsShapeInfo, const FBXJointShapeInfo& spineShapeInfo, const FBXJointShapeInfo& spine1ShapeInfo, const FBXJointShapeInfo& spine2ShapeInfo) { + const bool ENABLE_POLE_VECTORS = false; const float ELBOW_POLE_VECTOR_BLEND_FACTOR = 0.95f; int hipsIndex = indexOfJoint("Hips"); @@ -1268,7 +1269,7 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab int handJointIndex = _animSkeleton->nameToJointIndex("LeftHand"); int armJointIndex = _animSkeleton->nameToJointIndex("LeftArm"); int elbowJointIndex = _animSkeleton->nameToJointIndex("LeftForeArm"); - if (!leftArmEnabled && handJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) { + if (ENABLE_POLE_VECTORS && !leftArmEnabled && handJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) { glm::vec3 poleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, hipsIndex, true); // smooth toward desired pole vector from previous pole vector... to reduce jitter @@ -1315,7 +1316,7 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab int handJointIndex = _animSkeleton->nameToJointIndex("RightHand"); int armJointIndex = _animSkeleton->nameToJointIndex("RightArm"); int elbowJointIndex = _animSkeleton->nameToJointIndex("RightForeArm"); - if (!rightArmEnabled && handJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) { + if (ENABLE_POLE_VECTORS && !rightArmEnabled && handJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) { glm::vec3 poleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, hipsIndex, false); // smooth toward desired pole vector from previous pole vector... to reduce jitter @@ -1555,18 +1556,16 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo updateFeet(leftFootEnabled, rightFootEnabled, params.primaryControllerPoses[PrimaryControllerType_LeftFoot], params.primaryControllerPoses[PrimaryControllerType_RightFoot]); + + // Always relax IK chains toward joint limit centers. + _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToLimitCenterPoses); + // if the hips or the feet are being controlled. if (hipsEnabled || rightFootEnabled || leftFootEnabled) { - // for more predictable IK solve from the center of the joint limits, not from the underpose - _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToLimitCenterPoses); - // replace the feet animation with the default pose, this is to prevent unexpected toe wiggling. _animVars.set("defaultPoseOverlayAlpha", 1.0f); _animVars.set("defaultPoseOverlayBoneSet", (int)AnimOverlay::BothFeetBoneSet); } else { - // augment the IK with the underPose. - _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToUnderPoses); - // feet should follow source animation _animVars.unset("defaultPoseOverlayAlpha"); _animVars.unset("defaultPoseOverlayBoneSet"); From faf8328d6aeef60da16ee1b09a9d89b873adfbba Mon Sep 17 00:00:00 2001 From: vladest Date: Tue, 20 Mar 2018 15:47:30 +0100 Subject: [PATCH 17/72] Fix invalid message if cancel adding asset to AssetServer --- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 4bc8ec0bd3..4a6b0e9548 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -80,7 +80,7 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, auto result = offscreenUi->inputDialog(OffscreenUi::ICON_INFORMATION, "Specify Asset Path", dropEvent ? dropHelpText : helpText, mapping); - if (!result.isValid()) { + if (!result.isValid() || result.toString() == "") { completedCallback.call({ -1 }); return; } From 143a315f1d1ee4a8bc5ded4add1c89744d8745e7 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 20 Mar 2018 15:29:50 -0700 Subject: [PATCH 18/72] Fade edited objects are now selected with ray picking --- .../scripting/SelectionScriptingInterface.cpp | 22 ++++- .../scripting/SelectionScriptingInterface.h | 27 ++++- libraries/render-utils/src/FadeEffectJobs.cpp | 99 ++++++++----------- libraries/render-utils/src/FadeEffectJobs.h | 1 - .../utilities/render/debugTransition.js | 50 +++++++++- 5 files changed, 137 insertions(+), 62 deletions(-) diff --git a/interface/src/scripting/SelectionScriptingInterface.cpp b/interface/src/scripting/SelectionScriptingInterface.cpp index 233e61c8ae..f8a62e848c 100644 --- a/interface/src/scripting/SelectionScriptingInterface.cpp +++ b/interface/src/scripting/SelectionScriptingInterface.cpp @@ -110,7 +110,6 @@ bool SelectionScriptingInterface::enableListHighlight(const QString& listName, c } if (!(*highlightStyle).isBoundToList()) { - setupHandler(listName); (*highlightStyle).setBoundToList(true); } @@ -172,6 +171,18 @@ render::HighlightStyle SelectionScriptingInterface::getHighlightStyle(const QStr } } +bool SelectionScriptingInterface::enableListToScene(const QString& listName) { + setupHandler(listName); + + return true; +} + +bool SelectionScriptingInterface::disableListToScene(const QString& listName) { + removeHandler(listName); + + return true; +} + template bool SelectionScriptingInterface::addToGameplayObjects(const QString& listName, T idToAdd) { { QWriteLocker lock(&_selectionListsLock); @@ -303,6 +314,15 @@ void SelectionScriptingInterface::setupHandler(const QString& selectionName) { (*handler)->initialize(selectionName); } +void SelectionScriptingInterface::removeHandler(const QString& selectionName) { + QWriteLocker lock(&_selectionHandlersLock); + auto handler = _handlerMap.find(selectionName); + if (handler != _handlerMap.end()) { + delete handler.value(); + _handlerMap.erase(handler); + } +} + void SelectionScriptingInterface::onSelectedItemsListChanged(const QString& listName) { { QWriteLocker lock(&_selectionHandlersLock); diff --git a/interface/src/scripting/SelectionScriptingInterface.h b/interface/src/scripting/SelectionScriptingInterface.h index 8295375870..3046ac371e 100644 --- a/interface/src/scripting/SelectionScriptingInterface.h +++ b/interface/src/scripting/SelectionScriptingInterface.h @@ -160,13 +160,14 @@ public: * If the Selection doesn't exist, it will be created. * All objects in the list will be displayed with the highlight effect as specified from the highlightStyle. * The function can be called several times with different values in the style to modify it. - * + * * @function Selection.enableListHighlight * @param listName {string} name of the selection * @param highlightStyle {jsObject} highlight style fields (see Selection.getListHighlightStyle for a detailed description of the highlightStyle). * @returns {bool} true if the selection was successfully enabled for highlight. */ Q_INVOKABLE bool enableListHighlight(const QString& listName, const QVariantMap& highlightStyle); + /**jsdoc * Disable highlighting for the named selection. * If the Selection doesn't exist or wasn't enabled for highliting then nothing happens simply returning false. @@ -175,7 +176,27 @@ public: * @param listName {string} name of the selection * @returns {bool} true if the selection was successfully disabled for highlight, false otherwise. */ - Q_INVOKABLE bool disableListHighlight(const QString& listName); + Q_INVOKABLE bool disableListHighlight(const QString& listName); + /**jsdoc + * Enable scene selection for the named selection. + * If the Selection doesn't exist, it will be created. + * All objects in the list will be sent to a scene selection. + * + * @function Selection.enableListToScene + * @param listName {string} name of the selection + * @returns {bool} true if the selection was successfully enabled on the scene. + */ + Q_INVOKABLE bool enableListToScene(const QString& listName); + /**jsdoc + * Disable scene selection for the named selection. + * If the Selection doesn't exist or wasn't enabled on the scene then nothing happens simply returning false. + * + * @function Selection.disableListToScene + * @param listName {string} name of the selection + * @returns {bool} true if the selection was successfully disabled on the scene, false otherwise. + */ + Q_INVOKABLE bool disableListToScene(const QString& listName); + /**jsdoc * Query the highlight style values for the named selection. * If the Selection doesn't exist or hasn't been highlight enabled yet, it will return an empty object. @@ -223,7 +244,7 @@ private: template bool removeFromGameplayObjects(const QString& listName, T idToRemove); void setupHandler(const QString& selectionName); - + void removeHandler(const QString& selectionName); }; diff --git a/libraries/render-utils/src/FadeEffectJobs.cpp b/libraries/render-utils/src/FadeEffectJobs.cpp index da3f8dddc0..e6de306c6d 100644 --- a/libraries/render-utils/src/FadeEffectJobs.cpp +++ b/libraries/render-utils/src/FadeEffectJobs.cpp @@ -39,43 +39,52 @@ void FadeEditJob::run(const render::RenderContextPointer& renderContext, const F auto scene = renderContext->_scene; if (_isEditEnabled) { - float minIsectDistance = std::numeric_limits::max(); - auto& itemBounds = inputs.get0(); - auto editedItem = findNearestItem(renderContext, itemBounds, minIsectDistance); - render::Transaction transaction; - bool hasTransaction{ false }; + static const std::string selectionName("TransitionEdit"); + auto scene = renderContext->_scene; + if (!scene->isSelectionEmpty(selectionName)) { + auto selection = scene->getSelection(selectionName); + auto editedItem = selection.getItems().front(); + render::Transaction transaction; + bool hasTransaction{ false }; - if (editedItem != _editedItem && render::Item::isValidID(_editedItem)) { - // Remove transition from previously edited item as we've changed edited item - hasTransaction = true; + if (editedItem != _editedItem && render::Item::isValidID(_editedItem)) { + // Remove transition from previously edited item as we've changed edited item + hasTransaction = true; + transaction.removeTransitionFromItem(_editedItem); + } + _editedItem = editedItem; + + if (render::Item::isValidID(_editedItem)) { + static const render::Transition::Type categoryToTransition[FADE_CATEGORY_COUNT] = { + render::Transition::ELEMENT_ENTER_DOMAIN, + render::Transition::BUBBLE_ISECT_OWNER, + render::Transition::BUBBLE_ISECT_TRESPASSER, + render::Transition::USER_ENTER_DOMAIN, + render::Transition::AVATAR_CHANGE + }; + + auto transitionType = categoryToTransition[inputs.get1()]; + + transaction.queryTransitionOnItem(_editedItem, [transitionType, scene](render::ItemID id, const render::Transition* transition) { + if (transition == nullptr || transition->isFinished || transition->eventType != transitionType) { + // Relaunch transition + render::Transaction transaction; + transaction.addTransitionToItem(id, transitionType); + scene->enqueueTransaction(transaction); + } + }); + hasTransaction = true; + } + + if (hasTransaction) { + scene->enqueueTransaction(transaction); + } + } else if (render::Item::isValidID(_editedItem)) { + // Remove transition from previously edited item as we've disabled fade edition + render::Transaction transaction; transaction.removeTransitionFromItem(_editedItem); - } - _editedItem = editedItem; - - if (render::Item::isValidID(_editedItem)) { - static const render::Transition::Type categoryToTransition[FADE_CATEGORY_COUNT] = { - render::Transition::ELEMENT_ENTER_DOMAIN, - render::Transition::BUBBLE_ISECT_OWNER, - render::Transition::BUBBLE_ISECT_TRESPASSER, - render::Transition::USER_ENTER_DOMAIN, - render::Transition::AVATAR_CHANGE - }; - - auto transitionType = categoryToTransition[inputs.get1()]; - - transaction.queryTransitionOnItem(_editedItem, [transitionType, scene](render::ItemID id, const render::Transition* transition) { - if (transition == nullptr || transition->isFinished || transition->eventType!=transitionType) { - // Relaunch transition - render::Transaction transaction; - transaction.addTransitionToItem(id, transitionType); - scene->enqueueTransaction(transaction); - } - }); - hasTransaction = true; - } - - if (hasTransaction) { scene->enqueueTransaction(transaction); + _editedItem = render::Item::INVALID_ITEM_ID; } } else if (render::Item::isValidID(_editedItem)) { @@ -87,28 +96,6 @@ void FadeEditJob::run(const render::RenderContextPointer& renderContext, const F } } -render::ItemID FadeEditJob::findNearestItem(const render::RenderContextPointer& renderContext, const render::ItemBounds& inputs, float& minIsectDistance) const { - const glm::vec3 rayOrigin = renderContext->args->getViewFrustum().getPosition(); - const glm::vec3 rayDirection = renderContext->args->getViewFrustum().getDirection(); - BoxFace face; - glm::vec3 normal; - float isectDistance; - render::ItemID nearestItem = render::Item::INVALID_ITEM_ID; - const float minDistance = 1.f; - const float maxDistance = 50.f; - - for (const auto& itemBound : inputs) { - if (!itemBound.bound.contains(rayOrigin) && itemBound.bound.findRayIntersection(rayOrigin, rayDirection, isectDistance, face, normal)) { - auto& item = renderContext->_scene->getItem(itemBound.id); - if (item.getKey().isWorldSpace() && isectDistance>minDistance && isectDistance < minIsectDistance && isectDistance Date: Tue, 20 Mar 2018 17:48:41 -0700 Subject: [PATCH 19/72] Proposal to improve fade editing with some extra visual cues --- libraries/render-utils/src/FadeEffectJobs.cpp | 2 +- .../utilities/render/debugTransition.js | 80 ++++++++++++++++++- .../developer/utilities/render/transition.qml | 5 +- 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/FadeEffectJobs.cpp b/libraries/render-utils/src/FadeEffectJobs.cpp index e6de306c6d..a55fb304dd 100644 --- a/libraries/render-utils/src/FadeEffectJobs.cpp +++ b/libraries/render-utils/src/FadeEffectJobs.cpp @@ -581,7 +581,7 @@ void FadeJob::run(const render::RenderContextPointer& renderContext, FadeJob::Ou if (update(*jobConfig, scene, transaction, state, deltaTime)) { hasTransaction = true; } - if (isFirstItem && jobConfig->manualFade && (state.threshold != jobConfig->threshold)) { + if (isFirstItem && (state.threshold != jobConfig->threshold)) { jobConfig->setProperty("threshold", state.threshold); isFirstItem = false; } diff --git a/scripts/developer/utilities/render/debugTransition.js b/scripts/developer/utilities/render/debugTransition.js index 2cb48b7e2a..cef6e84268 100644 --- a/scripts/developer/utilities/render/debugTransition.js +++ b/scripts/developer/utilities/render/debugTransition.js @@ -66,7 +66,81 @@ wireEventBridge(onScreen); } + var isEditEnabled = false + var noiseSphere + var gradientSphere + var selectedEntity + var editedCategory + + var FADE_MIN_SCALE = 0.001 + var FADE_MAX_SCALE = 10000.0 + + function parameterToValuePow(parameter, minValue, maxOverMinValue) { + return minValue * Math.pow(maxOverMinValue, parameter); + //return parameter + } + + function update(dt) { + var gradientProperties = Entities.getEntityProperties(selectedEntity, ["position", "dimensions"]); + if (gradientProperties!=undefined) { + var pos = gradientProperties.position + if (pos!=undefined) { + var config = Render.getConfig("RenderMainView.Fade") + //print("Center at "+pos.x+" "+pos.y+" "+pos.z) + var dim = {x:config.baseSizeX, y:config.baseSizeY, z:config.baseSizeZ} + dim.x = parameterToValuePow(dim.x, FADE_MIN_SCALE, FADE_MAX_SCALE/ FADE_MIN_SCALE) + dim.y = parameterToValuePow(dim.y, FADE_MIN_SCALE, FADE_MAX_SCALE/ FADE_MIN_SCALE) + dim.z = parameterToValuePow(dim.z, FADE_MIN_SCALE, FADE_MAX_SCALE/ FADE_MIN_SCALE) + if (editedCategory==4 || editedCategory==5) { + dim.y = gradientProperties.dimensions.y + pos.y = pos.y - gradientProperties.dimensions.y/2 + } + Overlays.editOverlay(gradientSphere, { position: pos, dimensions: dim, alpha: config.baseLevel }) + dim.x = parameterToValuePow(config.noiseSizeX, FADE_MIN_SCALE, FADE_MAX_SCALE/ FADE_MIN_SCALE) + dim.y = parameterToValuePow(config.noiseSizeY, FADE_MIN_SCALE, FADE_MAX_SCALE/ FADE_MIN_SCALE) + dim.z = parameterToValuePow(config.noiseSizeZ, FADE_MIN_SCALE, FADE_MAX_SCALE/ FADE_MIN_SCALE) + Overlays.editOverlay(noiseSphere, { position: pos, dimensions: dim, alpha: config.noiseLevel }) + } + } + } + + Script.update.connect(update); + function fromQml(message) { + tokens = message.split(' ') + print("Received '"+message+"' from transition.qml") + if (tokens[0]=="edit") { + isEditEnabled = (tokens[1]=="true") + if (isEditEnabled) { + if (gradientSphere==undefined) { + gradientSphere = Overlays.addOverlay("sphere", { + position: MyAvatar.position, + rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0), + dimensions: { x: 1.0, y: 1.0, z: 1.0 }, + color: { red: 100, green: 150, blue: 255}, + alpha: 0.2, + solid: false + }); + } + if (noiseSphere==undefined) { + noiseSphere = Overlays.addOverlay("sphere", { + position: MyAvatar.position, + rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0), + dimensions: { x: 1.0, y: 1.0, z: 1.0 }, + color: { red: 255, green: 150, blue: 100}, + alpha: 0.2, + solid: false + }); + } + } else if (!isEditEnabled) { + Overlays.deleteOverlay(noiseSphere); + Overlays.deleteOverlay(gradientSphere); + noiseSphere = undefined + gradientSphere = undefined + } + } else if (tokens[0]=="category") { + editedCategory = parseInt(tokens[1]) + } } button.clicked.connect(onClicked); @@ -109,7 +183,6 @@ var currentSelectionName = "" var SelectionList = "TransitionEdit" - var selectedEntity = null Pointers.enablePointer(laser) Selection.enableListToScene(SelectionList) Selection.clearSelectedItemsList(SelectionList) @@ -120,6 +193,7 @@ } selectedEntity = id Selection.addToSelectedItemsList(SelectionList, "entity", selectedEntity) + update() }) function cleanup() { @@ -127,6 +201,8 @@ Pointers.removePointer(ray); Selection.removeListFromMap(SelectionList) Selection.disableListToScene(SelectionList); + Overlays.deleteOverlay(noiseSphere); + Overlays.deleteOverlay(gradientSphere); } - + Script.scriptEnding.connect(cleanup); }()); \ No newline at end of file diff --git a/scripts/developer/utilities/render/transition.qml b/scripts/developer/utilities/render/transition.qml index e83a85f8ed..a8737dfa6b 100644 --- a/scripts/developer/utilities/render/transition.qml +++ b/scripts/developer/utilities/render/transition.qml @@ -22,6 +22,8 @@ Rectangle { id: root anchors.margins: hifi.dimensions.contentMargin.x + signal sendToScript(var message); + color: hifi.colors.baseGray; property var config: Render.getConfig("RenderMainView.Fade"); @@ -48,7 +50,7 @@ Rectangle { checked: root.configEdit["editFade"] onCheckedChanged: { root.configEdit["editFade"] = checked; - Render.getConfig("RenderMainView.DrawFadedOpaqueBounds").enabled = checked; + root.sendToScript("edit "+checked); } } HifiControls.ComboBox { @@ -70,6 +72,7 @@ Rectangle { paramWidgetLoader.sourceComponent = undefined; postpone.interval = 100 postpone.start() + root.sendToScript("category "+currentIndex) } } } From f19b1d9890fb360dd7949c05054439561e9bab19 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 20 Mar 2018 18:12:55 -0700 Subject: [PATCH 20/72] Fix for character walk animations in desktop mode. --- libraries/animation/src/Rig.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 7996c3372c..0833b28142 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1557,8 +1557,13 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo params.primaryControllerPoses[PrimaryControllerType_LeftFoot], params.primaryControllerPoses[PrimaryControllerType_RightFoot]); - // Always relax IK chains toward joint limit centers. - _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToLimitCenterPoses); + if (headEnabled) { + // Blend IK chains toward the joint limit centers, this should stablize head and hand ik. + _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToLimitCenterPoses); + } else { + // Blend IK chains toward the UnderPoses, so some of the animaton motion is present in the IK solution. + _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToUnderPoses); + } // if the hips or the feet are being controlled. if (hipsEnabled || rightFootEnabled || leftFootEnabled) { From 0c6f5bb04d525c7649469517492835a05bcf959a Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 26 Mar 2018 10:51:25 -0700 Subject: [PATCH 21/72] adding python baking scripts --- tools/bake-tools/bake.py | 91 ++++++++++++++++++++++ tools/bake-tools/convertToRelativePaths.py | 82 +++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 tools/bake-tools/bake.py create mode 100644 tools/bake-tools/convertToRelativePaths.py diff --git a/tools/bake-tools/bake.py b/tools/bake-tools/bake.py new file mode 100644 index 0000000000..0c8d5e1048 --- /dev/null +++ b/tools/bake-tools/bake.py @@ -0,0 +1,91 @@ +import os, json, sys, shutil, subprocess, shlex, time +EXE = os.environ['HIFI_OVEN'] + +def listFiles(directory, extension): + items = os.listdir(directory) + fileList = [] + for f in items: + if f.endswith('.' + extension): + fileList.append(f) + return fileList + +def camelCaseString(string): + string = string.replace('-', ' ') + return ''.join(x for x in string.title() if not x.isspace()) + +def groupFiles(originalDirectory, newDirectory, files): + for file in files: + newPath = os.sep.join([newDirectory, file]) + originalPath = os.sep.join([originalDirectory, file]) + shutil.move(originalPath, newPath) + +def groupKTXFiles(directory, filePath): + baseFile = os.path.basename(filePath) + filename = os.path.splitext(baseFile)[0] + camelCaseFileName = camelCaseString(filename) + path = os.sep.join([directory, camelCaseFileName]) + files = listFiles(directory, 'ktx') + if len(files) > 0: + createDirectory(path) + groupFiles(directory, path, files) + + newFilePath = os.sep.join([path, baseFile+'.baked.fbx']) + originalFilePath = os.sep.join([directory, baseFile+'.baked.fbx']) + originalFilePath.strip() + shutil.move(originalFilePath, newFilePath) + +def bakeFile(filePath, outputDirectory): + createDirectory(outputDirectory) + cmd = EXE + ' -i ' + filePath + ' -o ' + outputDirectory + ' -t fbx' + args = shlex.split(cmd) + process = subprocess.Popen(cmd, stdout=False, stderr=False) + process.wait() + bakedFile = os.path.splitext(filePath)[0] + groupKTXFiles(outputDirectory, bakedFile) + +def bakeFilesInDirectory(directory, outputDirectory): + for root, subFolders, filenames in os.walk(directory): + for filename in filenames: + if filename.endswith('.fbx'): + filePath = os.sep.join([root, filename]) + absFilePath = os.path.abspath(filePath) + outputFolder = os.path.join(outputDirectory, os.path.relpath(root)) + print "Baking file: " + filename + bakeFile(absFilePath, outputFolder) + else: + filePath = os.sep.join([root, filename]) + absFilePath = os.path.abspath(filePath) + outputFolder = os.path.join(outputDirectory, os.path.relpath(root)) + newFilePath = os.sep.join([outputFolder, filename]) + createDirectory(outputFolder) + print "moving file: " + filename + " to: " + outputFolder + shutil.copy(absFilePath, newFilePath) + +def createDirectory(directory): + if not os.path.exists(directory): + os.makedirs(directory) + +def checkIfExeExists(): + if not os.path.isfile(EXE) and os.access(EXE, os.X_OK): + print 'HIFI_OVEN evironment variable is not set' + sys.exit() + +def handleOptions(): + option = sys.argv[1] + if option == '--help' or option == '-h': + print 'Usage: bake.py INPUT_DIRECTORY[directory to bake] OUTPUT_DIRECTORY[directory to place backed files]' + print 'Note: Output directory will be created if directory does not exist' + sys.exit() + +def main(): + argsLength = len(sys.argv) + if argsLength == 3: + checkIfExeExists() + rootDirectory = sys.argv[1] + outputDirectory = os.path.abspath(sys.argv[2]) + createDirectory(outputDirectory) + bakeFilesInDirectory(rootDirectory, outputDirectory) + elif argsLength == 2: + handleOptions() + +main() diff --git a/tools/bake-tools/convertToRelativePaths.py b/tools/bake-tools/convertToRelativePaths.py new file mode 100644 index 0000000000..27a7b7ac02 --- /dev/null +++ b/tools/bake-tools/convertToRelativePaths.py @@ -0,0 +1,82 @@ +import json, os, sys, gzip + +prefix = 'file:///~/' +MAP = {} +def createAssetMapping(assetDirectory): + baseDirectory = os.path.basename(os.path.normpath(assetDirectory)) + for root, subfolder, filenames in os.walk(assetDirectory): + for filename in filenames: + if not filename.endswith('.ktx'): + substring = os.path.commonprefix([assetDirectory, root]) + newPath = root.replace(substring, ''); + filePath = os.sep.join([newPath, filename]) + if filePath[0] == '\\': + filePath = filePath[1:] + finalPath = prefix + baseDirectory + '/' + filePath + finalPath = finalPath.replace('\\', '/') + file = os.path.splitext(filename)[0] + file = os.path.splitext(file)[0] + MAP[file] = finalPath + +def hasURL(prop): + if "URL" in prop: + return True + return False + + +def handleURL(url): + newUrl = url + if "atp:" in url: + baseFilename = os.path.basename(url) + filename = os.path.splitext(baseFilename)[0] + newUrl = MAP[filename] + print newUrl + return newUrl + +def handleOptions(): + option = sys.argv[1] + if option == '--help' or option == '-h': + print 'Usage: convertToRelativePaths.py INPUT[json file you want to update the urls] INPUT[directory that the baked files are located in]' + sys.exit() + +def main(): + argsLength = len(sys.argv) + if argsLength == 3: + jsonFile = sys.argv[1] + gzipFile = jsonFile + '.gz' + assetDirectory = sys.argv[2] + createAssetMapping(assetDirectory) + f = open(jsonFile) + data = json.load(f) + f.close() + for entity in data['Entities']: + for prop in entity: + value = entity[prop] + if hasURL(prop): + value = handleURL(value) + if prop == "script": + value = handleURL(value) + if prop == "textures": + try: + tmp = json.loads(value) + for index in tmp: + tmp[index] = handleURL(tmp[index]) + value = json.dumps(tmp) + except: + value = handleURL(value) + + if prop == "serverScripts": + value = handleURL(value) + + entity[prop] = value + + + jsonString = json.dumps(data) + jsonBytes= jsonString.encode('utf-8') + with gzip.GzipFile(gzipFile, 'w') as fout: # 4. gzip + fout.write(jsonBytes) + + elif argsLength == 2: + handleOptions() + +main() From bf48ecda6d199b6b4c3f4c1c2a88203aa27b672d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 26 Mar 2018 14:40:31 -0700 Subject: [PATCH 22/72] Fix cert location for content sets --- assignment-client/src/entities/EntityServer.cpp | 12 ++++++++---- .../qml/hifi/commerce/checkout/Checkout.qml | 2 +- .../qml/hifi/commerce/purchases/PurchasedItem.qml | 2 +- .../qml/hifi/commerce/purchases/Purchases.qml | 2 +- interface/src/commerce/Ledger.cpp | 5 ++++- interface/src/commerce/Ledger.h | 2 +- interface/src/commerce/QmlCommerce.cpp | 4 +++- interface/src/commerce/QmlCommerce.h | 2 +- 8 files changed, 20 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index e394884dc2..a6c35390cc 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -470,7 +470,6 @@ void EntityServer::startDynamicDomainVerification() { // Delete the entity if it doesn't pass static certificate verification tree->deleteEntity(i.value(), true); } else { - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest; networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); @@ -490,9 +489,14 @@ void EntityServer::startDynamicDomainVerification() { if (networkReply->error() == QNetworkReply::NoError) { if (jsonObject["domain_id"].toString() != thisDomainID) { - qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() - << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value(); - tree->deleteEntity(i.value(), true); + if (QDateTime::currentMSecsSinceEpoch() - entity->getProperties().getCreated()/1000 > _MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS) { + qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() + << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value(); + qCDebug(entities) << "Time since rez (seconds):" << (QDateTime::currentMSecsSinceEpoch() - entity->getProperties().getCreated() / 1000) / 1000; + tree->deleteEntity(i.value(), true); + } else { + qCDebug(entities) << "Entity failed dynamic domain verification, but was created too recently to necessitate deletion:" << i.value(); + } } else { qCDebug(entities) << "Entity passed dynamic domain verification:" << i.value(); } diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 9933953fe8..85469c7f94 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -772,7 +772,7 @@ Rectangle { lightboxPopup.button1text = "CANCEL"; lightboxPopup.button1method = "root.visible = false;" lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = "Commerce.replaceContentSet('" + root.itemHref + "');" + + lightboxPopup.button2method = "Commerce.replaceContentSet('" + root.itemHref + "', '" + root.certificateId + "');" + "root.visible = false;rezzedNotifContainer.visible = true; rezzedNotifContainerTimer.start();" + "UserActivityLogger.commerceEntityRezzed('" + root.itemId + "', 'checkout', '" + root.itemType + "');"; lightboxPopup.visible = true; diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index 4cfa61c9ed..2aac269d56 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -564,7 +564,7 @@ Item { onClicked: { Tablet.playSound(TabletEnums.ButtonClick); if (root.itemType === "contentSet") { - sendToPurchases({method: 'showReplaceContentLightbox', itemHref: root.itemHref}); + sendToPurchases({method: 'showReplaceContentLightbox', itemHref: root.itemHref, certID: root.certificateId}); } else if (root.itemType === "avatar") { sendToPurchases({method: 'showChangeAvatarLightbox', itemName: root.itemName, itemHref: root.itemHref}); } else if (root.itemType === "app") { diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 726e6bd338..1e935875e6 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -486,7 +486,7 @@ Rectangle { lightboxPopup.button1text = "CANCEL"; lightboxPopup.button1method = "root.visible = false;" lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = "Commerce.replaceContentSet('" + msg.itemHref + "'); root.visible = false;"; + lightboxPopup.button2method = "Commerce.replaceContentSet('" + msg.itemHref + "', '" + msg.certID + "'); root.visible = false;"; lightboxPopup.visible = true; } else if (msg.method === "showChangeAvatarLightbox") { lightboxPopup.titleText = "Change Avatar"; diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 0a9e867323..cb06cdfed7 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -293,7 +293,7 @@ void Ledger::account() { // The api/failResponse is called just for the side effect of logging. void Ledger::updateLocationSuccess(QNetworkReply& reply) { apiResponse("updateLocation", reply); } void Ledger::updateLocationFailure(QNetworkReply& reply) { failResponse("updateLocation", reply); } -void Ledger::updateLocation(const QString& asset_id, const QString location, const bool controlledFailure) { +void Ledger::updateLocation(const QString& asset_id, const QString& location, const bool& alsoUpdateSiblings, const bool controlledFailure) { auto wallet = DependencyManager::get(); auto walletScriptingInterface = DependencyManager::get(); uint walletStatus = walletScriptingInterface->getWalletStatus(); @@ -308,6 +308,9 @@ void Ledger::updateLocation(const QString& asset_id, const QString location, con QJsonObject transaction; transaction["certificate_id"] = asset_id; transaction["place_name"] = location; + if (alsoUpdateSiblings) { + transaction["also_update_siblings"] = true; + } QJsonDocument transactionDoc{ transaction }; auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); signedSend("transaction", transactionString, key, "location", "updateLocationSuccess", "updateLocationFailure", controlledFailure); diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index da97206bbc..1ccab9c2b1 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -31,7 +31,7 @@ public: void inventory(const QStringList& keys); void history(const QStringList& keys, const int& pageNumber); void account(); - void updateLocation(const QString& asset_id, const QString location, const bool controlledFailure = false); + void updateLocation(const QString& asset_id, const QString& location, const bool& alsoUpdateSiblings = false, const bool controlledFailure = false); void certificateInfo(const QString& certificateId); void transferHfcToNode(const QString& hfc_key, const QString& nodeID, const int& amount, const QString& optionalMessage); void transferHfcToUsername(const QString& hfc_key, const QString& username, const int& amount, const QString& optionalMessage); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 8e956249cc..7e91ffaa62 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -190,7 +190,9 @@ void QmlCommerce::transferHfcToUsername(const QString& username, const int& amou ledger->transferHfcToUsername(key, username, amount, optionalMessage); } -void QmlCommerce::replaceContentSet(const QString& itemHref) { +void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& certificateID) { + auto ledger = DependencyManager::get(); + ledger->updateLocation(certificateID, DependencyManager::get()->getPlaceName(), true); qApp->replaceDomainContent(itemHref); QJsonObject messageProperties = { { "status", "SuccessfulRequestToReplaceContent" }, diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index a3a0ebfd32..f58726e1d7 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -84,7 +84,7 @@ protected: Q_INVOKABLE void transferHfcToNode(const QString& nodeID, const int& amount, const QString& optionalMessage); Q_INVOKABLE void transferHfcToUsername(const QString& username, const int& amount, const QString& optionalMessage); - Q_INVOKABLE void replaceContentSet(const QString& itemHref); + Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID); Q_INVOKABLE QString getInstalledApps(); Q_INVOKABLE bool installApp(const QString& appHref); From 00c70278c838c1d187948e75ecdc46b68a1e6fc4 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 26 Mar 2018 15:03:10 -0700 Subject: [PATCH 23/72] Add getCreatedAgo() --- assignment-client/src/entities/EntityServer.cpp | 3 +-- libraries/entities/src/EntityItem.h | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index a6c35390cc..1862287b6d 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -489,10 +489,9 @@ void EntityServer::startDynamicDomainVerification() { if (networkReply->error() == QNetworkReply::NoError) { if (jsonObject["domain_id"].toString() != thisDomainID) { - if (QDateTime::currentMSecsSinceEpoch() - entity->getProperties().getCreated()/1000 > _MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS) { + if (entity->getCreatedAgo() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/1000)) { qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value(); - qCDebug(entities) << "Time since rez (seconds):" << (QDateTime::currentMSecsSinceEpoch() - entity->getProperties().getCreated() / 1000) / 1000; tree->deleteEntity(i.value(), true); } else { qCDebug(entities) << "Entity failed dynamic domain verification, but was created too recently to necessitate deletion:" << i.value(); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 0303964e18..962babb558 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -222,6 +222,10 @@ public: quint64 getCreated() const; /// get the created-time in useconds for the entity void setCreated(quint64 value); /// set the created-time in useconds for the entity + float getCreatedAgo() const /// Elapsed seconds since this entity was created + { + return (float)(usecTimestampNow() - getCreated()) / (float)USECS_PER_SECOND; + } /// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted bool isImmortal() const { return getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME; } From db2f3451bd30ba144c6bba6e94c64f7cc347e297 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 26 Mar 2018 16:20:29 -0700 Subject: [PATCH 24/72] Support .content.zip content sets --- interface/resources/qml/hifi/commerce/checkout/Checkout.qml | 2 +- interface/resources/qml/hifi/commerce/purchases/Purchases.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 85469c7f94..35c95a9a5c 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -188,7 +188,7 @@ Rectangle { onItemHrefChanged: { if (root.itemHref.indexOf(".fst") > -1) { root.itemType = "avatar"; - } else if (root.itemHref.indexOf('.json.gz') > -1) { + } else if (root.itemHref.indexOf('.json.gz') > -1 || root.itemHref.indexOf('.content.zip') > -1) { root.itemType = "contentSet"; } else if (root.itemHref.indexOf('.app.json') > -1) { root.itemType = "app"; diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 1e935875e6..cdcfa4a13e 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -792,7 +792,7 @@ Rectangle { currentItemType = "avatar"; } else if (currentCategories.indexOf("Wearables") > -1) { currentItemType = "wearable"; - } else if (currentRootFileUrl.endsWith('.json.gz')) { + } else if (currentRootFileUrl.endsWith('.json.gz') || currentRootFileUrl.endsWith('.content.zip')) { currentItemType = "contentSet"; } else if (currentRootFileUrl.endsWith('.app.json')) { currentItemType = "app"; From 194b00d732a477fe0a6270a356023407618fccc8 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Mar 2018 16:31:58 -0700 Subject: [PATCH 25/72] fix translate arrow normals --- scripts/system/libraries/entitySelectionTool.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index fced5fc4e9..1fb2f59a19 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -1653,11 +1653,11 @@ SelectionDisplay = (function() { mode: mode, onBegin: function(event, pickRay, pickResult) { if (direction === TRANSLATE_DIRECTION.X) { - pickNormal = { x:0, y:0, z:1 }; + pickNormal = { x:0, y:1, z:1 }; } else if (direction === TRANSLATE_DIRECTION.Y) { - pickNormal = { x:1, y:0, z:0 }; + pickNormal = { x:1, y:0, z:1 }; } else if (direction === TRANSLATE_DIRECTION.Z) { - pickNormal = { x:0, y:1, z:0 }; + pickNormal = { x:1, y:1, z:0 }; } var rotation = spaceMode === SPACE_LOCAL ? SelectionManager.localRotation : SelectionManager.worldRotation; @@ -1701,7 +1701,6 @@ SelectionDisplay = (function() { onMove: function(event) { pickRay = generalComputePickRay(event.x, event.y); - // translate mode left/right based on view toward entity var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, pickNormal); var vector = Vec3.subtract(newIntersection, lastPick); @@ -1719,7 +1718,7 @@ SelectionDisplay = (function() { var dotVector = Vec3.dot(vector, projectionVector); vector = Vec3.multiply(dotVector, projectionVector); vector = grid.snapToGrid(vector); - + var wantDebug = false; if (wantDebug) { print("translateUpDown... "); @@ -2017,10 +2016,10 @@ SelectionDisplay = (function() { vector = grid.snapToSpacing(vector); var changeInDimensions = Vec3.multiply(NEGATE_VECTOR, vec3Mult(localSigns, vector)); - if (directionEnum === STRETCH_DIRECTION.ALL) { - var toCameraDistance = getDistanceToCamera(position); - var dimensionsMultiple = toCameraDistance * STRETCH_DIRECTION_ALL_CAMERA_DISTANCE_MULTIPLE; - changeInDimensions = Vec3.multiply(changeInDimensions, dimensionsMultiple); + if (directionEnum === STRETCH_DIRECTION.ALL) { + var toCameraDistance = getDistanceToCamera(position); + var dimensionsMultiple = toCameraDistance * STRETCH_DIRECTION_ALL_CAMERA_DISTANCE_MULTIPLE; + changeInDimensions = Vec3.multiply(changeInDimensions, dimensionsMultiple); } var newDimensions; From 3d7f7f0e620270b6dc5b14bac5ac176c02139ad7 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 27 Mar 2018 14:05:43 -0700 Subject: [PATCH 26/72] fix parent tree grabbing --- .../system/controllers/controllerModules/farActionGrabEntity.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 09cea58cea..07450e54ba 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -475,7 +475,7 @@ Script.include("/~/system/libraries/Xform.js"); entityID = targetEntity.id; targetProps = targetEntity.props; - if (entityIsGrabbable(targetProps)) { + if (entityIsGrabbable(targetProps) || entityIsGrabbable(this.targetObject.entityProps)) { if (!entityIsDistanceGrabbable(targetProps)) { this.targetObject.makeDynamic(); } From 197662fd5e18c7a3a7b0c24d3fa7d3ca1f6cb086 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 27 Mar 2018 15:22:22 -0700 Subject: [PATCH 27/72] fix contextOverlay highlighing all entities --- interface/src/ui/overlays/ContextOverlayInterface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index dd05e5c6a8..f0c16fb977 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -254,7 +254,8 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveOverlay(const OverlayID& void ContextOverlayInterface::contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event) { bool isMouse = event.getID() == PointerManager::MOUSE_POINTER_ID || DependencyManager::get()->isMouse(event.getID()); - if (contextOverlayFilterPassed(entityID) && _enabled && !isMouse) { + if (_currentEntityWithContextOverlay == entityID && contextOverlayFilterPassed(entityID) + && _enabled && !isMouse) { enableEntityHighlight(entityID); } } From 9f3b82a417051c221b2cd533585f7a827959935e Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 27 Mar 2018 18:21:14 -0700 Subject: [PATCH 28/72] added the functions triggerVerticalRecenter,triggerHorizontalRecenter,and triggerRotationRecenter to MyAvatar.h, these allow java script calls to recenter the avatar on the fly --- interface/src/avatar/MyAvatar.cpp | 46 ++++++++++++++++++++++++++++++- interface/src/avatar/MyAvatar.h | 28 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9620a2dcec..b98620cbcb 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2760,6 +2760,27 @@ bool MyAvatar::isDriveKeyDisabled(DriveKeys key) const { } } +void MyAvatar::triggerVerticalRecenter() { + //do something here + _follow._forceActivateVertical = true; + + +} + +void MyAvatar::triggerHorizontalRecenter() { + //do something here + _follow._forceActivateHorizontal = true; + + +} + +void MyAvatar::triggerRotationRecenter() { + //do something here + _follow._forceActivateRotation = true; + + +} + // old school meat hook style glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { glm::vec3 headPosition; @@ -2953,7 +2974,9 @@ void MyAvatar::FollowHelper::decrementTimeRemaining(float dt) { bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 6.0f); // 30 degrees glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix); + return glm::dot(-myAvatar.getHeadControllerFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD; + } bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { @@ -2970,13 +2993,16 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const float MAX_FORWARD_LEAN = 0.15f; const float MAX_BACKWARD_LEAN = 0.1f; + if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) { return true; - } else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) { + } + else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) { return true; } return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN; + } bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { @@ -2984,6 +3010,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co const float CYLINDER_BOTTOM = -1.5f; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); + return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); } @@ -3002,6 +3029,23 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat activate(Vertical); } } + else { + if (!isActive(Rotation) && _forceActivateRotation) { + activate(Rotation); + _forceActivateRotation = false; + qCDebug(interfaceapp) << "the rotation property is activated+++++++++++++++++++++++" << endl; + } + if (!isActive(Horizontal) && _forceActivateHorizontal) { + activate(Horizontal); + _forceActivateHorizontal = false; + qCDebug(interfaceapp) << "the horizontal property is activated+++++++++++++++++++++++" << endl; + } + if (!isActive(Vertical) && _forceActivateVertical) { + activate(Vertical); + _forceActivateVertical = false; + qCDebug(interfaceapp) << "the vertical property is activated+++++++++++++++++++++++" << endl; + } + } glm::mat4 desiredWorldMatrix = myAvatar.getSensorToWorldMatrix() * desiredBodyMatrix; glm::mat4 currentWorldMatrix = myAvatar.getSensorToWorldMatrix() * currentBodyMatrix; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 5ca010d128..c3136b14c2 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -104,6 +104,9 @@ class MyAvatar : public Avatar { * @property rightHandTipPose {Pose} READ-ONLY. Returns a pose offset 30 cm from MyAvatar.rightHandPose * @property hmdLeanRecenterEnabled {bool} This can be used disable the hmd lean recenter behavior. This behavior is what causes your avatar * to follow your HMD as you walk around the room, in room scale VR. Disabling this is useful if you desire to pin the avatar to a fixed location. + * @property hmdVerticalRecenterEnabled {bool} This can be used to turn vertical recenter off and on. + * @property hmdHorizontalRecenterEnabled {bool} This can be used to turn horizontal recenter off and on. + * @property hmdRotationRecenterEnabled {bool} This can be used to turn rotational recenter off and on. * @property collisionsEnabled {bool} This can be used to disable collisions between the avatar and the world. * @property useAdvancedMovementControls {bool} Stores the user preference only, does not change user mappings, this is done in the defaultScript * "scripts/system/controllers/toggleAdvancedMovementForHandControllers.js". @@ -149,6 +152,9 @@ class MyAvatar : public Avatar { Q_PROPERTY(bool isAway READ getIsAway WRITE setAway) Q_PROPERTY(bool hmdLeanRecenterEnabled READ getHMDLeanRecenterEnabled WRITE setHMDLeanRecenterEnabled) + Q_PROPERTY(bool hmdVerticalRecenterEnabled READ getHMDVerticalRecenterEnabled WRITE setHMDVerticalRecenterEnabled) + Q_PROPERTY(bool hmdHorizontalRecenterEnabled READ getHMDHorizontalRecenterEnabled WRITE setHMDHorizontalRecenterEnabled) + Q_PROPERTY(bool hmdRotationRecenterEnabled READ getHMDRotationRecenterEnabled WRITE setHMDRotationRecenterEnabled) Q_PROPERTY(bool collisionsEnabled READ getCollisionsEnabled WRITE setCollisionsEnabled) Q_PROPERTY(bool characterControllerEnabled READ getCharacterControllerEnabled WRITE setCharacterControllerEnabled) Q_PROPERTY(bool useAdvancedMovementControls READ useAdvancedMovementControls WRITE setUseAdvancedMovementControls) @@ -374,6 +380,15 @@ public: Q_INVOKABLE void setHMDLeanRecenterEnabled(bool value) { _hmdLeanRecenterEnabled = value; } Q_INVOKABLE bool getHMDLeanRecenterEnabled() const { return _hmdLeanRecenterEnabled; } + Q_INVOKABLE void setHMDVerticalRecenterEnabled(bool value) { _hmdVerticalRecenterEnabled = value; } + Q_INVOKABLE bool getHMDVerticalRecenterEnabled() const { return _hmdVerticalRecenterEnabled; } + + Q_INVOKABLE void setHMDHorizontalRecenterEnabled(bool value) { _hmdHorizontalRecenterEnabled = value; } + Q_INVOKABLE bool getHMDHorizontalRecenterEnabled() const { return _hmdHorizontalRecenterEnabled; } + + Q_INVOKABLE void setHMDRotationRecenterEnabled(bool value) { _hmdRotationRecenterEnabled = value; } + Q_INVOKABLE bool getHMDRotationRecenterEnabled() const { return _hmdRotationRecenterEnabled; } + bool useAdvancedMovementControls() const { return _useAdvancedMovementControls.get(); } void setUseAdvancedMovementControls(bool useAdvancedMovementControls) { _useAdvancedMovementControls.set(useAdvancedMovementControls); } @@ -403,6 +418,10 @@ public: Q_INVOKABLE void enableDriveKey(DriveKeys key); Q_INVOKABLE bool isDriveKeyDisabled(DriveKeys key) const; + Q_INVOKABLE void triggerVerticalRecenter(); + Q_INVOKABLE void triggerHorizontalRecenter(); + Q_INVOKABLE void triggerRotationRecenter(); + eyeContactTarget getEyeContactTarget(); const MyHead* getMyHead() const; @@ -802,6 +821,12 @@ private: bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); + bool getForceActivateRotation(); + bool getForceActivateVertical(); + bool getForceActivateHorizontal(); + bool _forceActivateRotation{ false }; + bool _forceActivateVertical{ false }; + bool _forceActivateHorizontal{ false }; }; FollowHelper _follow; @@ -837,6 +862,9 @@ private: mutable std::mutex _controllerPoseMapMutex; bool _hmdLeanRecenterEnabled = true; + bool _hmdVerticalRecenterEnabled = true; + bool _hmdHorizontalRecenterEnabled = true; + bool _hmdRotationRecenterEnabled = true; AnimPose _prePhysicsRoomPose; std::mutex _holdActionsMutex; std::vector _holdActions; From 95f1d0e4fab16d91b65042090f7981d3527fbba0 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 28 Mar 2018 10:33:00 -0700 Subject: [PATCH 29/72] added get and set functions for the activate recenter variables --- interface/src/avatar/MyAvatar.cpp | 58 +++++++++++++++++++------------ interface/src/avatar/MyAvatar.h | 22 +++--------- 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b98620cbcb..2a523e9b9e 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2761,24 +2761,15 @@ bool MyAvatar::isDriveKeyDisabled(DriveKeys key) const { } void MyAvatar::triggerVerticalRecenter() { - //do something here - _follow._forceActivateVertical = true; - - + _follow.setForceActivateVertical(true); } void MyAvatar::triggerHorizontalRecenter() { - //do something here - _follow._forceActivateHorizontal = true; - - + _follow.setForceActivateHorizontal(true); } void MyAvatar::triggerRotationRecenter() { - //do something here - _follow._forceActivateRotation = true; - - + _follow.setForceActivateRotation(true); } // old school meat hook style @@ -3028,22 +3019,19 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); } - } - else { - if (!isActive(Rotation) && _forceActivateRotation) { + } else { + //qCDebug(interfaceapp) << "turned off the recenter" << endl; + if (!isActive(Rotation) && getForceActivateRotation()) { activate(Rotation); - _forceActivateRotation = false; - qCDebug(interfaceapp) << "the rotation property is activated+++++++++++++++++++++++" << endl; + setForceActivateRotation(false); } - if (!isActive(Horizontal) && _forceActivateHorizontal) { + if (!isActive(Horizontal) && getForceActivateHorizontal()) { activate(Horizontal); - _forceActivateHorizontal = false; - qCDebug(interfaceapp) << "the horizontal property is activated+++++++++++++++++++++++" << endl; + setForceActivateHorizontal(false); } - if (!isActive(Vertical) && _forceActivateVertical) { + if (!isActive(Vertical) && getForceActivateVertical()) { activate(Vertical); - _forceActivateVertical = false; - qCDebug(interfaceapp) << "the vertical property is activated+++++++++++++++++++++++" << endl; + setForceActivateVertical(false); } } @@ -3094,6 +3082,30 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co } } +bool MyAvatar::FollowHelper::getForceActivateRotation() { + return _forceActivateRotation; +} + +void MyAvatar::FollowHelper::setForceActivateRotation(bool val) { + _forceActivateRotation = val; +} + +bool MyAvatar::FollowHelper::getForceActivateVertical() { + return _forceActivateVertical; +} + +void MyAvatar::FollowHelper::setForceActivateVertical(bool val) { + _forceActivateVertical = val; +} + +bool MyAvatar::FollowHelper::getForceActivateHorizontal() { + return _forceActivateHorizontal; +} + +void MyAvatar::FollowHelper::setForceActivateHorizontal(bool val) { + _forceActivateHorizontal = val; +} + float MyAvatar::getAccelerationEnergy() { glm::vec3 velocity = getWorldVelocity(); int changeInVelocity = abs(velocity.length() - priorVelocity.length()); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index c3136b14c2..6f7caa5c7d 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -104,9 +104,6 @@ class MyAvatar : public Avatar { * @property rightHandTipPose {Pose} READ-ONLY. Returns a pose offset 30 cm from MyAvatar.rightHandPose * @property hmdLeanRecenterEnabled {bool} This can be used disable the hmd lean recenter behavior. This behavior is what causes your avatar * to follow your HMD as you walk around the room, in room scale VR. Disabling this is useful if you desire to pin the avatar to a fixed location. - * @property hmdVerticalRecenterEnabled {bool} This can be used to turn vertical recenter off and on. - * @property hmdHorizontalRecenterEnabled {bool} This can be used to turn horizontal recenter off and on. - * @property hmdRotationRecenterEnabled {bool} This can be used to turn rotational recenter off and on. * @property collisionsEnabled {bool} This can be used to disable collisions between the avatar and the world. * @property useAdvancedMovementControls {bool} Stores the user preference only, does not change user mappings, this is done in the defaultScript * "scripts/system/controllers/toggleAdvancedMovementForHandControllers.js". @@ -152,9 +149,6 @@ class MyAvatar : public Avatar { Q_PROPERTY(bool isAway READ getIsAway WRITE setAway) Q_PROPERTY(bool hmdLeanRecenterEnabled READ getHMDLeanRecenterEnabled WRITE setHMDLeanRecenterEnabled) - Q_PROPERTY(bool hmdVerticalRecenterEnabled READ getHMDVerticalRecenterEnabled WRITE setHMDVerticalRecenterEnabled) - Q_PROPERTY(bool hmdHorizontalRecenterEnabled READ getHMDHorizontalRecenterEnabled WRITE setHMDHorizontalRecenterEnabled) - Q_PROPERTY(bool hmdRotationRecenterEnabled READ getHMDRotationRecenterEnabled WRITE setHMDRotationRecenterEnabled) Q_PROPERTY(bool collisionsEnabled READ getCollisionsEnabled WRITE setCollisionsEnabled) Q_PROPERTY(bool characterControllerEnabled READ getCharacterControllerEnabled WRITE setCharacterControllerEnabled) Q_PROPERTY(bool useAdvancedMovementControls READ useAdvancedMovementControls WRITE setUseAdvancedMovementControls) @@ -380,15 +374,6 @@ public: Q_INVOKABLE void setHMDLeanRecenterEnabled(bool value) { _hmdLeanRecenterEnabled = value; } Q_INVOKABLE bool getHMDLeanRecenterEnabled() const { return _hmdLeanRecenterEnabled; } - Q_INVOKABLE void setHMDVerticalRecenterEnabled(bool value) { _hmdVerticalRecenterEnabled = value; } - Q_INVOKABLE bool getHMDVerticalRecenterEnabled() const { return _hmdVerticalRecenterEnabled; } - - Q_INVOKABLE void setHMDHorizontalRecenterEnabled(bool value) { _hmdHorizontalRecenterEnabled = value; } - Q_INVOKABLE bool getHMDHorizontalRecenterEnabled() const { return _hmdHorizontalRecenterEnabled; } - - Q_INVOKABLE void setHMDRotationRecenterEnabled(bool value) { _hmdRotationRecenterEnabled = value; } - Q_INVOKABLE bool getHMDRotationRecenterEnabled() const { return _hmdRotationRecenterEnabled; } - bool useAdvancedMovementControls() const { return _useAdvancedMovementControls.get(); } void setUseAdvancedMovementControls(bool useAdvancedMovementControls) { _useAdvancedMovementControls.set(useAdvancedMovementControls); } @@ -822,8 +807,11 @@ private: void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); bool getForceActivateRotation(); + void setForceActivateRotation(bool val); bool getForceActivateVertical(); + void setForceActivateVertical(bool val); bool getForceActivateHorizontal(); + void setForceActivateHorizontal(bool val); bool _forceActivateRotation{ false }; bool _forceActivateVertical{ false }; bool _forceActivateHorizontal{ false }; @@ -862,9 +850,7 @@ private: mutable std::mutex _controllerPoseMapMutex; bool _hmdLeanRecenterEnabled = true; - bool _hmdVerticalRecenterEnabled = true; - bool _hmdHorizontalRecenterEnabled = true; - bool _hmdRotationRecenterEnabled = true; + AnimPose _prePhysicsRoomPose; std::mutex _holdActionsMutex; std::vector _holdActions; From 0175028a88bbf0f4d4bed67a365a3b2681971bee Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 28 Mar 2018 11:31:51 -0700 Subject: [PATCH 30/72] Ensure location is correctly updated when replacing set from Checkout page --- interface/resources/qml/hifi/commerce/checkout/Checkout.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 2502498942..c0cf45d292 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -96,6 +96,7 @@ Rectangle { root.activeView = "checkoutFailure"; UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.message); } else { + root.certificateId = result.data.certificate_id; root.itemHref = result.data.download_url; if (result.data.categories.indexOf("Wearables") > -1) { root.itemType = "wearable"; From e4416db06fff64863614792d5cf5d4537f46596b Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 28 Mar 2018 16:54:53 -0400 Subject: [PATCH 31/72] Added save/file dialog for transition configurations in transition editor --- libraries/render-utils/src/FadeEffectJobs.cpp | 7 +-- libraries/render-utils/src/FadeEffectJobs.h | 4 +- .../utilities/render/debugTransition.js | 48 ++++++++++++++++--- .../developer/utilities/render/transition.qml | 36 ++++++++++---- 4 files changed, 72 insertions(+), 23 deletions(-) diff --git a/libraries/render-utils/src/FadeEffectJobs.cpp b/libraries/render-utils/src/FadeEffectJobs.cpp index a55fb304dd..1e2ea2bc15 100644 --- a/libraries/render-utils/src/FadeEffectJobs.cpp +++ b/libraries/render-utils/src/FadeEffectJobs.cpp @@ -340,11 +340,9 @@ QString FadeConfig::eventNames[FADE_CATEGORY_COUNT] = { "avatar_change", }; -void FadeConfig::save() const { - // Save will only work if the HIFI_USE_SOURCE_TREE_RESOURCES environment variable is set +void FadeConfig::save(const QString& configFilePath) const { assert(editedCategory < FADE_CATEGORY_COUNT); QJsonObject lProperties; - const QString configFilePath = PathUtils::resourcesPath() + "config/" + eventNames[editedCategory] + ".json"; QFile file(configFilePath); if (!file.open(QFile::WriteOnly | QFile::Text)) { qWarning() << "Fade event configuration file " << configFilePath << " cannot be opened"; @@ -369,8 +367,7 @@ void FadeConfig::save() const { } } -void FadeConfig::load() { - const QString configFilePath = PathUtils::resourcesPath() + "config/" + eventNames[editedCategory] + ".json"; +void FadeConfig::load(const QString& configFilePath) { QFile file(configFilePath); if (!file.exists()) { qWarning() << "Fade event configuration file " << configFilePath << " does not exist"; diff --git a/libraries/render-utils/src/FadeEffectJobs.h b/libraries/render-utils/src/FadeEffectJobs.h index f1026b6c2e..449995dba5 100644 --- a/libraries/render-utils/src/FadeEffectJobs.h +++ b/libraries/render-utils/src/FadeEffectJobs.h @@ -160,8 +160,8 @@ public: float manualThreshold{ 0.f }; bool manualFade{ false }; - Q_INVOKABLE void save() const; - Q_INVOKABLE void load(); + Q_INVOKABLE void save(const QString& filePath) const; + Q_INVOKABLE void load(const QString& filePath); static QString eventNames[FADE_CATEGORY_COUNT]; diff --git a/scripts/developer/utilities/render/debugTransition.js b/scripts/developer/utilities/render/debugTransition.js index cef6e84268..27b04bd32b 100644 --- a/scripts/developer/utilities/render/debugTransition.js +++ b/scripts/developer/utilities/render/debugTransition.js @@ -1,5 +1,3 @@ -"use strict"; - // // debugTransition.js // developer/utilities/render @@ -12,12 +10,17 @@ // (function() { + "use strict"; + var TABLET_BUTTON_NAME = "Transition"; var QMLAPP_URL = Script.resolvePath("./transition.qml"); var ICON_URL = Script.resolvePath("../../../system/assets/images/transition-i.svg"); var ACTIVE_ICON_URL = Script.resolvePath("../../../system/assets/images/transition-a.svg"); - + Script.include([ + Script.resolvePath("../../../system/libraries/stringHelpers.js"), + ]); + var onScreen = false; function onClicked() { @@ -106,10 +109,21 @@ Script.update.connect(update); + function loadConfiguration(fileUrl) { + var config = Render.getConfig("RenderMainView.Fade") + config.load(fileUrl) + } + + function saveConfiguration(fileUrl) { + var config = Render.getConfig("RenderMainView.Fade") + config.save(fileUrl) + } + function fromQml(message) { - tokens = message.split(' ') + tokens = message.split('*') print("Received '"+message+"' from transition.qml") - if (tokens[0]=="edit") { + command = tokens[0].toLowerCase() + if (command=="edit") { isEditEnabled = (tokens[1]=="true") if (isEditEnabled) { if (gradientSphere==undefined) { @@ -138,9 +152,28 @@ noiseSphere = undefined gradientSphere = undefined } - } else if (tokens[0]=="category") { + } else if (command=="category") { editedCategory = parseInt(tokens[1]) - } + } else if (command=="save") { + var filePath = tokens[1] + print("Raw token = "+filePath) + if (filePath.startsWith("file:///")) { + filePath = filePath.substr(8) + print("Saving configuration to "+filePath) + saveConfiguration(filePath) + } else { + print("Configurations can only be saved to local files") + } + } else if (command=="load") { + var filePath = tokens[1] + if (filePath.startsWith("file:///")) { + filePath = filePath.substr(8) + print("Loading configuration from "+filePath) + loadConfiguration(filePath) + } else { + print("Configurations can only be loaded from local files") + } + } } button.clicked.connect(onClicked); @@ -172,6 +205,7 @@ color: COLOR2, ignoreRayIntersection: true } + var laser = Pointers.createPointer(PickType.Ray, { joint: "Mouse", filter: Picks.PICK_ENTITIES, diff --git a/scripts/developer/utilities/render/transition.qml b/scripts/developer/utilities/render/transition.qml index a8737dfa6b..564090e2d6 100644 --- a/scripts/developer/utilities/render/transition.qml +++ b/scripts/developer/utilities/render/transition.qml @@ -11,6 +11,7 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 import "qrc:///qml/styles-uit" import "qrc:///qml/controls-uit" as HifiControls @@ -29,6 +30,24 @@ Rectangle { property var config: Render.getConfig("RenderMainView.Fade"); property var configEdit: Render.getConfig("RenderMainView.FadeEdit"); + FileDialog { + id: fileDialog + title: "Please choose a file" + folder: shortcuts.documents + nameFilters: [ "JSON files (*.json)", "All files (*)" ] + onAccepted: { + root.sendToScript(title.split(" ")[0]+"*"+fileUrl.toString()) + // This is a hack to be sure the widgets below properly reflect the change of category: delete the Component + // by setting the loader source to Null and then recreate it 500ms later + paramWidgetLoader.sourceComponent = undefined; + postpone.interval = 500 + postpone.start() + } + onRejected: { + } + Component.onCompleted: visible = false + } + ColumnLayout { spacing: 3 anchors.left: parent.left @@ -50,7 +69,7 @@ Rectangle { checked: root.configEdit["editFade"] onCheckedChanged: { root.configEdit["editFade"] = checked; - root.sendToScript("edit "+checked); + root.sendToScript("edit*"+checked); } } HifiControls.ComboBox { @@ -72,7 +91,7 @@ Rectangle { paramWidgetLoader.sourceComponent = undefined; postpone.interval = 100 postpone.start() - root.sendToScript("category "+currentIndex) + root.sendToScript("category*"+currentIndex) } } } @@ -107,19 +126,18 @@ Rectangle { id: saveAction text: "Save" onTriggered: { - root.config.save() + fileDialog.title = "Save configuration..." + fileDialog.selectExisting = false + fileDialog.open() } } Action { id: loadAction text: "Load" onTriggered: { - root.config.load() - // This is a hack to be sure the widgets below properly reflect the change of category: delete the Component - // by setting the loader source to Null and then recreate it 500ms later - paramWidgetLoader.sourceComponent = undefined; - postpone.interval = 500 - postpone.start() + fileDialog.title = "Load configuration..." + fileDialog.selectExisting = true + fileDialog.open() } } From 90d87c5b5d6dacf6a106e5a24aab44ecc393c5cc Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 28 Mar 2018 14:00:36 -0700 Subject: [PATCH 32/72] changed get functions to const in MyAvatar.cpp changed bool variables to atomic for thread safety --- interface/src/avatar/MyAvatar.cpp | 10 ++++------ interface/src/avatar/MyAvatar.h | 12 ++++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 46dad99bb5..a9cab9582d 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2991,8 +2991,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) { return true; - } - else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) { + } else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) { return true; } @@ -3024,7 +3023,6 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat activate(Vertical); } } else { - //qCDebug(interfaceapp) << "turned off the recenter" << endl; if (!isActive(Rotation) && getForceActivateRotation()) { activate(Rotation); setForceActivateRotation(false); @@ -3086,7 +3084,7 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co } } -bool MyAvatar::FollowHelper::getForceActivateRotation() { +bool MyAvatar::FollowHelper::getForceActivateRotation() const { return _forceActivateRotation; } @@ -3094,7 +3092,7 @@ void MyAvatar::FollowHelper::setForceActivateRotation(bool val) { _forceActivateRotation = val; } -bool MyAvatar::FollowHelper::getForceActivateVertical() { +bool MyAvatar::FollowHelper::getForceActivateVertical() const { return _forceActivateVertical; } @@ -3102,7 +3100,7 @@ void MyAvatar::FollowHelper::setForceActivateVertical(bool val) { _forceActivateVertical = val; } -bool MyAvatar::FollowHelper::getForceActivateHorizontal() { +bool MyAvatar::FollowHelper::getForceActivateHorizontal() const { return _forceActivateHorizontal; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 8644a277c0..6a9d53e6f4 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -807,15 +807,15 @@ private: bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); - bool getForceActivateRotation(); + bool getForceActivateRotation() const; void setForceActivateRotation(bool val); - bool getForceActivateVertical(); + bool getForceActivateVertical() const; void setForceActivateVertical(bool val); - bool getForceActivateHorizontal(); + bool getForceActivateHorizontal() const; void setForceActivateHorizontal(bool val); - bool _forceActivateRotation{ false }; - bool _forceActivateVertical{ false }; - bool _forceActivateHorizontal{ false }; + std::atomic _forceActivateRotation{ false }; + std::atomic _forceActivateVertical{ false }; + std::atomic _forceActivateHorizontal{ false }; }; FollowHelper _follow; From cb07fc47dc58e86c4982105a04e02e721dfb60db Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 27 Mar 2018 13:27:02 -0700 Subject: [PATCH 33/72] Fix ESS remote method calls for connect only users --- .../src/scripts/EntityScriptServer.cpp | 9 +---- domain-server/src/DomainServer.cpp | 38 +------------------ 2 files changed, 4 insertions(+), 43 deletions(-) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 1255c18e71..d242b393bf 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -105,8 +105,6 @@ EntityScriptServer::~EntityScriptServer() { static const QString ENTITY_SCRIPT_SERVER_LOGGING_NAME = "entity-script-server"; void EntityScriptServer::handleReloadEntityServerScriptPacket(QSharedPointer message, SharedNodePointer senderNode) { - // These are temporary checks until we can ensure that nodes eventually disconnect if the Domain Server stops telling them - // about each other. if (senderNode->getCanRez() || senderNode->getCanRezTmp() || senderNode->getCanRezCertified() || senderNode->getCanRezTmpCertified()) { auto entityID = QUuid::fromRfc4122(message->read(NUM_BYTES_RFC4122_UUID)); @@ -119,8 +117,6 @@ void EntityScriptServer::handleReloadEntityServerScriptPacket(QSharedPointer message, SharedNodePointer senderNode) { - // These are temporary checks until we can ensure that nodes eventually disconnect if the Domain Server stops telling them - // about each other. if (senderNode->getCanRez() || senderNode->getCanRezTmp() || senderNode->getCanRezCertified() || senderNode->getCanRezTmpCertified()) { MessageID messageID; message->readPrimitive(&messageID); @@ -190,15 +186,14 @@ void EntityScriptServer::updateEntityPPS() { } void EntityScriptServer::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { - // These are temporary checks until we can ensure that nodes eventually disconnect if the Domain Server stops telling them - // about each other. + bool canRezAny = senderNode->getCanRez() || senderNode->getCanRezTmp() || senderNode->getCanRezCertified() || senderNode->getCanRezTmpCertified(); bool enable = false; message->readPrimitive(&enable); auto senderUUID = senderNode->getUUID(); auto it = _logListeners.find(senderUUID); - if (enable && senderNode->getCanRez()) { + if (enable && canRezAny) { if (it == std::end(_logListeners)) { _logListeners.insert(senderUUID); qCInfo(entity_script_server) << "Node" << senderUUID << "subscribed to log stream"; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 197ac7eac2..dbf2907cc0 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1042,41 +1042,7 @@ void DomainServer::processListRequestPacket(QSharedPointer mess bool DomainServer::isInInterestSet(const SharedNodePointer& nodeA, const SharedNodePointer& nodeB) { auto nodeAData = static_cast(nodeA->getLinkedData()); - auto nodeBData = static_cast(nodeB->getLinkedData()); - - // if we have no linked data for node A then B can't possibly be in the interest set - if (!nodeAData) { - return false; - } - - // first check if the general interest set A contains the type for B - if (nodeAData->getNodeInterestSet().contains(nodeB->getType())) { - // given that there is a match in the general interest set, do any special checks - - // (1/19/17) Agents only need to connect to Entity Script Servers to perform administrative tasks - // related to entity server scripts. Only agents with rez permissions should be doing that, so - // if the agent does not have those permissions, we do not want them and the server to incur the - // overhead of connecting to one another. Additionally we exclude agents that do not care about the - // Entity Script Server and won't attempt to connect to it. - - bool isAgentWithoutRights = nodeA->getType() == NodeType::Agent - && nodeB->getType() == NodeType::EntityScriptServer - && !nodeA->getCanRez() && !nodeA->getCanRezTmp() - && !nodeA->getCanRezCertified() && !nodeA->getCanRezTmpCertified(); - - if (isAgentWithoutRights) { - return false; - } - - bool isScriptServerForIneffectiveAgent = - (nodeA->getType() == NodeType::EntityScriptServer && nodeB->getType() == NodeType::Agent) - && ((nodeBData && !nodeBData->getNodeInterestSet().contains(NodeType::EntityScriptServer)) - || (!nodeB->getCanRez() && !nodeB->getCanRezTmp() && !nodeB->getCanRezCertified() && !nodeB->getCanRezTmpCertified())); - - return !isScriptServerForIneffectiveAgent; - } else { - return false; - } + return nodeAData && nodeAData->getNodeInterestSet().contains(nodeB->getType()); } unsigned int DomainServer::countConnectedUsers() { @@ -3476,4 +3442,4 @@ void DomainServer::handleOctreeFileReplacementRequest(QSharedPointergetCanReplaceContent()) { handleOctreeFileReplacement(message->readAll()); } -} \ No newline at end of file +} From ca3fe28b05f80801bdf96abb97d83fcacb60b6dc Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 27 Mar 2018 18:51:44 -0700 Subject: [PATCH 34/72] JavaScript exceptions during Controller system callbacks are now logged (cherry picked from commit d3aec12e9e76e4aeb8ecbd449cc76afda1a0e35d) --- .../controllers/impl/endpoints/JSEndpoint.cpp | 47 ++++++++++++++++--- .../controllers/impl/endpoints/JSEndpoint.h | 11 ++--- .../impl/endpoints/ScriptEndpoint.cpp | 45 +++++++++++++++--- 3 files changed, 82 insertions(+), 21 deletions(-) diff --git a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp index 7f0e80cbae..2f20cd82c6 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp +++ b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp @@ -6,10 +6,43 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// NOTE: we don't need to include this header unless/until we add additional symbols. -// By removing this header we prevent these warnings on windows: -// -// warning LNK4221: This object file does not define any previously undefined public symbols, -// so it will not be used by any link operation that consumes this library -// -//#include "JSEndpoint.h" \ No newline at end of file +#include "JSEndpoint.h" +#include "../../Logging.h" + +using namespace controller; + +QString formatException(const QJSValue& exception) { + QString note { "UncaughtException" }; + QString result; + + const auto message = exception.toString(); + const auto fileName = exception.property("fileName").toString(); + const auto lineNumber = exception.property("lineNumber").toString(); + const auto stacktrace = exception.property("stack").toString(); + + const QString SCRIPT_EXCEPTION_FORMAT = "[%0] %1 in %2:%3"; + const QString SCRIPT_BACKTRACE_SEP = "\n "; + + result = QString(SCRIPT_EXCEPTION_FORMAT).arg(note, message, fileName, lineNumber); + if (!stacktrace.isEmpty()) { + result += QString("\n[Backtrace]%1%2").arg(SCRIPT_BACKTRACE_SEP).arg(stacktrace); + } + return result; +} + +float JSEndpoint::peek() const { + QJSValue result = _callable.call(); + if (result.isError()) { + qCDebug(controllers).noquote() << formatException(result); + return 0.0f; + } else { + return (float)result.toNumber(); + } +} + +void JSEndpoint::apply(float newValue, const Pointer& source) { + QJSValue result = _callable.call(QJSValueList({ QJSValue(newValue) })); + if (result.isError()) { + qCDebug(controllers).noquote() << formatException(result); + } +} diff --git a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h index 24d5ec93e9..4d179da8e6 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h +++ b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h @@ -24,16 +24,11 @@ public: : Endpoint(Input::INVALID_INPUT), _callable(callable) { } - virtual float peek() const override { - return (float)const_cast(this)->_callable.call().toNumber(); - } - - virtual void apply(float newValue, const Pointer& source) override { - _callable.call(QJSValueList({ QJSValue(newValue) })); - } + virtual float peek() const override; + virtual void apply(float newValue, const Pointer& source) override; private: - QJSValue _callable; + mutable QJSValue _callable; }; } diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp index 3e7fde347e..e2c48d776f 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp +++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp @@ -7,6 +7,7 @@ // #include "ScriptEndpoint.h" +#include "../../Logging.h" #include @@ -14,6 +15,25 @@ using namespace controller; +QString formatException(const QScriptValue& exception) { + QString note { "UncaughtException" }; + QString result; + + const auto message = exception.toString(); + const auto fileName = exception.property("fileName").toString(); + const auto lineNumber = exception.property("lineNumber").toString(); + const auto stacktrace = exception.property("stack").toString(); + + const QString SCRIPT_EXCEPTION_FORMAT = "[%0] %1 in %2:%3"; + const QString SCRIPT_BACKTRACE_SEP = "\n "; + + result = QString(SCRIPT_EXCEPTION_FORMAT).arg(note, message, fileName, lineNumber); + if (!stacktrace.isEmpty()) { + result += QString("\n[Backtrace]%1%2").arg(SCRIPT_BACKTRACE_SEP).arg(stacktrace); + } + return result; +} + float ScriptEndpoint::peek() const { const_cast(this)->updateValue(); return _lastValueRead; @@ -26,10 +46,11 @@ void ScriptEndpoint::updateValue() { } QScriptValue result = _callable.call(); - - // If the callable ever returns a non-number, we assume it's a pose - // and start reporting ourselves as a pose. - if (result.isNumber()) { + if (result.isError()) { + // print JavaScript exception + qCDebug(controllers).noquote() << formatException(result); + _lastValueRead = 0.0f; + } else if (result.isNumber()) { _lastValueRead = (float)_callable.call().toNumber(); } else { Pose::fromScriptValue(result, _lastPoseRead); @@ -52,8 +73,12 @@ void ScriptEndpoint::internalApply(float value, int sourceID) { Q_ARG(int, sourceID)); return; } - _callable.call(QScriptValue(), + QScriptValue result = _callable.call(QScriptValue(), QScriptValueList({ QScriptValue(value), QScriptValue(sourceID) })); + if (result.isError()) { + // print JavaScript exception + qCDebug(controllers).noquote() << formatException(result); + } } Pose ScriptEndpoint::peekPose() const { @@ -67,6 +92,10 @@ void ScriptEndpoint::updatePose() { return; } QScriptValue result = _callable.call(); + if (result.isError()) { + // print JavaScript exception + qCDebug(controllers).noquote() << formatException(result); + } Pose::fromScriptValue(result, _lastPoseRead); } @@ -85,6 +114,10 @@ void ScriptEndpoint::internalApply(const Pose& newPose, int sourceID) { Q_ARG(int, sourceID)); return; } - _callable.call(QScriptValue(), + QScriptValue result = _callable.call(QScriptValue(), QScriptValueList({ Pose::toScriptValue(_callable.engine(), newPose), QScriptValue(sourceID) })); + if (result.isError()) { + // print JavaScript exception + qCDebug(controllers).noquote() << formatException(result); + } } From 35ee1bec09963cc27135512eaa2a82a085fd295d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 28 Mar 2018 14:47:09 -0700 Subject: [PATCH 35/72] fix cmake changes for script copy for dev builds --- interface/CMakeLists.txt | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index e316556d29..fe00d86c3a 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -312,7 +312,7 @@ if (APPLE) COMPONENT ${CLIENT_COMPONENT} ) - set(RESOURCES_INSTALL_DIR "${INTERFACE_INSTALL_APP_PATH}/Contents/Resources") + set(SCRIPTS_INSTALL_DIR "${INTERFACE_INSTALL_APP_PATH}/Contents/Resources") set(RESOURCES_DEV_DIR "$/../Resources") # copy script files beside the executable @@ -326,13 +326,14 @@ if (APPLE) fixup_interface() else() - set(RESOURCES_DEV_DIR "$/resources") + set(INTERFACE_EXEC_DIR "$") + set(RESOURCES_DEV_DIR "${INTERFACE_EXEC_DIR}/resources") # copy the resources files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${RESOURCES_RCC}" - "$" + "${INTERFACE_EXEC_DIR}" # FIXME, the edit script code loads HTML from the scripts folder # which in turn relies on CSS that refers to the fonts. In theory # we should be able to modify the CSS to reference the QRC path to @@ -340,13 +341,13 @@ else() # so we have to retain a copy of the fonts outside of the resources binary COMMAND "${CMAKE_COMMAND}" -E copy_directory "${PROJECT_SOURCE_DIR}/resources/fonts" - "$/resources/fonts" + "${RESOURCES_DEV_DIR}/fonts" COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/scripts" - "${RESOURCES_DEV_DIR}/scripts" + "${INTERFACE_EXEC_DIR}/scripts" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${PROJECT_SOURCE_DIR}/resources/serverless/tutorial.json" - "$/resources/serverless/tutorial.json" + "${RESOURCES_DEV_DIR}/serverless/tutorial.json" ) # link target to external libraries @@ -363,7 +364,7 @@ else() PATTERN "*.exp" EXCLUDE ) - set(RESOURCES_INSTALL_DIR "${INTERFACE_INSTALL_DIR}") + set(SCRIPTS_INSTALL_DIR "${INTERFACE_INSTALL_DIR}") set(EXECUTABLE_COMPONENT ${CLIENT_COMPONENT}) @@ -371,11 +372,11 @@ else() endif() endif() -if (RESOURCES_INSTALL_DIR) +if (SCRIPTS_INSTALL_DIR) # setup install of scripts beside interface executable install( DIRECTORY "${CMAKE_SOURCE_DIR}/scripts/" - DESTINATION ${RESOURCES_INSTALL_DIR}/scripts + DESTINATION ${SCRIPTS_INSTALL_DIR}/scripts COMPONENT ${CLIENT_COMPONENT} ) endif() From 6639a245df244435f87c0093d964646227842ac4 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 28 Mar 2018 18:20:10 -0400 Subject: [PATCH 36/72] Object picking / edition for transitions are activate / deactivated when transition editor window is shown / hidden --- .../utilities/render/debugTransition.js | 133 ++++++++++-------- .../developer/utilities/render/transition.qml | 10 -- 2 files changed, 73 insertions(+), 70 deletions(-) diff --git a/scripts/developer/utilities/render/debugTransition.js b/scripts/developer/utilities/render/debugTransition.js index 27b04bd32b..450b2e3ac9 100644 --- a/scripts/developer/utilities/render/debugTransition.js +++ b/scripts/developer/utilities/render/debugTransition.js @@ -40,6 +40,71 @@ var hasEventBridge = false; + function enableSphereVisualization() { + if (gradientSphere==undefined) { + gradientSphere = Overlays.addOverlay("sphere", { + position: MyAvatar.position, + rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0), + dimensions: { x: 1.0, y: 1.0, z: 1.0 }, + color: { red: 100, green: 150, blue: 255}, + alpha: 0.2, + solid: false + }); + } + if (noiseSphere==undefined) { + noiseSphere = Overlays.addOverlay("sphere", { + position: MyAvatar.position, + rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0), + dimensions: { x: 1.0, y: 1.0, z: 1.0 }, + color: { red: 255, green: 150, blue: 100}, + alpha: 0.2, + solid: false + }); + } + } + + function disableSphereVisualization() { + Overlays.deleteOverlay(noiseSphere); + Overlays.deleteOverlay(gradientSphere); + noiseSphere = undefined + gradientSphere = undefined + } + + // Create a Laser pointer used to pick and add objects to selections + var END_DIMENSIONS = { x: 0.05, y: 0.05, z: 0.05 }; + var COLOR1 = {red: 255, green: 0, blue: 0}; + var COLOR2 = {red: 0, green: 255, blue: 0}; + var end1 = { + type: "sphere", + dimensions: END_DIMENSIONS, + color: COLOR1, + ignoreRayIntersection: true + } + var end2 = { + type: "sphere", + dimensions: END_DIMENSIONS, + color: COLOR2, + ignoreRayIntersection: true + } + var laser + + function enablePointer() { + laser = Pointers.createPointer(PickType.Ray, { + joint: "Mouse", + filter: Picks.PICK_ENTITIES, + renderStates: [{name: "one", end: end1}], + defaultRenderStates: [{name: "one", end: end2, distance: 2.0}], + enabled: true + }); + Pointers.setRenderState(laser, "one"); + Pointers.enablePointer(laser) + } + + function disablePointer() { + Pointers.disablePointer(laser) + Pointers.removePointer(laser); + } + function wireEventBridge(on) { if (!tablet) { print("Warning in wireEventBridge(): 'tablet' undefined!"); @@ -49,11 +114,15 @@ if (!hasEventBridge) { tablet.fromQml.connect(fromQml); hasEventBridge = true; + enablePointer(); + Render.getConfig("RenderMainView.FadeEdit")["editFade"] = true } } else { if (hasEventBridge) { tablet.fromQml.disconnect(fromQml); hasEventBridge = false; + disablePointer(); + Render.getConfig("RenderMainView.FadeEdit")["editFade"] = false } } } @@ -121,38 +190,9 @@ function fromQml(message) { tokens = message.split('*') - print("Received '"+message+"' from transition.qml") + //print("Received '"+message+"' from transition.qml") command = tokens[0].toLowerCase() - if (command=="edit") { - isEditEnabled = (tokens[1]=="true") - if (isEditEnabled) { - if (gradientSphere==undefined) { - gradientSphere = Overlays.addOverlay("sphere", { - position: MyAvatar.position, - rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0), - dimensions: { x: 1.0, y: 1.0, z: 1.0 }, - color: { red: 100, green: 150, blue: 255}, - alpha: 0.2, - solid: false - }); - } - if (noiseSphere==undefined) { - noiseSphere = Overlays.addOverlay("sphere", { - position: MyAvatar.position, - rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0), - dimensions: { x: 1.0, y: 1.0, z: 1.0 }, - color: { red: 255, green: 150, blue: 100}, - alpha: 0.2, - solid: false - }); - } - } else if (!isEditEnabled) { - Overlays.deleteOverlay(noiseSphere); - Overlays.deleteOverlay(gradientSphere); - noiseSphere = undefined - gradientSphere = undefined - } - } else if (command=="category") { + if (command=="category") { editedCategory = parseInt(tokens[1]) } else if (command=="save") { var filePath = tokens[1] @@ -189,35 +229,9 @@ }); - // Create a Laser pointer used to pick and add objects to selections - var END_DIMENSIONS = { x: 0.05, y: 0.05, z: 0.05 }; - var COLOR1 = {red: 255, green: 0, blue: 0}; - var COLOR2 = {red: 0, green: 255, blue: 0}; - var end1 = { - type: "sphere", - dimensions: END_DIMENSIONS, - color: COLOR1, - ignoreRayIntersection: true - } - var end2 = { - type: "sphere", - dimensions: END_DIMENSIONS, - color: COLOR2, - ignoreRayIntersection: true - } - - var laser = Pointers.createPointer(PickType.Ray, { - joint: "Mouse", - filter: Picks.PICK_ENTITIES, - renderStates: [{name: "one", end: end1}], - defaultRenderStates: [{name: "one", end: end2, distance: 2.0}], - enabled: true - }); - Pointers.setRenderState(laser, "one"); - var currentSelectionName = "" var SelectionList = "TransitionEdit" - Pointers.enablePointer(laser) + Selection.enableListToScene(SelectionList) Selection.clearSelectedItemsList(SelectionList) @@ -231,8 +245,7 @@ }) function cleanup() { - Pointers.disablePointer(laser) - Pointers.removePointer(ray); + disablePointer(); Selection.removeListFromMap(SelectionList) Selection.disableListToScene(SelectionList); Overlays.deleteOverlay(noiseSphere); diff --git a/scripts/developer/utilities/render/transition.qml b/scripts/developer/utilities/render/transition.qml index 564090e2d6..342b2b533e 100644 --- a/scripts/developer/utilities/render/transition.qml +++ b/scripts/developer/utilities/render/transition.qml @@ -62,16 +62,6 @@ Rectangle { Layout.fillWidth: true id: root_col - HifiControls.CheckBox { - anchors.verticalCenter: parent.verticalCenter - boxSize: 20 - text: "Edit" - checked: root.configEdit["editFade"] - onCheckedChanged: { - root.configEdit["editFade"] = checked; - root.sendToScript("edit*"+checked); - } - } HifiControls.ComboBox { anchors.verticalCenter: parent.verticalCenter Layout.fillWidth: true From 9a7f88cd783315a01c78fc462d93331cacd00c0e Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 28 Mar 2018 19:23:09 -0400 Subject: [PATCH 37/72] Moved save / load buttons to top --- .../developer/utilities/render/transition.qml | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/scripts/developer/utilities/render/transition.qml b/scripts/developer/utilities/render/transition.qml index 342b2b533e..b002de30aa 100644 --- a/scripts/developer/utilities/render/transition.qml +++ b/scripts/developer/utilities/render/transition.qml @@ -58,7 +58,7 @@ Rectangle { } RowLayout { - spacing: 20 + spacing: 8 Layout.fillWidth: true id: root_col @@ -84,6 +84,18 @@ Rectangle { root.sendToScript("category*"+currentIndex) } } + HifiControls.Button { + action: saveAction + Layout.fillWidth: true + anchors.top: parent.top + anchors.bottom: parent.bottom + } + HifiControls.Button { + action: loadAction + Layout.fillWidth: true + anchors.top: parent.top + anchors.bottom: parent.bottom + } } RowLayout { @@ -375,20 +387,6 @@ Rectangle { id: paramWidgetLoader sourceComponent: paramWidgets } - - Row { - anchors.left: parent.left - anchors.right: parent.right - - Button { - action: saveAction - } - Button { - action: loadAction - } - } - - } } \ No newline at end of file From 07cb1c1f9e9d13a2f04dfd17fb8a01433eedd945 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 29 Mar 2018 10:19:24 -0400 Subject: [PATCH 38/72] Moved gradient invert checkbox --- .../developer/utilities/render/transition.qml | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/scripts/developer/utilities/render/transition.qml b/scripts/developer/utilities/render/transition.qml index b002de30aa..a996c3a198 100644 --- a/scripts/developer/utilities/render/transition.qml +++ b/scripts/developer/utilities/render/transition.qml @@ -152,12 +152,7 @@ Rectangle { spacing: 3 width: root_col.width - HifiControls.CheckBox { - text: "Invert" - boxSize: 20 - checked: root.config["isInverted"] - onCheckedChanged: { root.config["isInverted"] = checked } - } + RowLayout { Layout.fillWidth: true @@ -219,16 +214,32 @@ Rectangle { } } - - ConfigSlider { + RowLayout { + spacing: 20 height: 36 - label: "Edge Width" - integral: false - config: root.config - property: "edgeWidth" - max: 1.0 - min: 0.0 + + HifiControls.CheckBox { + text: "Invert gradient" + anchors.verticalCenter: parent.verticalCenter + boxSize: 20 + checked: root.config["isInverted"] + onCheckedChanged: { root.config["isInverted"] = checked } + } + ConfigSlider { + anchors.left: undefined + anchors.verticalCenter: parent.verticalCenter + height: 36 + width: 300 + label: "Edge Width" + integral: false + config: root.config + property: "edgeWidth" + max: 1.0 + min: 0.0 + } } + + RowLayout { Layout.fillWidth: true From 648e6a6c9b524c6eed330599af2e7e94cfc69bc6 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 29 Mar 2018 10:47:18 -0400 Subject: [PATCH 39/72] Added description for each event --- scripts/developer/utilities/render/transition.qml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/scripts/developer/utilities/render/transition.qml b/scripts/developer/utilities/render/transition.qml index a996c3a198..8811a15e82 100644 --- a/scripts/developer/utilities/render/transition.qml +++ b/scripts/developer/utilities/render/transition.qml @@ -75,6 +75,14 @@ Rectangle { } } onCurrentIndexChanged: { + var descriptions = [ + "Time based threshold, gradients centered on object", + "Fixed threshold, gradients centered on owner avatar", + "Position based threshold (increases when trespasser moves closer to avatar), gradients centered on trespasser avatar", + "Time based threshold, gradients centered on bottom of object", + "UNSUPPORTED" + ] + description.text = descriptions[currentIndex] root.config["editedCategory"] = currentIndex; // This is a hack to be sure the widgets below properly reflect the change of category: delete the Component // by setting the loader source to Null and then recreate it 100ms later @@ -98,6 +106,13 @@ Rectangle { } } + HifiControls.Label { + id: description + text: "..." + Layout.fillWidth: true + wrapMode: Text.WordWrap + } + RowLayout { spacing: 20 height: 36 From ef63651b2bba29ed901883d23b6503e7100b6630 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 29 Mar 2018 12:07:56 -0400 Subject: [PATCH 40/72] Duration and timing controls are disabled when event is not time based --- scripts/developer/utilities/render/transition.qml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/developer/utilities/render/transition.qml b/scripts/developer/utilities/render/transition.qml index 8811a15e82..65f4f4354a 100644 --- a/scripts/developer/utilities/render/transition.qml +++ b/scripts/developer/utilities/render/transition.qml @@ -72,6 +72,8 @@ Rectangle { interval: 100; running: false; repeat: false onTriggered: { paramWidgetLoader.sourceComponent = paramWidgets + var isTimeBased = categoryBox.currentIndex==0 || categoryBox.currentIndex==3 + paramWidgetLoader.item.isTimeBased = isTimeBased } } onCurrentIndexChanged: { @@ -82,6 +84,7 @@ Rectangle { "Time based threshold, gradients centered on bottom of object", "UNSUPPORTED" ] + description.text = descriptions[currentIndex] root.config["editedCategory"] = currentIndex; // This is a hack to be sure the widgets below properly reflect the change of category: delete the Component @@ -166,7 +169,7 @@ Rectangle { ColumnLayout { spacing: 3 width: root_col.width - + property bool isTimeBased RowLayout { Layout.fillWidth: true @@ -327,6 +330,8 @@ Rectangle { Layout.fillWidth: true ConfigSlider { + enabled: isTimeBased + opacity: isTimeBased ? 1.0 : 0.0 anchors.left: undefined anchors.right: undefined Layout.fillWidth: true @@ -339,6 +344,8 @@ Rectangle { min: 0.1 } HifiControls.ComboBox { + enabled: isTimeBased + opacity: isTimeBased ? 1.0 : 0.0 Layout.fillWidth: true model: ["Linear", "Ease In", "Ease Out", "Ease In / Out"] currentIndex: root.config["timing"] From 8cdb59413d7c3ad06d90a082239261756990ecf5 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 29 Mar 2018 09:26:05 -0700 Subject: [PATCH 41/72] fix-qml-confict --- interface/resources/qml/{AudioScope.qml => AudioScopeUI.qml} | 1 + scripts/developer/utilities/audio/audioScope.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) rename interface/resources/qml/{AudioScope.qml => AudioScopeUI.qml} (99%) diff --git a/interface/resources/qml/AudioScope.qml b/interface/resources/qml/AudioScopeUI.qml similarity index 99% rename from interface/resources/qml/AudioScope.qml rename to interface/resources/qml/AudioScopeUI.qml index aa181dbf8d..b009c249bc 100644 --- a/interface/resources/qml/AudioScope.qml +++ b/interface/resources/qml/AudioScopeUI.qml @@ -12,6 +12,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "styles-uit" import "controls-uit" as HifiControlsUit +import "." as HifiRoot Item { id: root diff --git a/scripts/developer/utilities/audio/audioScope.js b/scripts/developer/utilities/audio/audioScope.js index 00c9e4b725..63cbf0a6e2 100644 --- a/scripts/developer/utilities/audio/audioScope.js +++ b/scripts/developer/utilities/audio/audioScope.js @@ -1,4 +1,4 @@ -var qml = Script.resourcesPath() + '/qml/AudioScope.qml'; +var qml = Script.resourcesPath() + '/qml/AudioScopeUI.qml'; var window = new OverlayWindow({ title: 'Audio Scope', source: qml, @@ -14,4 +14,4 @@ window.closed.connect(function () { AudioScope.setServerEcho(false); AudioScope.selectAudioScopeFiveFrames(); Script.stop(); -}); \ No newline at end of file +}); From 0bdf26faaf321d09d9501830862aafd778d7adcc Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 29 Mar 2018 09:29:01 -0700 Subject: [PATCH 42/72] minimize diff --- interface/resources/qml/AudioScopeUI.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/resources/qml/AudioScopeUI.qml b/interface/resources/qml/AudioScopeUI.qml index b009c249bc..aa181dbf8d 100644 --- a/interface/resources/qml/AudioScopeUI.qml +++ b/interface/resources/qml/AudioScopeUI.qml @@ -12,7 +12,6 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "styles-uit" import "controls-uit" as HifiControlsUit -import "." as HifiRoot Item { id: root From afe39aba46b9c69e3ba6a4c6981f8f8da37c5ac1 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 28 Mar 2018 13:47:31 -0700 Subject: [PATCH 43/72] fix octal code char issue --- libraries/entities/src/EntityTree.cpp | 6 +++--- libraries/entities/src/UpdateEntityOperator.cpp | 2 +- libraries/shared/src/OctalCode.cpp | 6 +++--- libraries/shared/src/OctalCode.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 75f024d0b9..2cf66911a4 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -425,8 +425,8 @@ bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperti if (!childEntity) { continue; } - EntityTreeElementPointer containingElement = childEntity->getElement(); - if (!containingElement) { + EntityTreeElementPointer childContainingElement = childEntity->getElement(); + if (!childContainingElement) { continue; } @@ -440,7 +440,7 @@ bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperti addToNeedsParentFixupList(childEntity); } - UpdateEntityOperator theChildOperator(getThisPointer(), containingElement, childEntity, queryCube); + UpdateEntityOperator theChildOperator(getThisPointer(), childContainingElement, childEntity, queryCube); recurseTreeWithOperator(&theChildOperator); foreach (SpatiallyNestablePointer childChild, childEntity->getChildren()) { if (childChild && childChild->getNestableType() == NestableType::Entity) { diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index fa7e5ca38f..32bd2f06ba 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -288,7 +288,7 @@ OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(const OctreeEle int indexOfChildContainingNewEntity = element->getMyChildContaining(_newEntityBox); if (childIndex == indexOfChildContainingNewEntity) { - return element->addChildAtIndex(childIndex);; + return element->addChildAtIndex(childIndex); } } } diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 1a0a19bf44..ae4338be6f 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -46,7 +46,7 @@ void printOctalCode(const unsigned char* octalCode) { } char sectionValue(const unsigned char* startByte, char startIndexInByte) { - char rightShift = 8 - startIndexInByte - 3; + int8_t rightShift = 8 - startIndexInByte - 3; if (rightShift < 0) { return ((startByte[0] << -rightShift) & 7) + (startByte[1] >> (8 + rightShift)); @@ -73,7 +73,7 @@ int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsi return sectionValue(descendantOctalCode + 1 + (branchStartBit / 8), branchStartBit % 8); } -unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber) { +unsigned char* childOctalCode(const unsigned char* parentOctalCode, int childNumber) { // find the length (in number of three bit code sequences) // in the parent @@ -111,7 +111,7 @@ unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNu // calculate the amount of left shift required // this will be -1 or -2 if there's wrap - char leftShift = 8 - (startBit % 8) - 3; + int8_t leftShift = 8 - (startBit % 8) - 3; if (leftShift < 0) { // we have a wrap-around to accomodate diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index a0d86f32d2..89c5e6d74e 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -30,7 +30,7 @@ using OctalCodePtrList = std::vector; void printOctalCode(const unsigned char* octalCode); size_t bytesRequiredForCodeLength(unsigned char threeBitCodes); int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode); -unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber); +unsigned char* childOctalCode(const unsigned char* parentOctalCode, int childNumber); const int OVERFLOWED_OCTCODE_BUFFER = -1; const int UNKNOWN_OCTCODE_LENGTH = -2; From 3f44b88d2d5d512d4dedcfa988b1951e76dca4a1 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 29 Mar 2018 10:09:51 -0700 Subject: [PATCH 44/72] added js documentation for the three trigger recenter functionsthat have been added to MyAvatar class --- interface/src/avatar/MyAvatar.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 6a9d53e6f4..118f14e71b 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -404,6 +404,28 @@ public: Q_INVOKABLE void enableDriveKey(DriveKeys key); Q_INVOKABLE bool isDriveKeyDisabled(DriveKeys key) const; + /**jsdoc + *The triggerVerticalRecenter function activates one time the recentering + *behaviour in the vertical direction. This call is only takes effect when the property + *MyAvatar.hmdLeanRecenterEnabled is set to false. + *@function MyAvatar.triggerVerticalRecenter + * + */ + + /**jsdoc + *The triggerHorizontalRecenter function activates one time the recentering behaviour + *in the horizontal direction. This call is only takes effect when the property + *MyAvatar.hmdLeanRecenterEnabled is set to false. + *@function MyAvatar.triggerHorizontalRecenter + */ + + /**jsdoc + *The triggerRotationRecenter function activates one time the recentering behaviour + *in the rotation of the root of the avatar. This call is only takes effect when the property + *MyAvatar.hmdLeanRecenterEnabled is set to false. + *@function MyAvatar.triggerRotationRecenter + */ + Q_INVOKABLE void triggerVerticalRecenter(); Q_INVOKABLE void triggerHorizontalRecenter(); Q_INVOKABLE void triggerRotationRecenter(); From dcfebde54a7ea2f66b2abd1f2abb5ac205b9dfe5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 29 Mar 2018 10:50:43 -0700 Subject: [PATCH 45/72] put back the pre serverless-domain behavior for when a json file is dragged-and-dropped into the interface window -- import the json rather than load as a serverless-domain --- interface/src/Application.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7e6c65f8f4..af0ac5bc78 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6275,8 +6275,9 @@ bool Application::canAcceptURL(const QString& urlString) const { bool Application::acceptURL(const QString& urlString, bool defaultUpload) { QUrl url(urlString); - if (isDomainURL(url)) { - // this is a URL for a domain, either hifi:// or serverless - have the AddressManager handle it + + if (url.scheme() == URL_SCHEME_HIFI) { + // this is a hifi URL - have the AddressManager handle it QMetaObject::invokeMethod(DependencyManager::get().data(), "handleLookupString", Qt::AutoConnection, Q_ARG(const QString&, urlString)); return true; From e738274e907f3243a3da7e5da64fc22784b1288a Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 29 Mar 2018 11:10:39 -0700 Subject: [PATCH 46/72] map flying down back to C key --- interface/resources/controllers/keyboardMouse.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json index 174f9af7d7..660bc281e3 100644 --- a/interface/resources/controllers/keyboardMouse.json +++ b/interface/resources/controllers/keyboardMouse.json @@ -114,7 +114,7 @@ { "from": "Keyboard.W", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_FORWARD" }, { "from": "Keyboard.S", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_BACKWARD" }, { "from": "Keyboard.Shift", "when": ["!Keyboard.Left", "!Keyboard.Right"], "to": "Actions.SPRINT" }, - { "from": "Keyboard.Control", "to": "Actions.VERTICAL_DOWN" }, + { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" }, { "from": "Keyboard.Left", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" }, { "from": "Keyboard.Right", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" }, { "from": "Keyboard.Up", "when": "Application.CameraFirstPerson", "to": "Actions.LONGITUDINAL_FORWARD" }, From 420672a7690d1ccaf4fb070812bc9abbc7c11f6f Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 29 Mar 2018 09:26:05 -0700 Subject: [PATCH 47/72] fix-qml-confict --- interface/resources/qml/{AudioScope.qml => AudioScopeUI.qml} | 1 + scripts/developer/utilities/audio/audioScope.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) rename interface/resources/qml/{AudioScope.qml => AudioScopeUI.qml} (99%) diff --git a/interface/resources/qml/AudioScope.qml b/interface/resources/qml/AudioScopeUI.qml similarity index 99% rename from interface/resources/qml/AudioScope.qml rename to interface/resources/qml/AudioScopeUI.qml index aa181dbf8d..b009c249bc 100644 --- a/interface/resources/qml/AudioScope.qml +++ b/interface/resources/qml/AudioScopeUI.qml @@ -12,6 +12,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "styles-uit" import "controls-uit" as HifiControlsUit +import "." as HifiRoot Item { id: root diff --git a/scripts/developer/utilities/audio/audioScope.js b/scripts/developer/utilities/audio/audioScope.js index 00c9e4b725..63cbf0a6e2 100644 --- a/scripts/developer/utilities/audio/audioScope.js +++ b/scripts/developer/utilities/audio/audioScope.js @@ -1,4 +1,4 @@ -var qml = Script.resourcesPath() + '/qml/AudioScope.qml'; +var qml = Script.resourcesPath() + '/qml/AudioScopeUI.qml'; var window = new OverlayWindow({ title: 'Audio Scope', source: qml, @@ -14,4 +14,4 @@ window.closed.connect(function () { AudioScope.setServerEcho(false); AudioScope.selectAudioScopeFiveFrames(); Script.stop(); -}); \ No newline at end of file +}); From f7a081c9ecf6180c848697041bf519a033da08cb Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 29 Mar 2018 09:29:01 -0700 Subject: [PATCH 48/72] minimize diff --- interface/resources/qml/AudioScopeUI.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/resources/qml/AudioScopeUI.qml b/interface/resources/qml/AudioScopeUI.qml index b009c249bc..aa181dbf8d 100644 --- a/interface/resources/qml/AudioScopeUI.qml +++ b/interface/resources/qml/AudioScopeUI.qml @@ -12,7 +12,6 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "styles-uit" import "controls-uit" as HifiControlsUit -import "." as HifiRoot Item { id: root From 3b9007809793ebcd2437fc231fa27fdf0666e867 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 30 Mar 2018 08:36:18 +1300 Subject: [PATCH 49/72] Remove Entities.currentAvatarEnergy and related from the API --- .../entities/src/EntityScriptingInterface.cpp | 59 +------------------ .../entities/src/EntityScriptingInterface.h | 18 ------ 2 files changed, 2 insertions(+), 75 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7e15e78624..c4a9956c90 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -258,12 +258,6 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties float volume = dimensions.x * dimensions.y * dimensions.z; auto density = propertiesWithSimID.getDensity(); auto newVelocity = propertiesWithSimID.getVelocity().length(); - float cost = calculateCost(density * volume, 0, newVelocity); - cost *= costMultiplier; - - if (cost > _currentAvatarEnergy) { - return QUuid(); - } EntityItemID id = EntityItemID(QUuid::createUuid()); @@ -295,9 +289,7 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties // queue the packet if (success) { - emit debitEnergySource(cost); queueEntityMessage(PacketType::EntityAdd, id, propertiesWithSimID); - return id; } else { return QUuid(); @@ -387,18 +379,6 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& EntityItemID entityID(id); if (!_entityTree) { queueEntityMessage(PacketType::EntityEdit, entityID, properties); - - //if there is no local entity entity tree, no existing velocity, use 0. - float cost = calculateCost(density * volume, oldVelocity, newVelocity); - cost *= costMultiplier; - - if (cost > _currentAvatarEnergy) { - return QUuid(); - } else { - //debit the avatar energy and continue - emit debitEnergySource(cost); - } - return id; } // If we have a local entity tree set, then also update it. @@ -442,23 +422,11 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& properties.setClientOnly(entity->getClientOnly()); properties.setOwningAvatarID(entity->getOwningAvatarID()); properties = convertPropertiesFromScriptSemantics(properties, properties.getScalesWithParent()); - - float cost = calculateCost(density * volume, oldVelocity, newVelocity); - cost *= costMultiplier; - - if (cost > _currentAvatarEnergy) { - updatedEntity = false; - } else { - //debit the avatar energy and continue - updatedEntity = _entityTree->updateEntity(entityID, properties); - if (updatedEntity) { - emit debitEnergySource(cost); - } - } + updatedEntity = _entityTree->updateEntity(entityID, properties); }); // FIXME: We need to figure out a better way to handle this. Allowing these edits to go through potentially - // breaks avatar energy and entities that are parented. + // breaks entities that are parented. // // To handle cases where a script needs to edit an entity with a _known_ entity id but doesn't exist // in the local entity tree, we need to allow those edits to go through to the server. @@ -581,16 +549,6 @@ void EntityScriptingInterface::deleteEntity(QUuid id) { float volume = dimensions.x * dimensions.y * dimensions.z; auto density = entity->getDensity(); auto velocity = entity->getWorldVelocity().length(); - float cost = calculateCost(density * volume, velocity, 0); - cost *= costMultiplier; - - if (cost > _currentAvatarEnergy) { - shouldDelete = false; - return; - } else { - //debit the avatar energy and continue - emit debitEnergySource(cost); - } if (entity->getLocked()) { shouldDelete = false; @@ -1816,19 +1774,6 @@ float EntityScriptingInterface::calculateCost(float mass, float oldVelocity, flo return std::abs(mass * (newVelocity - oldVelocity)); } -void EntityScriptingInterface::setCurrentAvatarEnergy(float energy) { - // qCDebug(entities) << "NEW AVATAR ENERGY IN ENTITY SCRIPTING INTERFACE: " << energy; - _currentAvatarEnergy = energy; -} - -float EntityScriptingInterface::getCostMultiplier() { - return costMultiplier; -} - -void EntityScriptingInterface::setCostMultiplier(float value) { - costMultiplier = value; -} - // TODO move this someplace that makes more sense... bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions, const glm::vec3& start, const glm::vec3& end, float radius) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 9613a7a310..f92a88e0d2 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -94,8 +94,6 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra * Interface has displayed and so knows about. * * @namespace Entities - * @property {number} currentAvatarEnergy - Deprecated - * @property {number} costMultiplier - Deprecated * @property {Uuid} keyboardFocusEntity - Get or set the {@link Entities.EntityType|Web} entity that has keyboard focus. * If no entity has keyboard focus, get returns null; set to null or {@link Uuid|Uuid.NULL} to * clear keyboard focus. @@ -104,8 +102,6 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra class EntityScriptingInterface : public OctreeScriptingInterface, public Dependency { Q_OBJECT - Q_PROPERTY(float currentAvatarEnergy READ getCurrentAvatarEnergy WRITE setCurrentAvatarEnergy) - Q_PROPERTY(float costMultiplier READ getCostMultiplier WRITE setCostMultiplier) Q_PROPERTY(QUuid keyboardFocusEntity READ getKeyboardFocusEntity WRITE setKeyboardFocusEntity) friend EntityPropertyMetadataRequest; @@ -1834,14 +1830,6 @@ signals: */ void clearingEntities(); - /**jsdoc - * @function Entities.debitEnergySource - * @param {number} value - The amount to debit. - * @returns {Signal} - * @deprecated This function is deprecated and will soon be removed. - */ - void debitEnergySource(float value); - /**jsdoc * Triggered in when a script in a {@link Entities.EntityType|Web} entity's Web page script sends an event over the * script's EventBridge. @@ -1882,14 +1870,8 @@ private: QSharedPointer _entitiesScriptEngine; bool _bidOnSimulationOwnership { false }; - float _currentAvatarEnergy = { FLT_MAX }; - float getCurrentAvatarEnergy() { return _currentAvatarEnergy; } - void setCurrentAvatarEnergy(float energy); ActivityTracking _activityTracking; - float costMultiplier = { 0.01f }; - float getCostMultiplier(); - void setCostMultiplier(float value); }; #endif // hifi_EntityScriptingInterface_h From e5da59a62f53e15bae36d524e208f249f6723719 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Fri, 16 Mar 2018 15:54:42 +0300 Subject: [PATCH 50/72] FB12870 - Tablet UI ->Asset Browser unresponsive when enabling/disabling "use baked version" --- interface/resources/qml/hifi/AssetServer.qml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 1ff954feff..526ea6aad0 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -39,6 +39,7 @@ Windows.ScrollingWindow { property var assetMappingsModel: Assets.mappingModel; property var currentDirectory; property var selectedItemCount: treeView.selection.selectedIndexes.length; + property int updatesCount: 0; // this is used for notifying model-dependent bindings about model updates Settings { category: "Overlay.AssetServer" @@ -51,6 +52,9 @@ Windows.ScrollingWindow { ApplicationInterface.uploadRequest.connect(uploadClicked); assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError); assetMappingsModel.autoRefreshEnabled = true; + assetMappingsModel.updated.connect(function() { + ++updatesCount; + }); reload(); } @@ -852,12 +856,17 @@ Windows.ScrollingWindow { checked = Qt.binding(isChecked); } + function getStatus() { + // kind of hack for ensuring getStatus() will be re-evaluated on updatesCount changes + return updatesCount, assetProxyModel.data(treeView.selection.currentIndex, 0x105); + } + function isEnabled() { if (!treeView.selection.hasSelection) { return false; } - var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105); + var status = getStatus(); if (status === "--") { return false; } @@ -882,9 +891,9 @@ Windows.ScrollingWindow { return false; } - var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105); - return isEnabled() && status !== "Not Baked"; - } + var status = getStatus(); + return isEnabled() && status !== "Not Baked"; + } } Item { From 7027ccb6d8ad626a2c230db45553852c00bbc957 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 30 Mar 2018 09:35:25 +1300 Subject: [PATCH 51/72] Remove unused code --- .../entities/src/EntityScriptingInterface.cpp | 23 ------------------- .../entities/src/EntityScriptingInterface.h | 1 - 2 files changed, 24 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index c4a9956c90..2e9b386ba5 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -254,11 +254,6 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties propertiesWithSimID = convertPropertiesFromScriptSemantics(propertiesWithSimID, scalesWithParent); propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged()); - auto dimensions = propertiesWithSimID.getDimensions(); - float volume = dimensions.x * dimensions.y * dimensions.z; - auto density = propertiesWithSimID.getDensity(); - auto newVelocity = propertiesWithSimID.getVelocity().length(); - EntityItemID id = EntityItemID(QUuid::createUuid()); // If we have a local entity tree set, then also update it. @@ -370,12 +365,6 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& EntityItemProperties properties = scriptSideProperties; - auto dimensions = properties.getDimensions(); - float volume = dimensions.x * dimensions.y * dimensions.z; - auto density = properties.getDensity(); - auto newVelocity = properties.getVelocity().length(); - float oldVelocity = { 0.0f }; - EntityItemID entityID(id); if (!_entityTree) { queueEntityMessage(PacketType::EntityEdit, entityID, properties); @@ -400,9 +389,6 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& // All of parentID, parentJointIndex, position, rotation are needed to make sense of any of them. // If any of these changed, pull any missing properties from the entity. - //existing entity, retrieve old velocity for check down below - oldVelocity = entity->getWorldVelocity().length(); - if (!scriptSideProperties.parentIDChanged()) { properties.setParentID(entity->getParentID()); } @@ -545,11 +531,6 @@ void EntityScriptingInterface::deleteEntity(QUuid id) { return; } - auto dimensions = entity->getScaledDimensions(); - float volume = dimensions.x * dimensions.y * dimensions.z; - auto density = entity->getDensity(); - auto velocity = entity->getWorldVelocity().length(); - if (entity->getLocked()) { shouldDelete = false; } else { @@ -1770,10 +1751,6 @@ void EntityScriptingInterface::emitScriptEvent(const EntityItemID& entityID, con } } -float EntityScriptingInterface::calculateCost(float mass, float oldVelocity, float newVelocity) { - return std::abs(mass * (newVelocity - oldVelocity)); -} - // TODO move this someplace that makes more sense... bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions, const glm::vec3& start, const glm::vec3& end, float radius) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index f92a88e0d2..4c2a2a47b4 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -122,7 +122,6 @@ public: void setEntityTree(EntityTreePointer modelTree); EntityTreePointer getEntityTree() { return _entityTree; } void setEntitiesScriptEngine(QSharedPointer engine); - float calculateCost(float mass, float oldVelocity, float newVelocity); void resetActivityTracking(); ActivityTracking getActivityTracking() const { return _activityTracking; } From 814cfa4587fd9eeb88b5ac13c9a7a12ec22b2d44 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Fri, 30 Mar 2018 00:09:28 +0300 Subject: [PATCH 52/72] fix TabletAssetServer --- .../qml/hifi/dialogs/TabletAssetServer.qml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index 138eb5c6f8..6bf8f8a5d5 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -40,6 +40,7 @@ Rectangle { property var assetMappingsModel: Assets.mappingModel; property var currentDirectory; property var selectedItemCount: treeView.selection.selectedIndexes.length; + property int updatesCount: 0; // this is used for notifying model-dependent bindings about model updates Settings { category: "Overlay.AssetServer" @@ -51,6 +52,9 @@ Rectangle { ApplicationInterface.uploadRequest.connect(uploadClicked); assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError); assetMappingsModel.autoRefreshEnabled = true; + assetMappingsModel.updated.connect(function() { + ++updatesCount; + }); reload(); } @@ -850,12 +854,17 @@ Rectangle { checked = Qt.binding(isChecked); } + function getStatus() { + // kind of hack for ensuring getStatus() will be re-evaluated on updatesCount changes + return updatesCount, assetProxyModel.data(treeView.selection.currentIndex, 0x105); + } + function isEnabled() { if (!treeView.selection.hasSelection) { return false; } - var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105); + var status = getStatus(); if (status === "--") { return false; } @@ -880,7 +889,7 @@ Rectangle { return false; } - var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105); + var status = getStatus(); return isEnabled() && status !== "Not Baked"; } } From 5a7e9d8e3eb185e086f674b5d5984adf3d5e8457 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 30 Mar 2018 09:48:04 -0700 Subject: [PATCH 53/72] fix shadows on primitives --- libraries/entities-renderer/src/RenderableShapeEntityItem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index b05854da4e..feb88bed4b 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -131,6 +131,8 @@ ItemKey ShapeEntityRenderer::getKey() { withReadLock([&] { if (isTransparent()) { builder.withTransparent(); + } else if (_canCastShadow) { + builder.withShadowCaster(); } }); From bd6dbadadee749a6fd86efbbf01367221e0573d9 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 30 Mar 2018 10:18:03 -0700 Subject: [PATCH 54/72] No magic numbers --- assignment-client/src/entities/EntityServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 1862287b6d..01d48cb0b2 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -489,7 +489,7 @@ void EntityServer::startDynamicDomainVerification() { if (networkReply->error() == QNetworkReply::NoError) { if (jsonObject["domain_id"].toString() != thisDomainID) { - if (entity->getCreatedAgo() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/1000)) { + if (entity->getCreatedAgo() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/MSECS_PER_SECOND)) { qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value(); tree->deleteEntity(i.value(), true); From 59fb448698f8276d6fa813a55033b1bb661ff0c9 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 30 Mar 2018 10:28:40 -0700 Subject: [PATCH 55/72] Remove duplicate function --- assignment-client/src/entities/EntityServer.cpp | 2 +- libraries/entities/src/EntityItem.h | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 01d48cb0b2..d2bcbf2886 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -489,7 +489,7 @@ void EntityServer::startDynamicDomainVerification() { if (networkReply->error() == QNetworkReply::NoError) { if (jsonObject["domain_id"].toString() != thisDomainID) { - if (entity->getCreatedAgo() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/MSECS_PER_SECOND)) { + if (entity->getAge() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/MSECS_PER_SECOND)) { qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value(); tree->deleteEntity(i.value(), true); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 962babb558..0303964e18 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -222,10 +222,6 @@ public: quint64 getCreated() const; /// get the created-time in useconds for the entity void setCreated(quint64 value); /// set the created-time in useconds for the entity - float getCreatedAgo() const /// Elapsed seconds since this entity was created - { - return (float)(usecTimestampNow() - getCreated()) / (float)USECS_PER_SECOND; - } /// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted bool isImmortal() const { return getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME; } From 0c2c09e77b83cfa1b98cf2dbef2e47032a1e5253 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 30 Mar 2018 15:22:48 -0400 Subject: [PATCH 56/72] Fixed layout in HMD --- scripts/developer/utilities/render/transition.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/developer/utilities/render/transition.qml b/scripts/developer/utilities/render/transition.qml index 65f4f4354a..f74468a273 100644 --- a/scripts/developer/utilities/render/transition.qml +++ b/scripts/developer/utilities/render/transition.qml @@ -64,7 +64,8 @@ Rectangle { HifiControls.ComboBox { anchors.verticalCenter: parent.verticalCenter - Layout.fillWidth: true + anchors.left : parent.left + width: 300 id: categoryBox model: ["Elements enter/leave domain", "Bubble isect. - Owner POV", "Bubble isect. - Trespasser POV", "Another user leaves/arrives", "Changing an avatar"] Timer { From c99676b51010245393fbc2bff31e1c51a1053653 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 30 Mar 2018 13:44:54 -0700 Subject: [PATCH 57/72] atlernate fix for selected entities --- interface/src/raypick/LaserPointer.cpp | 70 +++++++++++++------ interface/src/raypick/LaserPointer.h | 1 + .../ui/overlays/ContextOverlayInterface.cpp | 3 +- libraries/pointers/src/Pointer.cpp | 5 +- libraries/pointers/src/Pointer.h | 1 + 5 files changed, 53 insertions(+), 27 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index a4fe516590..7b99c37679 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -81,6 +81,50 @@ void LaserPointer::editRenderState(const std::string& state, const QVariant& sta }); } +PickResultPointer LaserPointer::getVisualPickResult(const PickResultPointer& pickResult) { + PickResultPointer visualPickResult = pickResult; + auto rayPickResult = std::static_pointer_cast(visualPickResult); + IntersectionType type = rayPickResult ? rayPickResult->type : IntersectionType::NONE; + + if (type != IntersectionType::HUD) { + if (!_lockEndObject.id.isNull()) { + PickRay pickRay = rayPickResult ? PickRay(rayPickResult->pickVariant) : PickRay(); + glm::vec3 endVec; + glm::vec3 pos; + glm::quat rot; + glm::vec3 dim; + glm::vec3 registrationPoint; + if (_lockEndObject.isOverlay) { + pos = vec3FromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "position").value); + rot = quatFromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "rotation").value); + dim = vec3FromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "dimensions").value); + registrationPoint = glm::vec3(0.5f); + } else { + EntityItemProperties props = DependencyManager::get()->getEntityProperties(_lockEndObject.id); + glm::mat4 entityMat = createMatFromQuatAndPos(props.getRotation(), props.getPosition()); + glm::mat4 finalPosAndRotMat = entityMat * _lockEndObject.offsetMat; + pos = extractTranslation(finalPosAndRotMat); + rot = glmExtractRotation(finalPosAndRotMat); + dim = props.getDimensions(); + registrationPoint = props.getRegistrationPoint(); + } + const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f); + endVec = pos + rot * (dim * (DEFAULT_REGISTRATION_POINT - registrationPoint)); + glm::vec3 direction = endVec - pickRay.origin; + float distance = glm::distance(pickRay.origin, endVec); + glm::vec3 normalizedDirection = glm::normalize(direction); + + rayPickResult->type = _lockEndObject.isOverlay ? IntersectionType::OVERLAY : IntersectionType::ENTITY; + rayPickResult->objectID = _lockEndObject.id; + rayPickResult->intersection = endVec; + rayPickResult->distance = distance; + rayPickResult->surfaceNormal = -normalizedDirection; + rayPickResult->pickVariant["direction"] = vec3toVariant(normalizedDirection); + } + } + return visualPickResult; +} + void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant& props) { if (!id.isNull() && props.isValid()) { QVariantMap propMap = props.toMap(); @@ -102,26 +146,7 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter endVec = pickRay.origin + pickRay.direction * distance; } else { if (!_lockEndObject.id.isNull()) { - glm::vec3 pos; - glm::quat rot; - glm::vec3 dim; - glm::vec3 registrationPoint; - if (_lockEndObject.isOverlay) { - pos = vec3FromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "position").value); - rot = quatFromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "rotation").value); - dim = vec3FromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "dimensions").value); - registrationPoint = glm::vec3(0.5f); - } else { - EntityItemProperties props = DependencyManager::get()->getEntityProperties(_lockEndObject.id); - glm::mat4 entityMat = createMatFromQuatAndPos(props.getRotation(), props.getPosition()); - glm::mat4 finalPosAndRotMat = entityMat * _lockEndObject.offsetMat; - pos = extractTranslation(finalPosAndRotMat); - rot = glmExtractRotation(finalPosAndRotMat); - dim = props.getDimensions(); - registrationPoint = props.getRegistrationPoint(); - } - const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f); - endVec = pos + rot * (dim * (DEFAULT_REGISTRATION_POINT - registrationPoint)); + endVec = pickRay.origin + pickRay.direction * distance; } else { if (type == IntersectionType::ENTITY) { endVec = DependencyManager::get()->getEntityTransform(objectID)[3]; @@ -132,7 +157,6 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter } } } - QVariant end = vec3toVariant(endVec); if (!renderState.getPathID().isNull()) { QVariantMap pathProps; @@ -195,7 +219,7 @@ void LaserPointer::updateVisuals(const PickResultPointer& pickResult) { IntersectionType type = rayPickResult ? rayPickResult->type : IntersectionType::NONE; if (_enabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && (type != IntersectionType::NONE || _laserLength > 0.0f || !_lockEndObject.id.isNull())) { - PickRay pickRay(rayPickResult->pickVariant); + PickRay pickRay = rayPickResult ? PickRay(rayPickResult->pickVariant): PickRay(); QUuid uid = rayPickResult->objectID; float distance = _laserLength > 0.0f ? _laserLength : rayPickResult->distance; updateRenderState(_renderStates[_currentRenderState], type, distance, uid, pickRay, false); @@ -386,4 +410,4 @@ glm::vec2 LaserPointer::findPos2D(const PickedObject& pickedObject, const glm::v default: return glm::vec2(NAN); } -} \ No newline at end of file +} diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index efc5c02729..78c84e5f80 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -82,6 +82,7 @@ public: protected: PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, const std::string& button = "", bool hover = true) override; + PickResultPointer getVisualPickResult(const PickResultPointer& pickResult) override; PickedObject getHoveredObject(const PickResultPointer& pickResult) override; Pointer::Buttons getPressedButtons(const PickResultPointer& pickResult) override; diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index f0c16fb977..dd05e5c6a8 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -254,8 +254,7 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveOverlay(const OverlayID& void ContextOverlayInterface::contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event) { bool isMouse = event.getID() == PointerManager::MOUSE_POINTER_ID || DependencyManager::get()->isMouse(event.getID()); - if (_currentEntityWithContextOverlay == entityID && contextOverlayFilterPassed(entityID) - && _enabled && !isMouse) { + if (contextOverlayFilterPassed(entityID) && _enabled && !isMouse) { enableEntityHighlight(entityID); } } diff --git a/libraries/pointers/src/Pointer.cpp b/libraries/pointers/src/Pointer.cpp index 5307e17355..031baece5f 100644 --- a/libraries/pointers/src/Pointer.cpp +++ b/libraries/pointers/src/Pointer.cpp @@ -68,8 +68,9 @@ void Pointer::update(unsigned int pointerID) { // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts withReadLock([&] { auto pickResult = getPrevPickResult(); - updateVisuals(pickResult); - generatePointerEvents(pointerID, pickResult); + auto visualPickResult = getVisualPickResult(pickResult); + updateVisuals(visualPickResult); + generatePointerEvents(pointerID, visualPickResult); }); } diff --git a/libraries/pointers/src/Pointer.h b/libraries/pointers/src/Pointer.h index 3197c80cad..0c842dbd88 100644 --- a/libraries/pointers/src/Pointer.h +++ b/libraries/pointers/src/Pointer.h @@ -89,6 +89,7 @@ protected: virtual bool shouldHover(const PickResultPointer& pickResult) { return true; } virtual bool shouldTrigger(const PickResultPointer& pickResult) { return true; } + virtual PickResultPointer getVisualPickResult(const PickResultPointer& pickResult) { return pickResult; }; static const float POINTER_MOVE_DELAY; static const float TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED; From 16749df83a4e931769389e80fb7f731e61be739d Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 30 Mar 2018 14:14:13 -0700 Subject: [PATCH 58/72] fix highlighting edge case --- .../controllers/controllerModules/farActionGrabEntity.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 09cea58cea..b20712eacd 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -14,7 +14,7 @@ PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic, getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI - Picks, makeLaserLockInfo Xform, makeLaserParams, AddressManager, getEntityParents + Picks, makeLaserLockInfo Xform, makeLaserParams, AddressManager, getEntityParents, Selection */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -467,8 +467,10 @@ Script.include("/~/system/libraries/Xform.js"); Script.clearTimeout(this.contextOverlayTimer); } this.contextOverlayTimer = false; - if (entityID !== this.entityWithContextOverlay) { + if (entityID === this.entityWithContextOverlay) { this.destroyContextOverlay(); + } else { + Selection.removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); } var targetEntity = this.targetObject.getTargetEntity(); From 4b7e2cb331c13aee070b9e5b6cb5401a3a672b20 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 30 Mar 2018 15:15:17 -0700 Subject: [PATCH 59/72] made requested changes --- interface/src/raypick/LaserPointer.cpp | 43 +++++++++++++------------- interface/src/raypick/LaserPointer.h | 2 +- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 7b99c37679..011b9e55e6 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -87,9 +87,9 @@ PickResultPointer LaserPointer::getVisualPickResult(const PickResultPointer& pic IntersectionType type = rayPickResult ? rayPickResult->type : IntersectionType::NONE; if (type != IntersectionType::HUD) { + glm::vec3 endVec; + PickRay pickRay = rayPickResult ? PickRay(rayPickResult->pickVariant) : PickRay(); if (!_lockEndObject.id.isNull()) { - PickRay pickRay = rayPickResult ? PickRay(rayPickResult->pickVariant) : PickRay(); - glm::vec3 endVec; glm::vec3 pos; glm::quat rot; glm::vec3 dim; @@ -120,6 +120,21 @@ PickResultPointer LaserPointer::getVisualPickResult(const PickResultPointer& pic rayPickResult->distance = distance; rayPickResult->surfaceNormal = -normalizedDirection; rayPickResult->pickVariant["direction"] = vec3toVariant(normalizedDirection); + } else if (_lockEnd) { + if (type == IntersectionType::ENTITY) { + endVec = DependencyManager::get()->getEntityTransform(rayPickResult->objectID)[3]; + } else if (type == IntersectionType::OVERLAY) { + endVec = vec3FromVariant(qApp->getOverlays().getProperty(rayPickResult->objectID, "position").value); + } else if (type == IntersectionType::AVATAR) { + endVec = DependencyManager::get()->getAvatar(rayPickResult->objectID)->getPosition(); + } + glm::vec3 direction = endVec - pickRay.origin; + float distance = glm::distance(pickRay.origin, endVec); + glm::vec3 normalizedDirection = glm::normalize(direction); + rayPickResult->intersection = endVec; + rayPickResult->distance = distance; + rayPickResult->surfaceNormal = -normalizedDirection; + rayPickResult->pickVariant["direction"] = vec3toVariant(normalizedDirection); } } return visualPickResult; @@ -133,7 +148,7 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant& } } -void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, float distance, const QUuid& objectID, const PickRay& pickRay, bool defaultState) { +void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, float distance, const QUuid& objectID, const PickRay& pickRay) { if (!renderState.getStartID().isNull()) { QVariantMap startProps; startProps.insert("position", vec3toVariant(pickRay.origin)); @@ -141,22 +156,8 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter startProps.insert("ignoreRayIntersection", renderState.doesStartIgnoreRays()); qApp->getOverlays().editOverlay(renderState.getStartID(), startProps); } - glm::vec3 endVec; - if (((defaultState || !_lockEnd) && _lockEndObject.id.isNull()) || type == IntersectionType::HUD) { - endVec = pickRay.origin + pickRay.direction * distance; - } else { - if (!_lockEndObject.id.isNull()) { - endVec = pickRay.origin + pickRay.direction * distance; - } else { - if (type == IntersectionType::ENTITY) { - endVec = DependencyManager::get()->getEntityTransform(objectID)[3]; - } else if (type == IntersectionType::OVERLAY) { - endVec = vec3FromVariant(qApp->getOverlays().getProperty(objectID, "position").value); - } else if (type == IntersectionType::AVATAR) { - endVec = DependencyManager::get()->getAvatar(objectID)->getPosition(); - } - } - } + glm::vec3 endVec = pickRay.origin + pickRay.direction * distance; + QVariant end = vec3toVariant(endVec); if (!renderState.getPathID().isNull()) { QVariantMap pathProps; @@ -222,12 +223,12 @@ void LaserPointer::updateVisuals(const PickResultPointer& pickResult) { PickRay pickRay = rayPickResult ? PickRay(rayPickResult->pickVariant): PickRay(); QUuid uid = rayPickResult->objectID; float distance = _laserLength > 0.0f ? _laserLength : rayPickResult->distance; - updateRenderState(_renderStates[_currentRenderState], type, distance, uid, pickRay, false); + updateRenderState(_renderStates[_currentRenderState], type, distance, uid, pickRay); disableRenderState(_defaultRenderStates[_currentRenderState].second); } else if (_enabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { disableRenderState(_renderStates[_currentRenderState]); PickRay pickRay = rayPickResult ? PickRay(rayPickResult->pickVariant) : PickRay(); - updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), pickRay, true); + updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), pickRay); } else if (!_currentRenderState.empty()) { disableRenderState(_renderStates[_currentRenderState]); disableRenderState(_defaultRenderStates[_currentRenderState].second); diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 78c84e5f80..964881be42 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -103,7 +103,7 @@ private: LockEndObject _lockEndObject; void updateRenderStateOverlay(const OverlayID& id, const QVariant& props); - void updateRenderState(const RenderState& renderState, const IntersectionType type, float distance, const QUuid& objectID, const PickRay& pickRay, bool defaultState); + void updateRenderState(const RenderState& renderState, const IntersectionType type, float distance, const QUuid& objectID, const PickRay& pickRay); void disableRenderState(const RenderState& renderState); struct TriggerState { From d5496d68fd84456c2abb96e0c338345e4510b172 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 30 Mar 2018 16:58:41 -0700 Subject: [PATCH 60/72] FIx the mac crash when in front of a mirror by using the VIewFrustum stack correctly --- libraries/render-utils/src/AntialiasingEffect.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index 4a9b69c099..ba5036ad68 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -380,6 +380,8 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const batch.setResourceTexture(AntialiasingPass_VelocityMapSlot, nullptr); batch.setResourceTexture(AntialiasingPass_NextMapSlot, nullptr); }); + + args->popViewFrustum(); } @@ -520,7 +522,7 @@ void JitterSample::run(const render::RenderContextPointer& renderContext) { viewFrustum.setProjection(projMat); viewFrustum.calculate(); - args->setViewFrustum(viewFrustum); + args->pushViewFrustum(viewFrustum); } else { mat4 projMats[2]; args->_context->getStereoProjections(projMats); @@ -538,4 +540,4 @@ void JitterSample::run(const render::RenderContextPointer& renderContext) { } -#endif \ No newline at end of file +#endif From a9a53c7d64249d8d78e188efc4411063d3fa3013 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 2 Apr 2018 10:51:39 -0700 Subject: [PATCH 61/72] make resquested changes --- interface/src/raypick/LaserPointer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 011b9e55e6..bd71e47cf0 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -120,7 +120,7 @@ PickResultPointer LaserPointer::getVisualPickResult(const PickResultPointer& pic rayPickResult->distance = distance; rayPickResult->surfaceNormal = -normalizedDirection; rayPickResult->pickVariant["direction"] = vec3toVariant(normalizedDirection); - } else if (_lockEnd) { + } else if (type != IntersectionType::NONE && _lockEnd) { if (type == IntersectionType::ENTITY) { endVec = DependencyManager::get()->getEntityTransform(rayPickResult->objectID)[3]; } else if (type == IntersectionType::OVERLAY) { From d4bc61fb3de6941ea3e470cea684eaa397ae6310 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 2 Apr 2018 13:53:30 -0700 Subject: [PATCH 62/72] Remove notifications and print outs for LOD changes because it was too much noise --- interface/src/LODManager.cpp | 10 +++++---- scripts/system/notifications.js | 38 ++++++--------------------------- 2 files changed, 13 insertions(+), 35 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 73408377c0..2e8d3011d7 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -86,10 +86,11 @@ void LODManager::autoAdjustLOD(float realTimeDelta) { if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; } - qCDebug(interfaceapp) << "adjusting LOD DOWN" + // DEBUG: Less is more, avoid logging all the time + /* qCDebug(interfaceapp) << "adjusting LOD DOWN" << "fps =" << currentFPS << "targetFPS =" << getLODDecreaseFPS() - << "octreeSizeScale =" << _octreeSizeScale; + << "octreeSizeScale =" << _octreeSizeScale; */ emit LODDecreased(); // Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime // to provide an FPS just above the decrease threshold. It will drift close to its @@ -111,10 +112,11 @@ void LODManager::autoAdjustLOD(float realTimeDelta) { if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; } - qCDebug(interfaceapp) << "adjusting LOD UP" + // DEBUG: Less is more, avoid logging all the time + /* qCDebug(interfaceapp) << "adjusting LOD UP" << "fps =" << currentFPS << "targetFPS =" << getLODDecreaseFPS() - << "octreeSizeScale =" << _octreeSizeScale; + << "octreeSizeScale =" << _octreeSizeScale; */ emit LODIncreased(); // Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime // to provide an FPS just below the increase threshold. It will drift close to its diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index 728760c1e7..94a8e1adec 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -1,6 +1,6 @@ "use strict"; /*jslint vars:true, plusplus:true, forin:true*/ -/*global Script, Settings, Window, Controller, Overlays, SoundArray, LODManager, MyAvatar, Tablet, Camera, HMD, Menu, Quat, Vec3*/ +/*global Script, Settings, Window, Controller, Overlays, SoundArray, MyAvatar, Tablet, Camera, HMD, Menu, Quat, Vec3*/ // // notifications.js // Version 0.801 @@ -84,21 +84,18 @@ var NOTIFICATION_MENU_ITEM_POST = " Notifications"; var PLAY_NOTIFICATION_SOUNDS_SETTING = "play_notification_sounds"; var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_"; - var lodTextID = false; - var NOTIFICATIONS_MESSAGE_CHANNEL = "Hifi-Notifications" + var NOTIFICATIONS_MESSAGE_CHANNEL = "Hifi-Notifications" var NotificationType = { UNKNOWN: 0, SNAPSHOT: 1, - LOD_WARNING: 2, - CONNECTION_REFUSED: 3, - EDIT_ERROR: 4, - TABLET: 5, - CONNECTION: 6, - WALLET: 7, + CONNECTION_REFUSED: 2, + EDIT_ERROR: 3, + TABLET: 4, + CONNECTION: 5, + WALLET: 6, properties: [ { text: "Snapshot" }, - { text: "Level of Detail" }, { text: "Connection Refused" }, { text: "Edit error" }, { text: "Tablet" }, @@ -153,10 +150,6 @@ // This handles the final dismissal of a notification after fading function dismiss(firstNoteOut, firstButOut, firstOut) { - if (firstNoteOut === lodTextID) { - lodTextID = false; - } - Overlays.deleteOverlay(firstNoteOut); Overlays.deleteOverlay(firstButOut); notifications.splice(firstOut, 1); @@ -418,9 +411,6 @@ function deleteNotification(index) { var notificationTextID = notifications[index]; - if (notificationTextID === lodTextID) { - lodTextID = false; - } Overlays.deleteOverlay(notificationTextID); Overlays.deleteOverlay(buttons[index]); notifications.splice(index, 1); @@ -674,20 +664,6 @@ } } - LODManager.LODDecreased.connect(function () { - var warningText = "\n" + - "Due to the complexity of the content, the \n" + - "level of detail has been decreased. " + - "You can now see: \n" + - LODManager.getLODFeedbackText(); - - if (lodTextID === false) { - lodTextID = createNotification(warningText, NotificationType.LOD_WARNING); - } else { - Overlays.editOverlay(lodTextID, { text: warningText }); - } - }); - Controller.keyPressEvent.connect(keyPressEvent); Controller.mousePressEvent.connect(mousePressEvent); Controller.keyReleaseEvent.connect(keyReleaseEvent); From 1f3063193a8e09409ffe5293a20a4ea75d68271f Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 2 Apr 2018 14:24:51 -0700 Subject: [PATCH 63/72] Tweak right-click to inspect --- .../ui/overlays/ContextOverlayInterface.cpp | 29 ++++++++++++++++++- .../src/ui/overlays/ContextOverlayInterface.h | 6 ++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index dd05e5c6a8..aca186a589 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -50,7 +50,9 @@ ContextOverlayInterface::ContextOverlayInterface() { _entityPropertyFlags += PROP_OWNING_AVATAR_ID; auto entityScriptingInterface = DependencyManager::get().data(); - connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, &ContextOverlayInterface::createOrDestroyContextOverlay); + connect(entityScriptingInterface, &EntityScriptingInterface::clickDownOnEntity, this, &ContextOverlayInterface::clickDownOnEntity); + connect(entityScriptingInterface, &EntityScriptingInterface::holdingClickOnEntity, this, &ContextOverlayInterface::holdingClickOnEntity); + connect(entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity, this, &ContextOverlayInterface::mouseReleaseOnEntity); connect(entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity, this, &ContextOverlayInterface::contextOverlays_hoverEnterEntity); connect(entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity, this, &ContextOverlayInterface::contextOverlays_hoverLeaveEntity); connect(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"), &TabletProxy::tabletShownChanged, this, [&]() { @@ -97,6 +99,31 @@ void ContextOverlayInterface::setEnabled(bool enabled) { _enabled = enabled; } +void ContextOverlayInterface::clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) { + if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(entityItemID)) { + _mouseDownEntity = entityItemID; + _mouseDownEntityTimestamp = usecTimestampNow(); + } else { + if (!_currentEntityWithContextOverlay.isNull()) { + disableEntityHighlight(_currentEntityWithContextOverlay); + destroyContextOverlay(_currentEntityWithContextOverlay, event); + } + } +} + +static const float CONTEXT_OVERLAY_CLICK_HOLD_TIME_MSEC = 400.0f; +void ContextOverlayInterface::holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) { + if (!_mouseDownEntity.isNull() && ((usecTimestampNow() - _mouseDownEntityTimestamp) > (CONTEXT_OVERLAY_CLICK_HOLD_TIME_MSEC * USECS_PER_MSEC))) { + _mouseDownEntity = EntityItemID(); + } +} + +void ContextOverlayInterface::mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) { + if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(entityItemID) && _mouseDownEntity == entityItemID) { + createOrDestroyContextOverlay(entityItemID, event); + } +} + bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) { if (_enabled && event.getButton() == PointerEvent::SecondaryButton) { if (contextOverlayFilterPassed(entityItemID)) { diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index fcdf2d5820..b80a3a70fb 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -64,6 +64,10 @@ signals: void contextOverlayClicked(const QUuid& currentEntityWithContextOverlay); public slots: + void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); + void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); + void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); + bool createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event); bool destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event); bool destroyContextOverlay(const EntityItemID& entityItemID); @@ -84,6 +88,8 @@ private: }; bool _verboseLogging{ true }; bool _enabled { true }; + EntityItemID _mouseDownEntity{}; + quint64 _mouseDownEntityTimestamp; EntityItemID _currentEntityWithContextOverlay{}; EntityItemID _lastInspectedEntity{}; QString _entityMarketplaceID; From 5a1eac563ba352cbbe1dc480c67d327ce489052b Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 2 Apr 2018 15:50:18 -0700 Subject: [PATCH 64/72] Code review fixes --- interface/src/LODManager.cpp | 10 ---------- scripts/system/notifications.js | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 2e8d3011d7..d7d73e962a 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -86,11 +86,6 @@ void LODManager::autoAdjustLOD(float realTimeDelta) { if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; } - // DEBUG: Less is more, avoid logging all the time - /* qCDebug(interfaceapp) << "adjusting LOD DOWN" - << "fps =" << currentFPS - << "targetFPS =" << getLODDecreaseFPS() - << "octreeSizeScale =" << _octreeSizeScale; */ emit LODDecreased(); // Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime // to provide an FPS just above the decrease threshold. It will drift close to its @@ -112,11 +107,6 @@ void LODManager::autoAdjustLOD(float realTimeDelta) { if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; } - // DEBUG: Less is more, avoid logging all the time - /* qCDebug(interfaceapp) << "adjusting LOD UP" - << "fps =" << currentFPS - << "targetFPS =" << getLODDecreaseFPS() - << "octreeSizeScale =" << _octreeSizeScale; */ emit LODIncreased(); // Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime // to provide an FPS just below the increase threshold. It will drift close to its diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index 94a8e1adec..8b68a9355e 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -84,7 +84,7 @@ var NOTIFICATION_MENU_ITEM_POST = " Notifications"; var PLAY_NOTIFICATION_SOUNDS_SETTING = "play_notification_sounds"; var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_"; - var NOTIFICATIONS_MESSAGE_CHANNEL = "Hifi-Notifications" + var NOTIFICATIONS_MESSAGE_CHANNEL = "Hifi-Notifications"; var NotificationType = { UNKNOWN: 0, From 077b2dab30d527136dfbd5b09ce9b38514af12cd Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 2 Apr 2018 16:09:43 -0700 Subject: [PATCH 65/72] Code review fixes --- scripts/system/notifications.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index 8b68a9355e..ba37f6ee4e 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -84,7 +84,7 @@ var NOTIFICATION_MENU_ITEM_POST = " Notifications"; var PLAY_NOTIFICATION_SOUNDS_SETTING = "play_notification_sounds"; var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_"; - var NOTIFICATIONS_MESSAGE_CHANNEL = "Hifi-Notifications"; + var NOTIFICATIONS_MESSAGE_CHANNEL = "Hifi-Notifications"; var NotificationType = { UNKNOWN: 0, From ccea3efe1e1d0714303d9c7aff54dc7a13db7b2c Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Mon, 2 Apr 2018 00:23:25 +0300 Subject: [PATCH 66/72] FB13789 - Log in/Sign up dialog is missing "Forgot Username?" and "Forgot Password?" links --- interface/resources/qml/controls-uit/TextField.qml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index f94541897b..6743d08275 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -163,10 +163,18 @@ TextField { text: textField.label colorScheme: textField.colorScheme anchors.left: parent.left - anchors.right: parent.right + + Binding on anchors.right { + when: parent.right + value: parent.right + } + Binding on wrapMode { + when: parent.right + value: Text.WordWrap + } + anchors.bottom: parent.top anchors.bottomMargin: 3 - wrapMode: Text.WordWrap visible: label != "" } } From 08b7326bd18d38d611a55e4ba59fd4be85ef2372 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Apr 2018 11:11:51 -0700 Subject: [PATCH 67/72] when moving a group of selections, don't move a child if a parent is being moved --- scripts/system/libraries/entitySelectionTool.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index fced5fc4e9..4fc767634b 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -1618,8 +1618,16 @@ SelectionDisplay = (function() { grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), cornerPosition); - for (var i = 0; i < SelectionManager.selections.length; i++) { - var properties = SelectionManager.savedProperties[SelectionManager.selections[i]]; + var toMove = SelectionManager.selections.filter(function (selection) { + if (SelectionManager.selections.indexOf(SelectionManager.savedProperties[selection].parentID) >= 0) { + return false; // a parent is also being moved, so don't issue an edit for this entity + } else { + return true; + } + }); + + for (var i = 0; i < toMove.length; i++) { + var properties = SelectionManager.savedProperties[toMove[i]]; if (!properties) { continue; } @@ -1628,7 +1636,7 @@ SelectionDisplay = (function() { y: 0, z: vector.z }); - Entities.editEntity(SelectionManager.selections[i], { + Entities.editEntity(toMove[i], { position: newPosition }); From 249a97b5d0e474f3197c17d263910bbbdf3104ce Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Apr 2018 12:02:12 -0700 Subject: [PATCH 68/72] don't move or rotate children if a parent is being changed by the same action --- .../system/libraries/entitySelectionTool.js | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 4fc767634b..c84ecef722 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -1618,6 +1618,8 @@ SelectionDisplay = (function() { grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), cornerPosition); + // editing a parent will cause all the children to automatically follow along, so don't + // edit any entity who has an ancestor in SelectionManager.selections var toMove = SelectionManager.selections.filter(function (selection) { if (SelectionManager.selections.indexOf(SelectionManager.savedProperties[selection].parentID) >= 0) { return false; // a parent is also being moved, so don't issue an edit for this entity @@ -1735,9 +1737,19 @@ SelectionDisplay = (function() { Vec3.print(" newIntersection:", newIntersection); Vec3.print(" vector:", vector); } - - for (var i = 0; i < SelectionManager.selections.length; i++) { - var id = SelectionManager.selections[i]; + + // editing a parent will cause all the children to automatically follow along, so don't + // edit any entity who has an ancestor in SelectionManager.selections + var toMove = SelectionManager.selections.filter(function (selection) { + if (SelectionManager.selections.indexOf(SelectionManager.savedProperties[selection].parentID) >= 0) { + return false; // a parent is also being moved, so don't issue an edit for this entity + } else { + return true; + } + }); + + for (var i = 0; i < toMove.length; i++) { + var id = toMove[i]; var properties = SelectionManager.savedProperties[id]; var newPosition = Vec3.sum(properties.position, vector); Entities.editEntity(id, { position: newPosition }); @@ -2174,8 +2186,19 @@ SelectionDisplay = (function() { // the selections center point. Otherwise, the rotation will be around the entities // registration point which does not need repositioning. var reposition = (SelectionManager.selections.length > 1); - for (var i = 0; i < SelectionManager.selections.length; i++) { - var entityID = SelectionManager.selections[i]; + + // editing a parent will cause all the children to automatically follow along, so don't + // edit any entity who has an ancestor in SelectionManager.selections + var toRotate = SelectionManager.selections.filter(function (selection) { + if (SelectionManager.selections.indexOf(SelectionManager.savedProperties[selection].parentID) >= 0) { + return false; // a parent is also being moved, so don't issue an edit for this entity + } else { + return true; + } + }); + + for (var i = 0; i < toRotate.length; i++) { + var entityID = toRotate[i]; var initialProperties = SelectionManager.savedProperties[entityID]; var newProperties = { From 4f5895cb16e52b908ccd2337928aee8912168264 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 3 Apr 2018 13:17:37 -0700 Subject: [PATCH 69/72] Added MD file to autoTester. --- tools/auto-tester/src/Test.cpp | 264 +++++++++++++++++++++--- tools/auto-tester/src/Test.h | 30 ++- tools/auto-tester/src/ui/AutoTester.cpp | 6 +- tools/auto-tester/src/ui/AutoTester.h | 5 +- tools/auto-tester/src/ui/AutoTester.ui | 23 ++- 5 files changed, 280 insertions(+), 48 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 347cfd90dc..98d4ae463c 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -24,15 +24,11 @@ extern AutoTester* autoTester; #include Test::Test() { - QString regex(EXPECTED_IMAGE_PREFIX + QString("\\\\d").repeated(NUM_DIGITS) + ".png"); - - expectedImageFilenameFormat = QRegularExpression(regex); - mismatchWindow.setModal(true); } bool Test::createTestResultsFolderPath(QString directory) { - QDateTime now = QDateTime::currentDateTime(); + QDateTime now = QDateTime::currentDateTime(); testResultsFolderPath = directory + "/" + TEST_RESULTS_FOLDER + "--" + now.toString(DATETIME_FORMAT); QDir testResultsFolder(testResultsFolderPath); @@ -76,7 +72,7 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) QImage expectedImage(expectedImagesFullFilenames[i]); if (resultImage.width() != expectedImage.width() || resultImage.height() != expectedImage.height()) { - messageBox.critical(0, "Internal error #1", "Images are not the same size"); + messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Images are not the same size"); exit(-1); } @@ -84,7 +80,7 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) try { similarityIndex = imageComparer.compareImages(resultImage, expectedImage); } catch (...) { - messageBox.critical(0, "Internal error #2", "Image not in expected format"); + messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Image not in expected format"); exit(-1); } @@ -131,20 +127,20 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage) { if (!QDir().exists(testResultsFolderPath)) { - messageBox.critical(0, "Internal error #3", "Folder " + testResultsFolderPath + " not found"); + messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Folder " + testResultsFolderPath + " not found"); exit(-1); } QString failureFolderPath { testResultsFolderPath + "/" + "Failure_" + QString::number(index) }; if (!QDir().mkdir(failureFolderPath)) { - messageBox.critical(0, "Internal error #4", "Failed to create folder " + failureFolderPath); + messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create folder " + failureFolderPath); exit(-1); } ++index; QFile descriptionFile(failureFolderPath + "/" + TEST_RESULTS_FILENAME); if (!descriptionFile.open(QIODevice::ReadWrite)) { - messageBox.critical(0, "Internal error #5", "Failed to create file " + TEST_RESULTS_FILENAME); + messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create file " + TEST_RESULTS_FILENAME); exit(-1); } @@ -164,14 +160,14 @@ void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure te sourceFile = testFailure._pathname + testFailure._expectedImageFilename; destinationFile = failureFolderPath + "/" + "Expected Image.jpg"; if (!QFile::copy(sourceFile, destinationFile)) { - messageBox.critical(0, "Internal error #6", "Failed to copy " + sourceFile + " to " + destinationFile); + messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to copy " + sourceFile + " to " + destinationFile); exit(-1); } sourceFile = testFailure._pathname + testFailure._actualImageFilename; destinationFile = failureFolderPath + "/" + "Actual Image.jpg"; if (!QFile::copy(sourceFile, destinationFile)) { - messageBox.critical(0, "Internal error #7", "Failed to copy " + sourceFile + " to " + destinationFile); + messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to copy " + sourceFile + " to " + destinationFile); exit(-1); } @@ -209,11 +205,6 @@ void Test::startTestsEvaluation() { QStringList sortedTestResultsFilenames = createListOfAll_imagesInDirectory("png", pathToTestResultsDirectory); QStringList expectedImagesURLs; - const QString URLPrefix("https://raw.githubusercontent.com"); - const QString githubUser("NissimHadar"); - const QString testsRepo("hifi_tests"); - const QString branch("addRecursionToAutotester"); - resultImagesFullFilenames.clear(); expectedImagesFilenames.clear(); expectedImagesFullFilenames.clear(); @@ -226,16 +217,16 @@ void Test::startTestsEvaluation() { QString expectedImagePartialSourceDirectory = getExpectedImagePartialSourceDirectory(currentFilename); // Images are stored on GitHub as ExpectedImage_ddddd.png - // Extract the digits at the end of the filename (exluding the file extension) + // Extract the digits at the end of the filename (excluding the file extension) QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); QString expectedImageStoredFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + ".png"; - QString imageURLString(URLPrefix + "/" + githubUser + "/" + testsRepo + "/" + branch + "/" + - expectedImagePartialSourceDirectory + "/" + expectedImageStoredFilename); + QString imageURLString("https://github.com/" + githubUser + "/hifi_tests/blob/" + gitHubBranch + "/" + + expectedImagePartialSourceDirectory + "/" + expectedImageStoredFilename + "?raw=true"); expectedImagesURLs << imageURLString; - // The image retrieved from Github needs a unique name + // The image retrieved from GitHub needs a unique name QString expectedImageFilename = currentFilename.replace("/", "_").replace(".", "_EI."); expectedImagesFilenames << expectedImageFilename; @@ -273,25 +264,31 @@ bool Test::isAValidDirectory(QString pathname) { return true; } -void Test::importTest(QTextStream& textStream, const QString& testPathname) { - // `testPathname` includes the full path to the test. We need the portion below (and including) `tests` - QStringList filenameParts = testPathname.split('/'); +QString Test::extractPathFromTestsDown(QString fullPath) { + // `fullPath` includes the full path to the test. We need the portion below (and including) `tests` + QStringList pathParts = fullPath.split('/'); int i{ 0 }; - while (i < filenameParts.length() && filenameParts[i] != "tests") { + while (i < pathParts.length() && pathParts[i] != "tests") { ++i; } - if (i == filenameParts.length()) { - messageBox.critical(0, "Internal error #10", "Bad testPathname"); + if (i == pathParts.length()) { + messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Bad testPathname"); exit(-1); } - QString filename; - for (int j = i; j < filenameParts.length(); ++j) { - filename += "/" + filenameParts[j]; + QString partialPath; + for (int j = i; j < pathParts.length(); ++j) { + partialPath += "/" + pathParts[j]; } - textStream << "Script.include(\"" << "https://raw.githubusercontent.com/" << user << "/hifi_tests/" << branch << filename + "\");" << endl; + return partialPath; +} + +void Test::importTest(QTextStream& textStream, const QString& testPathname) { + QString partialPath = extractPathFromTestsDown(testPathname); + textStream << "Script.include(\"" << "https://github.com/" << githubUser + << "/hifi_tests/blob/" << gitHubBranch << partialPath + "?raw=true\");" << endl; } // Creates a single script in a user-selected folder. @@ -353,7 +350,7 @@ void Test::createRecursiveScript(QString topLevelDirectory, bool interactiveMode QFile allTestsFilename(topLevelDirectory + "/" + recursiveTestsFilename); if (!allTestsFilename.open(QIODevice::WriteOnly | QIODevice::Text)) { messageBox.critical(0, - "Internal Error #8", + "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create \"" + recursiveTestsFilename + "\" in directory \"" + topLevelDirectory + "\"" ); @@ -363,7 +360,9 @@ void Test::createRecursiveScript(QString topLevelDirectory, bool interactiveMode QTextStream textStream(&allTestsFilename); textStream << "// This is an automatically generated file, created by auto-tester" << endl << endl; - textStream << "var autoTester = Script.require(\"https://raw.githubusercontent.com/" + user + "/hifi_tests/" + branch + "/tests/utils/autoTester.js\");" << endl; + textStream << "var autoTester = Script.require(\"https://github.com/" + githubUser + "/hifi_tests/blob/" + + gitHubBranch + "/tests/utils/autoTester.js?raw=true\");" << endl; + textStream << "autoTester.enableRecursive();" << endl << endl; QVector testPathnames; @@ -454,6 +453,203 @@ void Test::createTest() { messageBox.information(0, "Success", "Test images have been created"); } +ExtractedText Test::getTestScriptLines(QString testFileName) { + ExtractedText relevantTextFromTest; + + QFile inputFile(testFileName); + inputFile.open(QIODevice::ReadOnly); + if (!inputFile.isOpen()) { + messageBox.critical(0, + "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Failed to open \"" + testFileName + ); + } + + QTextStream stream(&inputFile); + QString line = stream.readLine(); + + // Name of test is the string in the following line: + // autoTester.perform("Apply Material Entities to Avatars", Script.resolvePath("."), function(testType) {... + const QString ws("\\h*"); //white-space character + const QString functionPerformName(ws + "autoTester" + ws + "\\." + ws + "perform"); + const QString quotedString("\\\".+\\\""); + const QString ownPath("Script" + ws + "\\." + ws + "resolvePath" + ws + "\\(" + ws + "\\\"\\.\\\"" + ws + "\\)"); + const QString functionParameter("function" + ws + "\\(testType" + ws + "\\)"); + QString regexTestTitle(ws + functionPerformName + "\\(" + quotedString + "\\," + ws + ownPath + "\\," + ws + functionParameter + ws + "{" + ".*"); + QRegularExpression lineContainingTitle = QRegularExpression(regexTestTitle); + + // Assert platform checks that test is running on the correct OS + const QString functionAssertPlatform(ws + "autoTester" + ws + "\\." + ws + "assertPlatform"); + const QString regexAssertPlatform(ws + functionAssertPlatform + ws + "\\(" + ws + quotedString + ".*"); + const QRegularExpression lineAssertPlatform = QRegularExpression(regexAssertPlatform); + + // Assert display checks that test is running on the correct display + const QString functionAssertDisplay(ws + "autoTester" + ws + "\\." + ws + "assertDisplay"); + const QString regexAssertDisplay(ws + functionAssertDisplay + ws + "\\(" + ws + quotedString + ".*"); + const QRegularExpression lineAssertDisplay = QRegularExpression(regexAssertDisplay); + + // Assert CPU checks that test is running on the correct type of CPU + const QString functionAssertCPU(ws + "autoTester" + ws + "\\." + ws + "assertCPU"); + const QString regexAssertCPU(ws + functionAssertCPU + ws + "\\(" + ws + quotedString + ".*"); + const QRegularExpression lineAssertCPU = QRegularExpression(regexAssertCPU); + + // Assert GPU checks that test is running on the correct type of GPU + const QString functionAssertGPU(ws + "autoTester" + ws + "\\." + ws + "assertGPU"); + const QString regexAssertGPU(ws + functionAssertGPU + ws + "\\(" + ws + quotedString + ".*"); + const QRegularExpression lineAssertGPU = QRegularExpression(regexAssertGPU); + + // Each step is either of the following forms: + // autoTester.addStepSnapshot("Take snapshot"... + // autoTester.addStep("Clean up after test"... + const QString functionAddStepSnapshotName(ws + "autoTester" + ws + "\\." + ws + "addStepSnapshot"); + const QString regexStepSnapshot(ws + functionAddStepSnapshotName + ws + "\\(" + ws + quotedString + ".*"); + const QRegularExpression lineStepSnapshot = QRegularExpression(regexStepSnapshot); + + const QString functionAddStepName(ws + "autoTester" + ws + "\\." + ws + "addStep"); + const QString regexStep(ws + functionAddStepName + ws + "\\(" + ws + quotedString + ws + "\\)" + ".*"); + const QRegularExpression lineStep = QRegularExpression(regexStep); + + while (!line.isNull()) { + line = stream.readLine(); + if (lineContainingTitle.match(line).hasMatch()) { + QStringList tokens = line.split('"'); + relevantTextFromTest.title = tokens[1]; + } else if (lineAssertPlatform.match(line).hasMatch()) { + QStringList platforms = line.split('"'); + relevantTextFromTest.platform = platforms[1]; + } else if (lineAssertDisplay.match(line).hasMatch()) { + QStringList displays = line.split('"'); + relevantTextFromTest.display = displays[1]; + } else if (lineAssertCPU.match(line).hasMatch()) { + QStringList cpus = line.split('"'); + relevantTextFromTest.cpu = cpus[1]; + } else if (lineAssertGPU.match(line).hasMatch()) { + QStringList gpus = line.split('"'); + relevantTextFromTest.gpu = gpus[1]; + } else if (lineStepSnapshot.match(line).hasMatch()) { + QStringList tokens = line.split('"'); + QString nameOfStep = tokens[1]; + + Step *step = new Step(); + step->text = nameOfStep; + step->takeSnapshot = true; + relevantTextFromTest.stepList.emplace_back(step); + } else if (lineStep.match(line).hasMatch()) { + QStringList tokens = line.split('"'); + QString nameOfStep = tokens[1]; + + Step *step = new Step(); + step->text = nameOfStep; + step->takeSnapshot = false; + relevantTextFromTest.stepList.emplace_back(step); + } + } + + inputFile.close(); + + return relevantTextFromTest; +} + +// Create an MD file for a user-selected test. +// The folder selected must contain a script named "test.js", the file produced is named "test.md" +void Test::createMDFile() { + // Folder selection + QString testDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); + if (testDirectory == "") { + return; + } + + // Verify folder contains test.js file + QString testFileName(testDirectory + "/" + TEST_FILENAME); + QFileInfo testFileInfo(testFileName); + if (!testFileInfo.exists()) { + messageBox.critical(0, "Error", "Could not find file: " + TEST_FILENAME); + return; + } + + ExtractedText testScriptLines = getTestScriptLines(testFileName); + + QString mdFilename(testDirectory + "/" + "test.md"); + QFile mdFile(mdFilename); + if (!mdFile.open(QIODevice::ReadWrite)) { + messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create file " + mdFilename); + exit(-1); + } + + QTextStream stream(&mdFile); + + //Test title + QString testName = testScriptLines.title; + stream << "# " << testName << "\n"; + + // Find the relevant part of the path to the test (i.e. from "tests" down + QString partialPath = extractPathFromTestsDown(testDirectory); + + stream << "## Run this script URL: [Manual](./test.js?raw=true) [Auto](./testAuto.js?raw=true)(from menu/Edit/Open and Run scripts from URL...)." << "\n\n"; + + stream << "## Preconditions" << "\n"; + stream << "- In an empty region of a domain with editing rights." << "\n\n"; + + // Platform + QStringList platforms = testScriptLines.platform.split(" ");; + stream << "## Platforms\n"; + stream << "Run the test on each of the following platforms\n"; + for (int i = 0; i < platforms.size(); ++i) { + // Note that the platforms parameter may include extra spaces, these appear as empty strings in the list + if (platforms[i] != QString()) { + stream << " - " << platforms[i] << "\n"; + } + } + + // Display + QStringList displays = testScriptLines.display.split(" "); + stream << "## Displays\n"; + stream << "Run the test on each of the following displays\n"; + for (int i = 0; i < displays.size(); ++i) { + // Note that the displays parameter may include extra spaces, these appear as empty strings in the list + if (displays[i] != QString()) { + stream << " - " << displays[i] << "\n"; + } + } + + // CPU + QStringList cpus = testScriptLines.cpu.split(" "); + stream << "## Processors\n"; + stream << "Run the test on each of the following processors\n"; + for (int i = 0; i < cpus.size(); ++i) { + // Note that the cpus parameter may include extra spaces, these appear as empty strings in the list + if (cpus[i] != QString()) { + stream << " - " << cpus[i] << "\n"; + } + } + + // GPU + QStringList gpus = testScriptLines.gpu.split(" "); + stream << "## Graphics Cards\n"; + stream << "Run the test on graphics cards from each of the following vendors\n"; + for (int i = 0; i < gpus.size(); ++i) { + // Note that the gpus parameter may include extra spaces, these appear as empty strings in the list + if (gpus[i] != QString()) { + stream << " - " << gpus[i] << "\n"; + } + } + + stream << "## Steps\n"; + stream << "Press space bar to advance step by step\n\n"; + + int snapShotIndex { 0 }; + for (int i = 0; i < testScriptLines.stepList.size(); ++i) { + stream << "### Step " << QString::number(i) << "\n"; + stream << "- " << testScriptLines.stepList[i]->text << "\n"; + if (testScriptLines.stepList[i]->takeSnapshot) { + stream << "- ![](./ExpectedImage_" << QString::number(snapShotIndex).rightJustified(5, '0') << ".png)\n"; + ++snapShotIndex; + } + } + + mdFile.close(); +} + void Test::copyJPGtoPNG(QString sourceJPGFullFilename, QString destinationPNGFullFilename) { QFile::remove(destinationPNGFullFilename); @@ -526,7 +722,7 @@ QString Test::getExpectedImagePartialSourceDirectory(QString filename) { } if (i < 0) { - messageBox.critical(0, "Internal error #9", "Bad filename"); + messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Bad filename"); exit(-1); } diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index cd5075002a..3d04b00df9 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -19,6 +19,24 @@ #include "ImageComparer.h" #include "ui/MismatchWindow.h" +class Step { +public: + QString text; + bool takeSnapshot; +}; + +using StepList = std::vector; + +class ExtractedText { +public: + QString title; + QString platform; + QString display; + QString cpu; + QString gpu; + StepList stepList; +}; + class Test { public: Test(); @@ -31,7 +49,7 @@ public: void createRecursiveScript(QString topLevelDirectory, bool interactiveMode); void createTest(); - void deleteOldSnapshots(); + void createMDFile(); bool compareImageLists(bool isInteractiveMode, QProgressBar* progressBar); @@ -47,7 +65,7 @@ public: void zipAndDeleteTestResultsFolder(); bool isAValidDirectory(QString pathname); - + QString extractPathFromTestsDown(QString fullPath); QString getExpectedImageDestinationDirectory(QString filename); QString getExpectedImagePartialSourceDirectory(QString filename); @@ -62,8 +80,6 @@ private: QDir imageDirectory; - QRegularExpression expectedImageFilenameFormat; - MismatchWindow mismatchWindow; ImageComparer imageComparer; @@ -81,9 +97,11 @@ private: QStringList resultImagesFullFilenames; // Used for accessing GitHub - const QString user { "NissimHadar" }; - const QString branch { "addRecursionToAutotester" }; + const QString githubUser{ "highfidelity" }; + const QString gitHubBranch { "master" }; const QString DATETIME_FORMAT { "yyyy-MM-dd_hh-mm-ss" }; + + ExtractedText getTestScriptLines(QString testFileName); }; #endif // hifi_test_h \ No newline at end of file diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index a5e13331dd..9153365184 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -33,7 +33,11 @@ void AutoTester::on_createRecursiveScriptsRecursivelyButton_clicked() { } void AutoTester::on_createTestButton_clicked() { - test->createTest(); + test->createTest(); +} + +void AutoTester::on_createMDFileButton_clicked() { + test->createMDFile(); } void AutoTester::on_closeButton_clicked() { diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index 938e7ca2d2..82ff3780e3 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -29,8 +29,9 @@ private slots: void on_evaluateTestsButton_clicked(); void on_createRecursiveScriptButton_clicked(); void on_createRecursiveScriptsRecursivelyButton_clicked(); - void on_createTestButton_clicked(); - void on_closeButton_clicked(); + void on_createTestButton_clicked(); + void on_createMDFileButton_clicked(); + void on_closeButton_clicked(); void saveImage(int index); diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index 55c3897e58..600de283ad 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -7,7 +7,7 @@ 0 0 607 - 395 + 514 @@ -18,7 +18,7 @@ 20 - 300 + 420 220 40 @@ -44,7 +44,7 @@ 20 - 135 + 255 220 40 @@ -70,7 +70,7 @@ 23 - 100 + 220 131 20 @@ -86,7 +86,7 @@ 20 - 190 + 310 255 23 @@ -108,6 +108,19 @@ Create Recursive Scripts Recursively + + + + 20 + 90 + 220 + 40 + + + + Create MD file + + From f20eddefc8f6e345b6ce2859eaf1b4d76179b86d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 3 Apr 2018 13:46:02 -0700 Subject: [PATCH 70/72] Fix 'Private' HMD preview texture enable/disable...again --- .../qml/hifi/commerce/wallet/PassphraseChange.qml | 12 ++++++++++++ .../qml/hifi/commerce/wallet/PassphraseModal.qml | 4 ---- .../qml/hifi/commerce/wallet/PassphraseSelection.qml | 3 --- .../qml/hifi/commerce/wallet/SecurityImageChange.qml | 11 +++++++++++ .../hifi/commerce/wallet/SecurityImageSelection.qml | 12 ------------ .../resources/qml/hifi/commerce/wallet/Wallet.qml | 2 +- .../qml/hifi/commerce/wallet/WalletSetup.qml | 11 +++++++---- 7 files changed, 31 insertions(+), 24 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml index 91d2ab9f7f..e74b0fa9dc 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml @@ -24,6 +24,18 @@ Item { HifiConstants { id: hifi; } id: root; + + // This will cause a bug -- if you bring up passphrase selection in HUD mode while + // in HMD while having HMD preview enabled, then move, then finish passphrase selection, + // HMD preview will stay off. + // TODO: Fix this unlikely bug + onVisibleChanged: { + if (visible) { + sendSignalToWallet({method: 'disableHmdPreview'}); + } else { + sendSignalToWallet({method: 'maybeEnableHmdPreview'}); + } + } // Username Text RalewayRegular { diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml index 1fa9054d69..7c38406697 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml @@ -68,10 +68,6 @@ Item { propagateComposedEvents: false; hoverEnabled: true; } - - Component.onDestruction: { - sendSignalToParent({method: 'maybeEnableHmdPreview'}); - } // This will cause a bug -- if you bring up passphrase selection in HUD mode while // in HMD while having HMD preview enabled, then move, then finish passphrase selection, diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml index 50bea2a3cf..5fd6b01d18 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml @@ -61,9 +61,6 @@ Item { if (root.shouldImmediatelyFocus) { focusFirstTextField(); } - sendMessageToLightbox({method: 'disableHmdPreview'}); - } else { - sendMessageToLightbox({method: 'maybeEnableHmdPreview'}); } } diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml index 86a4220b74..0d7fe9ed18 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml @@ -44,6 +44,17 @@ Item { } } + // This will cause a bug -- if you bring up security image selection in HUD mode while + // in HMD while having HMD preview enabled, then move, then finish passphrase selection, + // HMD preview will stay off. + // TODO: Fix this unlikely bug + onVisibleChanged: { + if (visible) { + sendSignalToWallet({method: 'disableHmdPreview'}); + } else { + sendSignalToWallet({method: 'maybeEnableHmdPreview'}); + } + } // Security Image Item { diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml index 56b78c5865..85fc0db3be 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml @@ -25,18 +25,6 @@ Item { id: root; property alias currentIndex: securityImageGrid.currentIndex; - - // This will cause a bug -- if you bring up security image selection in HUD mode while - // in HMD while having HMD preview enabled, then move, then finish passphrase selection, - // HMD preview will stay off. - // TODO: Fix this unlikely bug - onVisibleChanged: { - if (visible) { - sendSignalToWallet({method: 'disableHmdPreview'}); - } else { - sendSignalToWallet({method: 'maybeEnableHmdPreview'}); - } - } SecurityImageModel { id: gridModel; diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index b8b34dc395..b2e7daa066 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -237,7 +237,7 @@ Rectangle { } else { sendToScript(msg); } - } else if (msg.method === 'maybeEnableHmdPreview') { + } else { sendToScript(msg); } } diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml index bad592067c..6956252ee0 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml @@ -76,6 +76,12 @@ Item { var currentStepNumber = root.activeView.substring(5); UserActivityLogger.commerceWalletSetupProgress(timestamp, root.setupAttemptID, Math.round((timestamp - root.startingTimestamp)/1000), currentStepNumber, root.setupStepNames[currentStepNumber - 1]); + + if (root.activeView === "step_2" || root.activeView === "step_3") { + sendSignalToWallet({method: 'disableHmdPreview'}); + } else { + sendSignalToWallet({method: 'maybeEnableHmdPreview'}); + } } // @@ -441,7 +447,7 @@ Item { } Item { id: choosePassphraseContainer; - visible: root.hasShownSecurityImageTip && root.activeView === "step_3"; + visible: root.activeView === "step_3"; // Anchors anchors.top: titleBarContainer.bottom; anchors.topMargin: 30; @@ -451,10 +457,7 @@ Item { onVisibleChanged: { if (visible) { - sendSignalToWallet({method: 'disableHmdPreview'}); Commerce.getWalletAuthenticatedStatus(); - } else { - sendSignalToWallet({method: 'maybeEnableHmdPreview'}); } } From 5f47d511718595422f93ff859fedc8bfcddaa74d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 3 Apr 2018 15:35:46 -0700 Subject: [PATCH 71/72] Prevent Context Overlay from flashing when briefly hovering over certified entity --- .../system/controllers/controllerModules/farActionGrabEntity.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 07450e54ba..d8e2a217a4 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -295,6 +295,7 @@ Script.include("/~/system/libraries/Xform.js"); this.actionID = null; this.grabbedThingID = null; this.targetObject = null; + this.potentialEntityWithContextOverlay = false; }; this.updateRecommendedArea = function() { From 235996911a64002c94448a8f3f0d46295ee91cfe Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 4 Apr 2018 11:38:14 -0700 Subject: [PATCH 72/72] Fixed gcc warning. --- tools/auto-tester/src/Test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 98d4ae463c..0bbd35e280 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -638,7 +638,7 @@ void Test::createMDFile() { stream << "Press space bar to advance step by step\n\n"; int snapShotIndex { 0 }; - for (int i = 0; i < testScriptLines.stepList.size(); ++i) { + for (size_t i = 0; i < testScriptLines.stepList.size(); ++i) { stream << "### Step " << QString::number(i) << "\n"; stream << "- " << testScriptLines.stepList[i]->text << "\n"; if (testScriptLines.stepList[i]->takeSnapshot) {