Switched from storing Euler angles to using quaternions along with a

quaternion editor.  Also, use a default step of 0.01 for floats/doubles.
This commit is contained in:
Andrzej Kapolka 2014-04-07 15:41:42 -07:00
parent 404b804b2f
commit 15e9d45dc3
9 changed files with 136 additions and 38 deletions

View file

@ -395,7 +395,7 @@ void SphereRenderer::renderUnclipped(float alpha, Mode mode) {
glPushMatrix(); glPushMatrix();
const glm::vec3& translation = sphere->getTranslation(); const glm::vec3& translation = sphere->getTranslation();
glTranslatef(translation.x, translation.y, translation.z); glTranslatef(translation.x, translation.y, translation.z);
glm::quat rotation = glm::quat(glm::radians(sphere->getRotation())); glm::quat rotation = sphere->getRotation();
glm::vec3 axis = glm::axis(rotation); glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z);
@ -418,7 +418,7 @@ void StaticModelRenderer::init(Spanner* spanner) {
applyURL(staticModel->getURL()); applyURL(staticModel->getURL());
connect(spanner, SIGNAL(translationChanged(const glm::vec3&)), SLOT(applyTranslation(const glm::vec3&))); connect(spanner, SIGNAL(translationChanged(const glm::vec3&)), SLOT(applyTranslation(const glm::vec3&)));
connect(spanner, SIGNAL(rotationChanged(const glm::vec3&)), SLOT(applyRotation(const glm::vec3&))); connect(spanner, SIGNAL(rotationChanged(const glm::quat&)), SLOT(applyRotation(const glm::quat&)));
connect(spanner, SIGNAL(scaleChanged(float)), SLOT(applyScale(float))); connect(spanner, SIGNAL(scaleChanged(float)), SLOT(applyScale(float)));
connect(spanner, SIGNAL(urlChanged(const QUrl&)), SLOT(applyURL(const QUrl&))); connect(spanner, SIGNAL(urlChanged(const QUrl&)), SLOT(applyURL(const QUrl&)));
} }
@ -461,8 +461,8 @@ void StaticModelRenderer::applyTranslation(const glm::vec3& translation) {
_model->setTranslation(translation); _model->setTranslation(translation);
} }
void StaticModelRenderer::applyRotation(const glm::vec3& rotation) { void StaticModelRenderer::applyRotation(const glm::quat& rotation) {
_model->setRotation(glm::quat(glm::radians(rotation))); _model->setRotation(rotation);
} }
void StaticModelRenderer::applyScale(float scale) { void StaticModelRenderer::applyScale(float scale) {

View file

@ -189,7 +189,7 @@ protected:
private slots: private slots:
void applyTranslation(const glm::vec3& translation); void applyTranslation(const glm::vec3& translation);
void applyRotation(const glm::vec3& eulerAngles); // eulerAngles are in degrees void applyRotation(const glm::quat& rotation);
void applyScale(float scale); void applyScale(float scale);
void applyURL(const QUrl& url); void applyURL(const QUrl& url);

View file

@ -58,7 +58,10 @@ Model::SkinLocations Model::_skinShadowLocations;
void Model::setScale(const glm::vec3& scale) { void Model::setScale(const glm::vec3& scale) {
glm::vec3 deltaScale = _scale - scale; glm::vec3 deltaScale = _scale - scale;
if (glm::length2(deltaScale) > EPSILON) {
// decreased epsilon because this wasn't handling scale changes of 0.01
const float SMALLER_EPSILON = EPSILON * 0.0001f;
if (glm::length2(deltaScale) > SMALLER_EPSILON) {
_scale = scale; _scale = scale;
rebuildShapes(); rebuildShapes();
} }

View file

@ -35,6 +35,7 @@ REGISTER_SIMPLE_TYPE_STREAMER(SharedObjectPointer)
// some types don't quite work with our macro // some types don't quite work with our macro
static int vec3Streamer = Bitstream::registerTypeStreamer(qMetaTypeId<glm::vec3>(), new SimpleTypeStreamer<glm::vec3>()); static int vec3Streamer = Bitstream::registerTypeStreamer(qMetaTypeId<glm::vec3>(), new SimpleTypeStreamer<glm::vec3>());
static int quatStreamer = Bitstream::registerTypeStreamer(qMetaTypeId<glm::quat>(), new SimpleTypeStreamer<glm::quat>());
static int metaObjectStreamer = Bitstream::registerTypeStreamer(qMetaTypeId<const QMetaObject*>(), static int metaObjectStreamer = Bitstream::registerTypeStreamer(qMetaTypeId<const QMetaObject*>(),
new SimpleTypeStreamer<const QMetaObject*>()); new SimpleTypeStreamer<const QMetaObject*>());
@ -352,6 +353,14 @@ Bitstream& Bitstream::operator>>(glm::vec3& value) {
return *this >> value.x >> value.y >> value.z; return *this >> value.x >> value.y >> value.z;
} }
Bitstream& Bitstream::operator<<(const glm::quat& value) {
return *this << value.w << value.x << value.y << value.z;
}
Bitstream& Bitstream::operator>>(glm::quat& value) {
return *this >> value.w >> value.x >> value.y >> value.z;
}
Bitstream& Bitstream::operator<<(const QByteArray& string) { Bitstream& Bitstream::operator<<(const QByteArray& string) {
*this << string.size(); *this << string.size();
return write(string.constData(), string.size() * BITS_IN_BYTE); return write(string.constData(), string.size() * BITS_IN_BYTE);

View file

@ -312,6 +312,9 @@ public:
Bitstream& operator<<(const glm::vec3& value); Bitstream& operator<<(const glm::vec3& value);
Bitstream& operator>>(glm::vec3& value); Bitstream& operator>>(glm::vec3& value);
Bitstream& operator<<(const glm::quat& value);
Bitstream& operator>>(glm::quat& value);
Bitstream& operator<<(const QByteArray& string); Bitstream& operator<<(const QByteArray& string);
Bitstream& operator>>(QByteArray& string); Bitstream& operator>>(QByteArray& string);

View file

@ -1545,7 +1545,7 @@ void Transformable::setTranslation(const glm::vec3& translation) {
} }
} }
void Transformable::setRotation(const glm::vec3& rotation) { void Transformable::setRotation(const glm::quat& rotation) {
if (_rotation != rotation) { if (_rotation != rotation) {
emit rotationChanged(_rotation = rotation); emit rotationChanged(_rotation = rotation);
} }

View file

@ -533,7 +533,7 @@ public:
class Transformable : public Spanner { class Transformable : public Spanner {
Q_OBJECT Q_OBJECT
Q_PROPERTY(glm::vec3 translation MEMBER _translation WRITE setTranslation NOTIFY translationChanged) Q_PROPERTY(glm::vec3 translation MEMBER _translation WRITE setTranslation NOTIFY translationChanged)
Q_PROPERTY(glm::vec3 rotation MEMBER _rotation WRITE setRotation NOTIFY rotationChanged) Q_PROPERTY(glm::quat rotation MEMBER _rotation WRITE setRotation NOTIFY rotationChanged)
Q_PROPERTY(float scale MEMBER _scale WRITE setScale NOTIFY scaleChanged) Q_PROPERTY(float scale MEMBER _scale WRITE setScale NOTIFY scaleChanged)
public: public:
@ -543,8 +543,8 @@ public:
void setTranslation(const glm::vec3& translation); void setTranslation(const glm::vec3& translation);
const glm::vec3& getTranslation() const { return _translation; } const glm::vec3& getTranslation() const { return _translation; }
void setRotation(const glm::vec3& rotation); void setRotation(const glm::quat& rotation);
const glm::vec3& getRotation() const { return _rotation; } const glm::quat& getRotation() const { return _rotation; }
void setScale(float scale); void setScale(float scale);
float getScale() const { return _scale; } float getScale() const { return _scale; }
@ -552,13 +552,13 @@ public:
signals: signals:
void translationChanged(const glm::vec3& translation); void translationChanged(const glm::vec3& translation);
void rotationChanged(const glm::vec3& rotation); void rotationChanged(const glm::quat& rotation);
void scaleChanged(float scale); void scaleChanged(float scale);
private: private:
glm::vec3 _translation; glm::vec3 _translation;
glm::vec3 _rotation; // Euler Angles in degrees glm::quat _rotation;
float _scale; float _scale;
}; };

View file

@ -52,6 +52,7 @@ public:
DoubleEditor::DoubleEditor(QWidget* parent) : QDoubleSpinBox(parent) { DoubleEditor::DoubleEditor(QWidget* parent) : QDoubleSpinBox(parent) {
setMinimum(-FLT_MAX); setMinimum(-FLT_MAX);
setMaximum(FLT_MAX); setMaximum(FLT_MAX);
setSingleStep(0.01);
} }
DelegatingItemEditorFactory::DelegatingItemEditorFactory() : DelegatingItemEditorFactory::DelegatingItemEditorFactory() :
@ -127,6 +128,12 @@ static QItemEditorCreatorBase* createVec3EditorCreator() {
return creator; return creator;
} }
static QItemEditorCreatorBase* createQuatEditorCreator() {
QItemEditorCreatorBase* creator = new LazyItemEditorCreator<QuatEditor>();
getItemEditorFactory()->registerEditor(qMetaTypeId<glm::quat>(), creator);
return creator;
}
static QItemEditorCreatorBase* createParameterizedURLEditorCreator() { static QItemEditorCreatorBase* createParameterizedURLEditorCreator() {
QItemEditorCreatorBase* creator = new LazyItemEditorCreator<ParameterizedURLEditor>(); QItemEditorCreatorBase* creator = new LazyItemEditorCreator<ParameterizedURLEditor>();
getItemEditorFactory()->registerEditor(qMetaTypeId<ParameterizedURL>(), creator); getItemEditorFactory()->registerEditor(qMetaTypeId<ParameterizedURL>(), creator);
@ -138,6 +145,7 @@ static QItemEditorCreatorBase* qMetaObjectEditorCreator = createQMetaObjectEdito
static QItemEditorCreatorBase* qColorEditorCreator = createQColorEditorCreator(); static QItemEditorCreatorBase* qColorEditorCreator = createQColorEditorCreator();
static QItemEditorCreatorBase* qUrlEditorCreator = createQUrlEditorCreator(); static QItemEditorCreatorBase* qUrlEditorCreator = createQUrlEditorCreator();
static QItemEditorCreatorBase* vec3EditorCreator = createVec3EditorCreator(); static QItemEditorCreatorBase* vec3EditorCreator = createVec3EditorCreator();
static QItemEditorCreatorBase* quatEditorCreator = createQuatEditorCreator();
static QItemEditorCreatorBase* parameterizedURLEditorCreator = createParameterizedURLEditorCreator(); static QItemEditorCreatorBase* parameterizedURLEditorCreator = createParameterizedURLEditorCreator();
QByteArray signal(const char* signature) { QByteArray signal(const char* signature) {
@ -380,7 +388,7 @@ void QUrlEditor::updateSettings() {
QSettings().setValue("editorURLs", urls); QSettings().setValue("editorURLs", urls);
} }
Vec3Editor::Vec3Editor(QWidget* parent) : QWidget(parent) { BaseVec3Editor::BaseVec3Editor(QWidget* parent) : QWidget(parent) {
QHBoxLayout* layout = new QHBoxLayout(); QHBoxLayout* layout = new QHBoxLayout();
layout->setContentsMargins(QMargins()); layout->setContentsMargins(QMargins());
setLayout(layout); setLayout(layout);
@ -390,26 +398,59 @@ Vec3Editor::Vec3Editor(QWidget* parent) : QWidget(parent) {
layout->addWidget(_z = createComponentBox()); layout->addWidget(_z = createComponentBox());
} }
void Vec3Editor::setVector(const glm::vec3& vector) { QDoubleSpinBox* BaseVec3Editor::createComponentBox() {
_vector = vector;
_x->setValue(vector.x);
_y->setValue(vector.y);
_z->setValue(vector.z);
}
void Vec3Editor::updateVector() {
emit vectorChanged(_vector = glm::vec3(_x->value(), _y->value(), _z->value()));
}
QDoubleSpinBox* Vec3Editor::createComponentBox() {
QDoubleSpinBox* box = new QDoubleSpinBox(); QDoubleSpinBox* box = new QDoubleSpinBox();
box->setMinimum(-FLT_MAX); box->setMinimum(-FLT_MAX);
box->setMaximum(FLT_MAX); box->setMaximum(FLT_MAX);
box->setMinimumWidth(50); box->setMinimumWidth(50);
connect(box, SIGNAL(valueChanged(double)), SLOT(updateVector())); connect(box, SIGNAL(valueChanged(double)), SLOT(updateValue()));
return box; return box;
} }
Vec3Editor::Vec3Editor(QWidget* parent) : BaseVec3Editor(parent) {
_x->setSingleStep(0.01);
_y->setSingleStep(0.01);
_z->setSingleStep(0.01);
}
static void setComponentValue(QDoubleSpinBox* box, double value) {
box->blockSignals(true);
box->setValue(value);
box->blockSignals(false);
}
void Vec3Editor::setValue(const glm::vec3& value) {
_value = value;
setComponentValue(_x, value.x);
setComponentValue(_y, value.y);
setComponentValue(_z, value.z);
}
void Vec3Editor::updateValue() {
emit valueChanged(_value = glm::vec3(_x->value(), _y->value(), _z->value()));
}
QuatEditor::QuatEditor(QWidget* parent) : BaseVec3Editor(parent) {
_x->setRange(-180.0, 180.0);
_y->setRange(-90.0, 90.0);
_z->setRange(-180.0, 180.0);
_x->setWrapping(true);
_y->setWrapping(true);
_z->setWrapping(true);
}
void QuatEditor::setValue(const glm::quat& value) {
glm::vec3 eulers = glm::degrees(safeEulerAngles(_value = value));
setComponentValue(_x, eulers.x);
setComponentValue(_y, eulers.y);
setComponentValue(_z, eulers.z);
}
void QuatEditor::updateValue() {
emit valueChanged(_value = glm::quat(glm::radians(glm::vec3(_x->value(), _y->value(), _z->value()))));
}
ParameterizedURL::ParameterizedURL(const QUrl& url, const ScriptHash& parameters) : ParameterizedURL::ParameterizedURL(const QUrl& url, const ScriptHash& parameters) :
_url(url), _url(url),
_parameters(parameters) { _parameters(parameters) {

View file

@ -142,10 +142,31 @@ private:
QUrl _url; QUrl _url;
}; };
/// Editor for vector values. /// Base class for Vec3Editor and QuatEditor.
class Vec3Editor : public QWidget { class BaseVec3Editor : public QWidget {
Q_OBJECT Q_OBJECT
Q_PROPERTY(glm::vec3 vector MEMBER _vector WRITE setVector NOTIFY vectorChanged USER true)
public:
BaseVec3Editor(QWidget* parent);
protected slots:
virtual void updateValue() = 0;
protected:
QDoubleSpinBox* createComponentBox();
QDoubleSpinBox* _x;
QDoubleSpinBox* _y;
QDoubleSpinBox* _z;
};
/// Editor for vector values.
class Vec3Editor : public BaseVec3Editor {
Q_OBJECT
Q_PROPERTY(glm::vec3 value MEMBER _value WRITE setValue NOTIFY valueChanged USER true)
public: public:
@ -153,24 +174,45 @@ public:
signals: signals:
void vectorChanged(const glm::vec3& vector); void valueChanged(const glm::vec3& vector);
public slots: public slots:
void setVector(const glm::vec3& vector); void setValue(const glm::vec3& vector);
private slots: protected:
void updateVector(); virtual void updateValue();
private: private:
QDoubleSpinBox* createComponentBox(); glm::vec3 _value;
};
/// Editor for quaternion values.
class QuatEditor : public BaseVec3Editor {
Q_OBJECT
Q_PROPERTY(glm::quat value MEMBER _value WRITE setValue NOTIFY valueChanged USER true)
public:
QDoubleSpinBox* _x; QuatEditor(QWidget* parent);
QDoubleSpinBox* _y;
QDoubleSpinBox* _z; signals:
glm::vec3 _vector;
void valueChanged(const glm::quat& value);
public slots:
void setValue(const glm::quat& value);
protected:
virtual void updateValue();
private:
glm::quat _value;
}; };
typedef QHash<QScriptString, QVariant> ScriptHash; typedef QHash<QScriptString, QVariant> ScriptHash;