From d84e2fb048d9029cbb56291e19160173121941c9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 27 Mar 2017 12:04:55 -0700 Subject: [PATCH 01/10] Add AnimationCache to agent scripts --- assignment-client/src/Agent.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index a5063b09b6..0c3f021334 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -62,6 +62,7 @@ Agent::Agent(ReceivedMessage& message) : DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -419,6 +420,7 @@ void Agent::executeScript() { _scriptEngine->registerGlobalObject("Agent", this); _scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); + _scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); QScriptValue webSocketServerConstructorValue = _scriptEngine->newFunction(WebSocketServerClass::constructor); _scriptEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue); From aa8d231e82757a762596215eaffabedcded85aec Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Mar 2017 09:35:15 -0700 Subject: [PATCH 02/10] Remove extra setting of AnimationCache in Agent --- assignment-client/src/Agent.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 0c3f021334..4cf4049824 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -62,7 +62,6 @@ Agent::Agent(ReceivedMessage& message) : DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); From a2b2e3e1695f1070ddc1c8a096e655180b066232 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 28 Mar 2017 14:45:04 -0700 Subject: [PATCH 03/10] Revert "Revert "Don't hold KTX files open for longer than transfers require"" --- .../gpu/gl45/GL45BackendVariableTexture.cpp | 16 ++-- libraries/gpu/src/gpu/Texture.cpp | 40 ++++----- libraries/gpu/src/gpu/Texture.h | 15 +++- libraries/gpu/src/gpu/Texture_ktx.cpp | 60 +++++++------ libraries/ktx/src/ktx/KTX.cpp | 87 ++++++++++++++----- libraries/ktx/src/ktx/KTX.h | 73 +++++++++++----- libraries/ktx/src/ktx/Reader.cpp | 4 +- .../src/model-networking/KTXCache.cpp | 7 -- .../src/model-networking/KTXCache.h | 3 - .../src/model-networking/TextureCache.cpp | 17 +--- tests/ktx/src/main.cpp | 58 +++++++------ 11 files changed, 224 insertions(+), 156 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp index 188fff9979..4083f09251 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp @@ -85,14 +85,16 @@ TransferJob::TransferJob(const GL45VariableAllocationTexture& parent, uint16_t s auto transferDimensions = _parent._gpuObject.evalMipDimensions(sourceMip); GLenum format; GLenum type; - auto mipData = _parent._gpuObject.accessStoredMipFace(sourceMip, face); GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_parent._gpuObject.getTexelFormat(), _parent._gpuObject.getStoredMipFormat()); format = texelFormat.format; type = texelFormat.type; + auto mipSize = _parent._gpuObject.getStoredMipFaceSize(sourceMip, face); + if (0 == lines) { - _transferSize = mipData->getSize(); + _transferSize = mipSize; _bufferingLambda = [=] { + auto mipData = _parent._gpuObject.accessStoredMipFace(sourceMip, face); _buffer.resize(_transferSize); memcpy(&_buffer[0], mipData->readData(), _transferSize); _bufferingCompleted = true; @@ -101,11 +103,11 @@ TransferJob::TransferJob(const GL45VariableAllocationTexture& parent, uint16_t s } else { transferDimensions.y = lines; auto dimensions = _parent._gpuObject.evalMipDimensions(sourceMip); - auto mipSize = mipData->getSize(); auto bytesPerLine = (uint32_t)mipSize / dimensions.y; - _transferSize = bytesPerLine * lines; auto sourceOffset = bytesPerLine * lineOffset; + _transferSize = bytesPerLine * lines; _bufferingLambda = [=] { + auto mipData = _parent._gpuObject.accessStoredMipFace(sourceMip, face); _buffer.resize(_transferSize); memcpy(&_buffer[0], mipData->readData() + sourceOffset, _transferSize); _bufferingCompleted = true; @@ -585,10 +587,10 @@ void GL45ResourceTexture::populateTransferQueue() { // break down the transfers into chunks so that no single transfer is // consuming more than X bandwidth - auto mipData = _gpuObject.accessStoredMipFace(sourceMip, face); + auto mipSize = _gpuObject.getStoredMipFaceSize(sourceMip, face); const auto lines = mipDimensions.y; - auto bytesPerLine = (uint32_t)mipData->getSize() / lines; - Q_ASSERT(0 == (mipData->getSize() % lines)); + auto bytesPerLine = mipSize / lines; + Q_ASSERT(0 == (mipSize % lines)); uint32_t linesPerTransfer = (uint32_t)(MAX_TRANSFER_SIZE / bytesPerLine); uint32_t lineOffset = 0; while (lineOffset < lines) { diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 1f66b2900e..38019c5a03 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -149,6 +149,10 @@ PixelsPointer MemoryStorage::getMipFace(uint16 level, uint8 face) const { return PixelsPointer(); } +Size MemoryStorage::getMipFaceSize(uint16 level, uint8 face) const { + return getMipFace(level, face)->getSize(); +} + bool MemoryStorage::isMipAvailable(uint16 level, uint8 face) const { PixelsPointer mipFace = getMipFace(level, face); return (mipFace && mipFace->getSize()); @@ -478,43 +482,39 @@ uint16 Texture::autoGenerateMips(uint16 maxMip) { } uint16 Texture::getStoredMipWidth(uint16 level) const { - PixelsPointer mipFace = accessStoredMipFace(level); - if (mipFace && mipFace->getSize()) { - return evalMipWidth(level); + if (!isStoredMipFaceAvailable(level)) { + return 0; } - return 0; + return evalMipWidth(level); } uint16 Texture::getStoredMipHeight(uint16 level) const { - PixelsPointer mip = accessStoredMipFace(level); - if (mip && mip->getSize()) { - return evalMipHeight(level); + if (!isStoredMipFaceAvailable(level)) { + return 0; } - return 0; + return evalMipHeight(level); } uint16 Texture::getStoredMipDepth(uint16 level) const { - PixelsPointer mipFace = accessStoredMipFace(level); - if (mipFace && mipFace->getSize()) { - return evalMipDepth(level); + if (!isStoredMipFaceAvailable(level)) { + return 0; } - return 0; + return evalMipDepth(level); } uint32 Texture::getStoredMipNumTexels(uint16 level) const { - PixelsPointer mipFace = accessStoredMipFace(level); - if (mipFace && mipFace->getSize()) { - return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); + if (!isStoredMipFaceAvailable(level)) { + return 0; } - return 0; + return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); } uint32 Texture::getStoredMipSize(uint16 level) const { - PixelsPointer mipFace = accessStoredMipFace(level); - if (mipFace && mipFace->getSize()) { - return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize(); + if (!isStoredMipFaceAvailable(level)) { + return 0; } - return 0; + + return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize(); } gpu::Resource::Size Texture::getStoredSize() const { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index ce71b41b77..d6185df0d4 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -25,6 +25,8 @@ namespace ktx { class KTX; using KTXUniquePointer = std::unique_ptr; + struct KTXDescriptor; + using KTXDescriptorPointer = std::unique_ptr; struct Header; } @@ -261,6 +263,7 @@ public: virtual void reset() = 0; virtual PixelsPointer getMipFace(uint16 level, uint8 face = 0) const = 0; + virtual Size getMipFaceSize(uint16 level, uint8 face = 0) const = 0; virtual void assignMipData(uint16 level, const storage::StoragePointer& storage) = 0; virtual void assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) = 0; virtual bool isMipAvailable(uint16 level, uint8 face = 0) const = 0; @@ -286,6 +289,7 @@ public: public: void reset() override; PixelsPointer getMipFace(uint16 level, uint8 face = 0) const override; + Size getMipFaceSize(uint16 level, uint8 face = 0) const override; void assignMipData(uint16 level, const storage::StoragePointer& storage) override; void assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) override; bool isMipAvailable(uint16 level, uint8 face = 0) const override; @@ -297,8 +301,9 @@ public: class KtxStorage : public Storage { public: - KtxStorage(ktx::KTXUniquePointer& ktxData); + KtxStorage(const std::string& filename); PixelsPointer getMipFace(uint16 level, uint8 face = 0) const override; + Size getMipFaceSize(uint16 level, uint8 face = 0) const override; // By convention, all mip levels and faces MUST be populated when using KTX backing bool isMipAvailable(uint16 level, uint8 face = 0) const override { return true; } @@ -312,7 +317,8 @@ public: void reset() override { } protected: - ktx::KTXUniquePointer _ktxData; + std::string _filename; + ktx::KTXDescriptorPointer _ktxDescriptor; friend class Texture; }; @@ -475,9 +481,10 @@ public: // Access the the sub mips bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const { return _storage->isMipAvailable(level, face); } const PixelsPointer accessStoredMipFace(uint16 level, uint8 face = 0) const { return _storage->getMipFace(level, face); } + Size getStoredMipFaceSize(uint16 level, uint8 face = 0) const { return _storage->getMipFaceSize(level, face); } void setStorage(std::unique_ptr& newStorage); - void setKtxBacking(ktx::KTXUniquePointer& newBacking); + void setKtxBacking(const std::string& filename); // access sizes for the stored mips uint16 getStoredMipWidth(uint16 level) const; @@ -515,7 +522,7 @@ public: // Textures can be serialized directly to ktx data file, here is how static ktx::KTXUniquePointer serialize(const Texture& texture); - static Texture* unserialize(const ktx::KTXUniquePointer& srcData, TextureUsageType usageType = TextureUsageType::RESOURCE, Usage usage = Usage(), const Sampler::Desc& sampler = Sampler::Desc()); + static Texture* unserialize(const std::string& ktxFile, TextureUsageType usageType = TextureUsageType::RESOURCE, Usage usage = Usage(), const Sampler::Desc& sampler = Sampler::Desc()); static bool evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header); static bool evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat); diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index ab5be7475a..913ced8141 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -42,30 +42,37 @@ struct GPUKTXPayload { std::string GPUKTXPayload::KEY { "hifi.gpu" }; -KtxStorage::KtxStorage(ktx::KTXUniquePointer& ktxData) { - - // if the source ktx is valid let's config this KtxStorage correctly - if (ktxData && ktxData->getHeader()) { - - // now that we know the ktx, let's get the header info to configure this Texture::Storage: - Format mipFormat = Format::COLOR_BGRA_32; - Format texelFormat = Format::COLOR_SRGBA_32; - if (Texture::evalTextureFormat(*ktxData->getHeader(), mipFormat, texelFormat)) { - _format = mipFormat; - } - - +KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) { + { + ktx::StoragePointer storage { new storage::FileStorage(_filename.c_str()) }; + auto ktxPointer = ktx::KTX::create(storage); + _ktxDescriptor.reset(new ktx::KTXDescriptor(ktxPointer->toDescriptor())); } - _ktxData.reset(ktxData.release()); + // now that we know the ktx, let's get the header info to configure this Texture::Storage: + Format mipFormat = Format::COLOR_BGRA_32; + Format texelFormat = Format::COLOR_SRGBA_32; + if (Texture::evalTextureFormat(_ktxDescriptor->header, mipFormat, texelFormat)) { + _format = mipFormat; + } } PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const { - return _ktxData->getMipFaceTexelsData(level, face); + storage::StoragePointer result; + auto faceOffset = _ktxDescriptor->getMipFaceTexelsOffset(level, face); + auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face); + if (faceSize != 0 && faceOffset != 0) { + result = std::make_shared(_filename.c_str())->createView(faceSize, faceOffset)->toMemoryStorage(); + } + return result; } -void Texture::setKtxBacking(ktx::KTXUniquePointer& ktxBacking) { - auto newBacking = std::unique_ptr(new KtxStorage(ktxBacking)); +Size KtxStorage::getMipFaceSize(uint16 level, uint8 face) const { + return _ktxDescriptor->getMipFaceTexelsSize(level, face); +} + +void Texture::setKtxBacking(const std::string& filename) { + auto newBacking = std::unique_ptr(new KtxStorage(filename)); setStorage(newBacking); } @@ -177,11 +184,9 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { return ktxBuffer; } -Texture* Texture::unserialize(const ktx::KTXUniquePointer& srcData, TextureUsageType usageType, Usage usage, const Sampler::Desc& sampler) { - if (!srcData) { - return nullptr; - } - const auto& header = *srcData->getHeader(); +Texture* Texture::unserialize(const std::string& ktxfile, TextureUsageType usageType, Usage usage, const Sampler::Desc& sampler) { + ktx::KTXDescriptor descriptor { ktx::KTX::create(ktx::StoragePointer { new storage::FileStorage(ktxfile.c_str()) })->toDescriptor() }; + const auto& header = descriptor.header; Format mipFormat = Format::COLOR_BGRA_32; Format texelFormat = Format::COLOR_SRGBA_32; @@ -209,7 +214,7 @@ Texture* Texture::unserialize(const ktx::KTXUniquePointer& srcData, TextureUsage // If found, use the GPUKTXPayload gpuktxKeyValue; - bool isGPUKTXPayload = GPUKTXPayload::findInKeyValues(srcData->_keyValues, gpuktxKeyValue); + bool isGPUKTXPayload = GPUKTXPayload::findInKeyValues(descriptor.keyValues, gpuktxKeyValue); auto tex = Texture::create( (isGPUKTXPayload ? gpuktxKeyValue._usageType : usageType), type, @@ -225,14 +230,7 @@ Texture* Texture::unserialize(const ktx::KTXUniquePointer& srcData, TextureUsage // Assing the mips availables tex->setStoredMipFormat(mipFormat); - uint16_t level = 0; - for (auto& image : srcData->_images) { - for (uint32_t face = 0; face < image._numFaces; face++) { - tex->assignStoredMipFace(level, face, image._faceSize, image._faceBytes[face]); - } - level++; - } - + tex->setKtxBacking(ktxfile); return tex; } diff --git a/libraries/ktx/src/ktx/KTX.cpp b/libraries/ktx/src/ktx/KTX.cpp index bbd4e1bc86..6fca39788b 100644 --- a/libraries/ktx/src/ktx/KTX.cpp +++ b/libraries/ktx/src/ktx/KTX.cpp @@ -108,47 +108,39 @@ KTX::~KTX() { void KTX::resetStorage(const StoragePointer& storage) { _storage = storage; + if (_storage->size() >= sizeof(Header)) { + memcpy(&_header, _storage->data(), sizeof(Header)); + } } -const Header* KTX::getHeader() const { - if (!_storage) { - return nullptr; - } - return reinterpret_cast(_storage->data()); +const Header& KTX::getHeader() const { + return _header; } size_t KTX::getKeyValueDataSize() const { - if (_storage) { - return getHeader()->bytesOfKeyValueData; - } else { - return 0; - } + return _header.bytesOfKeyValueData; } size_t KTX::getTexelsDataSize() const { - if (_storage) { - //return _storage->size() - (sizeof(Header) + getKeyValueDataSize()); - return (_storage->data() + _storage->size()) - getTexelsData(); - } else { + if (!_storage) { return 0; } + return (_storage->data() + _storage->size()) - getTexelsData(); } const Byte* KTX::getKeyValueData() const { - if (_storage) { - return (_storage->data() + sizeof(Header)); - } else { + if (!_storage) { return nullptr; } + return (_storage->data() + sizeof(Header)); } const Byte* KTX::getTexelsData() const { - if (_storage) { - return (_storage->data() + sizeof(Header) + getKeyValueDataSize()); - } else { + if (!_storage) { return nullptr; } + return (_storage->data() + sizeof(Header) + getKeyValueDataSize()); } storage::StoragePointer KTX::getMipFaceTexelsData(uint16_t mip, uint8_t face) const { @@ -163,3 +155,58 @@ storage::StoragePointer KTX::getMipFaceTexelsData(uint16_t mip, uint8_t face) co } return result; } + +size_t KTXDescriptor::getMipFaceTexelsSize(uint16_t mip, uint8_t face) const { + size_t result { 0 }; + if (mip < images.size()) { + const auto& faces = images[mip]; + if (face < faces._numFaces) { + result = faces._faceSize; + } + } + return result; +} + +size_t KTXDescriptor::getMipFaceTexelsOffset(uint16_t mip, uint8_t face) const { + size_t result { 0 }; + if (mip < images.size()) { + const auto& faces = images[mip]; + if (face < faces._numFaces) { + result = faces._faceOffsets[face]; + } + } + return result; +} + +ImageDescriptor Image::toImageDescriptor(const Byte* baseAddress) const { + FaceOffsets offsets; + offsets.resize(_faceBytes.size()); + for (size_t face = 0; face < _numFaces; ++face) { + offsets[face] = _faceBytes[face] - baseAddress; + } + // Note, implicit cast of *this to const ImageHeader& + return ImageDescriptor(*this, offsets); +} + +Image ImageDescriptor::toImage(const ktx::StoragePointer& storage) const { + FaceBytes faces; + faces.resize(_faceOffsets.size()); + for (size_t face = 0; face < _numFaces; ++face) { + faces[face] = storage->data() + _faceOffsets[face]; + } + // Note, implicit cast of *this to const ImageHeader& + return Image(*this, faces); +} + +KTXDescriptor KTX::toDescriptor() const { + ImageDescriptors newDescriptors; + auto storageStart = _storage ? _storage->data() : nullptr; + for (size_t i = 0; i < _images.size(); ++i) { + newDescriptors.emplace_back(_images[i].toImageDescriptor(storageStart)); + } + return { this->_header, this->_keyValues, newDescriptors }; +} + +KTX::KTX(const StoragePointer& storage, const Header& header, const KeyValues& keyValues, const Images& images) + : _header(header), _storage(storage), _keyValues(keyValues), _images(images) { +} \ No newline at end of file diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h index 8e901b1105..f09986991a 100644 --- a/libraries/ktx/src/ktx/KTX.h +++ b/libraries/ktx/src/ktx/KTX.h @@ -407,43 +407,69 @@ namespace ktx { }; using KeyValues = KeyValue::KeyValues; - - struct Image { + struct ImageHeader { + using FaceOffsets = std::vector; using FaceBytes = std::vector; - - uint32_t _numFaces{ 1 }; - uint32_t _imageSize; - uint32_t _faceSize; - uint32_t _padding; - FaceBytes _faceBytes; - - - Image(uint32_t imageSize, uint32_t padding, const Byte* bytes) : - _numFaces(1), - _imageSize(imageSize), + const uint32_t _numFaces; + const uint32_t _imageSize; + const uint32_t _faceSize; + const uint32_t _padding; + ImageHeader(bool cube, uint32_t imageSize, uint32_t padding) : + _numFaces(cube ? NUM_CUBEMAPFACES : 1), + _imageSize(imageSize * _numFaces), _faceSize(imageSize), - _padding(padding), - _faceBytes(1, bytes) {} + _padding(padding) { + } + }; + struct Image; + + struct ImageDescriptor : public ImageHeader { + const FaceOffsets _faceOffsets; + ImageDescriptor(const ImageHeader& header, const FaceOffsets& offsets) : ImageHeader(header), _faceOffsets(offsets) {} + Image toImage(const ktx::StoragePointer& storage) const; + }; + + using ImageDescriptors = std::vector; + + struct Image : public ImageHeader { + FaceBytes _faceBytes; + Image(const ImageHeader& header, const FaceBytes& faces) : ImageHeader(header), _faceBytes(faces) {} + Image(uint32_t imageSize, uint32_t padding, const Byte* bytes) : + ImageHeader(false, imageSize, padding), + _faceBytes(1, bytes) {} Image(uint32_t pageSize, uint32_t padding, const FaceBytes& cubeFaceBytes) : - _numFaces(NUM_CUBEMAPFACES), - _imageSize(pageSize * NUM_CUBEMAPFACES), - _faceSize(pageSize), - _padding(padding) + ImageHeader(true, pageSize, padding) { if (cubeFaceBytes.size() == NUM_CUBEMAPFACES) { _faceBytes = cubeFaceBytes; } } + + ImageDescriptor toImageDescriptor(const Byte* baseAddress) const; }; + using Images = std::vector; + class KTX; + + // A KTX descriptor is a lightweight container for all the information about a serialized KTX file, but without the + // actual image / face data available. + struct KTXDescriptor { + KTXDescriptor(const Header& header, const KeyValues& keyValues, const ImageDescriptors& imageDescriptors) : header(header), keyValues(keyValues), images(imageDescriptors) {} + const Header header; + const KeyValues keyValues; + const ImageDescriptors images; + size_t getMipFaceTexelsSize(uint16_t mip = 0, uint8_t face = 0) const; + size_t getMipFaceTexelsOffset(uint16_t mip = 0, uint8_t face = 0) const; + }; + class KTX { void resetStorage(const StoragePointer& src); KTX(); + KTX(const StoragePointer& storage, const Header& header, const KeyValues& keyValues, const Images& images); public: - ~KTX(); // Define a KTX object manually to write it somewhere (in a file on disk?) @@ -475,18 +501,23 @@ namespace ktx { static Images parseImages(const Header& header, size_t srcSize, const Byte* srcBytes); // Access raw pointers to the main sections of the KTX - const Header* getHeader() const; + const Header& getHeader() const; + const Byte* getKeyValueData() const; const Byte* getTexelsData() const; storage::StoragePointer getMipFaceTexelsData(uint16_t mip = 0, uint8_t face = 0) const; const StoragePointer& getStorage() const { return _storage; } + KTXDescriptor toDescriptor() const; size_t getKeyValueDataSize() const; size_t getTexelsDataSize() const; + Header _header; StoragePointer _storage; KeyValues _keyValues; Images _images; + + friend struct KTXDescriptor; }; } diff --git a/libraries/ktx/src/ktx/Reader.cpp b/libraries/ktx/src/ktx/Reader.cpp index 277ce42e69..bf72faeba5 100644 --- a/libraries/ktx/src/ktx/Reader.cpp +++ b/libraries/ktx/src/ktx/Reader.cpp @@ -185,10 +185,10 @@ namespace ktx { result->resetStorage(src); // read metadata - result->_keyValues = parseKeyValues(result->getHeader()->bytesOfKeyValueData, result->getKeyValueData()); + result->_keyValues = parseKeyValues(result->getHeader().bytesOfKeyValueData, result->getKeyValueData()); // populate image table - result->_images = parseImages(*result->getHeader(), result->getTexelsDataSize(), result->getTexelsData()); + result->_images = parseImages(result->getHeader(), result->getTexelsDataSize(), result->getTexelsData()); return result; } diff --git a/libraries/model-networking/src/model-networking/KTXCache.cpp b/libraries/model-networking/src/model-networking/KTXCache.cpp index 63d35fe4a4..8ec1c4e41c 100644 --- a/libraries/model-networking/src/model-networking/KTXCache.cpp +++ b/libraries/model-networking/src/model-networking/KTXCache.cpp @@ -38,10 +38,3 @@ std::unique_ptr KTXCache::createFile(Metadata&& metadata, const std::strin KTXFile::KTXFile(Metadata&& metadata, const std::string& filepath) : cache::File(std::move(metadata), filepath) {} -std::unique_ptr KTXFile::getKTX() const { - ktx::StoragePointer storage = std::make_shared(getFilepath().c_str()); - if (*storage) { - return ktx::KTX::create(storage); - } - return {}; -} diff --git a/libraries/model-networking/src/model-networking/KTXCache.h b/libraries/model-networking/src/model-networking/KTXCache.h index 4ef5e52721..bbf7ceadea 100644 --- a/libraries/model-networking/src/model-networking/KTXCache.h +++ b/libraries/model-networking/src/model-networking/KTXCache.h @@ -39,9 +39,6 @@ protected: class KTXFile : public cache::File { Q_OBJECT -public: - std::unique_ptr getKTX() const; - protected: friend class KTXCache; diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 5dfaddd471..98b03eba1e 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -438,15 +438,9 @@ void NetworkTexture::loadContent(const QByteArray& content) { if (!texture) { KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash); if (ktxFile) { - // Ensure that the KTX deserialization worked - auto ktx = ktxFile->getKTX(); - if (ktx) { - texture.reset(gpu::Texture::unserialize(ktx)); - // Ensure that the texture population worked - if (texture) { - texture->setKtxBacking(ktx); - texture = textureCache->cacheTextureByHash(hash, texture); - } + texture.reset(gpu::Texture::unserialize(ktxFile->getFilepath())); + if (texture) { + texture = textureCache->cacheTextureByHash(hash, texture); } } } @@ -586,10 +580,7 @@ void ImageReader::read() { qCWarning(modelnetworking) << _url << "file cache failed"; } else { resource.staticCast()->_file = file; - auto fileKtx = file->getKTX(); - if (fileKtx) { - texture->setKtxBacking(fileKtx); - } + texture->setKtxBacking(file->getFilepath()); } } diff --git a/tests/ktx/src/main.cpp b/tests/ktx/src/main.cpp index aa6795e17b..3a6fcabf43 100644 --- a/tests/ktx/src/main.cpp +++ b/tests/ktx/src/main.cpp @@ -111,38 +111,40 @@ int main(int argc, char** argv) { outFile.close(); } - auto ktxFile = ktx::KTX::create(std::shared_ptr(new storage::FileStorage(TEST_IMAGE_KTX))); { - const auto& memStorage = ktxMemory->getStorage(); - const auto& fileStorage = ktxFile->getStorage(); - Q_ASSERT(memStorage->size() == fileStorage->size()); - Q_ASSERT(memStorage->data() != fileStorage->data()); - Q_ASSERT(0 == memcmp(memStorage->data(), fileStorage->data(), memStorage->size())); - Q_ASSERT(ktxFile->_images.size() == ktxMemory->_images.size()); - auto imageCount = ktxFile->_images.size(); - auto startMemory = ktxMemory->_storage->data(); - auto startFile = ktxFile->_storage->data(); - for (size_t i = 0; i < imageCount; ++i) { - auto memImages = ktxMemory->_images[i]; - auto fileImages = ktxFile->_images[i]; - Q_ASSERT(memImages._padding == fileImages._padding); - Q_ASSERT(memImages._numFaces == fileImages._numFaces); - Q_ASSERT(memImages._imageSize == fileImages._imageSize); - Q_ASSERT(memImages._faceSize == fileImages._faceSize); - Q_ASSERT(memImages._faceBytes.size() == memImages._numFaces); - Q_ASSERT(fileImages._faceBytes.size() == fileImages._numFaces); - auto faceCount = fileImages._numFaces; - for (uint32_t face = 0; face < faceCount; ++face) { - auto memFace = memImages._faceBytes[face]; - auto memOffset = memFace - startMemory; - auto fileFace = fileImages._faceBytes[face]; - auto fileOffset = fileFace - startFile; - Q_ASSERT(memOffset % 4 == 0); - Q_ASSERT(memOffset == fileOffset); + auto ktxFile = ktx::KTX::create(std::shared_ptr(new storage::FileStorage(TEST_IMAGE_KTX))); + { + const auto& memStorage = ktxMemory->getStorage(); + const auto& fileStorage = ktxFile->getStorage(); + Q_ASSERT(memStorage->size() == fileStorage->size()); + Q_ASSERT(memStorage->data() != fileStorage->data()); + Q_ASSERT(0 == memcmp(memStorage->data(), fileStorage->data(), memStorage->size())); + Q_ASSERT(ktxFile->_images.size() == ktxMemory->_images.size()); + auto imageCount = ktxFile->_images.size(); + auto startMemory = ktxMemory->_storage->data(); + auto startFile = ktxFile->_storage->data(); + for (size_t i = 0; i < imageCount; ++i) { + auto memImages = ktxMemory->_images[i]; + auto fileImages = ktxFile->_images[i]; + Q_ASSERT(memImages._padding == fileImages._padding); + Q_ASSERT(memImages._numFaces == fileImages._numFaces); + Q_ASSERT(memImages._imageSize == fileImages._imageSize); + Q_ASSERT(memImages._faceSize == fileImages._faceSize); + Q_ASSERT(memImages._faceBytes.size() == memImages._numFaces); + Q_ASSERT(fileImages._faceBytes.size() == fileImages._numFaces); + auto faceCount = fileImages._numFaces; + for (uint32_t face = 0; face < faceCount; ++face) { + auto memFace = memImages._faceBytes[face]; + auto memOffset = memFace - startMemory; + auto fileFace = fileImages._faceBytes[face]; + auto fileOffset = fileFace - startFile; + Q_ASSERT(memOffset % 4 == 0); + Q_ASSERT(memOffset == fileOffset); + } } } } - testTexture->setKtxBacking(ktxFile); + testTexture->setKtxBacking(TEST_IMAGE_KTX.toStdString()); return 0; } From bdfbc131851154ee1f8e1aa3609edfc9c9e40397 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Mar 2017 15:09:03 -0700 Subject: [PATCH 04/10] add support for hand rotations to the kinect plugin, add notes on mapping from kinect orientations to our frame orientations --- plugins/hifiKinect/src/KinectPlugin.cpp | 101 +++++++++++++++++++----- 1 file changed, 82 insertions(+), 19 deletions(-) diff --git a/plugins/hifiKinect/src/KinectPlugin.cpp b/plugins/hifiKinect/src/KinectPlugin.cpp index 0bff69ed57..2b9691cfe2 100644 --- a/plugins/hifiKinect/src/KinectPlugin.cpp +++ b/plugins/hifiKinect/src/KinectPlugin.cpp @@ -397,29 +397,92 @@ void KinectPlugin::ProcessBody(INT64 time, int bodyCount, IBody** bodies) { joints[j].Position.Y, joints[j].Position.Z }; - // Kinect Documentation is unclear on what these orientations are, are they absolute? - // or are the relative to the parent bones. It appears as if it has changed between the - // older 1.x SDK and the 2.0 sdk - // - // https://social.msdn.microsoft.com/Forums/en-US/31c9aff6-7dab-433d-9af9-59942dfd3d69/kinect-v20-preview-sdk-jointorientation-vs-boneorientation?forum=kinectv2sdk - // seems to suggest these are absolute... - // "These quaternions are absolute, so you can take a mesh in local space, transform it by the quaternion, - // and it will match the exact orientation of the bone. If you want relative orientation quaternion, you - // can multiply the absolute quaternion by the inverse of the parent joint's quaternion." - // - // - Bone direction(Y green) - always matches the skeleton. - // - Normal(Z blue) - joint roll, perpendicular to the bone - // - Binormal(X orange) - perpendicular to the bone and normal - - glm::quat jointOrientation { jointOrientations[j].Orientation.x, + // This is the rotation in the kinect camera/sensor frame... we adjust that in update... + // NOTE: glm::quat(W!!!, x, y, z)... not (x,y,z,w)!!! + glm::quat jointOrientation { jointOrientations[j].Orientation.w, + jointOrientations[j].Orientation.x, jointOrientations[j].Orientation.y, - jointOrientations[j].Orientation.z, - jointOrientations[j].Orientation.w }; + jointOrientations[j].Orientation.z }; // filling in the _joints data... if (joints[j].TrackingState != TrackingState_NotTracked) { _joints[j].position = jointPosition; + + // Kinect Documentation... + // + // https://social.msdn.microsoft.com/Forums/en-US/31c9aff6-7dab-433d-9af9-59942dfd3d69/kinect-v20-preview-sdk-jointorientation-vs-boneorientation?forum=kinectv2sdk + // seems to suggest these are absolute... + // "These quaternions are absolute, so you can take a mesh in local space, transform it by the quaternion, + // and it will match the exact orientation of the bone. If you want relative orientation quaternion, you + // can multiply the absolute quaternion by the inverse of the parent joint's quaternion." + // + // This is consistent with our findings, but does not include "enough information" + // - Bone direction(Y green) - always matches the skeleton. + // - Normal(Z blue) - joint roll, perpendicular to the bone + // - Binormal(X orange) - perpendicular to the bone and normal + + // NOTE: Common notation of vectors on paper... + // (+) is the back of the arrow - this vector is pointing into the page + // (o) is the point of the arrow - this vector is pointing out of the page + // + + // From ABOVE the kinect coordinate frame looks like this: + // + // Assuming standing facing the kinect camera + // Right Hand with fingers pointing up (green/y) + // thumb pointing behind body (blue/z) + // palm facing the head (point out back of my hand, red/x) + // + // The identity rotation relative to the cameras frame... (the joint data from SDK) + // + // y | | | | + // | | | | | + // | | | + // z----(o) \ |right| + // x \_ | + // | | + // | | + // + // Expected... identity rotation for left hand..... [to be verified] + // Left Hand with fingers pointing up (green/y) + // thumb pointing forward (blue/z) + // palm facing outward away from head (point out back of my hand, red/x) + // + // Our desired coordinate system... + // "the local coordinate of the palm in our system"... + // + // From ABOVE the hand canonical axes look like this: + // + // + // | | | | y | | | | + // | | | | | | | | | + // | | | | | + // |left | / x----(+) \ |right| + // | _/ z \_ | + // | | | | + // | | | | + // + // Right hand rule... make the hitch hiking sign... + // thumb points in direction of the axis you want to rotate around + // fisted fingers curl in positive rotation direction.... + // + // To transform from Kinect to our RIGHT Hand.... Negative 90 deg around Y + // + // FIXME -- Double check if JointType_HandRight vs JointType_WristRight is actually + // the joint we want to be using!! + // //_joints[j].orientation = jointOrientation; + if (joints[j].JointType == JointType_HandRight) { + static const quat kinectToHandRight = glm::angleAxis(-PI / 2.0f, Vectors::UNIT_Y); + _joints[j].orientation = jointOrientation * kinectToHandRight; + } else if (joints[j].JointType == JointType_HandLeft) { + // To transform from Kinect to our LEFT Hand.... Postive 90 deg around Y + static const quat kinectToHandLeft = glm::angleAxis(PI / 2.0f, Vectors::UNIT_Y); + _joints[j].orientation = jointOrientation * kinectToHandLeft; + } else { + _joints[j].orientation = jointOrientation; + } + } } } @@ -541,8 +604,8 @@ void KinectPlugin::InputDevice::update(float deltaTime, const controller::InputC continue; } - // FIXME - determine the correct orientation transform - glm::quat rot = joints[i].orientation; + // Note: we want our rotations presenting in the AVATAR frame, so we need to adjust that here. + glm::quat rot = controllerToAvatarRotation * joints[i].orientation; if (i < prevJoints.size()) { linearVel = (pos - (prevJoints[i].position * METERS_PER_CENTIMETER)) / deltaTime; // m/s From a03d3a1ca8b2afc88073d8c78b8187d07e24a4fe Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 28 Mar 2017 16:00:18 -0700 Subject: [PATCH 05/10] Clean up the utilities scrips of the render folder --- scripts/developer/utilities/render/BG.qml | 22 ---- scripts/developer/utilities/render/debug.js | 39 ------ scripts/developer/utilities/render/debugBG.js | 21 --- .../{debugRender.js => debugCulling.js} | 0 .../utilities/render/debugFramebuffer.js | 51 -------- .../utilities/render/debugToneMapping.js | 20 --- .../utilities/render/framebuffer.qml | 57 -------- .../utilities/render/globalLight.qml | 36 ------ scripts/developer/utilities/render/main.qml | 122 ------------------ 9 files changed, 368 deletions(-) delete mode 100644 scripts/developer/utilities/render/BG.qml delete mode 100644 scripts/developer/utilities/render/debug.js delete mode 100644 scripts/developer/utilities/render/debugBG.js rename scripts/developer/utilities/render/{debugRender.js => debugCulling.js} (100%) delete mode 100644 scripts/developer/utilities/render/debugFramebuffer.js delete mode 100644 scripts/developer/utilities/render/debugToneMapping.js delete mode 100644 scripts/developer/utilities/render/framebuffer.qml delete mode 100644 scripts/developer/utilities/render/globalLight.qml delete mode 100644 scripts/developer/utilities/render/main.qml diff --git a/scripts/developer/utilities/render/BG.qml b/scripts/developer/utilities/render/BG.qml deleted file mode 100644 index 40ce5a89fe..0000000000 --- a/scripts/developer/utilities/render/BG.qml +++ /dev/null @@ -1,22 +0,0 @@ -// -// BG.qml -// examples/utilities/tools/render -// -// Created by Zach Pomerantz on 2/8/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html -// -import QtQuick 2.5 -import QtQuick.Controls 1.4 - -Item { - Timer { - running: true; repeat: true - onTriggered: time.text = Render.getConfig("DrawBackgroundDeferred").gpuTime - } - - Text { id: time; font.pointSize: 20 } -} - diff --git a/scripts/developer/utilities/render/debug.js b/scripts/developer/utilities/render/debug.js deleted file mode 100644 index eba967491b..0000000000 --- a/scripts/developer/utilities/render/debug.js +++ /dev/null @@ -1,39 +0,0 @@ -// -// debug.js -// examples/utilities/tools/render -// -// Zach Pomerantz, created on 1/27/2016. -// Copyright 2016 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 -// - -oldConfig = Render.toJSON(); -Render.RenderShadowTask.enabled = true; -var RDT = Render.RenderDeferredTask; -RDT.AmbientOcclusion.enabled = true; -RDT.DebugDeferredBuffer.enabled = false; - -// Set up the qml ui -var qml = Script.resolvePath('main.qml'); -var window = new OverlayWindow({ - title: 'Render Engine Configuration', - source: qml, - width: 400, height: 900, -}); -window.setPosition(25, 50); -window.closed.connect(function() { Script.stop(); }); - -// Debug buffer sizing -var resizing = false; -Controller.mousePressEvent.connect(function() { resizing = true; }); -Controller.mouseReleaseEvent.connect(function() { resizing = false; }); -Controller.mouseMoveEvent.connect(function(e) { resizing && setDebugBufferSize(e.x); }); -function setDebugBufferSize(x) { - x = (2.0 * (x / Window.innerWidth) - 1.0); // scale - x = Math.min(Math.max(-1, x), 1); // clamp - Render.RenderDeferredTask.DebugDeferredBuffer.size = {x: x, y: -1, z: 1, w: 1}; -} - -Script.scriptEnding.connect(function() { Render.load(oldConfig); } ); diff --git a/scripts/developer/utilities/render/debugBG.js b/scripts/developer/utilities/render/debugBG.js deleted file mode 100644 index 21fe024c32..0000000000 --- a/scripts/developer/utilities/render/debugBG.js +++ /dev/null @@ -1,21 +0,0 @@ -// -// debugBG.js -// examples/utilities/tools/render -// -// Zach Pomerantz, created on 1/27/2016. -// Copyright 2016 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 -// - -// Set up the qml ui -var qml = Script.resolvePath('BG.qml'); -var window = new OverlayWindow({ - title: 'Background Timer', - source: qml, - width: 300 -}); -window.setPosition(25, 50); -window.closed.connect(function() { Script.stop(); }); - diff --git a/scripts/developer/utilities/render/debugRender.js b/scripts/developer/utilities/render/debugCulling.js similarity index 100% rename from scripts/developer/utilities/render/debugRender.js rename to scripts/developer/utilities/render/debugCulling.js diff --git a/scripts/developer/utilities/render/debugFramebuffer.js b/scripts/developer/utilities/render/debugFramebuffer.js deleted file mode 100644 index 12a19085c8..0000000000 --- a/scripts/developer/utilities/render/debugFramebuffer.js +++ /dev/null @@ -1,51 +0,0 @@ -// -// ddebugFramBuffer.js -// examples/utilities/tools/render -// -// Sam Gateau created on 2/18/2016. -// Copyright 2016 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 -// - -var DDB = Render.RenderDeferredTask.DebugDeferredBuffer; -oldConfig = DDB.toJSON(); -DDB.enabled = true; - - -// Set up the qml ui -var qml = Script.resolvePath('framebuffer.qml'); -var window = new OverlayWindow({ - title: 'Framebuffer Debug', - source: qml, - width: 400, height: 50, -}); -window.setPosition(25, 50); -window.closed.connect(function() { Script.stop(); }); - -// Debug buffer sizing -var resizing = false; - -Controller.mousePressEvent.connect(function (e) { - if (shouldStartResizing(e.x)) { - resizing = true; - } -}); -Controller.mouseReleaseEvent.connect(function() { resizing = false; }); -Controller.mouseMoveEvent.connect(function (e) { resizing && setDebugBufferSize(e.x); }); - - -function shouldStartResizing(eventX) { - var x = Math.abs(eventX - Window.innerWidth * (1.0 + DDB.size.x) / 2.0); - var mode = DDB.mode; - return mode !== -1 && x < 20; -} - -function setDebugBufferSize(x) { - x = (2.0 * (x / Window.innerWidth) - 1.0); // scale - x = Math.min(Math.max(-1, x), 1); // clamp - DDB.size = { x: x, y: -1, z: 1, w: 1 }; -} - -Script.scriptEnding.connect(function () { DDB.fromJSON(oldConfig); }); diff --git a/scripts/developer/utilities/render/debugToneMapping.js b/scripts/developer/utilities/render/debugToneMapping.js deleted file mode 100644 index ef14c24fb7..0000000000 --- a/scripts/developer/utilities/render/debugToneMapping.js +++ /dev/null @@ -1,20 +0,0 @@ -// -// debugToneMapping.js -// -// Created by Sam Gateau on 6/30/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html -// - -// Set up the qml ui -var qml = Script.resolvePath('toneMapping.qml'); -var window = new OverlayWindow({ - title: 'Tone Mapping', - source: qml, - width: 400, height: 200, -}); -window.setPosition(250, 1000); -window.closed.connect(function() { Script.stop(); }); - diff --git a/scripts/developer/utilities/render/framebuffer.qml b/scripts/developer/utilities/render/framebuffer.qml deleted file mode 100644 index 65046106dc..0000000000 --- a/scripts/developer/utilities/render/framebuffer.qml +++ /dev/null @@ -1,57 +0,0 @@ -// -// main.qml -// examples/utilities/tools/render -// -// Created by Zach Pomerantz on 2/8/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html -// -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import "configSlider" - -Column { - spacing: 8 - Column { - id: debug - property var config: Render.getConfig("DebugDeferredBuffer") - - function setDebugMode(mode) { - debug.config.enabled = (mode != -1); - debug.config.mode = mode; - } - - ComboBox { - currentIndex: 0 - model: ListModel { - id: cbItems - ListElement { text: "Off"; color: "Yellow" } - ListElement { text: "Depth"; color: "Green" } - ListElement { text: "Albedo"; color: "Yellow" } - ListElement { text: "Normal"; color: "White" } - ListElement { text: "Roughness"; color: "White" } - ListElement { text: "Metallic"; color: "White" } - ListElement { text: "Emissive"; color: "White" } - ListElement { text: "Unlit"; color: "White" } - ListElement { text: "Occlusion"; color: "White" } - ListElement { text: "Lightmap"; color: "White" } - ListElement { text: "Scattering"; color: "White" } - ListElement { text: "Lighting"; color: "White" } - ListElement { text: "Shadow"; color: "White" } - ListElement { text: "Linear Depth"; color: "White" } - ListElement { text: "Mid Curvature"; color: "White" } - ListElement { text: "Mid Normal"; color: "White" } - ListElement { text: "Low Curvature"; color: "White" } - ListElement { text: "Low Normal"; color: "White" } - ListElement { text: "Debug Scattering"; color: "White" } - ListElement { text: "Ambient Occlusion"; color: "White" } - ListElement { text: "Ambient Occlusion Blurred"; color: "White" } - ListElement { text: "Custom"; color: "White" } - } - width: 200 - onCurrentIndexChanged: { debug.setDebugMode(currentIndex - 1) } - } - } -} diff --git a/scripts/developer/utilities/render/globalLight.qml b/scripts/developer/utilities/render/globalLight.qml deleted file mode 100644 index ac0d7ebcd5..0000000000 --- a/scripts/developer/utilities/render/globalLight.qml +++ /dev/null @@ -1,36 +0,0 @@ -// -// globalLight.qml -// examples/utilities/render -// -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html -// -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import "configSlider" - -Column { - id: root - spacing: 8 - property var currentZoneID - property var zoneProperties - - Component.onCompleted: { - Entities.getProperties - sceneOctree.enabled = true; - itemSelection.enabled = true; - sceneOctree.showVisibleCells = false; - sceneOctree.showEmptyCells = false; - itemSelection.showInsideItems = false; - itemSelection.showInsideSubcellItems = false; - itemSelection.showPartialItems = false; - itemSelection.showPartialSubcellItems = false; - } - Component.onDestruction: { - sceneOctree.enabled = false; - itemSelection.enabled = false; - Render.getConfig("FetchSceneSelection").freezeFrustum = false; - Render.getConfig("CullSceneSelection").freezeFrustum = false; - } diff --git a/scripts/developer/utilities/render/main.qml b/scripts/developer/utilities/render/main.qml deleted file mode 100644 index aecd566207..0000000000 --- a/scripts/developer/utilities/render/main.qml +++ /dev/null @@ -1,122 +0,0 @@ -// -// main.qml -// examples/utilities/tools/render -// -// Created by Zach Pomerantz on 2/8/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html -// -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import "configSlider" - -Column { - id: root - spacing: 16 - Switch { - checked: true - onClicked: ui.visible = checked - } - - Column { - id: ui - spacing: 8 - - Repeater { - model: [ "Opaque:DrawOpaqueDeferred", "Transparent:DrawTransparentDeferred", - "Opaque Overlays:DrawOverlay3DOpaque", "Transparent Overlays:DrawOverlay3DTransparent" ] - ConfigSlider { - label: qsTr(modelData.split(":")[0]) - integral: true - config: Render.getConfig(modelData.split(":")[1]) - property: "maxDrawn" - max: config.numDrawn - min: -1 - } - } - - Row { - CheckBox { - text: qsTr("Display Status") - onCheckedChanged: { Render.getConfig("DrawStatus").showDisplay = checked } - } - CheckBox { - text: qsTr("Network/Physics Status") - onCheckedChanged: { Render.getConfig("DrawStatus").showNetwork = checked } - } - } - - ConfigSlider { - label: qsTr("Tone Mapping Exposure") - config: Render.getConfig("ToneMapping") - property: "exposure" - min: -10; max: 10 - } - - Column { - id: ambientOcclusion - property var config: Render.getConfig("AmbientOcclusion") - - Label { text: qsTr("Ambient Occlusion") } - // TODO: Add gpuTimer - CheckBox { text: qsTr("Dithering"); checked: ambientOcclusion.config.ditheringEnabled } - Repeater { - model: [ - "Resolution Level:resolutionLevel:4", - "Obscurance Level:obscuranceLevel:1", - "Radius:radius:2", - "Falloff Bias:falloffBias:0.2", - "Edge Sharpness:edgeSharpness:1", - "Blur Radius:blurRadius:6", - "Blur Deviation:blurDeviation:3" - ] - ConfigSlider { - label: qsTr(modelData.split(":")[0]) - config: ambientOcclusion.config - property: modelData.split(":")[1] - max: modelData.split(":")[2] - } - } - Repeater { - model: [ - "Samples:numSamples:32", - "Spiral Turns:numSpiralTurns:30:" - ] - ConfigSlider { - label: qsTr(modelData.split(":")[0]) - integral: true - config: ambientOcclusion.config - property: modelData.split(":")[1] - max: modelData.split(":")[2] - } - } - } - - Column { - id: debug - property var config: Render.getConfig("DebugDeferredBuffer") - - function setDebugMode(mode) { - debug.config.enabled = (mode != 0); - debug.config.mode = mode; - } - - Label { text: qsTr("Debug Buffer") } - ExclusiveGroup { id: bufferGroup } - Repeater { - model: [ - "Off", "Diffuse", "Metallic", "Roughness", "Normal", "Depth", - "Lighting", "Shadow", "Pyramid Depth", "Ambient Occlusion", "Custom Shader" - ] - RadioButton { - text: qsTr(modelData) - exclusiveGroup: bufferGroup - checked: index == 0 - onCheckedChanged: if (checked && index > 0) debug.setDebugMode(index - 1); - } - } - } - } -} From ecc31802b821f9d864f9242152a5983b76d44be1 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 28 Mar 2017 17:23:36 -0700 Subject: [PATCH 06/10] Added translation support to AC avatar animations. --- .../src/avatars/ScriptableAvatar.cpp | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 516bf7a1e3..7fb319031b 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -9,11 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include +#include #include +#include #include "ScriptableAvatar.h" + QByteArray ScriptableAvatar::toByteArrayStateful(AvatarDataDetail dataDetail) { _globalPosition = getPosition(); return AvatarData::toByteArrayStateful(dataDetail); @@ -57,6 +61,14 @@ void ScriptableAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { _animSkeleton.reset(); AvatarData::setSkeletonModelURL(skeletonModelURL); } + +static AnimPose composeAnimPose(const FBXJoint& fbxJoint, const glm::quat rotation, const glm::vec3 translation) { + glm::mat4 translationMat = glm::translate(translation); + glm::mat4 rotationMat = glm::mat4_cast(fbxJoint.preRotation * rotation * fbxJoint.postRotation); + glm::mat4 finalMat = translationMat * fbxJoint.preTransform * rotationMat * fbxJoint.postTransform; + return AnimPose(finalMat); +} + void ScriptableAvatar::update(float deltatime) { if (_bind.isNull() && !_skeletonFBXURL.isEmpty()) { // AvatarData will parse the .fst, but not get the .fbx skeleton. _bind = DependencyManager::get()->getAnimation(_skeletonFBXURL); @@ -81,32 +93,42 @@ void ScriptableAvatar::update(float deltatime) { if (_jointData.size() != nJoints) { _jointData.resize(nJoints); } - + const int frameCount = _animation->getFrames().size(); const FBXAnimationFrame& floorFrame = _animation->getFrames().at((int)glm::floor(currentFrame) % frameCount); const FBXAnimationFrame& ceilFrame = _animation->getFrames().at((int)glm::ceil(currentFrame) % frameCount); const float frameFraction = glm::fract(currentFrame); std::vector poses = _animSkeleton->getRelativeDefaultPoses(); - + + float UNIT_SCALE = 0.01f; + for (int i = 0; i < animationJointNames.size(); i++) { const QString& name = animationJointNames[i]; // As long as we need the model preRotations anyway, let's get the jointIndex from the bind skeleton rather than // trusting the .fst (which is sometimes not updated to match changes to .fbx). int mapping = _bind->getGeometry().getJointIndex(name); if (mapping != -1 && !_maskedJoints.contains(name)) { - // Eventually, this should probably deal with post rotations and translations, too. - poses[mapping].rot() = modelJoints[mapping].preRotation * - safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction);; + + AnimPose floorPose = composeAnimPose(modelJoints[mapping], floorFrame.rotations[i], floorFrame.translations[i] * UNIT_SCALE); + AnimPose ceilPose = composeAnimPose(modelJoints[mapping], ceilFrame.rotations[i], floorFrame.translations[i] * UNIT_SCALE); + blend(1, &floorPose, &ceilPose, frameFraction, &poses[mapping]); } } - _animSkeleton->convertRelativePosesToAbsolute(poses); + + std::vector absPoses = poses; + _animSkeleton->convertRelativePosesToAbsolute(absPoses); for (int i = 0; i < nJoints; i++) { JointData& data = _jointData[i]; - AnimPose& pose = poses[i]; - if (data.rotation != pose.rot()) { - data.rotation = pose.rot(); + AnimPose& absPose = absPoses[i]; + if (data.rotation != absPose.rot()) { + data.rotation = absPose.rot(); data.rotationSet = true; } + AnimPose& relPose = poses[i]; + if (data.translation != relPose.trans()) { + data.translation = relPose.trans(); + data.translationSet = true; + } } } else { From e100e3d19b0d38a701122b0cb29584b8f8b813c6 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 28 Mar 2017 17:34:15 -0700 Subject: [PATCH 07/10] made UNIT_SCALE const --- assignment-client/src/avatars/ScriptableAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 7fb319031b..57456b00c3 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -100,7 +100,7 @@ void ScriptableAvatar::update(float deltatime) { const float frameFraction = glm::fract(currentFrame); std::vector poses = _animSkeleton->getRelativeDefaultPoses(); - float UNIT_SCALE = 0.01f; + const float UNIT_SCALE = 0.01f; for (int i = 0; i < animationJointNames.size(); i++) { const QString& name = animationJointNames[i]; From 80fb7bc28706b38ce8a42597c3b7d82c8fa1f05f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Mar 2017 18:42:15 -0700 Subject: [PATCH 08/10] add extra debugging to the kinect plugin --- plugins/hifiKinect/src/KinectPlugin.cpp | 23 +++++++++++++++++++++-- plugins/hifiKinect/src/KinectPlugin.h | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/plugins/hifiKinect/src/KinectPlugin.cpp b/plugins/hifiKinect/src/KinectPlugin.cpp index 2b9691cfe2..19b5c94297 100644 --- a/plugins/hifiKinect/src/KinectPlugin.cpp +++ b/plugins/hifiKinect/src/KinectPlugin.cpp @@ -239,6 +239,14 @@ void KinectPlugin::init() { auto preference = new CheckPreference(KINECT_PLUGIN, "Enabled", getter, setter); preferences->addPreference(preference); } + { + auto debugGetter = [this]()->bool { return _enabled; }; + auto debugSetter = [this](bool value) { + _debug = value; saveSettings(); + }; + auto preference = new CheckPreference(KINECT_PLUGIN, "Extra Debugging", debugGetter, debugSetter); + preferences->addPreference(preference); + } } bool KinectPlugin::isSupported() const { @@ -389,9 +397,11 @@ void KinectPlugin::ProcessBody(INT64 time, int bodyCount, IBody** bodies) { if (SUCCEEDED(hr)) { auto jointCount = _countof(joints); - //qDebug() << __FUNCTION__ << "nBodyCount:" << nBodyCount << "body:" << i << "jointCount:" << jointCount; + if (_debug) { + qDebug() << __FUNCTION__ << "nBodyCount:" << nBodyCount << "body:" << i << "jointCount:" << jointCount; + } + for (int j = 0; j < jointCount; ++j) { - //QString jointName = kinectJointNames[joints[j].JointType]; glm::vec3 jointPosition { joints[j].Position.X, joints[j].Position.Y, @@ -404,6 +414,14 @@ void KinectPlugin::ProcessBody(INT64 time, int bodyCount, IBody** bodies) { jointOrientations[j].Orientation.y, jointOrientations[j].Orientation.z }; + if (_debug) { + QString jointName = kinectJointNames[joints[j].JointType]; + qDebug() << __FUNCTION__ << "joint[" << j << "]:" << jointName + << "position:" << jointPosition + << "orientation:" << jointOrientation + << "isTracked:" << joints[j].TrackingState != TrackingState_NotTracked; + } + // filling in the _joints data... if (joints[j].TrackingState != TrackingState_NotTracked) { _joints[j].position = jointPosition; @@ -545,6 +563,7 @@ void KinectPlugin::saveSettings() const { settings.beginGroup(idString); { settings.setValue(QString("enabled"), _enabled); + settings.setValue(QString("extraDebug"), _debug); } settings.endGroup(); } diff --git a/plugins/hifiKinect/src/KinectPlugin.h b/plugins/hifiKinect/src/KinectPlugin.h index b10698fa31..90794fa6b0 100644 --- a/plugins/hifiKinect/src/KinectPlugin.h +++ b/plugins/hifiKinect/src/KinectPlugin.h @@ -89,6 +89,7 @@ protected: static const char* KINECT_ID_STRING; bool _enabled { false }; + bool _debug { false }; mutable bool _initialized { false }; // copy of data directly from the KinectDataReader SDK From 9d3e8818f78438615a3f1993020c29daaa53f210 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Mar 2017 18:49:36 -0700 Subject: [PATCH 09/10] fix build --- plugins/hifiKinect/src/KinectPlugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/hifiKinect/src/KinectPlugin.cpp b/plugins/hifiKinect/src/KinectPlugin.cpp index 19b5c94297..8313ea0d49 100644 --- a/plugins/hifiKinect/src/KinectPlugin.cpp +++ b/plugins/hifiKinect/src/KinectPlugin.cpp @@ -398,7 +398,7 @@ void KinectPlugin::ProcessBody(INT64 time, int bodyCount, IBody** bodies) { if (SUCCEEDED(hr)) { auto jointCount = _countof(joints); if (_debug) { - qDebug() << __FUNCTION__ << "nBodyCount:" << nBodyCount << "body:" << i << "jointCount:" << jointCount; + qDebug() << __FUNCTION__ << "nBodyCount:" << bodyCount << "body:" << i << "jointCount:" << jointCount; } for (int j = 0; j < jointCount; ++j) { @@ -419,7 +419,7 @@ void KinectPlugin::ProcessBody(INT64 time, int bodyCount, IBody** bodies) { qDebug() << __FUNCTION__ << "joint[" << j << "]:" << jointName << "position:" << jointPosition << "orientation:" << jointOrientation - << "isTracked:" << joints[j].TrackingState != TrackingState_NotTracked; + << "isTracked:" << (joints[j].TrackingState != TrackingState_NotTracked); } // filling in the _joints data... From c618e8e0018217c8867320ee6a0598686d602337 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 29 Mar 2017 16:52:52 +1300 Subject: [PATCH 10/10] Open feed in tablet after sharing snapshot from tablet --- scripts/system/snapshot.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 010544a2c6..8f393846c0 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -33,7 +33,13 @@ function shouldOpenFeedAfterShare() { return persisted && (persisted !== 'false'); } function showFeedWindow() { - DialogsManager.showFeed(); + if ((HMD.active && Settings.getValue("hmdTabletBecomesToolbar")) + || (!HMD.active && Settings.getValue("desktopTabletBecomesToolbar"))) { + DialogsManager.showFeed(); + } else { + tablet.loadQMLSource("TabletAddressDialog.qml"); + HMD.openTablet(); + } } var outstanding;