mirror of
https://github.com/overte-org/overte.git
synced 2025-04-14 08:47:16 +02:00
Cleaning up clip and transform
This commit is contained in:
parent
b9a0d0b843
commit
ee1545f649
23 changed files with 381 additions and 188 deletions
|
@ -126,7 +126,7 @@ MyAvatar::MyAvatar(RigPointer rig) :
|
||||||
});
|
});
|
||||||
|
|
||||||
// FIXME how to deal with driving multiple avatars locally?
|
// FIXME how to deal with driving multiple avatars locally?
|
||||||
Frame::registerFrameHandler(AVATAR_FRAME_TYPE, [this](Frame::Pointer frame) {
|
Frame::registerFrameHandler(AVATAR_FRAME_TYPE, [this](Frame::ConstPointer frame) {
|
||||||
qDebug() << "Playback of avatar frame length: " << frame->data.size();
|
qDebug() << "Playback of avatar frame length: " << frame->data.size();
|
||||||
avatarStateFromFrame(frame->data, this);
|
avatarStateFromFrame(frame->data, this);
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
// 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 "AvatarData.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -22,6 +25,7 @@
|
||||||
#include <QtNetwork/QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
#include <QtNetwork/QNetworkRequest>
|
#include <QtNetwork/QNetworkRequest>
|
||||||
|
|
||||||
|
#include <Transform.h>
|
||||||
#include <NetworkAccessManager.h>
|
#include <NetworkAccessManager.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <udt/PacketHeaders.h>
|
#include <udt/PacketHeaders.h>
|
||||||
|
@ -29,12 +33,10 @@
|
||||||
#include <StreamUtils.h>
|
#include <StreamUtils.h>
|
||||||
#include <UUID.h>
|
#include <UUID.h>
|
||||||
#include <shared/JSONHelpers.h>
|
#include <shared/JSONHelpers.h>
|
||||||
#include <shared/UniformTransform.h>
|
|
||||||
#include <recording/Deck.h>
|
#include <recording/Deck.h>
|
||||||
#include <recording/Clip.h>
|
#include <recording/Clip.h>
|
||||||
|
|
||||||
#include "AvatarLogging.h"
|
#include "AvatarLogging.h"
|
||||||
#include "AvatarData.h"
|
|
||||||
|
|
||||||
quint64 DEFAULT_FILTERED_LOG_EXPIRY = 2 * USECS_PER_SECOND;
|
quint64 DEFAULT_FILTERED_LOG_EXPIRY = 2 * USECS_PER_SECOND;
|
||||||
|
|
||||||
|
@ -908,7 +910,7 @@ void AvatarData::play() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<UniformTransform> AvatarData::getRecordingBasis() const {
|
std::shared_ptr<Transform> AvatarData::getRecordingBasis() const {
|
||||||
return _recordingBasis;
|
return _recordingBasis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1506,12 +1508,12 @@ void registerAvatarTypes(QScriptEngine* engine) {
|
||||||
new AttachmentDataObject(), QScriptEngine::ScriptOwnership));
|
new AttachmentDataObject(), QScriptEngine::ScriptOwnership));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::setRecordingBasis(std::shared_ptr<UniformTransform> recordingBasis) {
|
void AvatarData::setRecordingBasis(std::shared_ptr<Transform> recordingBasis) {
|
||||||
if (!recordingBasis) {
|
if (!recordingBasis) {
|
||||||
recordingBasis = std::make_shared<UniformTransform>();
|
recordingBasis = std::make_shared<Transform>();
|
||||||
recordingBasis->rotation = getOrientation();
|
recordingBasis->setRotation(getOrientation());
|
||||||
recordingBasis->translation = getPosition();
|
recordingBasis->setTranslation(getPosition());
|
||||||
recordingBasis->scale = getTargetScale();
|
recordingBasis->setScale(getTargetScale());
|
||||||
}
|
}
|
||||||
_recordingBasis = recordingBasis;
|
_recordingBasis = recordingBasis;
|
||||||
}
|
}
|
||||||
|
@ -1520,6 +1522,14 @@ void AvatarData::clearRecordingBasis() {
|
||||||
_recordingBasis.reset();
|
_recordingBasis.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform AvatarData::getTransform() const {
|
||||||
|
Transform result;
|
||||||
|
result.setRotation(getOrientation());
|
||||||
|
result.setTranslation(getPosition());
|
||||||
|
result.setScale(getTargetScale());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static const QString JSON_AVATAR_BASIS = QStringLiteral("basisTransform");
|
static const QString JSON_AVATAR_BASIS = QStringLiteral("basisTransform");
|
||||||
static const QString JSON_AVATAR_RELATIVE = QStringLiteral("relativeTransform");
|
static const QString JSON_AVATAR_RELATIVE = QStringLiteral("relativeTransform");
|
||||||
static const QString JSON_AVATAR_JOINT_ROTATIONS = QStringLiteral("jointRotations");
|
static const QString JSON_AVATAR_JOINT_ROTATIONS = QStringLiteral("jointRotations");
|
||||||
|
@ -1557,15 +1567,14 @@ QByteArray avatarStateToFrame(const AvatarData* _avatar) {
|
||||||
|
|
||||||
auto recordingBasis = _avatar->getRecordingBasis();
|
auto recordingBasis = _avatar->getRecordingBasis();
|
||||||
if (recordingBasis) {
|
if (recordingBasis) {
|
||||||
// FIXME if the resulting relative basis is identity, we shouldn't record anything
|
// Find the relative transform
|
||||||
// Record the transformation basis
|
auto relativeTransform = recordingBasis->relativeTransform(_avatar->getTransform());
|
||||||
root[JSON_AVATAR_BASIS] = recordingBasis->toJson();
|
|
||||||
|
|
||||||
// Record the relative transform
|
// if the resulting relative basis is identity, we shouldn't record anything
|
||||||
auto relativeTransform = recordingBasis->relativeTransform(
|
if (!relativeTransform.isIdentity()) {
|
||||||
UniformTransform(_avatar->getPosition(), _avatar->getOrientation(), _avatar->getTargetScale()));
|
root[JSON_AVATAR_RELATIVE] = Transform::toJson(relativeTransform);
|
||||||
|
root[JSON_AVATAR_BASIS] = Transform::toJson(*recordingBasis);
|
||||||
root[JSON_AVATAR_RELATIVE] = relativeTransform.toJson();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonArray jointRotations;
|
QJsonArray jointRotations;
|
||||||
|
@ -1617,22 +1626,25 @@ void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// During playback you can either have the recording basis set to the avatar current state
|
if (root.contains(JSON_AVATAR_RELATIVE)) {
|
||||||
// meaning that all playback is relative to this avatars starting position, or
|
// During playback you can either have the recording basis set to the avatar current state
|
||||||
// the basis can be loaded from the recording, meaning the playback is relative to the
|
// meaning that all playback is relative to this avatars starting position, or
|
||||||
// original avatar location
|
// the basis can be loaded from the recording, meaning the playback is relative to the
|
||||||
// The first is more useful for playing back recordings on your own avatar, while
|
// original avatar location
|
||||||
// the latter is more useful for playing back other avatars within your scene.
|
// The first is more useful for playing back recordings on your own avatar, while
|
||||||
auto currentBasis = _avatar->getRecordingBasis();
|
// the latter is more useful for playing back other avatars within your scene.
|
||||||
if (!currentBasis) {
|
|
||||||
currentBasis = UniformTransform::parseJson(root[JSON_AVATAR_BASIS]);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto relativeTransform = UniformTransform::parseJson(root[JSON_AVATAR_RELATIVE]);
|
auto currentBasis = _avatar->getRecordingBasis();
|
||||||
auto worldTransform = currentBasis->worldTransform(*relativeTransform);
|
if (!currentBasis) {
|
||||||
_avatar->setPosition(worldTransform.translation);
|
currentBasis = std::make_shared<Transform>(Transform::fromJson(root[JSON_AVATAR_BASIS]));
|
||||||
_avatar->setOrientation(worldTransform.rotation);
|
}
|
||||||
_avatar->setTargetScale(worldTransform.scale);
|
|
||||||
|
auto relativeTransform = Transform::fromJson(root[JSON_AVATAR_RELATIVE]);
|
||||||
|
auto worldTransform = currentBasis->worldTransform(relativeTransform);
|
||||||
|
_avatar->setPosition(worldTransform.getTranslation());
|
||||||
|
_avatar->setOrientation(worldTransform.getRotation());
|
||||||
|
_avatar->setTargetScale(worldTransform.getScale().x);
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (root.contains(JSON_AVATAR_ATTACHEMENTS)) {
|
if (root.contains(JSON_AVATAR_ATTACHEMENTS)) {
|
||||||
|
|
|
@ -134,7 +134,8 @@ class QDataStream;
|
||||||
|
|
||||||
class AttachmentData;
|
class AttachmentData;
|
||||||
class JointData;
|
class JointData;
|
||||||
struct UniformTransform;
|
class Transform;
|
||||||
|
using TransformPointer = std::shared_ptr<Transform>;
|
||||||
|
|
||||||
class AvatarData : public QObject {
|
class AvatarData : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -333,10 +334,10 @@ public:
|
||||||
|
|
||||||
bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; }
|
bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; }
|
||||||
|
|
||||||
|
Transform getTransform() const;
|
||||||
void clearRecordingBasis();
|
void clearRecordingBasis();
|
||||||
std::shared_ptr<UniformTransform> getRecordingBasis() const;
|
TransformPointer getRecordingBasis() const;
|
||||||
void setRecordingBasis(std::shared_ptr<UniformTransform> recordingBasis = std::shared_ptr<UniformTransform>());
|
void setRecordingBasis(TransformPointer recordingBasis = TransformPointer());
|
||||||
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void sendAvatarDataPacket();
|
void sendAvatarDataPacket();
|
||||||
|
@ -437,7 +438,7 @@ protected:
|
||||||
|
|
||||||
// During recording, this holds the starting position, orientation & scale of the recorded avatar
|
// During recording, this holds the starting position, orientation & scale of the recorded avatar
|
||||||
// During playback, it holds the
|
// During playback, it holds the
|
||||||
std::shared_ptr<UniformTransform> _recordingBasis;
|
TransformPointer _recordingBasis;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
|
friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
|
||||||
|
|
|
@ -38,7 +38,7 @@ Clip::Pointer Clip::duplicate() {
|
||||||
Time currentPosition = position();
|
Time currentPosition = position();
|
||||||
seek(0);
|
seek(0);
|
||||||
|
|
||||||
Frame::Pointer frame = nextFrame();
|
auto frame = nextFrame();
|
||||||
while (frame) {
|
while (frame) {
|
||||||
result->addFrame(frame);
|
result->addFrame(frame);
|
||||||
frame = nextFrame();
|
frame = nextFrame();
|
||||||
|
|
|
@ -34,16 +34,17 @@ public:
|
||||||
virtual void seek(Time offset) = 0;
|
virtual void seek(Time offset) = 0;
|
||||||
virtual Time position() const = 0;
|
virtual Time position() const = 0;
|
||||||
|
|
||||||
virtual FramePointer peekFrame() const = 0;
|
virtual FrameConstPointer peekFrame() const = 0;
|
||||||
virtual FramePointer nextFrame() = 0;
|
virtual FrameConstPointer nextFrame() = 0;
|
||||||
virtual void skipFrame() = 0;
|
virtual void skipFrame() = 0;
|
||||||
virtual void addFrame(FramePointer) = 0;
|
virtual void addFrame(FrameConstPointer) = 0;
|
||||||
|
|
||||||
static Pointer fromFile(const QString& filePath);
|
static Pointer fromFile(const QString& filePath);
|
||||||
static void toFile(const QString& filePath, Pointer clip);
|
static void toFile(const QString& filePath, Pointer clip);
|
||||||
static Pointer newClip();
|
static Pointer newClip();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
friend class WrapperClip;
|
||||||
using Mutex = std::recursive_mutex;
|
using Mutex = std::recursive_mutex;
|
||||||
using Locker = std::unique_lock<Mutex>;
|
using Locker = std::unique_lock<Mutex>;
|
||||||
|
|
||||||
|
|
|
@ -46,9 +46,6 @@ public:
|
||||||
Time position() const;
|
Time position() const;
|
||||||
void seek(Time position);
|
void seek(Time position);
|
||||||
|
|
||||||
void setPlaybackSpeed(float factor) { _playbackSpeed = factor; }
|
|
||||||
float getPlaybackSpeed() { return _playbackSpeed; }
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void playbackStateChanged();
|
void playbackStateChanged();
|
||||||
|
|
||||||
|
@ -62,7 +59,6 @@ private:
|
||||||
Clips _clips;
|
Clips _clips;
|
||||||
quint64 _startEpoch { 0 };
|
quint64 _startEpoch { 0 };
|
||||||
Time _position { 0 };
|
Time _position { 0 };
|
||||||
float _playbackSpeed { 1.0f };
|
|
||||||
bool _pause { true };
|
bool _pause { true };
|
||||||
bool _loop { false };
|
bool _loop { false };
|
||||||
Time _length { 0 };
|
Time _length { 0 };
|
||||||
|
|
|
@ -28,6 +28,8 @@ struct Frame;
|
||||||
|
|
||||||
using FramePointer = std::shared_ptr<Frame>;
|
using FramePointer = std::shared_ptr<Frame>;
|
||||||
|
|
||||||
|
using FrameConstPointer = std::shared_ptr<const Frame>;
|
||||||
|
|
||||||
// A recording of some set of state from the application, usually avatar
|
// A recording of some set of state from the application, usually avatar
|
||||||
// data + audio for a single person
|
// data + audio for a single person
|
||||||
class Clip;
|
class Clip;
|
||||||
|
|
|
@ -104,7 +104,7 @@ Frame::Handler Frame::registerFrameHandler(FrameType type, Handler handler) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Frame::handleFrame(const Frame::Pointer& frame) {
|
void Frame::handleFrame(const Frame::ConstPointer& frame) {
|
||||||
Handler handler;
|
Handler handler;
|
||||||
{
|
{
|
||||||
Locker lock(mutex);
|
Locker lock(mutex);
|
||||||
|
|
|
@ -21,7 +21,8 @@ namespace recording {
|
||||||
struct Frame {
|
struct Frame {
|
||||||
public:
|
public:
|
||||||
using Pointer = std::shared_ptr<Frame>;
|
using Pointer = std::shared_ptr<Frame>;
|
||||||
using Handler = std::function<void(Frame::Pointer frame)>;
|
using ConstPointer = std::shared_ptr<const Frame>;
|
||||||
|
using Handler = std::function<void(Frame::ConstPointer frame)>;
|
||||||
|
|
||||||
static const FrameType TYPE_INVALID = 0xFFFF;
|
static const FrameType TYPE_INVALID = 0xFFFF;
|
||||||
static const FrameType TYPE_HEADER = 0x0;
|
static const FrameType TYPE_HEADER = 0x0;
|
||||||
|
@ -37,7 +38,7 @@ public:
|
||||||
static QMap<QString, FrameType> getFrameTypes();
|
static QMap<QString, FrameType> getFrameTypes();
|
||||||
static QMap<FrameType, QString> getFrameTypeNames();
|
static QMap<FrameType, QString> getFrameTypeNames();
|
||||||
static Handler registerFrameHandler(FrameType type, Handler handler);
|
static Handler registerFrameHandler(FrameType type, Handler handler);
|
||||||
static void handleFrame(const Pointer& frame);
|
static void handleFrame(const ConstPointer& frame);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ using namespace recording;
|
||||||
void BufferClip::seek(Time offset) {
|
void BufferClip::seek(Time offset) {
|
||||||
Locker lock(_mutex);
|
Locker lock(_mutex);
|
||||||
auto itr = std::lower_bound(_frames.begin(), _frames.end(), offset,
|
auto itr = std::lower_bound(_frames.begin(), _frames.end(), offset,
|
||||||
[](Frame::Pointer a, Time b)->bool {
|
[](Frame::ConstPointer a, Time b)->bool {
|
||||||
return a->timeOffset < b;
|
return a->timeOffset < b;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -34,18 +34,18 @@ Time BufferClip::position() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FramePointer BufferClip::peekFrame() const {
|
FrameConstPointer BufferClip::peekFrame() const {
|
||||||
Locker lock(_mutex);
|
Locker lock(_mutex);
|
||||||
FramePointer result;
|
FrameConstPointer result;
|
||||||
if (_frameIndex < _frames.size()) {
|
if (_frameIndex < _frames.size()) {
|
||||||
result = _frames[_frameIndex];
|
result = _frames[_frameIndex];
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FramePointer BufferClip::nextFrame() {
|
FrameConstPointer BufferClip::nextFrame() {
|
||||||
Locker lock(_mutex);
|
Locker lock(_mutex);
|
||||||
FramePointer result;
|
FrameConstPointer result;
|
||||||
if (_frameIndex < _frames.size()) {
|
if (_frameIndex < _frames.size()) {
|
||||||
result = _frames[_frameIndex];
|
result = _frames[_frameIndex];
|
||||||
++_frameIndex;
|
++_frameIndex;
|
||||||
|
@ -53,7 +53,7 @@ FramePointer BufferClip::nextFrame() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferClip::addFrame(FramePointer newFrame) {
|
void BufferClip::addFrame(FrameConstPointer newFrame) {
|
||||||
if (newFrame->timeOffset < 0.0f) {
|
if (newFrame->timeOffset < 0.0f) {
|
||||||
throw std::runtime_error("Frames may not have negative time offsets");
|
throw std::runtime_error("Frames may not have negative time offsets");
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,15 +28,15 @@ public:
|
||||||
virtual void seek(Time offset) override;
|
virtual void seek(Time offset) override;
|
||||||
virtual Time position() const override;
|
virtual Time position() const override;
|
||||||
|
|
||||||
virtual FramePointer peekFrame() const override;
|
virtual FrameConstPointer peekFrame() const override;
|
||||||
virtual FramePointer nextFrame() override;
|
virtual FrameConstPointer nextFrame() override;
|
||||||
virtual void skipFrame() override;
|
virtual void skipFrame() override;
|
||||||
virtual void addFrame(FramePointer) override;
|
virtual void addFrame(FrameConstPointer) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void reset() override;
|
virtual void reset() override;
|
||||||
|
|
||||||
std::vector<FramePointer> _frames;
|
std::vector<FrameConstPointer> _frames;
|
||||||
mutable size_t _frameIndex { 0 };
|
mutable size_t _frameIndex { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -240,12 +240,12 @@ FramePointer FileClip::readFrame(uint32_t frameIndex) const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FramePointer FileClip::peekFrame() const {
|
FrameConstPointer FileClip::peekFrame() const {
|
||||||
Locker lock(_mutex);
|
Locker lock(_mutex);
|
||||||
return readFrame(_frameIndex);
|
return readFrame(_frameIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
FramePointer FileClip::nextFrame() {
|
FrameConstPointer FileClip::nextFrame() {
|
||||||
Locker lock(_mutex);
|
Locker lock(_mutex);
|
||||||
auto result = readFrame(_frameIndex);
|
auto result = readFrame(_frameIndex);
|
||||||
if (_frameIndex < _frameHeaders.size()) {
|
if (_frameIndex < _frameHeaders.size()) {
|
||||||
|
@ -262,7 +262,7 @@ void FileClip::reset() {
|
||||||
_frameIndex = 0;
|
_frameIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileClip::addFrame(FramePointer) {
|
void FileClip::addFrame(FrameConstPointer) {
|
||||||
throw std::runtime_error("File clips are read only");
|
throw std::runtime_error("File clips are read only");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,10 +32,10 @@ public:
|
||||||
virtual void seek(Time offset) override;
|
virtual void seek(Time offset) override;
|
||||||
virtual Time position() const override;
|
virtual Time position() const override;
|
||||||
|
|
||||||
virtual FramePointer peekFrame() const override;
|
virtual FrameConstPointer peekFrame() const override;
|
||||||
virtual FramePointer nextFrame() override;
|
virtual FrameConstPointer nextFrame() override;
|
||||||
virtual void skipFrame() override;
|
virtual void skipFrame() override;
|
||||||
virtual void addFrame(FramePointer) override;
|
virtual void addFrame(FrameConstPointer) override;
|
||||||
|
|
||||||
const QJsonDocument& getHeader() {
|
const QJsonDocument& getHeader() {
|
||||||
return _fileHeader;
|
return _fileHeader;
|
||||||
|
|
51
libraries/recording/src/recording/impl/OffsetClip.cpp
Normal file
51
libraries/recording/src/recording/impl/OffsetClip.cpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis 2015/11/04
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "OffsetClip.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
#include <QtCore/QJsonDocument>
|
||||||
|
#include <QtCore/QJsonObject>
|
||||||
|
|
||||||
|
#include <Finally.h>
|
||||||
|
|
||||||
|
#include "../Frame.h"
|
||||||
|
#include "../Logging.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace recording;
|
||||||
|
|
||||||
|
OffsetClip::OffsetClip(const Clip::Pointer& wrappedClip, Time offset)
|
||||||
|
: WrapperClip(wrappedClip), _offset(offset) { }
|
||||||
|
|
||||||
|
void OffsetClip::seek(Time offset) {
|
||||||
|
_wrappedClip->seek(offset - _offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
Time OffsetClip::position() const {
|
||||||
|
return _wrappedClip->position() + _offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameConstPointer OffsetClip::peekFrame() const {
|
||||||
|
auto result = std::make_shared<Frame>(*_wrappedClip->peekFrame());
|
||||||
|
result->timeOffset += _offset;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameConstPointer OffsetClip::nextFrame() {
|
||||||
|
auto result = std::make_shared<Frame>(*_wrappedClip->nextFrame());
|
||||||
|
result->timeOffset += _offset;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Time OffsetClip::duration() const {
|
||||||
|
return _wrappedClip->duration() + _offset;
|
||||||
|
}
|
||||||
|
|
37
libraries/recording/src/recording/impl/OffsetClip.h
Normal file
37
libraries/recording/src/recording/impl/OffsetClip.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis 2015/11/05
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef hifi_Recording_Impl_OffsetClip_h
|
||||||
|
#define hifi_Recording_Impl_OffsetClip_h
|
||||||
|
|
||||||
|
#include "WrapperClip.h"
|
||||||
|
|
||||||
|
namespace recording {
|
||||||
|
|
||||||
|
class OffsetClip : public WrapperClip {
|
||||||
|
public:
|
||||||
|
using Pointer = std::shared_ptr<OffsetClip>;
|
||||||
|
|
||||||
|
OffsetClip(const Clip::Pointer& wrappedClip, Time offset);
|
||||||
|
virtual ~OffsetClip();
|
||||||
|
|
||||||
|
virtual Time duration() const override;
|
||||||
|
virtual void seek(Time offset) override;
|
||||||
|
virtual Time position() const override;
|
||||||
|
|
||||||
|
virtual FrameConstPointer peekFrame() const override;
|
||||||
|
virtual FrameConstPointer nextFrame() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const Time _offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
60
libraries/recording/src/recording/impl/WrapperClip.cpp
Normal file
60
libraries/recording/src/recording/impl/WrapperClip.cpp
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis 2015/11/04
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "WrapperClip.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
|
#include <Finally.h>
|
||||||
|
|
||||||
|
#include "../Frame.h"
|
||||||
|
#include "../Logging.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace recording;
|
||||||
|
|
||||||
|
WrapperClip::WrapperClip(const Clip::Pointer& wrappedClip)
|
||||||
|
: _wrappedClip(wrappedClip) { }
|
||||||
|
|
||||||
|
void WrapperClip::seek(Time offset) {
|
||||||
|
_wrappedClip->seek(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
Time WrapperClip::position() const {
|
||||||
|
return _wrappedClip->position();
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameConstPointer WrapperClip::peekFrame() const {
|
||||||
|
return _wrappedClip->peekFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameConstPointer WrapperClip::nextFrame() {
|
||||||
|
return _wrappedClip->nextFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WrapperClip::skipFrame() {
|
||||||
|
_wrappedClip->skipFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WrapperClip::reset() {
|
||||||
|
_wrappedClip->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WrapperClip::addFrame(FrameConstPointer) {
|
||||||
|
throw std::runtime_error("Wrapper clips are read only");
|
||||||
|
}
|
||||||
|
|
||||||
|
Time WrapperClip::duration() const {
|
||||||
|
return _wrappedClip->duration();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WrapperClip::frameCount() const {
|
||||||
|
return _wrappedClip->frameCount();
|
||||||
|
}
|
||||||
|
|
48
libraries/recording/src/recording/impl/WrapperClip.h
Normal file
48
libraries/recording/src/recording/impl/WrapperClip.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis 2015/11/05
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef hifi_Recording_Impl_WrapperClip_h
|
||||||
|
#define hifi_Recording_Impl_WrapperClip_h
|
||||||
|
|
||||||
|
#include "../Clip.h"
|
||||||
|
|
||||||
|
#include <QtCore/QFile>
|
||||||
|
#include <QtCore/QJsonDocument>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
namespace recording {
|
||||||
|
|
||||||
|
class WrapperClip : public Clip {
|
||||||
|
public:
|
||||||
|
using Pointer = std::shared_ptr<WrapperClip>;
|
||||||
|
|
||||||
|
WrapperClip(const Clip::Pointer& wrappedClip);
|
||||||
|
virtual ~WrapperClip();
|
||||||
|
|
||||||
|
virtual Time duration() const override;
|
||||||
|
virtual size_t frameCount() const override;
|
||||||
|
|
||||||
|
virtual void seek(Time offset) override;
|
||||||
|
virtual Time position() const override;
|
||||||
|
|
||||||
|
virtual FrameConstPointer peekFrame() const override;
|
||||||
|
virtual FrameConstPointer nextFrame() override;
|
||||||
|
virtual void skipFrame() override;
|
||||||
|
virtual void addFrame(FrameConstPointer) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void reset() override;
|
||||||
|
|
||||||
|
const Clip::Pointer _wrappedClip;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -23,6 +23,9 @@ const float TWO_PI = 2.0f * PI;
|
||||||
const float PI_OVER_TWO = 0.5f * PI;
|
const float PI_OVER_TWO = 0.5f * PI;
|
||||||
const float RADIANS_PER_DEGREE = PI / 180.0f;
|
const float RADIANS_PER_DEGREE = PI / 180.0f;
|
||||||
const float DEGREES_PER_RADIAN = 180.0f / PI;
|
const float DEGREES_PER_RADIAN = 180.0f / PI;
|
||||||
|
const float ARCMINUTES_PER_DEGREE = 60.0f;
|
||||||
|
const float ARCSECONDS_PER_ARCMINUTE = 60.0f;
|
||||||
|
const float ARCSECONDS_PER_DEGREE = ARCMINUTES_PER_DEGREE * ARCSECONDS_PER_ARCMINUTE;
|
||||||
|
|
||||||
const float EPSILON = 0.000001f; //smallish positive number - used as margin of error for some computations
|
const float EPSILON = 0.000001f; //smallish positive number - used as margin of error for some computations
|
||||||
const float SQUARE_ROOT_OF_2 = (float)sqrt(2.0f);
|
const float SQUARE_ROOT_OF_2 = (float)sqrt(2.0f);
|
||||||
|
|
|
@ -11,6 +11,12 @@
|
||||||
|
|
||||||
#include "Transform.h"
|
#include "Transform.h"
|
||||||
|
|
||||||
|
#include <QtCore/QJsonValue>
|
||||||
|
#include <QtCore/QJsonObject>
|
||||||
|
#include <QtCore/QJsonArray>
|
||||||
|
|
||||||
|
#include "NumericalConstants.h"
|
||||||
|
#include "shared/JSONHelpers.h"
|
||||||
|
|
||||||
void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotationScaleMatrix) {
|
void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotationScaleMatrix) {
|
||||||
const float ACCURACY_THREASHOLD = 0.00001f;
|
const float ACCURACY_THREASHOLD = 0.00001f;
|
||||||
|
@ -65,7 +71,74 @@ void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotat
|
||||||
rotation = (glm::quat_cast(matRot));
|
rotation = (glm::quat_cast(matRot));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform Transform::relativeTransform(const Transform& worldTransform) const {
|
||||||
|
if (isIdentity()) {
|
||||||
|
return worldTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*this == worldTransform) {
|
||||||
|
return Transform();
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform result;
|
||||||
|
inverseMult(result, *this, worldTransform);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform Transform::worldTransform(const Transform& relativeTransform) const {
|
||||||
|
if (relativeTransform.isIdentity()) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isIdentity()) {
|
||||||
|
return relativeTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform result;
|
||||||
|
mult(result, *this, relativeTransform);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const QString JSON_TRANSLATION = QStringLiteral("translation");
|
||||||
|
static const QString JSON_ROTATION = QStringLiteral("rotation");
|
||||||
|
static const QString JSON_SCALE = QStringLiteral("scale");
|
||||||
|
|
||||||
|
Transform Transform::fromJson(const QJsonValue& json) {
|
||||||
|
if (!json.isObject()) {
|
||||||
|
return Transform();
|
||||||
|
}
|
||||||
|
QJsonObject obj = json.toObject();
|
||||||
|
Transform result;
|
||||||
|
if (obj.contains(JSON_ROTATION)) {
|
||||||
|
result.setRotation(quatFromJsonValue(obj[JSON_ROTATION]));
|
||||||
|
}
|
||||||
|
if (obj.contains(JSON_TRANSLATION)) {
|
||||||
|
result.setTranslation(vec3FromJsonValue(obj[JSON_TRANSLATION]));
|
||||||
|
}
|
||||||
|
if (obj.contains(JSON_SCALE)) {
|
||||||
|
result.setScale(vec3FromJsonValue(obj[JSON_TRANSLATION]));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject Transform::toJson(const Transform& transform) {
|
||||||
|
if (transform.isIdentity()) {
|
||||||
|
return QJsonObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject result;
|
||||||
|
auto json = toJsonValue(transform.getTranslation());
|
||||||
|
if (!json.isNull()) {
|
||||||
|
result[JSON_TRANSLATION] = json;
|
||||||
|
}
|
||||||
|
json = toJsonValue(transform.getRotation());
|
||||||
|
if (!json.isNull()) {
|
||||||
|
result[JSON_ROTATION] = json;
|
||||||
|
}
|
||||||
|
json = toJsonValue(transform.getScale());
|
||||||
|
if (!json.isNull()) {
|
||||||
|
result[JSON_SCALE] = json;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
class QJsonObject;
|
||||||
|
class QJsonValue;
|
||||||
|
|
||||||
inline bool isValidScale(glm::vec3 scale) {
|
inline bool isValidScale(glm::vec3 scale) {
|
||||||
bool result = scale.x != 0.0f && scale.y != 0.0f && scale.z != 0.0f;
|
bool result = scale.x != 0.0f && scale.y != 0.0f && scale.z != 0.0f;
|
||||||
assert(result);
|
assert(result);
|
||||||
|
@ -35,6 +38,7 @@ inline bool isValidScale(float scale) {
|
||||||
|
|
||||||
class Transform {
|
class Transform {
|
||||||
public:
|
public:
|
||||||
|
using Pointer = std::shared_ptr<Transform>;
|
||||||
typedef glm::mat4 Mat4;
|
typedef glm::mat4 Mat4;
|
||||||
typedef glm::mat3 Mat3;
|
typedef glm::mat3 Mat3;
|
||||||
typedef glm::vec4 Vec4;
|
typedef glm::vec4 Vec4;
|
||||||
|
@ -81,6 +85,10 @@ public:
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const Transform& other) const {
|
||||||
|
return _rotation == other._rotation && _scale == other._scale && _translation == other._translation;
|
||||||
|
}
|
||||||
|
|
||||||
Transform& setIdentity();
|
Transform& setIdentity();
|
||||||
|
|
||||||
const Vec3& getTranslation() const;
|
const Vec3& getTranslation() const;
|
||||||
|
@ -111,6 +119,8 @@ public:
|
||||||
Transform& evalFromRawMatrix(const Mat4& matrix);
|
Transform& evalFromRawMatrix(const Mat4& matrix);
|
||||||
Transform& evalFromRawMatrix(const Mat3& rotationScalematrix);
|
Transform& evalFromRawMatrix(const Mat3& rotationScalematrix);
|
||||||
|
|
||||||
|
Mat4 getMatrix() const;
|
||||||
|
Mat4 getInverseMatrix() const;
|
||||||
Mat4& getMatrix(Mat4& result) const;
|
Mat4& getMatrix(Mat4& result) const;
|
||||||
Mat4& getInverseMatrix(Mat4& result) const;
|
Mat4& getInverseMatrix(Mat4& result) const;
|
||||||
Mat4& getInverseTransposeMatrix(Mat4& result) const;
|
Mat4& getInverseTransposeMatrix(Mat4& result) const;
|
||||||
|
@ -120,6 +130,9 @@ public:
|
||||||
|
|
||||||
Transform& evalInverse(Transform& result) const;
|
Transform& evalInverse(Transform& result) const;
|
||||||
|
|
||||||
|
Transform relativeTransform(const Transform& world) const;
|
||||||
|
Transform worldTransform(const Transform& relative) const;
|
||||||
|
|
||||||
static void evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotationScaleMatrix);
|
static void evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotationScaleMatrix);
|
||||||
|
|
||||||
static Transform& mult(Transform& result, const Transform& left, const Transform& right);
|
static Transform& mult(Transform& result, const Transform& left, const Transform& right);
|
||||||
|
@ -127,6 +140,10 @@ public:
|
||||||
// Left will be inversed before the multiplication
|
// Left will be inversed before the multiplication
|
||||||
static Transform& inverseMult(Transform& result, const Transform& left, const Transform& right);
|
static Transform& inverseMult(Transform& result, const Transform& left, const Transform& right);
|
||||||
|
|
||||||
|
|
||||||
|
static Transform fromJson(const QJsonValue& json);
|
||||||
|
static QJsonObject toJson(const Transform& transform);
|
||||||
|
|
||||||
Vec4 transform(const Vec4& pos) const;
|
Vec4 transform(const Vec4& pos) const;
|
||||||
Vec3 transform(const Vec3& pos) const;
|
Vec3 transform(const Vec3& pos) const;
|
||||||
|
|
||||||
|
@ -368,6 +385,18 @@ inline Transform& Transform::postScale(const Vec3& scale) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Transform::Mat4 Transform::getMatrix() const {
|
||||||
|
Transform::Mat4 result;
|
||||||
|
getMatrix(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Transform::Mat4 Transform::getInverseMatrix() const {
|
||||||
|
Transform::Mat4 result;
|
||||||
|
getInverseMatrix(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
inline Transform::Mat4& Transform::getMatrix(Transform::Mat4& result) const {
|
inline Transform::Mat4& Transform::getMatrix(Transform::Mat4& result) const {
|
||||||
if (isRotating()) {
|
if (isRotating()) {
|
||||||
Mat3 rot = glm::mat3_cast(_rotation);
|
Mat3 rot = glm::mat3_cast(_rotation);
|
||||||
|
|
|
@ -52,6 +52,9 @@ quat quatFromJsonValue(const QJsonValue& q) {
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 vec3FromJsonValue(const QJsonValue& v) {
|
vec3 vec3FromJsonValue(const QJsonValue& v) {
|
||||||
|
if (v.isDouble()) {
|
||||||
|
return vec3((float)v.toDouble());
|
||||||
|
}
|
||||||
return glmFromJson<vec3>(v);
|
return glmFromJson<vec3>(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Bradley Austin Davis on 2015/11/09
|
|
||||||
// Copyright 2013-2015 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "UniformTransform.h"
|
|
||||||
|
|
||||||
#include "JSONHelpers.h"
|
|
||||||
|
|
||||||
#include <QtCore/QJsonValue>
|
|
||||||
#include <QtCore/QJsonObject>
|
|
||||||
#include <QtCore/QJsonArray>
|
|
||||||
|
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
|
||||||
|
|
||||||
const float UniformTransform::DEFAULT_SCALE = 1.0f;
|
|
||||||
|
|
||||||
std::shared_ptr<UniformTransform> UniformTransform::parseJson(const QJsonValue& basis) {
|
|
||||||
std::shared_ptr<UniformTransform> result = std::make_shared<UniformTransform>();
|
|
||||||
result->fromJson(basis);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const QString JSON_TRANSLATION = QStringLiteral("translation");
|
|
||||||
static const QString JSON_ROTATION = QStringLiteral("rotation");
|
|
||||||
static const QString JSON_SCALE = QStringLiteral("scale");
|
|
||||||
|
|
||||||
void UniformTransform::fromJson(const QJsonValue& basisValue) {
|
|
||||||
if (!basisValue.isObject()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QJsonObject basis = basisValue.toObject();
|
|
||||||
if (basis.contains(JSON_ROTATION)) {
|
|
||||||
rotation = quatFromJsonValue(basis[JSON_ROTATION]);
|
|
||||||
}
|
|
||||||
if (basis.contains(JSON_TRANSLATION)) {
|
|
||||||
translation = vec3FromJsonValue(basis[JSON_TRANSLATION]);
|
|
||||||
}
|
|
||||||
if (basis.contains(JSON_SCALE)) {
|
|
||||||
scale = (float)basis[JSON_SCALE].toDouble();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::mat4 toMat4(const UniformTransform& transform) {
|
|
||||||
return glm::translate(glm::mat4(), transform.translation) * glm::mat4_cast(transform.rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
UniformTransform fromMat4(const glm::mat4& m) {
|
|
||||||
UniformTransform result;
|
|
||||||
result.translation = vec3(m[3]);
|
|
||||||
result.rotation = glm::quat_cast(m);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniformTransform UniformTransform::relativeTransform(const UniformTransform& worldTransform) const {
|
|
||||||
UniformTransform result = fromMat4(glm::inverse(toMat4(*this)) * toMat4(worldTransform));
|
|
||||||
result.scale = scale / worldTransform.scale;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniformTransform UniformTransform::worldTransform(const UniformTransform& relativeTransform) const {
|
|
||||||
UniformTransform result = fromMat4(toMat4(*this) * toMat4(relativeTransform));
|
|
||||||
result.scale = relativeTransform.scale * scale;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject UniformTransform::toJson() const {
|
|
||||||
QJsonObject result;
|
|
||||||
auto json = toJsonValue(translation);
|
|
||||||
if (!json.isNull()) {
|
|
||||||
result[JSON_TRANSLATION] = json;
|
|
||||||
}
|
|
||||||
json = toJsonValue(rotation);
|
|
||||||
if (!json.isNull()) {
|
|
||||||
result[JSON_ROTATION] = json;
|
|
||||||
}
|
|
||||||
if (scale != DEFAULT_SCALE) {
|
|
||||||
result[JSON_SCALE] = scale;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Bradley Austin Davis on 2015/11/09
|
|
||||||
// Copyright 2013-2015 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#ifndef hifi_Shared_UniformTransform_h
|
|
||||||
#define hifi_Shared_UniformTransform_h
|
|
||||||
|
|
||||||
#include "../GLMHelpers.h"
|
|
||||||
|
|
||||||
class QJsonValue;
|
|
||||||
|
|
||||||
struct UniformTransform {
|
|
||||||
static const float DEFAULT_SCALE;
|
|
||||||
glm::vec3 translation;
|
|
||||||
glm::quat rotation;
|
|
||||||
float scale { DEFAULT_SCALE };
|
|
||||||
|
|
||||||
UniformTransform() {}
|
|
||||||
|
|
||||||
UniformTransform(const glm::vec3& translation, const glm::quat& rotation, const float& scale)
|
|
||||||
: translation(translation), rotation(rotation), scale(scale) {}
|
|
||||||
|
|
||||||
UniformTransform relativeTransform(const UniformTransform& worldTransform) const;
|
|
||||||
glm::vec3 relativeVector(const UniformTransform& worldTransform) const;
|
|
||||||
|
|
||||||
UniformTransform worldTransform(const UniformTransform& relativeTransform) const;
|
|
||||||
glm::vec3 worldVector(const UniformTransform& relativeTransform) const;
|
|
||||||
|
|
||||||
QJsonObject toJson() const;
|
|
||||||
void fromJson(const QJsonValue& json);
|
|
||||||
|
|
||||||
static std::shared_ptr<UniformTransform> parseJson(const QJsonValue& json);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in a new issue