mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 19:01:09 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into PAL_v2
This commit is contained in:
commit
e66c075f8e
29 changed files with 377 additions and 586 deletions
|
@ -419,6 +419,7 @@ void Agent::executeScript() {
|
||||||
_scriptEngine->registerGlobalObject("Agent", this);
|
_scriptEngine->registerGlobalObject("Agent", this);
|
||||||
|
|
||||||
_scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get<SoundCache>().data());
|
_scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||||
|
_scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||||
|
|
||||||
QScriptValue webSocketServerConstructorValue = _scriptEngine->newFunction(WebSocketServerClass::constructor);
|
QScriptValue webSocketServerConstructorValue = _scriptEngine->newFunction(WebSocketServerClass::constructor);
|
||||||
_scriptEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue);
|
_scriptEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue);
|
||||||
|
|
|
@ -9,11 +9,15 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <glm/gtx/transform.hpp>
|
||||||
|
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
|
#include <AnimUtil.h>
|
||||||
#include "ScriptableAvatar.h"
|
#include "ScriptableAvatar.h"
|
||||||
|
|
||||||
|
|
||||||
QByteArray ScriptableAvatar::toByteArrayStateful(AvatarDataDetail dataDetail) {
|
QByteArray ScriptableAvatar::toByteArrayStateful(AvatarDataDetail dataDetail) {
|
||||||
_globalPosition = getPosition();
|
_globalPosition = getPosition();
|
||||||
return AvatarData::toByteArrayStateful(dataDetail);
|
return AvatarData::toByteArrayStateful(dataDetail);
|
||||||
|
@ -57,6 +61,14 @@ void ScriptableAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
_animSkeleton.reset();
|
_animSkeleton.reset();
|
||||||
AvatarData::setSkeletonModelURL(skeletonModelURL);
|
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) {
|
void ScriptableAvatar::update(float deltatime) {
|
||||||
if (_bind.isNull() && !_skeletonFBXURL.isEmpty()) { // AvatarData will parse the .fst, but not get the .fbx skeleton.
|
if (_bind.isNull() && !_skeletonFBXURL.isEmpty()) { // AvatarData will parse the .fst, but not get the .fbx skeleton.
|
||||||
_bind = DependencyManager::get<AnimationCache>()->getAnimation(_skeletonFBXURL);
|
_bind = DependencyManager::get<AnimationCache>()->getAnimation(_skeletonFBXURL);
|
||||||
|
@ -81,32 +93,42 @@ void ScriptableAvatar::update(float deltatime) {
|
||||||
if (_jointData.size() != nJoints) {
|
if (_jointData.size() != nJoints) {
|
||||||
_jointData.resize(nJoints);
|
_jointData.resize(nJoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int frameCount = _animation->getFrames().size();
|
const int frameCount = _animation->getFrames().size();
|
||||||
const FBXAnimationFrame& floorFrame = _animation->getFrames().at((int)glm::floor(currentFrame) % frameCount);
|
const FBXAnimationFrame& floorFrame = _animation->getFrames().at((int)glm::floor(currentFrame) % frameCount);
|
||||||
const FBXAnimationFrame& ceilFrame = _animation->getFrames().at((int)glm::ceil(currentFrame) % frameCount);
|
const FBXAnimationFrame& ceilFrame = _animation->getFrames().at((int)glm::ceil(currentFrame) % frameCount);
|
||||||
const float frameFraction = glm::fract(currentFrame);
|
const float frameFraction = glm::fract(currentFrame);
|
||||||
std::vector<AnimPose> poses = _animSkeleton->getRelativeDefaultPoses();
|
std::vector<AnimPose> poses = _animSkeleton->getRelativeDefaultPoses();
|
||||||
|
|
||||||
|
const float UNIT_SCALE = 0.01f;
|
||||||
|
|
||||||
for (int i = 0; i < animationJointNames.size(); i++) {
|
for (int i = 0; i < animationJointNames.size(); i++) {
|
||||||
const QString& name = animationJointNames[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
|
// 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).
|
// trusting the .fst (which is sometimes not updated to match changes to .fbx).
|
||||||
int mapping = _bind->getGeometry().getJointIndex(name);
|
int mapping = _bind->getGeometry().getJointIndex(name);
|
||||||
if (mapping != -1 && !_maskedJoints.contains(name)) {
|
if (mapping != -1 && !_maskedJoints.contains(name)) {
|
||||||
// Eventually, this should probably deal with post rotations and translations, too.
|
|
||||||
poses[mapping].rot() = modelJoints[mapping].preRotation *
|
AnimPose floorPose = composeAnimPose(modelJoints[mapping], floorFrame.rotations[i], floorFrame.translations[i] * UNIT_SCALE);
|
||||||
safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction);;
|
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<AnimPose> absPoses = poses;
|
||||||
|
_animSkeleton->convertRelativePosesToAbsolute(absPoses);
|
||||||
for (int i = 0; i < nJoints; i++) {
|
for (int i = 0; i < nJoints; i++) {
|
||||||
JointData& data = _jointData[i];
|
JointData& data = _jointData[i];
|
||||||
AnimPose& pose = poses[i];
|
AnimPose& absPose = absPoses[i];
|
||||||
if (data.rotation != pose.rot()) {
|
if (data.rotation != absPose.rot()) {
|
||||||
data.rotation = pose.rot();
|
data.rotation = absPose.rot();
|
||||||
data.rotationSet = true;
|
data.rotationSet = true;
|
||||||
}
|
}
|
||||||
|
AnimPose& relPose = poses[i];
|
||||||
|
if (data.translation != relPose.trans()) {
|
||||||
|
data.translation = relPose.trans();
|
||||||
|
data.translationSet = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -55,7 +55,7 @@ OriginalDesktop.Desktop {
|
||||||
// Literal 50 is overwritten by settings from previous session, and sysToolbar.x comes from settings when not constrained.
|
// Literal 50 is overwritten by settings from previous session, and sysToolbar.x comes from settings when not constrained.
|
||||||
x: sysToolbar.x
|
x: sysToolbar.x
|
||||||
y: 50
|
y: 50
|
||||||
shown: false
|
shown: true
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
|
|
|
@ -49,7 +49,6 @@ Window {
|
||||||
id: content
|
id: content
|
||||||
implicitHeight: horizontal ? row.height : column.height
|
implicitHeight: horizontal ? row.height : column.height
|
||||||
implicitWidth: horizontal ? row.width : column.width
|
implicitWidth: horizontal ? row.width : column.width
|
||||||
property bool wasVisibleBeforeBeingPinned: false
|
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: row
|
id: row
|
||||||
|
@ -62,18 +61,6 @@ Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component { id: toolbarButtonBuilder; ToolbarButton { } }
|
Component { id: toolbarButtonBuilder; ToolbarButton { } }
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: desktop
|
|
||||||
onPinnedChanged: {
|
|
||||||
if (desktop.pinned) {
|
|
||||||
content.wasVisibleBeforeBeingPinned = window.visible;
|
|
||||||
window.visible = false;
|
|
||||||
} else {
|
|
||||||
window.visible = content.wasVisibleBeforeBeingPinned;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -136,10 +123,11 @@ Window {
|
||||||
buttons.push(result);
|
buttons.push(result);
|
||||||
|
|
||||||
result.opacity = 1;
|
result.opacity = 1;
|
||||||
updatePinned();
|
|
||||||
|
|
||||||
sortButtons();
|
sortButtons();
|
||||||
|
|
||||||
|
shown = true;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,24 +137,12 @@ Window {
|
||||||
console.warn("Tried to remove non-existent button " + name);
|
console.warn("Tried to remove non-existent button " + name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buttons[index].destroy();
|
buttons[index].destroy();
|
||||||
buttons.splice(index, 1);
|
buttons.splice(index, 1);
|
||||||
updatePinned();
|
|
||||||
|
|
||||||
if (buttons.length === 0) {
|
if (buttons.length === 0) {
|
||||||
fadeOut(function () {});
|
shown = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePinned() {
|
|
||||||
var newPinned = false;
|
|
||||||
for (var i in buttons) {
|
|
||||||
var child = buttons[i];
|
|
||||||
if (child.pinned) {
|
|
||||||
newPinned = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pinned = newPinned;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,5 +121,6 @@ private:
|
||||||
friend class AudioInjectorManager;
|
friend class AudioInjectorManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(AudioInjector*)
|
||||||
|
|
||||||
#endif // hifi_AudioInjector_h
|
#endif // hifi_AudioInjector_h
|
||||||
|
|
|
@ -60,8 +60,10 @@ void EntityEditPacketSender::queueEditAvatarEntityMessage(PacketType type,
|
||||||
|
|
||||||
// the ID of the parent/avatar changes from session to session. use a special UUID to indicate the avatar
|
// the ID of the parent/avatar changes from session to session. use a special UUID to indicate the avatar
|
||||||
QJsonObject jsonObject = jsonProperties.object();
|
QJsonObject jsonObject = jsonProperties.object();
|
||||||
if (QUuid(jsonObject["parentID"].toString()) == _myAvatar->getID()) {
|
if (jsonObject.contains("parentID")) {
|
||||||
jsonObject["parentID"] = AVATAR_SELF_ID.toString();
|
if (QUuid(jsonObject["parentID"].toString()) == _myAvatar->getID()) {
|
||||||
|
jsonObject["parentID"] = AVATAR_SELF_ID.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
jsonProperties = QJsonDocument(jsonObject);
|
jsonProperties = QJsonDocument(jsonObject);
|
||||||
|
|
||||||
|
|
|
@ -85,14 +85,16 @@ TransferJob::TransferJob(const GL45VariableAllocationTexture& parent, uint16_t s
|
||||||
auto transferDimensions = _parent._gpuObject.evalMipDimensions(sourceMip);
|
auto transferDimensions = _parent._gpuObject.evalMipDimensions(sourceMip);
|
||||||
GLenum format;
|
GLenum format;
|
||||||
GLenum type;
|
GLenum type;
|
||||||
auto mipData = _parent._gpuObject.accessStoredMipFace(sourceMip, face);
|
|
||||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_parent._gpuObject.getTexelFormat(), _parent._gpuObject.getStoredMipFormat());
|
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_parent._gpuObject.getTexelFormat(), _parent._gpuObject.getStoredMipFormat());
|
||||||
format = texelFormat.format;
|
format = texelFormat.format;
|
||||||
type = texelFormat.type;
|
type = texelFormat.type;
|
||||||
|
auto mipSize = _parent._gpuObject.getStoredMipFaceSize(sourceMip, face);
|
||||||
|
|
||||||
|
|
||||||
if (0 == lines) {
|
if (0 == lines) {
|
||||||
_transferSize = mipData->getSize();
|
_transferSize = mipSize;
|
||||||
_bufferingLambda = [=] {
|
_bufferingLambda = [=] {
|
||||||
|
auto mipData = _parent._gpuObject.accessStoredMipFace(sourceMip, face);
|
||||||
_buffer.resize(_transferSize);
|
_buffer.resize(_transferSize);
|
||||||
memcpy(&_buffer[0], mipData->readData(), _transferSize);
|
memcpy(&_buffer[0], mipData->readData(), _transferSize);
|
||||||
_bufferingCompleted = true;
|
_bufferingCompleted = true;
|
||||||
|
@ -101,11 +103,11 @@ TransferJob::TransferJob(const GL45VariableAllocationTexture& parent, uint16_t s
|
||||||
} else {
|
} else {
|
||||||
transferDimensions.y = lines;
|
transferDimensions.y = lines;
|
||||||
auto dimensions = _parent._gpuObject.evalMipDimensions(sourceMip);
|
auto dimensions = _parent._gpuObject.evalMipDimensions(sourceMip);
|
||||||
auto mipSize = mipData->getSize();
|
|
||||||
auto bytesPerLine = (uint32_t)mipSize / dimensions.y;
|
auto bytesPerLine = (uint32_t)mipSize / dimensions.y;
|
||||||
_transferSize = bytesPerLine * lines;
|
|
||||||
auto sourceOffset = bytesPerLine * lineOffset;
|
auto sourceOffset = bytesPerLine * lineOffset;
|
||||||
|
_transferSize = bytesPerLine * lines;
|
||||||
_bufferingLambda = [=] {
|
_bufferingLambda = [=] {
|
||||||
|
auto mipData = _parent._gpuObject.accessStoredMipFace(sourceMip, face);
|
||||||
_buffer.resize(_transferSize);
|
_buffer.resize(_transferSize);
|
||||||
memcpy(&_buffer[0], mipData->readData() + sourceOffset, _transferSize);
|
memcpy(&_buffer[0], mipData->readData() + sourceOffset, _transferSize);
|
||||||
_bufferingCompleted = true;
|
_bufferingCompleted = true;
|
||||||
|
@ -585,10 +587,10 @@ void GL45ResourceTexture::populateTransferQueue() {
|
||||||
|
|
||||||
// break down the transfers into chunks so that no single transfer is
|
// break down the transfers into chunks so that no single transfer is
|
||||||
// consuming more than X bandwidth
|
// consuming more than X bandwidth
|
||||||
auto mipData = _gpuObject.accessStoredMipFace(sourceMip, face);
|
auto mipSize = _gpuObject.getStoredMipFaceSize(sourceMip, face);
|
||||||
const auto lines = mipDimensions.y;
|
const auto lines = mipDimensions.y;
|
||||||
auto bytesPerLine = (uint32_t)mipData->getSize() / lines;
|
auto bytesPerLine = mipSize / lines;
|
||||||
Q_ASSERT(0 == (mipData->getSize() % lines));
|
Q_ASSERT(0 == (mipSize % lines));
|
||||||
uint32_t linesPerTransfer = (uint32_t)(MAX_TRANSFER_SIZE / bytesPerLine);
|
uint32_t linesPerTransfer = (uint32_t)(MAX_TRANSFER_SIZE / bytesPerLine);
|
||||||
uint32_t lineOffset = 0;
|
uint32_t lineOffset = 0;
|
||||||
while (lineOffset < lines) {
|
while (lineOffset < lines) {
|
||||||
|
|
|
@ -149,6 +149,10 @@ PixelsPointer MemoryStorage::getMipFace(uint16 level, uint8 face) const {
|
||||||
return PixelsPointer();
|
return PixelsPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Size MemoryStorage::getMipFaceSize(uint16 level, uint8 face) const {
|
||||||
|
return getMipFace(level, face)->getSize();
|
||||||
|
}
|
||||||
|
|
||||||
bool MemoryStorage::isMipAvailable(uint16 level, uint8 face) const {
|
bool MemoryStorage::isMipAvailable(uint16 level, uint8 face) const {
|
||||||
PixelsPointer mipFace = getMipFace(level, face);
|
PixelsPointer mipFace = getMipFace(level, face);
|
||||||
return (mipFace && mipFace->getSize());
|
return (mipFace && mipFace->getSize());
|
||||||
|
@ -478,43 +482,39 @@ uint16 Texture::autoGenerateMips(uint16 maxMip) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 Texture::getStoredMipWidth(uint16 level) const {
|
uint16 Texture::getStoredMipWidth(uint16 level) const {
|
||||||
PixelsPointer mipFace = accessStoredMipFace(level);
|
if (!isStoredMipFaceAvailable(level)) {
|
||||||
if (mipFace && mipFace->getSize()) {
|
return 0;
|
||||||
return evalMipWidth(level);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return evalMipWidth(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 Texture::getStoredMipHeight(uint16 level) const {
|
uint16 Texture::getStoredMipHeight(uint16 level) const {
|
||||||
PixelsPointer mip = accessStoredMipFace(level);
|
if (!isStoredMipFaceAvailable(level)) {
|
||||||
if (mip && mip->getSize()) {
|
return 0;
|
||||||
return evalMipHeight(level);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return evalMipHeight(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 Texture::getStoredMipDepth(uint16 level) const {
|
uint16 Texture::getStoredMipDepth(uint16 level) const {
|
||||||
PixelsPointer mipFace = accessStoredMipFace(level);
|
if (!isStoredMipFaceAvailable(level)) {
|
||||||
if (mipFace && mipFace->getSize()) {
|
return 0;
|
||||||
return evalMipDepth(level);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return evalMipDepth(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Texture::getStoredMipNumTexels(uint16 level) const {
|
uint32 Texture::getStoredMipNumTexels(uint16 level) const {
|
||||||
PixelsPointer mipFace = accessStoredMipFace(level);
|
if (!isStoredMipFaceAvailable(level)) {
|
||||||
if (mipFace && mipFace->getSize()) {
|
return 0;
|
||||||
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Texture::getStoredMipSize(uint16 level) const {
|
uint32 Texture::getStoredMipSize(uint16 level) const {
|
||||||
PixelsPointer mipFace = accessStoredMipFace(level);
|
if (!isStoredMipFaceAvailable(level)) {
|
||||||
if (mipFace && mipFace->getSize()) {
|
return 0;
|
||||||
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize();
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::Resource::Size Texture::getStoredSize() const {
|
gpu::Resource::Size Texture::getStoredSize() const {
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
namespace ktx {
|
namespace ktx {
|
||||||
class KTX;
|
class KTX;
|
||||||
using KTXUniquePointer = std::unique_ptr<KTX>;
|
using KTXUniquePointer = std::unique_ptr<KTX>;
|
||||||
|
struct KTXDescriptor;
|
||||||
|
using KTXDescriptorPointer = std::unique_ptr<KTXDescriptor>;
|
||||||
struct Header;
|
struct Header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,6 +263,7 @@ public:
|
||||||
|
|
||||||
virtual void reset() = 0;
|
virtual void reset() = 0;
|
||||||
virtual PixelsPointer getMipFace(uint16 level, uint8 face = 0) const = 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 assignMipData(uint16 level, const storage::StoragePointer& storage) = 0;
|
||||||
virtual void assignMipFaceData(uint16 level, uint8 face, 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;
|
virtual bool isMipAvailable(uint16 level, uint8 face = 0) const = 0;
|
||||||
|
@ -286,6 +289,7 @@ public:
|
||||||
public:
|
public:
|
||||||
void reset() override;
|
void reset() override;
|
||||||
PixelsPointer getMipFace(uint16 level, uint8 face = 0) const 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 assignMipData(uint16 level, const storage::StoragePointer& storage) override;
|
||||||
void assignMipFaceData(uint16 level, uint8 face, 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;
|
bool isMipAvailable(uint16 level, uint8 face = 0) const override;
|
||||||
|
@ -297,8 +301,9 @@ public:
|
||||||
|
|
||||||
class KtxStorage : public Storage {
|
class KtxStorage : public Storage {
|
||||||
public:
|
public:
|
||||||
KtxStorage(ktx::KTXUniquePointer& ktxData);
|
KtxStorage(const std::string& filename);
|
||||||
PixelsPointer getMipFace(uint16 level, uint8 face = 0) const override;
|
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
|
// 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; }
|
bool isMipAvailable(uint16 level, uint8 face = 0) const override { return true; }
|
||||||
|
|
||||||
|
@ -312,7 +317,8 @@ public:
|
||||||
void reset() override { }
|
void reset() override { }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ktx::KTXUniquePointer _ktxData;
|
std::string _filename;
|
||||||
|
ktx::KTXDescriptorPointer _ktxDescriptor;
|
||||||
friend class Texture;
|
friend class Texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -475,9 +481,10 @@ public:
|
||||||
// Access the the sub mips
|
// Access the the sub mips
|
||||||
bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const { return _storage->isMipAvailable(level, face); }
|
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); }
|
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<Storage>& newStorage);
|
void setStorage(std::unique_ptr<Storage>& newStorage);
|
||||||
void setKtxBacking(ktx::KTXUniquePointer& newBacking);
|
void setKtxBacking(const std::string& filename);
|
||||||
|
|
||||||
// access sizes for the stored mips
|
// access sizes for the stored mips
|
||||||
uint16 getStoredMipWidth(uint16 level) const;
|
uint16 getStoredMipWidth(uint16 level) const;
|
||||||
|
@ -515,7 +522,7 @@ public:
|
||||||
|
|
||||||
// Textures can be serialized directly to ktx data file, here is how
|
// Textures can be serialized directly to ktx data file, here is how
|
||||||
static ktx::KTXUniquePointer serialize(const Texture& texture);
|
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 evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header);
|
||||||
static bool evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat);
|
static bool evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat);
|
||||||
|
|
||||||
|
|
|
@ -42,30 +42,37 @@ struct GPUKTXPayload {
|
||||||
|
|
||||||
std::string GPUKTXPayload::KEY { "hifi.gpu" };
|
std::string GPUKTXPayload::KEY { "hifi.gpu" };
|
||||||
|
|
||||||
KtxStorage::KtxStorage(ktx::KTXUniquePointer& ktxData) {
|
KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) {
|
||||||
|
{
|
||||||
// if the source ktx is valid let's config this KtxStorage correctly
|
ktx::StoragePointer storage { new storage::FileStorage(_filename.c_str()) };
|
||||||
if (ktxData && ktxData->getHeader()) {
|
auto ktxPointer = ktx::KTX::create(storage);
|
||||||
|
_ktxDescriptor.reset(new ktx::KTXDescriptor(ktxPointer->toDescriptor()));
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_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 {
|
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<storage::FileStorage>(_filename.c_str())->createView(faceSize, faceOffset)->toMemoryStorage();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::setKtxBacking(ktx::KTXUniquePointer& ktxBacking) {
|
Size KtxStorage::getMipFaceSize(uint16 level, uint8 face) const {
|
||||||
auto newBacking = std::unique_ptr<Storage>(new KtxStorage(ktxBacking));
|
return _ktxDescriptor->getMipFaceTexelsSize(level, face);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture::setKtxBacking(const std::string& filename) {
|
||||||
|
auto newBacking = std::unique_ptr<Storage>(new KtxStorage(filename));
|
||||||
setStorage(newBacking);
|
setStorage(newBacking);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,11 +184,9 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
|
||||||
return ktxBuffer;
|
return ktxBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture* Texture::unserialize(const ktx::KTXUniquePointer& srcData, TextureUsageType usageType, Usage usage, const Sampler::Desc& sampler) {
|
Texture* Texture::unserialize(const std::string& ktxfile, TextureUsageType usageType, Usage usage, const Sampler::Desc& sampler) {
|
||||||
if (!srcData) {
|
ktx::KTXDescriptor descriptor { ktx::KTX::create(ktx::StoragePointer { new storage::FileStorage(ktxfile.c_str()) })->toDescriptor() };
|
||||||
return nullptr;
|
const auto& header = descriptor.header;
|
||||||
}
|
|
||||||
const auto& header = *srcData->getHeader();
|
|
||||||
|
|
||||||
Format mipFormat = Format::COLOR_BGRA_32;
|
Format mipFormat = Format::COLOR_BGRA_32;
|
||||||
Format texelFormat = Format::COLOR_SRGBA_32;
|
Format texelFormat = Format::COLOR_SRGBA_32;
|
||||||
|
@ -209,7 +214,7 @@ Texture* Texture::unserialize(const ktx::KTXUniquePointer& srcData, TextureUsage
|
||||||
|
|
||||||
// If found, use the
|
// If found, use the
|
||||||
GPUKTXPayload gpuktxKeyValue;
|
GPUKTXPayload gpuktxKeyValue;
|
||||||
bool isGPUKTXPayload = GPUKTXPayload::findInKeyValues(srcData->_keyValues, gpuktxKeyValue);
|
bool isGPUKTXPayload = GPUKTXPayload::findInKeyValues(descriptor.keyValues, gpuktxKeyValue);
|
||||||
|
|
||||||
auto tex = Texture::create( (isGPUKTXPayload ? gpuktxKeyValue._usageType : usageType),
|
auto tex = Texture::create( (isGPUKTXPayload ? gpuktxKeyValue._usageType : usageType),
|
||||||
type,
|
type,
|
||||||
|
@ -225,14 +230,7 @@ Texture* Texture::unserialize(const ktx::KTXUniquePointer& srcData, TextureUsage
|
||||||
|
|
||||||
// Assing the mips availables
|
// Assing the mips availables
|
||||||
tex->setStoredMipFormat(mipFormat);
|
tex->setStoredMipFormat(mipFormat);
|
||||||
uint16_t level = 0;
|
tex->setKtxBacking(ktxfile);
|
||||||
for (auto& image : srcData->_images) {
|
|
||||||
for (uint32_t face = 0; face < image._numFaces; face++) {
|
|
||||||
tex->assignStoredMipFace(level, face, image._faceSize, image._faceBytes[face]);
|
|
||||||
}
|
|
||||||
level++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tex;
|
return tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,47 +108,39 @@ KTX::~KTX() {
|
||||||
|
|
||||||
void KTX::resetStorage(const StoragePointer& storage) {
|
void KTX::resetStorage(const StoragePointer& storage) {
|
||||||
_storage = storage;
|
_storage = storage;
|
||||||
|
if (_storage->size() >= sizeof(Header)) {
|
||||||
|
memcpy(&_header, _storage->data(), sizeof(Header));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Header* KTX::getHeader() const {
|
const Header& KTX::getHeader() const {
|
||||||
if (!_storage) {
|
return _header;
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return reinterpret_cast<const Header*>(_storage->data());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t KTX::getKeyValueDataSize() const {
|
size_t KTX::getKeyValueDataSize() const {
|
||||||
if (_storage) {
|
return _header.bytesOfKeyValueData;
|
||||||
return getHeader()->bytesOfKeyValueData;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t KTX::getTexelsDataSize() const {
|
size_t KTX::getTexelsDataSize() const {
|
||||||
if (_storage) {
|
if (!_storage) {
|
||||||
//return _storage->size() - (sizeof(Header) + getKeyValueDataSize());
|
|
||||||
return (_storage->data() + _storage->size()) - getTexelsData();
|
|
||||||
} else {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
return (_storage->data() + _storage->size()) - getTexelsData();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Byte* KTX::getKeyValueData() const {
|
const Byte* KTX::getKeyValueData() const {
|
||||||
if (_storage) {
|
if (!_storage) {
|
||||||
return (_storage->data() + sizeof(Header));
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
return (_storage->data() + sizeof(Header));
|
||||||
}
|
}
|
||||||
|
|
||||||
const Byte* KTX::getTexelsData() const {
|
const Byte* KTX::getTexelsData() const {
|
||||||
if (_storage) {
|
if (!_storage) {
|
||||||
return (_storage->data() + sizeof(Header) + getKeyValueDataSize());
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
return (_storage->data() + sizeof(Header) + getKeyValueDataSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
storage::StoragePointer KTX::getMipFaceTexelsData(uint16_t mip, uint8_t face) const {
|
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;
|
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) {
|
||||||
|
}
|
|
@ -407,43 +407,69 @@ namespace ktx {
|
||||||
};
|
};
|
||||||
using KeyValues = KeyValue::KeyValues;
|
using KeyValues = KeyValue::KeyValues;
|
||||||
|
|
||||||
|
struct ImageHeader {
|
||||||
struct Image {
|
using FaceOffsets = std::vector<size_t>;
|
||||||
using FaceBytes = std::vector<const Byte*>;
|
using FaceBytes = std::vector<const Byte*>;
|
||||||
|
const uint32_t _numFaces;
|
||||||
uint32_t _numFaces{ 1 };
|
const uint32_t _imageSize;
|
||||||
uint32_t _imageSize;
|
const uint32_t _faceSize;
|
||||||
uint32_t _faceSize;
|
const uint32_t _padding;
|
||||||
uint32_t _padding;
|
ImageHeader(bool cube, uint32_t imageSize, uint32_t padding) :
|
||||||
FaceBytes _faceBytes;
|
_numFaces(cube ? NUM_CUBEMAPFACES : 1),
|
||||||
|
_imageSize(imageSize * _numFaces),
|
||||||
|
|
||||||
Image(uint32_t imageSize, uint32_t padding, const Byte* bytes) :
|
|
||||||
_numFaces(1),
|
|
||||||
_imageSize(imageSize),
|
|
||||||
_faceSize(imageSize),
|
_faceSize(imageSize),
|
||||||
_padding(padding),
|
_padding(padding) {
|
||||||
_faceBytes(1, bytes) {}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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<ImageDescriptor>;
|
||||||
|
|
||||||
|
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) :
|
Image(uint32_t pageSize, uint32_t padding, const FaceBytes& cubeFaceBytes) :
|
||||||
_numFaces(NUM_CUBEMAPFACES),
|
ImageHeader(true, pageSize, padding)
|
||||||
_imageSize(pageSize * NUM_CUBEMAPFACES),
|
|
||||||
_faceSize(pageSize),
|
|
||||||
_padding(padding)
|
|
||||||
{
|
{
|
||||||
if (cubeFaceBytes.size() == NUM_CUBEMAPFACES) {
|
if (cubeFaceBytes.size() == NUM_CUBEMAPFACES) {
|
||||||
_faceBytes = cubeFaceBytes;
|
_faceBytes = cubeFaceBytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImageDescriptor toImageDescriptor(const Byte* baseAddress) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Images = std::vector<Image>;
|
using Images = std::vector<Image>;
|
||||||
|
|
||||||
|
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 {
|
class KTX {
|
||||||
void resetStorage(const StoragePointer& src);
|
void resetStorage(const StoragePointer& src);
|
||||||
|
|
||||||
KTX();
|
KTX();
|
||||||
|
KTX(const StoragePointer& storage, const Header& header, const KeyValues& keyValues, const Images& images);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
~KTX();
|
~KTX();
|
||||||
|
|
||||||
// Define a KTX object manually to write it somewhere (in a file on disk?)
|
// 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);
|
static Images parseImages(const Header& header, size_t srcSize, const Byte* srcBytes);
|
||||||
|
|
||||||
// Access raw pointers to the main sections of the KTX
|
// Access raw pointers to the main sections of the KTX
|
||||||
const Header* getHeader() const;
|
const Header& getHeader() const;
|
||||||
|
|
||||||
const Byte* getKeyValueData() const;
|
const Byte* getKeyValueData() const;
|
||||||
const Byte* getTexelsData() const;
|
const Byte* getTexelsData() const;
|
||||||
storage::StoragePointer getMipFaceTexelsData(uint16_t mip = 0, uint8_t face = 0) const;
|
storage::StoragePointer getMipFaceTexelsData(uint16_t mip = 0, uint8_t face = 0) const;
|
||||||
const StoragePointer& getStorage() const { return _storage; }
|
const StoragePointer& getStorage() const { return _storage; }
|
||||||
|
|
||||||
|
KTXDescriptor toDescriptor() const;
|
||||||
size_t getKeyValueDataSize() const;
|
size_t getKeyValueDataSize() const;
|
||||||
size_t getTexelsDataSize() const;
|
size_t getTexelsDataSize() const;
|
||||||
|
|
||||||
|
Header _header;
|
||||||
StoragePointer _storage;
|
StoragePointer _storage;
|
||||||
KeyValues _keyValues;
|
KeyValues _keyValues;
|
||||||
Images _images;
|
Images _images;
|
||||||
|
|
||||||
|
friend struct KTXDescriptor;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,10 +185,10 @@ namespace ktx {
|
||||||
result->resetStorage(src);
|
result->resetStorage(src);
|
||||||
|
|
||||||
// read metadata
|
// read metadata
|
||||||
result->_keyValues = parseKeyValues(result->getHeader()->bytesOfKeyValueData, result->getKeyValueData());
|
result->_keyValues = parseKeyValues(result->getHeader().bytesOfKeyValueData, result->getKeyValueData());
|
||||||
|
|
||||||
// populate image table
|
// populate image table
|
||||||
result->_images = parseImages(*result->getHeader(), result->getTexelsDataSize(), result->getTexelsData());
|
result->_images = parseImages(result->getHeader(), result->getTexelsDataSize(), result->getTexelsData());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,10 +38,3 @@ std::unique_ptr<File> KTXCache::createFile(Metadata&& metadata, const std::strin
|
||||||
KTXFile::KTXFile(Metadata&& metadata, const std::string& filepath) :
|
KTXFile::KTXFile(Metadata&& metadata, const std::string& filepath) :
|
||||||
cache::File(std::move(metadata), filepath) {}
|
cache::File(std::move(metadata), filepath) {}
|
||||||
|
|
||||||
std::unique_ptr<ktx::KTX> KTXFile::getKTX() const {
|
|
||||||
ktx::StoragePointer storage = std::make_shared<storage::FileStorage>(getFilepath().c_str());
|
|
||||||
if (*storage) {
|
|
||||||
return ktx::KTX::create(storage);
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
|
@ -39,9 +39,6 @@ protected:
|
||||||
class KTXFile : public cache::File {
|
class KTXFile : public cache::File {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
|
||||||
std::unique_ptr<ktx::KTX> getKTX() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class KTXCache;
|
friend class KTXCache;
|
||||||
|
|
||||||
|
|
|
@ -438,15 +438,9 @@ void NetworkTexture::loadContent(const QByteArray& content) {
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash);
|
KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash);
|
||||||
if (ktxFile) {
|
if (ktxFile) {
|
||||||
// Ensure that the KTX deserialization worked
|
texture.reset(gpu::Texture::unserialize(ktxFile->getFilepath()));
|
||||||
auto ktx = ktxFile->getKTX();
|
if (texture) {
|
||||||
if (ktx) {
|
texture = textureCache->cacheTextureByHash(hash, texture);
|
||||||
texture.reset(gpu::Texture::unserialize(ktx));
|
|
||||||
// Ensure that the texture population worked
|
|
||||||
if (texture) {
|
|
||||||
texture->setKtxBacking(ktx);
|
|
||||||
texture = textureCache->cacheTextureByHash(hash, texture);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -586,10 +580,7 @@ void ImageReader::read() {
|
||||||
qCWarning(modelnetworking) << _url << "file cache failed";
|
qCWarning(modelnetworking) << _url << "file cache failed";
|
||||||
} else {
|
} else {
|
||||||
resource.staticCast<NetworkTexture>()->_file = file;
|
resource.staticCast<NetworkTexture>()->_file = file;
|
||||||
auto fileKtx = file->getKTX();
|
texture->setKtxBacking(file->getFilepath());
|
||||||
if (fileKtx) {
|
|
||||||
texture->setKtxBacking(fileKtx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -239,6 +239,14 @@ void KinectPlugin::init() {
|
||||||
auto preference = new CheckPreference(KINECT_PLUGIN, "Enabled", getter, setter);
|
auto preference = new CheckPreference(KINECT_PLUGIN, "Enabled", getter, setter);
|
||||||
preferences->addPreference(preference);
|
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 {
|
bool KinectPlugin::isSupported() const {
|
||||||
|
@ -389,37 +397,110 @@ void KinectPlugin::ProcessBody(INT64 time, int bodyCount, IBody** bodies) {
|
||||||
|
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
auto jointCount = _countof(joints);
|
auto jointCount = _countof(joints);
|
||||||
//qDebug() << __FUNCTION__ << "nBodyCount:" << nBodyCount << "body:" << i << "jointCount:" << jointCount;
|
if (_debug) {
|
||||||
|
qDebug() << __FUNCTION__ << "nBodyCount:" << bodyCount << "body:" << i << "jointCount:" << jointCount;
|
||||||
|
}
|
||||||
|
|
||||||
for (int j = 0; j < jointCount; ++j) {
|
for (int j = 0; j < jointCount; ++j) {
|
||||||
//QString jointName = kinectJointNames[joints[j].JointType];
|
|
||||||
|
|
||||||
glm::vec3 jointPosition { joints[j].Position.X,
|
glm::vec3 jointPosition { joints[j].Position.X,
|
||||||
joints[j].Position.Y,
|
joints[j].Position.Y,
|
||||||
joints[j].Position.Z };
|
joints[j].Position.Z };
|
||||||
|
|
||||||
// Kinect Documentation is unclear on what these orientations are, are they absolute?
|
// This is the rotation in the kinect camera/sensor frame... we adjust that in update...
|
||||||
// or are the relative to the parent bones. It appears as if it has changed between the
|
// NOTE: glm::quat(W!!!, x, y, z)... not (x,y,z,w)!!!
|
||||||
// older 1.x SDK and the 2.0 sdk
|
glm::quat jointOrientation { jointOrientations[j].Orientation.w,
|
||||||
//
|
jointOrientations[j].Orientation.x,
|
||||||
// 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,
|
|
||||||
jointOrientations[j].Orientation.y,
|
jointOrientations[j].Orientation.y,
|
||||||
jointOrientations[j].Orientation.z,
|
jointOrientations[j].Orientation.z };
|
||||||
jointOrientations[j].Orientation.w };
|
|
||||||
|
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...
|
// filling in the _joints data...
|
||||||
if (joints[j].TrackingState != TrackingState_NotTracked) {
|
if (joints[j].TrackingState != TrackingState_NotTracked) {
|
||||||
_joints[j].position = jointPosition;
|
_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;
|
//_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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -482,6 +563,7 @@ void KinectPlugin::saveSettings() const {
|
||||||
settings.beginGroup(idString);
|
settings.beginGroup(idString);
|
||||||
{
|
{
|
||||||
settings.setValue(QString("enabled"), _enabled);
|
settings.setValue(QString("enabled"), _enabled);
|
||||||
|
settings.setValue(QString("extraDebug"), _debug);
|
||||||
}
|
}
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
@ -541,8 +623,8 @@ void KinectPlugin::InputDevice::update(float deltaTime, const controller::InputC
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME - determine the correct orientation transform
|
// Note: we want our rotations presenting in the AVATAR frame, so we need to adjust that here.
|
||||||
glm::quat rot = joints[i].orientation;
|
glm::quat rot = controllerToAvatarRotation * joints[i].orientation;
|
||||||
|
|
||||||
if (i < prevJoints.size()) {
|
if (i < prevJoints.size()) {
|
||||||
linearVel = (pos - (prevJoints[i].position * METERS_PER_CENTIMETER)) / deltaTime; // m/s
|
linearVel = (pos - (prevJoints[i].position * METERS_PER_CENTIMETER)) / deltaTime; // m/s
|
||||||
|
|
|
@ -89,6 +89,7 @@ protected:
|
||||||
static const char* KINECT_ID_STRING;
|
static const char* KINECT_ID_STRING;
|
||||||
|
|
||||||
bool _enabled { false };
|
bool _enabled { false };
|
||||||
|
bool _debug { false };
|
||||||
mutable bool _initialized { false };
|
mutable bool _initialized { false };
|
||||||
|
|
||||||
// copy of data directly from the KinectDataReader SDK
|
// copy of data directly from the KinectDataReader SDK
|
||||||
|
|
|
@ -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 }
|
|
||||||
}
|
|
||||||
|
|
|
@ -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); } );
|
|
|
@ -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(); });
|
|
||||||
|
|
|
@ -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); });
|
|
|
@ -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(); });
|
|
||||||
|
|
|
@ -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) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -33,7 +33,13 @@ function shouldOpenFeedAfterShare() {
|
||||||
return persisted && (persisted !== 'false');
|
return persisted && (persisted !== 'false');
|
||||||
}
|
}
|
||||||
function showFeedWindow() {
|
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;
|
var outstanding;
|
||||||
|
|
|
@ -111,38 +111,40 @@ int main(int argc, char** argv) {
|
||||||
outFile.close();
|
outFile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ktxFile = ktx::KTX::create(std::shared_ptr<storage::Storage>(new storage::FileStorage(TEST_IMAGE_KTX)));
|
|
||||||
{
|
{
|
||||||
const auto& memStorage = ktxMemory->getStorage();
|
auto ktxFile = ktx::KTX::create(std::shared_ptr<storage::Storage>(new storage::FileStorage(TEST_IMAGE_KTX)));
|
||||||
const auto& fileStorage = ktxFile->getStorage();
|
{
|
||||||
Q_ASSERT(memStorage->size() == fileStorage->size());
|
const auto& memStorage = ktxMemory->getStorage();
|
||||||
Q_ASSERT(memStorage->data() != fileStorage->data());
|
const auto& fileStorage = ktxFile->getStorage();
|
||||||
Q_ASSERT(0 == memcmp(memStorage->data(), fileStorage->data(), memStorage->size()));
|
Q_ASSERT(memStorage->size() == fileStorage->size());
|
||||||
Q_ASSERT(ktxFile->_images.size() == ktxMemory->_images.size());
|
Q_ASSERT(memStorage->data() != fileStorage->data());
|
||||||
auto imageCount = ktxFile->_images.size();
|
Q_ASSERT(0 == memcmp(memStorage->data(), fileStorage->data(), memStorage->size()));
|
||||||
auto startMemory = ktxMemory->_storage->data();
|
Q_ASSERT(ktxFile->_images.size() == ktxMemory->_images.size());
|
||||||
auto startFile = ktxFile->_storage->data();
|
auto imageCount = ktxFile->_images.size();
|
||||||
for (size_t i = 0; i < imageCount; ++i) {
|
auto startMemory = ktxMemory->_storage->data();
|
||||||
auto memImages = ktxMemory->_images[i];
|
auto startFile = ktxFile->_storage->data();
|
||||||
auto fileImages = ktxFile->_images[i];
|
for (size_t i = 0; i < imageCount; ++i) {
|
||||||
Q_ASSERT(memImages._padding == fileImages._padding);
|
auto memImages = ktxMemory->_images[i];
|
||||||
Q_ASSERT(memImages._numFaces == fileImages._numFaces);
|
auto fileImages = ktxFile->_images[i];
|
||||||
Q_ASSERT(memImages._imageSize == fileImages._imageSize);
|
Q_ASSERT(memImages._padding == fileImages._padding);
|
||||||
Q_ASSERT(memImages._faceSize == fileImages._faceSize);
|
Q_ASSERT(memImages._numFaces == fileImages._numFaces);
|
||||||
Q_ASSERT(memImages._faceBytes.size() == memImages._numFaces);
|
Q_ASSERT(memImages._imageSize == fileImages._imageSize);
|
||||||
Q_ASSERT(fileImages._faceBytes.size() == fileImages._numFaces);
|
Q_ASSERT(memImages._faceSize == fileImages._faceSize);
|
||||||
auto faceCount = fileImages._numFaces;
|
Q_ASSERT(memImages._faceBytes.size() == memImages._numFaces);
|
||||||
for (uint32_t face = 0; face < faceCount; ++face) {
|
Q_ASSERT(fileImages._faceBytes.size() == fileImages._numFaces);
|
||||||
auto memFace = memImages._faceBytes[face];
|
auto faceCount = fileImages._numFaces;
|
||||||
auto memOffset = memFace - startMemory;
|
for (uint32_t face = 0; face < faceCount; ++face) {
|
||||||
auto fileFace = fileImages._faceBytes[face];
|
auto memFace = memImages._faceBytes[face];
|
||||||
auto fileOffset = fileFace - startFile;
|
auto memOffset = memFace - startMemory;
|
||||||
Q_ASSERT(memOffset % 4 == 0);
|
auto fileFace = fileImages._faceBytes[face];
|
||||||
Q_ASSERT(memOffset == fileOffset);
|
auto fileOffset = fileFace - startFile;
|
||||||
|
Q_ASSERT(memOffset % 4 == 0);
|
||||||
|
Q_ASSERT(memOffset == fileOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
testTexture->setKtxBacking(ktxFile);
|
testTexture->setKtxBacking(TEST_IMAGE_KTX.toStdString());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue