mirror of
https://github.com/overte-org/overte.git
synced 2025-04-12 19:58:15 +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?
|
||||
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();
|
||||
avatarStateFromFrame(frame->data, this);
|
||||
});
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include "AvatarData.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
|
@ -22,6 +25,7 @@
|
|||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
|
||||
#include <Transform.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <NodeList.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
|
@ -29,12 +33,10 @@
|
|||
#include <StreamUtils.h>
|
||||
#include <UUID.h>
|
||||
#include <shared/JSONHelpers.h>
|
||||
#include <shared/UniformTransform.h>
|
||||
#include <recording/Deck.h>
|
||||
#include <recording/Clip.h>
|
||||
|
||||
#include "AvatarLogging.h"
|
||||
#include "AvatarData.h"
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1506,12 +1508,12 @@ void registerAvatarTypes(QScriptEngine* engine) {
|
|||
new AttachmentDataObject(), QScriptEngine::ScriptOwnership));
|
||||
}
|
||||
|
||||
void AvatarData::setRecordingBasis(std::shared_ptr<UniformTransform> recordingBasis) {
|
||||
void AvatarData::setRecordingBasis(std::shared_ptr<Transform> recordingBasis) {
|
||||
if (!recordingBasis) {
|
||||
recordingBasis = std::make_shared<UniformTransform>();
|
||||
recordingBasis->rotation = getOrientation();
|
||||
recordingBasis->translation = getPosition();
|
||||
recordingBasis->scale = getTargetScale();
|
||||
recordingBasis = std::make_shared<Transform>();
|
||||
recordingBasis->setRotation(getOrientation());
|
||||
recordingBasis->setTranslation(getPosition());
|
||||
recordingBasis->setScale(getTargetScale());
|
||||
}
|
||||
_recordingBasis = recordingBasis;
|
||||
}
|
||||
|
@ -1520,6 +1522,14 @@ void AvatarData::clearRecordingBasis() {
|
|||
_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_RELATIVE = QStringLiteral("relativeTransform");
|
||||
static const QString JSON_AVATAR_JOINT_ROTATIONS = QStringLiteral("jointRotations");
|
||||
|
@ -1557,15 +1567,14 @@ QByteArray avatarStateToFrame(const AvatarData* _avatar) {
|
|||
|
||||
auto recordingBasis = _avatar->getRecordingBasis();
|
||||
if (recordingBasis) {
|
||||
// FIXME if the resulting relative basis is identity, we shouldn't record anything
|
||||
// Record the transformation basis
|
||||
root[JSON_AVATAR_BASIS] = recordingBasis->toJson();
|
||||
// Find the relative transform
|
||||
auto relativeTransform = recordingBasis->relativeTransform(_avatar->getTransform());
|
||||
|
||||
// Record the relative transform
|
||||
auto relativeTransform = recordingBasis->relativeTransform(
|
||||
UniformTransform(_avatar->getPosition(), _avatar->getOrientation(), _avatar->getTargetScale()));
|
||||
|
||||
root[JSON_AVATAR_RELATIVE] = relativeTransform.toJson();
|
||||
// if the resulting relative basis is identity, we shouldn't record anything
|
||||
if (!relativeTransform.isIdentity()) {
|
||||
root[JSON_AVATAR_RELATIVE] = Transform::toJson(relativeTransform);
|
||||
root[JSON_AVATAR_BASIS] = Transform::toJson(*recordingBasis);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// meaning that all playback is relative to this avatars starting position, or
|
||||
// the basis can be loaded from the recording, meaning the playback is relative to the
|
||||
// original avatar location
|
||||
// The first is more useful for playing back recordings on your own avatar, while
|
||||
// the latter is more useful for playing back other avatars within your scene.
|
||||
auto currentBasis = _avatar->getRecordingBasis();
|
||||
if (!currentBasis) {
|
||||
currentBasis = UniformTransform::parseJson(root[JSON_AVATAR_BASIS]);
|
||||
}
|
||||
if (root.contains(JSON_AVATAR_RELATIVE)) {
|
||||
// During playback you can either have the recording basis set to the avatar current state
|
||||
// meaning that all playback is relative to this avatars starting position, or
|
||||
// the basis can be loaded from the recording, meaning the playback is relative to the
|
||||
// original avatar location
|
||||
// The first is more useful for playing back recordings on your own avatar, while
|
||||
// the latter is more useful for playing back other avatars within your scene.
|
||||
|
||||
auto relativeTransform = UniformTransform::parseJson(root[JSON_AVATAR_RELATIVE]);
|
||||
auto worldTransform = currentBasis->worldTransform(*relativeTransform);
|
||||
_avatar->setPosition(worldTransform.translation);
|
||||
_avatar->setOrientation(worldTransform.rotation);
|
||||
_avatar->setTargetScale(worldTransform.scale);
|
||||
auto currentBasis = _avatar->getRecordingBasis();
|
||||
if (!currentBasis) {
|
||||
currentBasis = std::make_shared<Transform>(Transform::fromJson(root[JSON_AVATAR_BASIS]));
|
||||
}
|
||||
|
||||
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 (root.contains(JSON_AVATAR_ATTACHEMENTS)) {
|
||||
|
|
|
@ -134,7 +134,8 @@ class QDataStream;
|
|||
|
||||
class AttachmentData;
|
||||
class JointData;
|
||||
struct UniformTransform;
|
||||
class Transform;
|
||||
using TransformPointer = std::shared_ptr<Transform>;
|
||||
|
||||
class AvatarData : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -333,10 +334,10 @@ public:
|
|||
|
||||
bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; }
|
||||
|
||||
Transform getTransform() const;
|
||||
void clearRecordingBasis();
|
||||
std::shared_ptr<UniformTransform> getRecordingBasis() const;
|
||||
void setRecordingBasis(std::shared_ptr<UniformTransform> recordingBasis = std::shared_ptr<UniformTransform>());
|
||||
|
||||
TransformPointer getRecordingBasis() const;
|
||||
void setRecordingBasis(TransformPointer recordingBasis = TransformPointer());
|
||||
|
||||
public slots:
|
||||
void sendAvatarDataPacket();
|
||||
|
@ -437,7 +438,7 @@ protected:
|
|||
|
||||
// During recording, this holds the starting position, orientation & scale of the recorded avatar
|
||||
// During playback, it holds the
|
||||
std::shared_ptr<UniformTransform> _recordingBasis;
|
||||
TransformPointer _recordingBasis;
|
||||
|
||||
private:
|
||||
friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
|
||||
|
|
|
@ -38,7 +38,7 @@ Clip::Pointer Clip::duplicate() {
|
|||
Time currentPosition = position();
|
||||
seek(0);
|
||||
|
||||
Frame::Pointer frame = nextFrame();
|
||||
auto frame = nextFrame();
|
||||
while (frame) {
|
||||
result->addFrame(frame);
|
||||
frame = nextFrame();
|
||||
|
|
|
@ -34,16 +34,17 @@ public:
|
|||
virtual void seek(Time offset) = 0;
|
||||
virtual Time position() const = 0;
|
||||
|
||||
virtual FramePointer peekFrame() const = 0;
|
||||
virtual FramePointer nextFrame() = 0;
|
||||
virtual FrameConstPointer peekFrame() const = 0;
|
||||
virtual FrameConstPointer nextFrame() = 0;
|
||||
virtual void skipFrame() = 0;
|
||||
virtual void addFrame(FramePointer) = 0;
|
||||
virtual void addFrame(FrameConstPointer) = 0;
|
||||
|
||||
static Pointer fromFile(const QString& filePath);
|
||||
static void toFile(const QString& filePath, Pointer clip);
|
||||
static Pointer newClip();
|
||||
|
||||
protected:
|
||||
friend class WrapperClip;
|
||||
using Mutex = std::recursive_mutex;
|
||||
using Locker = std::unique_lock<Mutex>;
|
||||
|
||||
|
|
|
@ -46,9 +46,6 @@ public:
|
|||
Time position() const;
|
||||
void seek(Time position);
|
||||
|
||||
void setPlaybackSpeed(float factor) { _playbackSpeed = factor; }
|
||||
float getPlaybackSpeed() { return _playbackSpeed; }
|
||||
|
||||
signals:
|
||||
void playbackStateChanged();
|
||||
|
||||
|
@ -62,7 +59,6 @@ private:
|
|||
Clips _clips;
|
||||
quint64 _startEpoch { 0 };
|
||||
Time _position { 0 };
|
||||
float _playbackSpeed { 1.0f };
|
||||
bool _pause { true };
|
||||
bool _loop { false };
|
||||
Time _length { 0 };
|
||||
|
|
|
@ -28,6 +28,8 @@ struct 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
|
||||
// data + audio for a single person
|
||||
class Clip;
|
||||
|
|
|
@ -104,7 +104,7 @@ Frame::Handler Frame::registerFrameHandler(FrameType type, Handler handler) {
|
|||
return result;
|
||||
}
|
||||
|
||||
void Frame::handleFrame(const Frame::Pointer& frame) {
|
||||
void Frame::handleFrame(const Frame::ConstPointer& frame) {
|
||||
Handler handler;
|
||||
{
|
||||
Locker lock(mutex);
|
||||
|
|
|
@ -21,7 +21,8 @@ namespace recording {
|
|||
struct Frame {
|
||||
public:
|
||||
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_HEADER = 0x0;
|
||||
|
@ -37,7 +38,7 @@ public:
|
|||
static QMap<QString, FrameType> getFrameTypes();
|
||||
static QMap<FrameType, QString> getFrameTypeNames();
|
||||
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) {
|
||||
Locker lock(_mutex);
|
||||
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;
|
||||
}
|
||||
);
|
||||
|
@ -34,18 +34,18 @@ Time BufferClip::position() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
FramePointer BufferClip::peekFrame() const {
|
||||
FrameConstPointer BufferClip::peekFrame() const {
|
||||
Locker lock(_mutex);
|
||||
FramePointer result;
|
||||
FrameConstPointer result;
|
||||
if (_frameIndex < _frames.size()) {
|
||||
result = _frames[_frameIndex];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
FramePointer BufferClip::nextFrame() {
|
||||
FrameConstPointer BufferClip::nextFrame() {
|
||||
Locker lock(_mutex);
|
||||
FramePointer result;
|
||||
FrameConstPointer result;
|
||||
if (_frameIndex < _frames.size()) {
|
||||
result = _frames[_frameIndex];
|
||||
++_frameIndex;
|
||||
|
@ -53,7 +53,7 @@ FramePointer BufferClip::nextFrame() {
|
|||
return result;
|
||||
}
|
||||
|
||||
void BufferClip::addFrame(FramePointer newFrame) {
|
||||
void BufferClip::addFrame(FrameConstPointer newFrame) {
|
||||
if (newFrame->timeOffset < 0.0f) {
|
||||
throw std::runtime_error("Frames may not have negative time offsets");
|
||||
}
|
||||
|
|
|
@ -28,15 +28,15 @@ public:
|
|||
virtual void seek(Time offset) override;
|
||||
virtual Time position() const override;
|
||||
|
||||
virtual FramePointer peekFrame() const override;
|
||||
virtual FramePointer nextFrame() override;
|
||||
virtual FrameConstPointer peekFrame() const override;
|
||||
virtual FrameConstPointer nextFrame() override;
|
||||
virtual void skipFrame() override;
|
||||
virtual void addFrame(FramePointer) override;
|
||||
virtual void addFrame(FrameConstPointer) override;
|
||||
|
||||
private:
|
||||
virtual void reset() override;
|
||||
|
||||
std::vector<FramePointer> _frames;
|
||||
std::vector<FrameConstPointer> _frames;
|
||||
mutable size_t _frameIndex { 0 };
|
||||
};
|
||||
|
||||
|
|
|
@ -240,12 +240,12 @@ FramePointer FileClip::readFrame(uint32_t frameIndex) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
FramePointer FileClip::peekFrame() const {
|
||||
FrameConstPointer FileClip::peekFrame() const {
|
||||
Locker lock(_mutex);
|
||||
return readFrame(_frameIndex);
|
||||
}
|
||||
|
||||
FramePointer FileClip::nextFrame() {
|
||||
FrameConstPointer FileClip::nextFrame() {
|
||||
Locker lock(_mutex);
|
||||
auto result = readFrame(_frameIndex);
|
||||
if (_frameIndex < _frameHeaders.size()) {
|
||||
|
@ -262,7 +262,7 @@ void FileClip::reset() {
|
|||
_frameIndex = 0;
|
||||
}
|
||||
|
||||
void FileClip::addFrame(FramePointer) {
|
||||
void FileClip::addFrame(FrameConstPointer) {
|
||||
throw std::runtime_error("File clips are read only");
|
||||
}
|
||||
|
||||
|
|
|
@ -32,10 +32,10 @@ public:
|
|||
virtual void seek(Time offset) override;
|
||||
virtual Time position() const override;
|
||||
|
||||
virtual FramePointer peekFrame() const override;
|
||||
virtual FramePointer nextFrame() override;
|
||||
virtual FrameConstPointer peekFrame() const override;
|
||||
virtual FrameConstPointer nextFrame() override;
|
||||
virtual void skipFrame() override;
|
||||
virtual void addFrame(FramePointer) override;
|
||||
virtual void addFrame(FrameConstPointer) override;
|
||||
|
||||
const QJsonDocument& getHeader() {
|
||||
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 RADIANS_PER_DEGREE = PI / 180.0f;
|
||||
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 SQUARE_ROOT_OF_2 = (float)sqrt(2.0f);
|
||||
|
|
|
@ -11,6 +11,12 @@
|
|||
|
||||
#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) {
|
||||
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));
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
class QJsonObject;
|
||||
class QJsonValue;
|
||||
|
||||
inline bool isValidScale(glm::vec3 scale) {
|
||||
bool result = scale.x != 0.0f && scale.y != 0.0f && scale.z != 0.0f;
|
||||
assert(result);
|
||||
|
@ -35,6 +38,7 @@ inline bool isValidScale(float scale) {
|
|||
|
||||
class Transform {
|
||||
public:
|
||||
using Pointer = std::shared_ptr<Transform>;
|
||||
typedef glm::mat4 Mat4;
|
||||
typedef glm::mat3 Mat3;
|
||||
typedef glm::vec4 Vec4;
|
||||
|
@ -81,6 +85,10 @@ public:
|
|||
return (*this);
|
||||
}
|
||||
|
||||
bool operator==(const Transform& other) const {
|
||||
return _rotation == other._rotation && _scale == other._scale && _translation == other._translation;
|
||||
}
|
||||
|
||||
Transform& setIdentity();
|
||||
|
||||
const Vec3& getTranslation() const;
|
||||
|
@ -111,6 +119,8 @@ public:
|
|||
Transform& evalFromRawMatrix(const Mat4& matrix);
|
||||
Transform& evalFromRawMatrix(const Mat3& rotationScalematrix);
|
||||
|
||||
Mat4 getMatrix() const;
|
||||
Mat4 getInverseMatrix() const;
|
||||
Mat4& getMatrix(Mat4& result) const;
|
||||
Mat4& getInverseMatrix(Mat4& result) const;
|
||||
Mat4& getInverseTransposeMatrix(Mat4& result) const;
|
||||
|
@ -120,6 +130,9 @@ public:
|
|||
|
||||
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 Transform& mult(Transform& result, const Transform& left, const Transform& right);
|
||||
|
@ -127,6 +140,10 @@ public:
|
|||
// Left will be inversed before the multiplication
|
||||
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;
|
||||
Vec3 transform(const Vec3& pos) const;
|
||||
|
||||
|
@ -368,6 +385,18 @@ inline Transform& Transform::postScale(const Vec3& scale) {
|
|||
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 {
|
||||
if (isRotating()) {
|
||||
Mat3 rot = glm::mat3_cast(_rotation);
|
||||
|
|
|
@ -52,6 +52,9 @@ quat quatFromJsonValue(const QJsonValue& q) {
|
|||
}
|
||||
|
||||
vec3 vec3FromJsonValue(const QJsonValue& v) {
|
||||
if (v.isDouble()) {
|
||||
return vec3((float)v.toDouble());
|
||||
}
|
||||
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