diff options
Diffstat (limited to 'src/runtime/q3dsqmlscript.cpp')
-rw-r--r-- | src/runtime/q3dsqmlscript.cpp | 742 |
1 files changed, 742 insertions, 0 deletions
diff --git a/src/runtime/q3dsqmlscript.cpp b/src/runtime/q3dsqmlscript.cpp new file mode 100644 index 0000000..725c752 --- /dev/null +++ b/src/runtime/q3dsqmlscript.cpp @@ -0,0 +1,742 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dsqmlscript.h" + +#include "Qt3DSQmlEngine.h" +#include "Qt3DSElementSystem.h" +#include "Qt3DSApplication.h" +#include "Qt3DSPresentation.h" +#include "Qt3DSInputEngine.h" +#include "Qt3DSInputFrame.h" +#include "Qt3DSQmlElementHelper.h" +#include "Qt3DSHash.h" +#include "Qt3DSEulerAngles.h" +#include "Qt3DSMathUtils.h" + +#include <QMetaProperty> + +using namespace Q3DStudio; +using namespace qt3ds::runtime; + +QJSValue argToQJSValue(qt3ds::foundation::IStringTable &strTable, + Q3DStudio::UINT8 type, const UVariant &value) { + switch (type) { + case ATTRIBUTETYPE_INT32: + case ATTRIBUTETYPE_HASH: + return QJSValue(value.m_INT32); + case ATTRIBUTETYPE_FLOAT: + return QJSValue(value.m_FLOAT); + case ATTRIBUTETYPE_BOOL: + return QJSValue(value.m_INT32 != 0); + case ATTRIBUTETYPE_STRING: + return QJSValue(strTable.HandleToStr(value.m_StringHandle)); + case ATTRIBUTETYPE_NONE: + return QJSValue(); + default: + qCCritical(qt3ds::INVALID_OPERATION) + << "Pushed event argument value of unknown type: "<< type; + } + return QJSValue(); +} + +void eventCallback(void *contextData, SEventCommand &event) +{ + auto data = static_cast<Q3DSQmlScript::EventData *>(contextData); + qt3ds::foundation::IStringTable &strTable( + event.m_Target->GetBelongedPresentation()->GetStringTable()); + QJSValue arg1 = argToQJSValue(strTable, event.m_Arg1Type, event.m_Arg1); + QJSValue arg2 = argToQJSValue(strTable, event.m_Arg2Type, event.m_Arg2); + data->function.call({arg1, arg2}); +} + +Q3DSQmlScript::Q3DSQmlScript(CQmlEngine &api, Q3DSQmlBehavior &object, + TElement &behavior, TElement &owner) + : QObject(nullptr) + , m_api(api) + , m_object(object) + , m_behavior(behavior) + , m_owner(owner) + , m_initialized(false) + , m_lastActivationState(false) + , m_deltaTime(0.0f) + , m_lastTime(0) +{ + qt3ds::foundation::IStringTable &strTable + = m_behavior.GetBelongedPresentation()->GetStringTable(); + const QMetaObject *meta = object.metaObject(); + for (int i = 0; i < meta->propertyCount(); ++i) { + QMetaProperty property = meta->property(i); + QVariant::Type t = property.type(); + if (static_cast<QMetaType::Type>(t) == QMetaType::QVariant) { + // detect type from behavior property + auto nameHash = CHash::HashAttribute(property.name()); + Option<element::TPropertyDescAndValuePtr> value = behavior.FindProperty(nameHash); + if (value.hasValue()) { + switch (value->first.m_Type) { + case ATTRIBUTETYPE_INT32: + case ATTRIBUTETYPE_HASH: + t = QVariant::Int; + break; + case ATTRIBUTETYPE_FLOAT: + t = QVariant::Double; + break; + case ATTRIBUTETYPE_BOOL: + t = QVariant::Bool; + break; + case ATTRIBUTETYPE_STRING: + t = QVariant::String; + break; + case ATTRIBUTETYPE_FLOAT4: + t = QVariant::Vector4D; + break; + case ATTRIBUTETYPE_FLOAT3: + t = QVariant::Vector3D; + break; + case ATTRIBUTETYPE_FLOAT2: + t = QVariant::Vector2D; + break; + default: + break; + } + } else { + // detect vectors + QByteArray name(property.name()); + QByteArray xname = name + QByteArrayLiteral(".x"); + Option<element::TPropertyDescAndValuePtr> xvalue + = behavior.FindProperty(CHash::HashAttribute(xname.data())); + QByteArray rname = name + QByteArrayLiteral(".r"); + Option<element::TPropertyDescAndValuePtr> rvalue + = behavior.FindProperty(CHash::HashAttribute(rname.data())); + if (xvalue.hasValue()) { + QByteArray yname = name + QByteArrayLiteral(".y"); + QByteArray zname = name + QByteArrayLiteral(".z"); + QByteArray wname = name + QByteArrayLiteral(".w"); + + Option<element::TPropertyDescAndValuePtr> yvalue + = behavior.FindProperty(CHash::HashAttribute(yname.data())); + Option<element::TPropertyDescAndValuePtr> zvalue + = behavior.FindProperty(CHash::HashAttribute(zname.data())); + Option<element::TPropertyDescAndValuePtr> wvalue + = behavior.FindProperty(CHash::HashAttribute(wname.data())); + int count = 1; + count += yvalue.hasValue() ? 1 : 0; + count += zvalue.hasValue() ? 1 : 0; + count += wvalue.hasValue() ? 1 : 0; + if (count == 2) + t = QVariant::Vector2D; + else if (count == 3) + t = QVariant::Vector3D; + else if (count == 4) + t = QVariant::Vector4D; + } else if (rvalue.hasValue()) { + QByteArray gname = name + QByteArrayLiteral(".g"); + QByteArray bname = name + QByteArrayLiteral(".b"); + QByteArray aname = name + QByteArrayLiteral(".a"); + Option<element::TPropertyDescAndValuePtr> gvalue + = behavior.FindProperty(CHash::HashAttribute(gname.data())); + Option<element::TPropertyDescAndValuePtr> bvalue + = behavior.FindProperty(CHash::HashAttribute(bname.data())); + Option<element::TPropertyDescAndValuePtr> avalue + = behavior.FindProperty(CHash::HashAttribute(aname.data())); + int count = 1; + count += gvalue.hasValue() ? 1 : 0; + count += bvalue.hasValue() ? 1 : 0; + count += avalue.hasValue() ? 1 : 0; + if (count == 2) + t = QVariant::Vector2D; + else if (count == 3) + t = QVariant::Vector3D; + else if (count == 4) + t = QVariant::Vector4D; + } + } + } + switch (t) { + case QVariant::Bool: { + const char *name = property.name(); + auto nameHash = CHash::HashAttribute(name); + Option<element::TPropertyDescAndValuePtr> value = behavior.FindProperty(nameHash); + if (value.hasValue()) { + std::function<void()> mapper = [&object, property, value]() -> void { + Q3DStudio::UVariant *val = value->second; + property.write(&object, QVariant::fromValue<bool>(val->m_INT32 > 0)); + }; + m_mappedProperties.push_back(mapper); + } + } break; + case QVariant::Int: + case QVariant::UInt: + case QVariant::LongLong: + case QVariant::ULongLong: { + const char *name = property.name(); + auto nameHash = CHash::HashAttribute(name); + Option<element::TPropertyDescAndValuePtr> value = behavior.FindProperty(nameHash); + if (value.hasValue()) { + std::function<void()> mapper = [&object, property, value]() { + Q3DStudio::UVariant *val = value->second; + property.write(&object, QVariant::fromValue(val->m_INT32)); + }; + m_mappedProperties.push_back(mapper); + } + } break; + case QVariant::Double: { + const char *name = property.name(); + auto nameHash = CHash::HashAttribute(name); + Option<element::TPropertyDescAndValuePtr> value = behavior.FindProperty(nameHash); + if (value.hasValue()) { + std::function<void()> mapper = [&object, property, value]() { + Q3DStudio::UVariant *val = value->second; + property.write(&object, QVariant::fromValue(val->m_FLOAT)); + }; + m_mappedProperties.push_back(mapper); + } + } break; + case QVariant::String: { + const char *name = property.name(); + auto nameHash = CHash::HashAttribute(name); + Option<element::TPropertyDescAndValuePtr> value = behavior.FindProperty(nameHash); + if (value.hasValue()) { + std::function<void()> mapper = [&object, property, value, &strTable]() { + Q3DStudio::UVariant *val = value->second; + property.write(&object, QVariant::fromValue( + QString::fromUtf8(strTable.HandleToStr(val->m_StringHandle).c_str()))); + }; + m_mappedProperties.push_back(mapper); + } + } break; + case QVariant::Vector2D: { + std::function<void()> mapper; + auto nameHash = CHash::HashAttribute(property.name()); + Option<element::TPropertyDescAndValuePtr> prop = behavior.FindProperty(nameHash); + if (prop.hasValue() && prop->first.m_Type == Q3DStudio::ATTRIBUTETYPE_FLOAT2) { + mapper = [&object, property, prop]() { + QVector2D vec; + Q3DStudio::UVariant *value = prop->second; + vec.setX(value->m_FLOAT3[0]); + vec.setY(value->m_FLOAT3[1]); + property.write(&object, QVariant::fromValue(vec)); + }; + m_mappedProperties.push_back(mapper); + } else { + QByteArray name(property.name()); + QByteArray cname = name + QByteArrayLiteral(".x"); + auto nameHash = CHash::HashAttribute(cname.data()); + Option<element::TPropertyDescAndValuePtr> xvalue = behavior.FindProperty(nameHash); + if (xvalue.hasValue()) { + cname = name + QByteArrayLiteral(".y"); + nameHash = CHash::HashAttribute(cname.data()); + Option<element::TPropertyDescAndValuePtr> yvalue + = behavior.FindProperty(nameHash); + + if (xvalue.hasValue() && yvalue.hasValue()) { + mapper = [&object, property, xvalue, yvalue]() { + QVector2D vec; + vec.setX(xvalue->second->m_FLOAT); + vec.setY(yvalue->second->m_FLOAT); + property.write(&object, QVariant::fromValue(vec)); + }; + m_mappedProperties.push_back(mapper); + } + } + } + } break; + case QVariant::Vector3D: { + std::function<void()> mapper; + auto nameHash = CHash::HashAttribute(property.name()); + Option<element::TPropertyDescAndValuePtr> prop = behavior.FindProperty(nameHash); + if (prop.hasValue() && prop->first.m_Type == Q3DStudio::ATTRIBUTETYPE_FLOAT3) { + mapper = [&object, property, prop]() { + QVector3D vec; + Q3DStudio::UVariant *value = prop->second; + vec.setX(value->m_FLOAT3[0]); + vec.setY(value->m_FLOAT3[1]); + vec.setZ(value->m_FLOAT3[2]); + property.write(&object, QVariant::fromValue(vec)); + }; + m_mappedProperties.push_back(mapper); + } else { + QByteArray name(property.name()); + QByteArray cname = name + QByteArrayLiteral(".x"); + auto nameHash = CHash::HashAttribute(cname.data()); + Option<element::TPropertyDescAndValuePtr> xvalue = behavior.FindProperty(nameHash); + if (xvalue.hasValue()) { + cname = name + QByteArrayLiteral(".y"); + nameHash = CHash::HashAttribute(cname.data()); + Option<element::TPropertyDescAndValuePtr> yvalue + = behavior.FindProperty(nameHash); + cname = name + QByteArrayLiteral(".z"); + nameHash = CHash::HashAttribute(cname.data()); + Option<element::TPropertyDescAndValuePtr> zvalue + = behavior.FindProperty(nameHash); + + if (xvalue.hasValue() && yvalue.hasValue() && zvalue.hasValue()) { + mapper = [&object, property, xvalue, yvalue, zvalue]() { + QVector3D vec; + vec.setX(xvalue->second->m_FLOAT); + vec.setY(yvalue->second->m_FLOAT); + vec.setZ(zvalue->second->m_FLOAT); + property.write(&object, QVariant::fromValue(vec)); + }; + m_mappedProperties.push_back(mapper); + } + } + } + } break; + case QVariant::Color: + case QVariant::Vector4D: { + std::function<void()> mapper; + auto nameHash = CHash::HashAttribute(property.name()); + Option<element::TPropertyDescAndValuePtr> prop = behavior.FindProperty(nameHash); + if (prop.hasValue() && prop->first.m_Type == Q3DStudio::ATTRIBUTETYPE_FLOAT4) { + mapper = [&object, property, prop]() { + QVector4D vec; + Q3DStudio::UVariant *value = prop->second; + vec.setX(value->m_FLOAT4[0]); + vec.setY(value->m_FLOAT4[1]); + vec.setZ(value->m_FLOAT4[2]); + vec.setW(value->m_FLOAT4[3]); + property.write(&object, QVariant::fromValue(vec)); + }; + m_mappedProperties.push_back(mapper); + } else { + QByteArray name(property.name()); + QByteArray cname = name + QByteArrayLiteral(".x"); + auto nameHash = CHash::HashAttribute(cname.data()); + Option<element::TPropertyDescAndValuePtr> xvalue = behavior.FindProperty(nameHash); + if (xvalue.hasValue()) { + cname = name + QByteArrayLiteral(".y"); + nameHash = CHash::HashAttribute(cname.data()); + Option<element::TPropertyDescAndValuePtr> yvalue + = behavior.FindProperty(nameHash); + cname = name + QByteArrayLiteral(".z"); + nameHash = CHash::HashAttribute(cname.data()); + Option<element::TPropertyDescAndValuePtr> zvalue + = behavior.FindProperty(nameHash); + cname = name + QByteArrayLiteral(".w"); + nameHash = CHash::HashAttribute(cname.data()); + Option<element::TPropertyDescAndValuePtr> wvalue + = behavior.FindProperty(nameHash); + + if (xvalue.hasValue() && yvalue.hasValue() && zvalue.hasValue() + && wvalue.hasValue()) { + mapper = [&object, property, xvalue, yvalue, zvalue, wvalue]() { + QVector4D vec; + vec.setX(xvalue->second->m_FLOAT); + vec.setY(yvalue->second->m_FLOAT); + vec.setZ(zvalue->second->m_FLOAT); + vec.setW(wvalue->second->m_FLOAT); + property.write(&object, QVariant::fromValue(vec)); + }; + m_mappedProperties.push_back(mapper); + } + } else { + cname = name + QByteArrayLiteral(".r"); + auto nameHash = CHash::HashAttribute(cname.data()); + Option<element::TPropertyDescAndValuePtr> rvalue + = behavior.FindProperty(nameHash); + if (rvalue.hasValue()) { + cname = name + QByteArrayLiteral(".g"); + nameHash = CHash::HashAttribute(cname.data()); + Option<element::TPropertyDescAndValuePtr> gvalue + = behavior.FindProperty(nameHash); + cname = name + QByteArrayLiteral(".b"); + nameHash = CHash::HashAttribute(cname.data()); + Option<element::TPropertyDescAndValuePtr> bvalue + = behavior.FindProperty(nameHash); + cname = name + QByteArrayLiteral(".a"); + nameHash = CHash::HashAttribute(cname.data()); + Option<element::TPropertyDescAndValuePtr> avalue + = behavior.FindProperty(nameHash); + + if (rvalue.hasValue() && gvalue.hasValue() && bvalue.hasValue() + && avalue.hasValue()) { + mapper = [&object, property, rvalue, gvalue, bvalue, avalue]() { + QVector4D vec; + vec.setX(rvalue->second->m_FLOAT); + vec.setY(gvalue->second->m_FLOAT); + vec.setZ(bvalue->second->m_FLOAT); + vec.setW(avalue->second->m_FLOAT); + property.write(&object, QVariant::fromValue(vec)); + }; + m_mappedProperties.push_back(mapper); + } + } + } + } + } break; + default: + break; + } + } +} + +Q3DSQmlScript::~Q3DSQmlScript() +{ + for (const EventCallbackInfo &callback : m_eventCallbacks) + delete callback.data; +} + +void Q3DSQmlScript::update() +{ + updateProperties(); + + bool active = m_behavior.GetActive(); + + if (active && !m_initialized) { + m_initialized = true; + Q_EMIT m_object.initialize(); + } + + TTimeUnit time = static_cast<CPresentation *>(m_behavior.GetBelongedPresentation())->GetTime(); + m_deltaTime = (time - m_lastTime) / 1000.0f; + m_lastTime = time; + + if (m_lastActivationState != active) { + if (active) + Q_EMIT m_object.activate(); + else + Q_EMIT m_object.deactivate(); + } + m_lastActivationState = active; + if (active) + Q_EMIT m_object.update(); +} + +void Q3DSQmlScript::call(const QString &function) +{ + const QMetaObject *meta = m_object.metaObject(); + const QString normalized = function + "()"; + if (meta->indexOfMethod(normalized.toUtf8().constData()) != -1) + QMetaObject::invokeMethod(&m_object, function.toUtf8().constData()); +} + +void Q3DSQmlScript::updateProperties() +{ + using namespace qt3ds::foundation; + using namespace qt3ds::runtime::element; + + if (!m_behavior.GetActive() || !m_behavior.IsDirty()) + return; + + for (auto m : qAsConst(m_mappedProperties)) + m(); +} + +bool Q3DSQmlScript::hasBehavior(const TElement *behavior) +{ + return &m_behavior == behavior; +} + +float Q3DSQmlScript::getDeltaTime() +{ + return m_deltaTime; +} + +float Q3DSQmlScript::getAttribute(const QString &attribute) +{ + if (!m_behavior.GetActive()) + return 0; + + float floatValue = 0; + m_api.GetAttribute(&m_owner, + attribute.toUtf8().constData(), + (char *)&floatValue); + return floatValue; +} + +void Q3DSQmlScript::setAttribute(const QString &attribute, const QVariant &value) +{ + setAttribute("", attribute, value); +} + +void Q3DSQmlScript::setAttribute(const QString &handle, const QString &attribute, + const QVariant &value) +{ + if (!m_behavior.GetActive()) + return; + + TElement *element = &m_owner; + if (!handle.isEmpty()) + element = getElementByPath(handle); + if (!element) + return; + + QByteArray valueStr; + float valueFloat; + + const char *valuePtr = nullptr; + switch (static_cast<QMetaType::Type>(value.type())) { + case QMetaType::Bool: + case QMetaType::Int: + case QMetaType::Double: + case QMetaType::Float: + valueFloat = value.toFloat(); + valuePtr = reinterpret_cast<const char *>(&valueFloat); + break; + case QMetaType::QVector2D: { + QVector2D vec = value.value<QVector2D>(); + float val[2]; + val[0] = vec.x(); + val[1] = vec.y(); + const QByteArray name = attribute.toUtf8(); + QByteArray cname = name + QByteArrayLiteral(".x"); + m_api.SetAttribute(element, cname.constData(), reinterpret_cast<const char *>(val)); + cname = name + QByteArrayLiteral(".y"); + m_api.SetAttribute(element, cname.constData(), reinterpret_cast<const char *>(val + 1)); + return; + } + case QMetaType::QVector3D: { + QVector3D vec = value.value<QVector3D>(); + float val[3]; + val[0] = vec.x(); + val[1] = vec.y(); + val[2] = vec.z(); + const QByteArray name = attribute.toUtf8(); + QByteArray cname = name + QByteArrayLiteral(".x"); + m_api.SetAttribute(element, cname.constData(), reinterpret_cast<const char *>(val)); + cname = name + QByteArrayLiteral(".y"); + m_api.SetAttribute(element, cname.constData(), reinterpret_cast<const char *>(val + 1)); + cname = name + QByteArrayLiteral(".z"); + m_api.SetAttribute(element, cname.constData(), reinterpret_cast<const char *>(val + 2)); + return; + } + case QMetaType::QColor: + case QMetaType::QVector4D: { + QVector4D vec = value.value<QVector4D>(); + float val[4]; + val[0] = vec.x(); + val[1] = vec.y(); + val[2] = vec.z(); + val[3] = vec.w(); + const QByteArray name = attribute.toUtf8(); + QByteArray cname = name + QByteArrayLiteral(".x"); + if (m_api.GetAttribute(element, cname.constData(), reinterpret_cast<char *>(&valueFloat))) { + m_api.SetAttribute(element, cname.constData(), reinterpret_cast<const char *>(val)); + cname = name + QByteArrayLiteral(".y"); + m_api.SetAttribute(element, cname.constData(), reinterpret_cast<const char *>(val + 1)); + cname = name + QByteArrayLiteral(".z"); + m_api.SetAttribute(element, cname.constData(), reinterpret_cast<const char *>(val + 2)); + cname = name + QByteArrayLiteral(".w"); + m_api.SetAttribute(element, cname.constData(), reinterpret_cast<const char *>(val + 3)); + } else { + QByteArray cname = name + QByteArrayLiteral(".r"); + if (m_api.GetAttribute(element, cname.constData(), + reinterpret_cast<char *>(&valueFloat))) { + m_api.SetAttribute(element, cname.constData(), + reinterpret_cast<const char *>(val)); + cname = name + QByteArrayLiteral(".g"); + m_api.SetAttribute(element, cname.constData(), + reinterpret_cast<const char *>(val + 1)); + cname = name + QByteArrayLiteral(".b"); + m_api.SetAttribute(element, cname.constData(), + reinterpret_cast<const char *>(val + 2)); + cname = name + QByteArrayLiteral(".a"); + m_api.SetAttribute(element, cname.constData(), + reinterpret_cast<const char *>(val + 3)); + } + } + return; + } + case QMetaType::QString: + default: + valueStr = value.toString().toUtf8(); + valuePtr = valueStr.constData(); + break; + } + + m_api.SetAttribute(element, attribute.toUtf8().constData(), valuePtr); +} + +void Q3DSQmlScript::fireEvent(const QString &event) +{ + if (!m_behavior.GetActive()) + return; + m_api.FireEvent(m_behavior.m_Path, event.toUtf8().constData()); +} + +void Q3DSQmlScript::registerForEvent(const QString &event, const QJSValue &function) +{ + registerForEvent("", event, function); +} + +void Q3DSQmlScript::registerForEvent(const QString &handle, const QString &event, + const QJSValue &function) +{ + if (!m_behavior.GetActive()) + return; + + TElement *element = &m_owner; + if (!handle.isEmpty()) + element = getElementByPath(handle); + if (!element) + return; + + if (!function.isCallable()) + return; + + CPresentation *presentation + = static_cast<CPresentation *>(m_behavior.GetBelongedPresentation()); + TEventCommandHash eventHash = CHash::HashEventCommand(event.toUtf8().constData()); + + for (auto &&callback : m_eventCallbacks) { + if (callback.element == element && callback.eventHash == eventHash) + return; + } + + EventData *data = new EventData(); + data->function = function; + + m_eventCallbacks.push_back({element, eventHash, data}); + + presentation->RegisterEventCallback(element, eventHash, &eventCallback, data); +} + +void Q3DSQmlScript::unregisterForEvent(const QString &event) +{ + unregisterForEvent("", event); +} + +void Q3DSQmlScript::unregisterForEvent(const QString &handle, const QString &event) +{ + if (!m_behavior.GetActive()) + return; + + TElement *element = &m_owner; + if (!handle.isEmpty()) + element = getElementByPath(handle); + if (!element) + return; + + CPresentation *presentation + = static_cast<CPresentation *>(m_behavior.GetBelongedPresentation()); + TEventCommandHash eventHash = CHash::HashEventCommand(event.toUtf8().constData()); + EventData *data = nullptr; + + for (int i = 0; i < m_eventCallbacks.size(); ++i) { + if (m_eventCallbacks[i].element == element && m_eventCallbacks[i].eventHash == eventHash) { + data = m_eventCallbacks[i].data; + m_eventCallbacks.erase(m_eventCallbacks.begin() + i); + break; + } + } + + if (data) { + presentation->UnregisterEventCallback(element, eventHash, &eventCallback, data); + delete data; + } +} + +QVector2D Q3DSQmlScript::getMousePosition() +{ + CPresentation *presentation + = static_cast<CPresentation *>(m_behavior.GetBelongedPresentation()); + qt3ds::runtime::IApplication &app = presentation->GetApplication(); + + SInputFrame input = app.GetInputEngine().GetInputFrame(); + if (app.GetPrimaryPresentation()) { + Q3DStudio::SMousePosition position = + app.GetPrimaryPresentation()->GetScene()->WindowToPresentation( + Q3DStudio::SMousePosition(static_cast<INT32>(input.m_PickX), + static_cast<INT32>(input.m_PickY))); + + return QVector2D(position.m_X, position.m_Y); + } + return QVector2D(0, 0); +} + +QMatrix4x4 Q3DSQmlScript::calculateGlobalTransform(const QString &handle) +{ + TElement *element = &m_owner; + if (!handle.isEmpty()) + element = getElementByPath(handle); + if (!element) + return QMatrix4x4(); + + RuntimeMatrix transform; + IScene *scene = element->GetBelongedPresentation()->GetScene(); + scene->CalculateGlobalTransform(element, transform); + transform.FlipCoordinateSystem(); + + return QMatrix4x4(&transform.m_Data[0][0]); +} + +QVector3D Q3DSQmlScript::lookAt(const QVector3D &target) +{ + FLOAT theMag = ::sqrtf(target.x() * target.x() + target.z() * target.z()); + FLOAT thePitch = -::atan2f(target.y(), theMag); + FLOAT theYaw = ::atan2f(target.x(), target.z()); + + return QVector3D(radToDeg(thePitch), radToDeg(theYaw), 0.0f); +} + +QVector3D Q3DSQmlScript::matrixToEuler(const QMatrix4x4 &matrix) +{ + CEulerAngleConverter converter; + const float *qMatrix = matrix.constData(); + HMatrix hHatrix; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) + hHatrix[i][j] = qMatrix[j * 4 + i]; + } + EulerAngles eulerAngles = converter.Eul_FromHMatrix(hHatrix, EulOrdYXZs); + return QVector3D(-eulerAngles.y, -eulerAngles.x, -eulerAngles.z); +} + +QString Q3DSQmlScript::getParent(const QString &handle) +{ + TElement *element = &m_owner; + if (!handle.isEmpty()) + element = getElementByPath(handle); + if (!element) + return ""; + + TElement *parent = element->GetParent(); + if (!parent) + return ""; + return parent->m_Path.c_str(); +} + +void Q3DSQmlScript::setDataInputValue(const QString &name, const QVariant &value, + qt3ds::runtime::DataInputValueRole valueRole) +{ + m_api.SetDataInputValue(name, value, valueRole); +} + +TElement *Q3DSQmlScript::getElementByPath(const QString &path) +{ + if (!m_api.GetApplication()) + return nullptr; + + TElement *element = CQmlElementHelper::GetElement( + *m_api.GetApplication(), + m_api.GetApplication()->GetPrimaryPresentation(), + path.toUtf8().constData(), &m_owner); + return element; +} |